From 970ad7ccfbd2d074ba1193021968324c546758a1 Mon Sep 17 00:00:00 2001 From: krlmlr Date: Thu, 21 Nov 2024 17:50:18 +0000 Subject: [PATCH] chore: Update vendored sources to duckdb/duckdb@059ac75f6225fde78b686bc85f23d2e70af1dbe0 Merge feature into main (duckdb/duckdb#14690) --- src/Makevars | 2 +- src/Makevars.win | 2 +- .../extension/parquet/column_reader.cpp | 187 +- .../extension/parquet/column_writer.cpp | 242 +- src/duckdb/extension/parquet/geo_parquet.cpp | 9 +- .../parquet/include/boolean_column_reader.hpp | 4 - .../parquet/include/column_reader.hpp | 38 +- .../parquet/include/column_writer.hpp | 10 +- .../parquet/include/decode_utils.hpp | 140 +- .../extension/parquet/include/geo_parquet.hpp | 7 +- .../parquet/include/null_column_reader.hpp | 15 +- .../parquet/include/parquet_crypto.hpp | 2 +- .../parquet/include/parquet_dbp_decoder.hpp | 191 +- .../parquet/include/parquet_dbp_encoder.hpp | 179 + .../parquet/include/parquet_decimal_utils.hpp | 5 +- .../parquet/include/parquet_extension.hpp | 8 + .../include/parquet_file_metadata_cache.hpp | 4 +- .../parquet/include/parquet_reader.hpp | 6 +- .../parquet/include/parquet_statistics.hpp | 14 +- .../parquet/include/parquet_writer.hpp | 24 +- .../parquet/include/resizable_buffer.hpp | 1 + .../parquet/include/string_column_reader.hpp | 8 - .../include/templated_column_reader.hpp | 43 +- .../parquet/include/thrift_tools.hpp | 9 + .../parquet/include/zstd_file_system.hpp | 4 + .../extension/parquet/parquet_extension.cpp | 97 +- .../extension/parquet/parquet_metadata.cpp | 8 +- .../extension/parquet/parquet_reader.cpp | 81 +- .../extension/parquet/parquet_statistics.cpp | 17 +- .../extension/parquet/parquet_writer.cpp | 48 +- .../extension/parquet/zstd_file_system.cpp | 13 + src/duckdb/src/catalog/catalog.cpp | 337 +- src/duckdb/src/catalog/catalog_entry.cpp | 3 + .../catalog_entry/duck_index_entry.cpp | 13 +- .../catalog_entry/duck_schema_entry.cpp | 3 + .../catalog_entry/duck_table_entry.cpp | 228 +- .../scalar_function_catalog_entry.cpp | 14 +- .../catalog_entry/table_catalog_entry.cpp | 34 + .../table_function_catalog_entry.cpp | 2 +- .../src/catalog/catalog_entry_retriever.cpp | 65 +- .../src/catalog/catalog_search_path.cpp | 23 +- src/duckdb/src/catalog/catalog_set.cpp | 1 + .../src/catalog/default/default_functions.cpp | 8 +- src/duckdb/src/catalog/dependency_manager.cpp | 48 + src/duckdb/src/catalog/duck_catalog.cpp | 10 +- .../src/common/arrow/arrow_merge_event.cpp | 2 +- src/duckdb/src/common/enum_util.cpp | 9496 ++---- src/duckdb/src/common/enums/metric_type.cpp | 8 + .../src/common/enums/optimizer_type.cpp | 2 + .../common/enums/physical_operator_type.cpp | 2 + src/duckdb/src/common/local_file_system.cpp | 4 +- src/duckdb/src/common/multi_file_reader.cpp | 53 +- src/duckdb/src/common/opener_file_system.cpp | 37 + src/duckdb/src/common/radix_partitioning.cpp | 5 +- src/duckdb/src/common/random_engine.cpp | 18 +- src/duckdb/src/common/render_tree.cpp | 22 +- .../src/common/sort/partition_state.cpp | 4 +- src/duckdb/src/common/string_util.cpp | 63 +- src/duckdb/src/common/types.cpp | 2 +- .../types/column/column_data_allocator.cpp | 4 + .../types/column/column_data_collection.cpp | 66 +- .../column/column_data_collection_segment.cpp | 27 +- .../types/row/partitioned_tuple_data.cpp | 15 +- .../common/types/row/tuple_data_allocator.cpp | 14 + .../types/row/tuple_data_collection.cpp | 7 + src/duckdb/src/common/types/validity_mask.cpp | 4 + src/duckdb/src/common/types/value.cpp | 7 +- .../vector_operations/is_distinct_from.cpp | 66 +- .../aggregate/algebraic/avg.cpp | 196 - .../aggregate/algebraic/corr.cpp | 13 - .../aggregate/algebraic/covar.cpp | 17 - .../aggregate/algebraic/stddev.cpp | 34 - .../aggregate/distributive/approx_count.cpp | 99 - .../aggregate/distributive/arg_min_max.cpp | 694 - .../aggregate/distributive/bitagg.cpp | 231 - .../aggregate/distributive/bitstring_agg.cpp | 322 - .../aggregate/distributive/bool.cpp | 108 - .../aggregate/distributive/entropy.cpp | 183 - .../aggregate/distributive/kurtosis.cpp | 113 - .../aggregate/distributive/product.cpp | 61 - .../aggregate/distributive/skew.cpp | 86 - .../aggregate/distributive/string_agg.cpp | 175 - .../aggregate/distributive/sum.cpp | 234 - .../aggregate/holistic/approx_top_k.cpp | 413 - .../holistic/approximate_quantile.cpp | 408 - .../core_functions/aggregate/holistic/mad.cpp | 330 - .../aggregate/holistic/mode.cpp | 429 - .../aggregate/holistic/quantile.cpp | 846 - .../aggregate/holistic/reservoir_quantile.cpp | 449 - .../aggregate/nested/binned_histogram.cpp | 405 - .../aggregate/nested/histogram.cpp | 234 - .../core_functions/aggregate/nested/list.cpp | 212 - .../aggregate/regression/regr_avg.cpp | 64 - .../aggregate/regression/regr_count.cpp | 18 - .../aggregate/regression/regr_intercept.cpp | 63 - .../aggregate/regression/regr_r2.cpp | 72 - .../aggregate/regression/regr_slope.cpp | 20 - .../aggregate/regression/regr_sxx_syy.cpp | 75 - .../aggregate/regression/regr_sxy.cpp | 53 - .../src/core_functions/function_list.cpp | 428 - .../src/core_functions/lambda_functions.cpp | 414 - .../scalar/array/array_functions.cpp | 273 - .../scalar/array/array_value.cpp | 87 - .../core_functions/scalar/bit/bitstring.cpp | 115 - .../src/core_functions/scalar/blob/base64.cpp | 45 - .../src/core_functions/scalar/blob/encode.cpp | 40 - .../src/core_functions/scalar/date/age.cpp | 49 - .../core_functions/scalar/date/current.cpp | 54 - .../core_functions/scalar/date/date_diff.cpp | 454 - .../core_functions/scalar/date/date_part.cpp | 2230 -- .../core_functions/scalar/date/date_sub.cpp | 454 - .../core_functions/scalar/date/date_trunc.cpp | 734 - .../src/core_functions/scalar/date/epoch.cpp | 48 - .../core_functions/scalar/date/make_date.cpp | 146 - .../scalar/date/time_bucket.cpp | 370 - .../scalar/date/to_interval.cpp | 232 - .../scalar/debug/vector_type.cpp | 24 - .../scalar/enum/enum_functions.cpp | 169 - .../core_functions/scalar/generic/alias.cpp | 18 - .../scalar/generic/can_implicitly_cast.cpp | 40 - .../scalar/generic/current_setting.cpp | 68 - .../core_functions/scalar/generic/hash.cpp | 19 - .../core_functions/scalar/generic/least.cpp | 239 - .../core_functions/scalar/generic/stats.cpp | 54 - .../scalar/generic/system_functions.cpp | 148 - .../core_functions/scalar/generic/typeof.cpp | 29 - .../scalar/list/array_slice.cpp | 455 - .../core_functions/scalar/list/flatten.cpp | 171 - .../scalar/list/list_aggregates.cpp | 530 - .../scalar/list/list_distance.cpp | 125 - .../scalar/list/list_filter.cpp | 49 - .../scalar/list/list_has_any_or_all.cpp | 227 - .../scalar/list/list_reduce.cpp | 232 - .../core_functions/scalar/list/list_sort.cpp | 416 - .../scalar/list/list_transform.cpp | 41 - .../core_functions/scalar/list/list_value.cpp | 203 - .../src/core_functions/scalar/list/range.cpp | 275 - .../core_functions/scalar/map/cardinality.cpp | 50 - .../src/core_functions/scalar/map/map.cpp | 222 - .../core_functions/scalar/map/map_concat.cpp | 200 - .../core_functions/scalar/map/map_entries.cpp | 79 - .../core_functions/scalar/map/map_extract.cpp | 116 - .../scalar/map/map_from_entries.cpp | 59 - .../scalar/map/map_keys_values.cpp | 110 - .../core_functions/scalar/math/numeric.cpp | 1423 - .../scalar/operators/bitwise.cpp | 312 - .../core_functions/scalar/random/random.cpp | 63 - .../core_functions/scalar/random/setseed.cpp | 61 - .../core_functions/scalar/string/ascii.cpp | 24 - .../src/core_functions/scalar/string/bar.cpp | 98 - .../src/core_functions/scalar/string/chr.cpp | 48 - .../scalar/string/damerau_levenshtein.cpp | 104 - .../scalar/string/format_bytes.cpp | 34 - .../core_functions/scalar/string/hamming.cpp | 45 - .../src/core_functions/scalar/string/hex.cpp | 436 - .../core_functions/scalar/string/instr.cpp | 58 - .../core_functions/scalar/string/jaccard.cpp | 58 - .../scalar/string/jaro_winkler.cpp | 71 - .../scalar/string/left_right.cpp | 100 - .../scalar/string/levenshtein.cpp | 84 - .../src/core_functions/scalar/string/pad.cpp | 143 - .../scalar/string/parse_path.cpp | 348 - .../core_functions/scalar/string/printf.cpp | 187 - .../core_functions/scalar/string/repeat.cpp | 87 - .../core_functions/scalar/string/replace.cpp | 84 - .../core_functions/scalar/string/reverse.cpp | 55 - .../scalar/string/starts_with.cpp | 44 - .../core_functions/scalar/string/to_base.cpp | 66 - .../scalar/string/translate.cpp | 96 - .../src/core_functions/scalar/string/trim.cpp | 158 - .../core_functions/scalar/string/unicode.cpp | 28 - .../scalar/string/url_encode.cpp | 49 - .../scalar/struct/struct_insert.cpp | 109 - .../scalar/union/union_extract.cpp | 108 - .../core_functions/scalar/union/union_tag.cpp | 58 - .../scalar/union/union_value.cpp | 68 - .../src/execution/aggregate_hashtable.cpp | 13 +- .../src/execution/expression_executor.cpp | 2 + .../expression_executor/execute_between.cpp | 6 + .../src/execution/index/art/plan_art.cpp | 105 +- src/duckdb/src/execution/join_hashtable.cpp | 18 +- .../physical_partitioned_aggregate.cpp | 226 + .../physical_ungrouped_aggregate.cpp | 147 +- .../operator/aggregate/physical_window.cpp | 117 +- .../buffer_manager/csv_buffer_manager.cpp | 7 + .../csv_scanner/scanner/scanner_boundary.cpp | 8 + .../scanner/string_value_scanner.cpp | 264 +- .../csv_scanner/sniffer/csv_sniffer.cpp | 5 + .../csv_scanner/sniffer/dialect_detection.cpp | 64 +- .../state_machine/csv_state_machine_cache.cpp | 13 +- .../table_function/global_csv_state.cpp | 14 +- .../csv_scanner/util/csv_validator.cpp | 63 + .../helper/physical_reservoir_sample.cpp | 11 +- .../operator/helper/physical_set.cpp | 2 +- .../operator/helper/physical_vacuum.cpp | 5 +- .../join/perfect_hash_join_executor.cpp | 15 +- .../join/physical_blockwise_nl_join.cpp | 119 +- .../operator/join/physical_hash_join.cpp | 209 +- .../operator/join/physical_iejoin.cpp | 78 +- .../operator/join/physical_range_join.cpp | 1 - .../operator/order/physical_order.cpp | 10 +- .../operator/order/physical_top_n.cpp | 450 +- .../persistent/physical_batch_insert.cpp | 22 +- .../operator/persistent/physical_export.cpp | 39 +- .../operator/persistent/physical_insert.cpp | 12 +- .../scan/physical_positional_scan.cpp | 8 + .../operator/scan/physical_table_scan.cpp | 30 +- .../operator/schema/physical_alter.cpp | 1 - .../operator/schema/physical_attach.cpp | 12 +- .../schema/physical_create_art_index.cpp | 69 +- .../execution/operator/set/physical_union.cpp | 6 +- .../src/execution/physical_operator.cpp | 18 +- .../physical_plan/plan_aggregate.cpp | 113 +- .../physical_plan/plan_comparison_join.cpp | 36 +- .../physical_plan/plan_create_index.cpp | 24 +- .../execution/physical_plan/plan_distinct.cpp | 7 +- .../execution/physical_plan/plan_export.cpp | 4 - .../execution/physical_plan/plan_filter.cpp | 2 +- .../execution/physical_plan/plan_order.cpp | 14 +- .../execution/physical_plan/plan_sample.cpp | 11 +- .../execution/physical_plan/plan_simple.cpp | 3 +- .../execution/radix_partitioned_hashtable.cpp | 63 +- src/duckdb/src/execution/window_executor.cpp | 1460 +- .../src/execution/window_segment_tree.cpp | 476 +- .../function/aggregate/distributive/count.cpp | 18 +- .../{first.cpp => first_last_any.cpp} | 37 +- .../aggregate/distributive/minmax.cpp | 30 +- .../aggregate/distributive_functions.cpp | 15 - .../aggregate/sorted_aggregate_function.cpp | 3 +- .../src/function/built_in_functions.cpp | 87 +- src/duckdb/src/function/function.cpp | 14 +- src/duckdb/src/function/function_list.cpp | 174 + .../src/function/pragma/pragma_queries.cpp | 4 - .../register_function_list.cpp} | 13 +- .../compress_integral.cpp | 67 +- .../compress_string.cpp | 39 +- .../compressed_materialization_functions.cpp | 29 - .../compressed_materialization_utils.cpp | 21 + .../scalar}/create_sort_key.cpp | 16 +- .../scalar/date/strftime.cpp | 8 +- .../src/function/scalar/generic/binning.cpp | 507 - .../scalar/generic/constant_or_null.cpp | 12 +- .../scalar/generic/error.cpp | 3 +- .../function/scalar/generic/getvariable.cpp | 4 +- .../src/function/scalar/generic_functions.cpp | 11 - .../scalar/list/contains_or_position.cpp | 8 +- .../src/function/scalar/list/list_extract.cpp | 47 +- .../src/function/scalar/list/list_resize.cpp | 16 +- .../src/function/scalar/list/list_select.cpp | 5 +- .../src/function/scalar/list/list_zip.cpp | 4 +- .../scalar/map/map_contains.cpp | 4 +- .../src/function/scalar/nested_functions.cpp | 11 - .../scalar/{operators => operator}/add.cpp | 0 .../{operators => operator}/arithmetic.cpp | 127 +- .../{operators => operator}/multiply.cpp | 0 .../{operators => operator}/subtract.cpp | 0 src/duckdb/src/function/scalar/operators.cpp | 14 - .../src/function/scalar/sequence/nextval.cpp | 9 +- .../function/scalar/sequence_functions.cpp | 10 - .../function/scalar/string/caseconvert.cpp | 52 +- .../src/function/scalar/string/concat.cpp | 42 +- .../src/function/scalar/string/concat_ws.cpp | 4 +- .../src/function/scalar/string/contains.cpp | 34 +- .../src/function/scalar/string/length.cpp | 49 +- .../src/function/scalar/string/like.cpp | 94 +- .../scalar/string/md5.cpp | 4 +- .../function/scalar/string/nfc_normalize.cpp | 8 +- .../src/function/scalar/string/prefix.cpp | 4 - .../src/function/scalar/string/regexp.cpp | 21 +- .../string/regexp/regexp_extract_all.cpp | 3 +- .../scalar/string/regexp_escape.cpp | 4 +- .../scalar/string/sha1.cpp | 2 +- .../scalar/string/sha256.cpp | 2 +- .../scalar/string/string_split.cpp | 9 +- .../function/scalar/string/strip_accents.cpp | 9 +- .../src/function/scalar/string/substring.cpp | 27 +- .../src/function/scalar/string/suffix.cpp | 4 - .../src/function/scalar/string_functions.cpp | 22 - .../function/scalar/struct/struct_extract.cpp | 23 +- .../scalar/struct/struct_pack.cpp | 10 +- .../scalar/system/aggregate_export.cpp | 11 +- src/duckdb/src/function/table/arrow.cpp | 16 +- src/duckdb/src/function/table/glob.cpp | 2 +- src/duckdb/src/function/table/read_csv.cpp | 12 +- src/duckdb/src/function/table/sniff_csv.cpp | 17 +- .../function/table/system/duckdb_columns.cpp | 2 +- .../table/system/duckdb_constraints.cpp | 2 +- .../function/table/system/duckdb_settings.cpp | 2 +- .../function/table/system/duckdb_tables.cpp | 14 +- .../table/system/pragma_table_info.cpp | 6 + src/duckdb/src/function/table/table_scan.cpp | 26 +- .../function/table/version/pragma_version.cpp | 6 +- src/duckdb/src/function/table_function.cpp | 12 +- src/duckdb/src/include/duckdb.h | 54 + .../src/include/duckdb/catalog/catalog.hpp | 82 +- .../include/duckdb/catalog/catalog_entry.hpp | 6 +- .../catalog_entry/duck_index_entry.hpp | 2 +- .../catalog_entry/duck_table_entry.hpp | 7 + .../catalog/catalog_entry/function_entry.hpp | 1 + .../scalar_function_catalog_entry.hpp | 2 +- .../catalog_entry/table_catalog_entry.hpp | 13 +- .../table_function_catalog_entry.hpp | 2 +- .../catalog_entry/type_catalog_entry.hpp | 1 + .../catalog/catalog_entry_retriever.hpp | 39 +- .../duckdb/catalog/catalog_search_path.hpp | 5 +- .../duckdb/catalog/dependency_manager.hpp | 7 + .../common/arrow/appender/list_data.hpp | 4 +- .../common/arrow/appender/list_view_data.hpp | 4 +- .../src/include/duckdb/common/chrono.hpp | 1 + .../src/include/duckdb/common/enum_util.hpp | 24 + .../duckdb/common/enums/memory_tag.hpp | 5 +- .../duckdb/common/enums/metric_type.hpp | 2 + .../duckdb/common/enums/optimizer_type.hpp | 2 + .../common/enums/physical_operator_type.hpp | 1 + .../duckdb/common/enums/profiler_format.hpp | 2 +- .../enums}/quantile_enum.hpp | 4 +- .../common/exception/parser_exception.hpp | 4 + .../duckdb/common/extra_operator_info.hpp | 9 +- .../src/include/duckdb/common/file_buffer.hpp | 2 +- .../duckdb/common/multi_file_reader.hpp | 16 +- .../duckdb/common/opener_file_system.hpp | 21 +- .../common/operator/comparison_operators.hpp | 14 - .../include/duckdb/common/optional_idx.hpp | 4 + .../src/include/duckdb/common/platform.hpp | 4 +- .../duckdb/common/radix_partitioning.hpp | 19 +- .../include/duckdb/common/random_engine.hpp | 4 + .../serializer/serialization_traits.hpp | 1 + .../src/include/duckdb/common/string_util.hpp | 12 + .../include/duckdb/common/tree_renderer.hpp | 2 + .../tree_renderer/graphviz_tree_renderer.hpp | 2 +- .../tree_renderer/html_tree_renderer.hpp | 2 +- .../tree_renderer/json_tree_renderer.hpp | 2 +- .../tree_renderer/text_tree_renderer.hpp | 2 +- .../types/column/column_data_allocator.hpp | 8 + .../types/column/column_data_collection.hpp | 15 +- .../column/column_data_collection_segment.hpp | 3 +- .../duckdb/common/types/data_chunk.hpp | 2 +- .../types/row/partitioned_tuple_data.hpp | 4 - .../common/types/row/tuple_data_allocator.hpp | 4 + .../types/row/tuple_data_collection.hpp | 4 + .../vector_operations/aggregate_executor.hpp | 25 +- .../vector_operations/binary_executor.hpp | 27 + .../vector_operations/unary_executor.hpp | 4 + .../vector_operations/vector_operations.hpp | 11 - .../aggregate/algebraic/corr.hpp | 74 - .../aggregate/algebraic/covar.hpp | 101 - .../aggregate/algebraic/stddev.hpp | 151 - .../aggregate/algebraic_functions.hpp | 126 - .../aggregate/distributive_functions.hpp | 266 - .../aggregate/histogram_helpers.hpp | 99 - .../aggregate/holistic_functions.hpp | 96 - .../aggregate/nested_functions.hpp | 53 - .../aggregate/quantile_helpers.hpp | 65 - .../aggregate/quantile_sort_tree.hpp | 349 - .../aggregate/quantile_state.hpp | 300 - .../aggregate/regression/regr_count.hpp | 42 - .../aggregate/regression/regr_slope.hpp | 61 - .../aggregate/regression_functions.hpp | 99 - .../core_functions/aggregate/sum_helpers.hpp | 175 - .../duckdb/core_functions/array_kernels.hpp | 107 - .../core_functions/scalar/array_functions.hpp | 93 - .../core_functions/scalar/bit_functions.hpp | 54 - .../core_functions/scalar/blob_functions.hpp | 69 - .../core_functions/scalar/date_functions.hpp | 636 - .../core_functions/scalar/enum_functions.hpp | 63 - .../scalar/generic_functions.hpp | 180 - .../core_functions/scalar/list_functions.hpp | 390 - .../core_functions/scalar/map_functions.hpp | 105 - .../core_functions/scalar/math_functions.hpp | 453 - .../scalar/operators_functions.hpp | 72 - .../scalar/random_functions.hpp | 51 - .../scalar/string_functions.hpp | 537 - .../core_functions/scalar/union_functions.hpp | 45 - .../duckdb/execution/aggregate_hashtable.hpp | 1 + .../physical_partitioned_aggregate.hpp | 70 + .../physical_ungrouped_aggregate.hpp | 3 +- .../operator/aggregate/physical_window.hpp | 7 +- .../aggregate/ungrouped_aggregate_state.hpp | 22 +- .../operator/csv_scanner/base_scanner.hpp | 11 +- .../operator/csv_scanner/csv_buffer.hpp | 3 + .../csv_scanner/csv_buffer_manager.hpp | 2 + .../csv_scanner/csv_reader_options.hpp | 6 +- .../operator/csv_scanner/csv_state.hpp | 25 +- .../csv_scanner/csv_state_machine.hpp | 47 +- .../csv_scanner/csv_state_machine_cache.hpp | 8 +- .../operator/csv_scanner/csv_validator.hpp | 58 + .../operator/csv_scanner/global_csv_state.hpp | 3 + .../operator/csv_scanner/scanner_boundary.hpp | 6 + .../csv_scanner/string_value_scanner.hpp | 39 +- .../helper/physical_batch_collector.hpp | 4 +- .../physical_buffered_batch_collector.hpp | 4 +- .../operator/helper/physical_limit.hpp | 4 +- .../operator/join/join_filter_pushdown.hpp | 15 +- .../join/perfect_hash_join_executor.hpp | 4 +- .../operator/join/physical_hash_join.hpp | 20 +- .../operator/order/physical_order.hpp | 10 +- .../physical_batch_copy_to_file.hpp | 4 +- .../persistent/physical_batch_insert.hpp | 4 +- .../scan/physical_positional_scan.hpp | 1 + .../operator/scan/physical_table_scan.hpp | 12 +- .../schema/physical_create_art_index.hpp | 29 +- .../execution/operator/set/physical_cte.hpp | 4 - .../duckdb/execution/partition_info.hpp | 79 + .../duckdb/execution/physical_operator.hpp | 21 +- .../execution/physical_operator_states.hpp | 12 +- .../execution/physical_plan_generator.hpp | 2 - .../duckdb/execution/window_executor.hpp | 397 +- .../duckdb/execution/window_segment_tree.hpp | 75 +- .../aggregate/distributive_function_utils.hpp | 31 + .../aggregate/distributive_functions.hpp | 71 +- .../aggregate/minmax_n_helpers.hpp | 2 +- .../aggregate/sort_key_helpers.hpp | 4 +- .../duckdb/function/aggregate_function.hpp | 66 +- .../duckdb/function/built_in_functions.hpp | 13 +- .../create_sort_key.hpp | 3 +- .../function_list.hpp | 8 +- .../include/duckdb/function/function_set.hpp | 20 +- .../lambda_functions.hpp | 2 +- .../compressed_materialization_functions.hpp | 177 +- .../compressed_materialization_utils.hpp | 45 + .../duckdb/function/scalar/date_functions.hpp | 45 + .../duckdb/function/scalar/generic_common.hpp | 36 + .../function/scalar/generic_functions.hpp | 55 +- .../scalar/list/contains_or_position.hpp | 2 +- .../duckdb/function/scalar/list_functions.hpp | 156 + .../scalar/map_functions.hpp} | 12 +- .../function/scalar/nested_functions.hpp | 48 +- .../function/scalar/operator_functions.hpp | 102 + .../duckdb/function/scalar/operators.hpp | 18 +- .../function/scalar/sequence_functions.hpp | 41 +- .../duckdb/function/scalar/sequence_utils.hpp | 38 + .../duckdb/function/scalar/string_common.hpp | 49 + .../function/scalar/string_functions.hpp | 471 +- .../scalar/struct_functions.hpp | 24 +- .../scalar/system_functions.hpp} | 21 +- .../duckdb/function/scalar_function.hpp | 1 + .../include/duckdb/function/table/arrow.hpp | 3 +- .../function/table/system_functions.hpp | 2 + .../duckdb/function/table_function.hpp | 65 +- .../to_interval.hpp | 2 +- .../src/include/duckdb/main/appender.hpp | 2 + .../include/duckdb/main/attached_database.hpp | 9 +- .../duckdb/main/capi/extension_api.hpp | 14 + .../src/include/duckdb/main/client_config.hpp | 10 + .../include/duckdb/main/client_context.hpp | 9 +- .../duckdb/main/client_context_wrapper.hpp | 5 + src/duckdb/src/include/duckdb/main/config.hpp | 26 +- .../src/include/duckdb/main/connection.hpp | 10 +- .../duckdb/main/database_file_opener.hpp | 2 +- .../include/duckdb/main/database_manager.hpp | 3 + .../include/duckdb/main/extension_entries.hpp | 546 +- .../include/duckdb/main/extension_helper.hpp | 13 + .../include/duckdb/main/extension_util.hpp | 17 +- .../include/duckdb/main/query_profiler.hpp | 3 + .../src/include/duckdb/main/relation.hpp | 32 +- .../duckdb/main/relation/delete_relation.hpp | 4 +- .../main/relation/table_function_relation.hpp | 4 +- .../duckdb/main/relation/table_relation.hpp | 1 + .../duckdb/main/relation/update_relation.hpp | 5 +- .../duckdb/main/relation/value_relation.hpp | 2 + .../duckdb/main/relation/view_relation.hpp | 1 + .../src/include/duckdb/main/settings.hpp | 930 +- .../include/duckdb/main/table_description.hpp | 18 +- .../optimizer/build_probe_side_optimizer.hpp | 2 +- .../optimizer/column_lifetime_analyzer.hpp | 21 +- .../optimizer/common_aggregate_optimizer.hpp | 4 +- .../duckdb/optimizer/empty_result_pullup.hpp | 27 + .../duckdb/optimizer/filter_pushdown.hpp | 2 + .../duckdb/optimizer/sampling_pushdown.hpp | 25 + .../optimizer/statistics_propagator.hpp | 2 +- .../duckdb/parallel/pipeline_executor.hpp | 34 +- .../parser/constraints/unique_constraint.hpp | 72 +- .../expression/columnref_expression.hpp | 3 + .../parser/expression/star_expression.hpp | 12 +- .../duckdb/parser/parsed_data/alter_info.hpp | 1 + .../alter_scalar_function_info.hpp | 5 +- .../parser/parsed_data/alter_table_info.hpp | 23 +- .../duckdb/parser/parsed_data/attach_info.hpp | 7 +- .../parsed_data/comment_on_column_info.hpp | 2 +- .../parsed_data/create_function_info.hpp | 9 +- .../parser/parsed_data/create_index_info.hpp | 6 +- .../parser/parsed_data/sample_options.hpp | 14 +- .../include/duckdb/parser/qualified_name.hpp | 73 +- .../duckdb/parser/qualified_name_set.hpp | 22 +- .../duckdb/parser/tableref/basetableref.hpp | 21 +- .../src/include/duckdb/parser/tokens.hpp | 2 +- .../src/include/duckdb/parser/transformer.hpp | 4 +- .../include/duckdb/planner/bind_context.hpp | 72 +- .../src/include/duckdb/planner/binder.hpp | 26 +- .../include/duckdb/planner/binding_alias.hpp | 44 + .../constraints/bound_unique_constraint.hpp | 21 +- .../src/include/duckdb/planner/expression.hpp | 2 + .../expression/bound_cast_expression.hpp | 2 + .../duckdb/planner/expression_binder.hpp | 6 +- .../expression_binder/having_binder.hpp | 2 + .../expression_binder/index_binder.hpp | 11 +- .../planner/filter/conjunction_filter.hpp | 3 +- .../duckdb/planner/filter/optional_filter.hpp | 35 + .../duckdb/planner/logical_operator.hpp | 4 + .../planner/logical_operator_visitor.hpp | 3 + .../operator/logical_comparison_join.hpp | 2 + .../planner/operator/logical_create_index.hpp | 18 +- .../planner/operator/logical_filter.hpp | 4 + .../duckdb/planner/operator/logical_get.hpp | 5 +- .../duckdb/planner/operator/logical_join.hpp | 4 + .../duckdb/planner/operator/logical_order.hpp | 6 +- .../include/duckdb/planner/table_binding.hpp | 10 +- .../include/duckdb/planner/table_filter.hpp | 3 +- .../duckdb/storage/arena_allocator.hpp | 1 + .../duckdb/storage/buffer/block_handle.hpp | 13 +- .../duckdb/storage/buffer/buffer_pool.hpp | 13 +- .../include/duckdb/storage/buffer_manager.hpp | 3 +- .../storage/compression/alp/alp_constants.hpp | 2 +- .../src/include/duckdb/storage/data_table.hpp | 35 +- .../storage/standard_buffer_manager.hpp | 4 +- .../storage/statistics/column_statistics.hpp | 2 +- .../statistics/distinct_statistics.hpp | 9 +- .../include/duckdb/storage/storage_info.hpp | 12 +- .../duckdb/storage/storage_manager.hpp | 7 +- .../storage_options.hpp} | 13 +- .../duckdb/storage/table/append_state.hpp | 2 + .../duckdb/storage/table/row_group.hpp | 2 + .../storage/table/row_group_collection.hpp | 11 +- .../storage/table/row_version_manager.hpp | 3 +- .../duckdb/storage/table/scan_state.hpp | 20 +- .../duckdb/storage/table/table_index_list.hpp | 2 +- .../duckdb/storage/table/update_segment.hpp | 30 +- .../duckdb/storage/table_io_manager.hpp | 3 + .../duckdb/storage/temporary_file_manager.hpp | 289 +- .../duckdb/storage/write_ahead_log.hpp | 2 +- .../duckdb/transaction/commit_state.hpp | 4 +- .../duckdb/transaction/duck_transaction.hpp | 5 +- .../transaction/duck_transaction_manager.hpp | 1 + .../duckdb/transaction/local_storage.hpp | 4 - .../duckdb/transaction/rollback_state.hpp | 7 +- .../duckdb/transaction/transaction.hpp | 3 +- .../duckdb/transaction/undo_buffer.hpp | 20 +- .../transaction/undo_buffer_allocator.hpp | 79 + .../duckdb/transaction/update_info.hpp | 56 +- .../duckdb/transaction/wal_write_state.hpp | 5 +- src/duckdb/src/include/duckdb_extension.h | 39 +- src/duckdb/src/main/appender.cpp | 84 +- src/duckdb/src/main/attached_database.cpp | 24 +- src/duckdb/src/main/capi/appender-c.cpp | 13 +- src/duckdb/src/main/capi/config-c.cpp | 21 +- src/duckdb/src/main/capi/prepared-c.cpp | 21 +- .../src/main/capi/table_description-c.cpp | 53 +- src/duckdb/src/main/client_context.cpp | 47 +- .../src/main/client_context_wrapper.cpp | 4 + src/duckdb/src/main/client_data.cpp | 2 +- src/duckdb/src/main/config.cpp | 257 +- src/duckdb/src/main/connection.cpp | 19 +- src/duckdb/src/main/database.cpp | 12 +- src/duckdb/src/main/database_manager.cpp | 20 +- .../src/main/extension/extension_helper.cpp | 24 +- .../src/main/extension/extension_load.cpp | 25 +- .../src/main/extension/extension_util.cpp | 57 +- src/duckdb/src/main/query_profiler.cpp | 100 +- src/duckdb/src/main/relation.cpp | 42 +- src/duckdb/src/main/relation.cpp.orig | 414 + .../src/main/relation/aggregate_relation.cpp | 6 +- .../main/relation/create_table_relation.cpp | 2 +- .../main/relation/create_view_relation.cpp | 4 +- .../main/relation/cross_product_relation.cpp | 4 +- .../src/main/relation/delete_relation.cpp | 4 +- .../src/main/relation/delim_get_relation.cpp | 2 +- .../src/main/relation/distinct_relation.cpp | 2 +- .../src/main/relation/explain_relation.cpp | 2 +- .../src/main/relation/filter_relation.cpp | 2 +- .../src/main/relation/insert_relation.cpp | 2 +- .../src/main/relation/join_relation.cpp | 9 +- .../src/main/relation/order_relation.cpp | 2 +- .../src/main/relation/projection_relation.cpp | 2 +- .../src/main/relation/query_relation.cpp | 2 +- .../src/main/relation/setop_relation.cpp | 4 +- .../src/main/relation/subquery_relation.cpp | 2 +- .../main/relation/table_function_relation.cpp | 11 +- .../src/main/relation/table_relation.cpp | 11 +- .../src/main/relation/update_relation.cpp | 4 +- .../src/main/relation/value_relation.cpp | 20 +- .../src/main/relation/view_relation.cpp | 10 +- .../src/main/relation/write_csv_relation.cpp | 2 +- .../main/relation/write_parquet_relation.cpp | 2 +- .../main/settings/autogenerated_settings.cpp | 1068 + .../src/main/settings/custom_settings.cpp | 1220 + src/duckdb/src/main/settings/settings.cpp | 2056 -- .../optimizer/build_probe_side_optimizer.cpp | 71 +- .../optimizer/column_lifetime_analyzer.cpp | 196 +- .../optimizer/common_aggregate_optimizer.cpp | 26 +- .../optimizer/compressed_materialization.cpp | 6 +- .../src/optimizer/empty_result_pullup.cpp | 93 + .../src/optimizer/expression_rewriter.cpp | 7 +- src/duckdb/src/optimizer/filter_combiner.cpp | 123 +- src/duckdb/src/optimizer/filter_pushdown.cpp | 5 +- .../join_filter_pushdown_optimizer.cpp | 234 +- src/duckdb/src/optimizer/optimizer.cpp | 30 +- .../src/optimizer/pullup/pullup_filter.cpp | 6 +- .../optimizer/pushdown/pushdown_filter.cpp | 2 +- .../pushdown/pushdown_projection.cpp | 4 +- .../optimizer/pushdown/pushdown_unnest.cpp | 52 + .../src/optimizer/remove_unused_columns.cpp | 2 +- .../rule/arithmetic_simplification.cpp | 3 +- .../src/optimizer/rule/like_optimizations.cpp | 4 +- .../optimizer/rule/regex_optimizations.cpp | 7 +- .../src/optimizer/sampling_pushdown.cpp | 24 + .../statistics/operator/propagate_filter.cpp | 2 +- src/duckdb/src/parallel/pipeline.cpp | 5 +- src/duckdb/src/parallel/pipeline_executor.cpp | 110 +- .../parser/constraints/unique_constraint.cpp | 81 +- .../expression/columnref_expression.cpp | 18 +- .../expression/lambdaref_expression.cpp | 2 +- .../src/parser/expression/star_expression.cpp | 48 +- .../src/parser/parsed_data/alter_info.cpp | 28 +- .../alter_scalar_function_info.cpp | 8 +- .../parser/parsed_data/alter_table_info.cpp | 30 +- .../src/parser/parsed_data/attach_info.cpp | 12 +- .../create_aggregate_function_info.cpp | 2 +- .../parsed_data/create_function_info.cpp | 19 + .../parser/parsed_data/create_index_info.cpp | 29 +- .../parser/parsed_data/create_macro_info.cpp | 2 +- .../create_pragma_function_info.cpp | 2 +- .../create_scalar_function_info.cpp | 5 +- .../parser/parsed_data/create_schema_info.cpp | 2 +- .../create_table_function_info.cpp | 2 +- .../parser/parsed_data/create_table_info.cpp | 1 + .../src/parser/parsed_data/sample_options.cpp | 30 +- src/duckdb/src/parser/qualified_name.cpp | 94 + .../src/parser/query_node/select_node.cpp | 4 +- src/duckdb/src/parser/tableref.cpp | 4 +- .../constraint/transform_constraint.cpp | 40 +- .../expression/transform_columnref.cpp | 72 +- .../transform/helpers/transform_sample.cpp | 12 +- .../statement/transform_alter_table.cpp | 21 +- .../transform/statement/transform_copy.cpp | 1 - .../statement/transform_create_table.cpp | 38 +- .../statement/transform_create_table_as.cpp | 14 +- .../transform/statement/transform_show.cpp | 24 +- src/duckdb/src/planner/bind_context.cpp | 405 +- src/duckdb/src/planner/binder.cpp | 54 +- .../expression/bind_aggregate_expression.cpp | 1 + .../expression/bind_columnref_expression.cpp | 170 +- .../expression/bind_operator_expression.cpp | 9 +- .../expression/bind_star_expression.cpp | 53 + .../expression/bind_unnest_expression.cpp | 4 +- .../binder/query_node/bind_select_node.cpp | 6 +- .../binder/query_node/bind_setop_node.cpp | 23 +- .../binder/query_node/plan_subquery.cpp | 8 +- .../planner/binder/statement/bind_copy.cpp | 12 +- .../planner/binder/statement/bind_create.cpp | 97 +- .../binder/statement/bind_create_table.cpp | 254 +- .../planner/binder/statement/bind_export.cpp | 4 - .../planner/binder/statement/bind_simple.cpp | 113 +- .../binder/tableref/bind_basetableref.cpp | 40 +- .../planner/binder/tableref/bind_joinref.cpp | 68 +- .../planner/binder/tableref/bind_showref.cpp | 117 +- src/duckdb/src/planner/binding_alias.cpp | 69 + src/duckdb/src/planner/expression.cpp | 6 + .../expression/bound_cast_expression.cpp | 12 + .../expression/bound_function_expression.cpp | 2 +- .../expression_binder/having_binder.cpp | 16 + .../expression_binder/index_binder.cpp | 48 + src/duckdb/src/planner/filter/null_filter.cpp | 1 - .../src/planner/filter/optional_filter.cpp | 28 + .../src/planner/filter/struct_filter.cpp | 4 +- src/duckdb/src/planner/logical_operator.cpp | 5 +- .../src/planner/logical_operator_visitor.cpp | 70 +- .../operator/logical_comparison_join.cpp | 23 + .../planner/operator/logical_create_index.cpp | 28 +- .../src/planner/operator/logical_get.cpp | 4 + .../src/planner/operator/logical_order.cpp | 15 +- src/duckdb/src/planner/planner.cpp | 2 +- .../subquery/flatten_dependent_join.cpp | 6 +- src/duckdb/src/planner/table_binding.cpp | 63 +- .../src/storage/buffer/block_handle.cpp | 2 +- .../src/storage/buffer/block_manager.cpp | 2 +- src/duckdb/src/storage/buffer/buffer_pool.cpp | 76 +- src/duckdb/src/storage/buffer_manager.cpp | 4 + src/duckdb/src/storage/checkpoint_manager.cpp | 15 +- src/duckdb/src/storage/data_table.cpp | 117 +- src/duckdb/src/storage/local_storage.cpp | 12 +- .../serialize_logical_operator.cpp | 8 +- .../storage/serialization/serialize_nodes.cpp | 32 +- .../serialization/serialize_parse_info.cpp | 14 + .../serialize_parsed_expression.cpp | 25 +- .../serialization/serialize_table_filter.cpp | 15 + .../src/storage/standard_buffer_manager.cpp | 31 +- .../storage/statistics/column_statistics.cpp | 6 +- .../statistics/distinct_statistics.cpp | 35 +- src/duckdb/src/storage/storage_manager.cpp | 56 +- .../src/storage/table/column_segment.cpp | 3 + src/duckdb/src/storage/table/row_group.cpp | 23 +- .../storage/table/row_group_collection.cpp | 76 +- .../src/storage/table/row_version_manager.cpp | 43 +- src/duckdb/src/storage/table/scan_state.cpp | 17 +- .../src/storage/table/update_segment.cpp | 497 +- src/duckdb/src/storage/table_index_list.cpp | 4 +- .../src/storage/temporary_file_manager.cpp | 563 +- src/duckdb/src/storage/wal_replay.cpp | 138 +- src/duckdb/src/storage/write_ahead_log.cpp | 83 +- src/duckdb/src/transaction/cleanup_state.cpp | 1 - src/duckdb/src/transaction/commit_state.cpp | 5 +- .../src/transaction/duck_transaction.cpp | 54 +- .../transaction/duck_transaction_manager.cpp | 12 +- src/duckdb/src/transaction/rollback_state.cpp | 7 +- .../src/transaction/transaction_context.cpp | 10 +- src/duckdb/src/transaction/undo_buffer.cpp | 59 +- .../src/transaction/undo_buffer_allocator.cpp | 72 + .../src/transaction/wal_write_state.cpp | 16 +- .../libpg_query/include/nodes/parsenodes.hpp | 6 +- .../libpg_query/src_backend_parser_gram.cpp | 27397 ++++++++-------- .../third_party/parquet/parquet_constants.cpp | 17 - .../third_party/parquet/parquet_constants.h | 24 - .../third_party/parquet/parquet_types.cpp | 5096 ++- .../third_party/parquet/parquet_types.h | 2789 +- .../snappy/snappy-stubs-internal.h | 28 +- src/duckdb/third_party/zstd/common/debug.cpp | 36 + .../zstd/common/entropy_common.cpp | 222 +- .../third_party/zstd/common/error_private.cpp | 14 +- .../zstd/common/fse_decompress.cpp | 223 +- src/duckdb/third_party/zstd/common/pool.cpp | 376 + .../third_party/zstd/common/threading.cpp | 193 + src/duckdb/third_party/zstd/common/xxhash.cpp | 32 +- .../third_party/zstd/common/zstd_common.cpp | 41 +- .../zstd/compress/fse_compress.cpp | 258 +- src/duckdb/third_party/zstd/compress/hist.cpp | 59 +- .../zstd/compress/huf_compress.cpp | 1248 +- .../zstd/compress/zstd_compress.cpp | 5112 ++- .../zstd/compress/zstd_compress_literals.cpp | 163 +- .../zstd/compress/zstd_compress_sequences.cpp | 70 +- .../compress/zstd_compress_superblock.cpp | 698 +- .../zstd/compress/zstd_double_fast.cpp | 556 +- .../third_party/zstd/compress/zstd_fast.cpp | 1009 +- .../third_party/zstd/compress/zstd_lazy.cpp | 1617 +- .../third_party/zstd/compress/zstd_ldm.cpp | 556 +- .../third_party/zstd/compress/zstd_opt.cpp | 972 +- .../zstd/compress/zstdmt_compress.cpp | 1885 ++ .../zstd/decompress/huf_decompress.cpp | 1833 +- .../zstd/decompress/zstd_ddict.cpp | 35 +- .../zstd/decompress/zstd_decompress.cpp | 994 +- .../zstd/decompress/zstd_decompress_block.cpp | 1586 +- .../zstd/deprecated/zbuff_common.cpp | 30 + .../zstd/deprecated/zbuff_compress.cpp | 171 + .../zstd/deprecated/zbuff_decompress.cpp | 80 + src/duckdb/third_party/zstd/dict/cover.cpp | 1265 + .../third_party/zstd/dict/divsufsort.cpp | 1916 ++ .../third_party/zstd/dict/fastcover.cpp | 769 + src/duckdb/third_party/zstd/dict/zdict.cpp | 1136 + src/duckdb/third_party/zstd/include/zdict.h | 473 + src/duckdb/third_party/zstd/include/zstd.h | 2264 +- .../zstd/include/zstd/common/allocations.h | 58 + .../zstd/include/zstd/common/bits.h | 204 + .../zstd/include/zstd/common/bitstream.h | 173 +- .../zstd/include/zstd/common/compiler.h | 290 +- .../zstd/include/zstd/common/cpu.h | 253 + .../zstd/include/zstd/common/debug.h | 62 +- .../zstd/include/zstd/common/error_private.h | 100 +- .../zstd/include/zstd/common/fse.h | 488 +- .../zstd/include/zstd/common/fse_static.h | 421 - .../zstd/include/zstd/common/huf.h | 325 +- .../zstd/include/zstd/common/huf_static.h | 238 - .../zstd/include/zstd/common/mem.h | 210 +- .../zstd/include/zstd/common/pool.h | 84 + .../include/zstd/common/portability_macros.h | 158 + .../zstd/include/zstd/common/threading.h | 152 + .../zstd/common/{xxhash.h => xxhash.hpp} | 1 - .../{xxhash_static.h => xxhash_static.hpp} | 0 .../zstd/include/zstd/common/zstd_deps.h | 122 + .../zstd/include/zstd/common/zstd_internal.h | 317 +- .../zstd/include/zstd/common/zstd_trace.h | 159 + .../zstd/include/zstd/compress/clevels.h | 136 + .../zstd/include/zstd/compress/hist.h | 8 +- .../zstd/compress/zstd_compress_internal.h | 851 +- .../zstd/compress/zstd_compress_literals.h | 24 +- .../zstd/compress/zstd_compress_sequences.h | 4 +- .../zstd/compress/zstd_compress_superblock.h | 5 +- .../zstd/include/zstd/compress/zstd_cwksp.h | 422 +- .../include/zstd/compress/zstd_double_fast.h | 19 +- .../zstd/include/zstd/compress/zstd_fast.h | 7 +- .../zstd/include/zstd/compress/zstd_lazy.h | 156 +- .../zstd/include/zstd/compress/zstd_ldm.h | 20 +- .../include/zstd/compress/zstd_ldm_geartab.h | 110 + .../zstd/include/zstd/compress/zstd_opt.h | 42 +- .../include/zstd/compress/zstdmt_compress.h | 107 + .../zstd/include/zstd/decompress/zstd_ddict.h | 7 +- .../zstd/decompress/zstd_decompress_block.h | 26 +- .../decompress/zstd_decompress_internal.h | 104 +- .../zstd/include/zstd/deprecated/zbuff.h | 214 + .../zstd/include/zstd/dict/cover.h | 156 + .../zstd/include/zstd/dict/divsufsort.h | 62 + .../include/{zstd/common => }/zstd_errors.h | 42 +- .../third_party/zstd/include/zstd_static.h | 1070 - src/duckdb/ub_src_common.cpp | 2 + src/duckdb/ub_src_core_functions.cpp | 6 - ...src_core_functions_aggregate_algebraic.cpp | 8 - ..._core_functions_aggregate_distributive.cpp | 24 - ..._src_core_functions_aggregate_holistic.cpp | 12 - ...ub_src_core_functions_aggregate_nested.cpp | 6 - ...rc_core_functions_aggregate_regression.cpp | 14 - .../ub_src_core_functions_scalar_array.cpp | 4 - .../ub_src_core_functions_scalar_bit.cpp | 2 - .../ub_src_core_functions_scalar_blob.cpp | 6 - .../ub_src_core_functions_scalar_date.cpp | 22 - .../ub_src_core_functions_scalar_debug.cpp | 2 - .../ub_src_core_functions_scalar_enum.cpp | 2 - .../ub_src_core_functions_scalar_generic.cpp | 18 - .../ub_src_core_functions_scalar_list.cpp | 22 - .../ub_src_core_functions_scalar_map.cpp | 16 - .../ub_src_core_functions_scalar_math.cpp | 2 - ...ub_src_core_functions_scalar_operators.cpp | 2 - .../ub_src_core_functions_scalar_random.cpp | 4 - .../ub_src_core_functions_scalar_string.cpp | 58 - .../ub_src_core_functions_scalar_struct.cpp | 4 - .../ub_src_core_functions_scalar_union.cpp | 6 - .../ub_src_execution_operator_aggregate.cpp | 2 + ...rc_execution_operator_csv_scanner_util.cpp | 2 + src/duckdb/ub_src_function.cpp | 4 + src/duckdb/ub_src_function_aggregate.cpp | 2 - ...ub_src_function_aggregate_distributive.cpp | 4 +- src/duckdb/ub_src_function_scalar.cpp | 10 +- src/duckdb/ub_src_function_scalar_date.cpp | 2 + src/duckdb/ub_src_function_scalar_generic.cpp | 4 +- src/duckdb/ub_src_function_scalar_map.cpp | 2 + .../ub_src_function_scalar_operator.cpp | 8 + .../ub_src_function_scalar_operators.cpp | 8 - src/duckdb/ub_src_function_scalar_string.cpp | 10 + src/duckdb/ub_src_function_scalar_struct.cpp | 2 + src/duckdb/ub_src_main_settings.cpp | 4 +- src/duckdb/ub_src_optimizer.cpp | 4 + src/duckdb/ub_src_optimizer_pushdown.cpp | 2 + src/duckdb/ub_src_parser.cpp | 2 + src/duckdb/ub_src_parser_parsed_data.cpp | 2 + src/duckdb/ub_src_planner.cpp | 2 + src/duckdb/ub_src_planner_filter.cpp | 2 + src/duckdb/ub_src_transaction.cpp | 2 + src/include/sources.mk | 2 +- 835 files changed, 66575 insertions(+), 67190 deletions(-) create mode 100644 src/duckdb/extension/parquet/include/parquet_dbp_encoder.hpp create mode 100644 src/duckdb/src/common/opener_file_system.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/algebraic/avg.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/algebraic/corr.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/algebraic/covar.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/algebraic/stddev.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/distributive/approx_count.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/distributive/arg_min_max.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/distributive/bitagg.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/distributive/bitstring_agg.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/distributive/bool.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/distributive/entropy.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/distributive/kurtosis.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/distributive/product.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/distributive/skew.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/distributive/string_agg.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/distributive/sum.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/holistic/approx_top_k.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/holistic/approximate_quantile.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/holistic/mad.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/holistic/mode.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/holistic/quantile.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/holistic/reservoir_quantile.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/nested/binned_histogram.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/nested/histogram.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/nested/list.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/regression/regr_avg.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/regression/regr_count.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/regression/regr_intercept.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/regression/regr_r2.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/regression/regr_slope.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/regression/regr_sxx_syy.cpp delete mode 100644 src/duckdb/src/core_functions/aggregate/regression/regr_sxy.cpp delete mode 100644 src/duckdb/src/core_functions/function_list.cpp delete mode 100644 src/duckdb/src/core_functions/lambda_functions.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/array/array_functions.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/array/array_value.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/bit/bitstring.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/blob/base64.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/blob/encode.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/date/age.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/date/current.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/date/date_diff.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/date/date_part.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/date/date_sub.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/date/date_trunc.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/date/epoch.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/date/make_date.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/date/time_bucket.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/date/to_interval.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/debug/vector_type.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/enum/enum_functions.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/generic/alias.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/generic/can_implicitly_cast.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/generic/current_setting.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/generic/hash.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/generic/least.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/generic/stats.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/generic/system_functions.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/generic/typeof.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/list/array_slice.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/list/flatten.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/list/list_aggregates.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/list/list_distance.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/list/list_filter.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/list/list_has_any_or_all.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/list/list_reduce.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/list/list_sort.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/list/list_transform.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/list/list_value.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/list/range.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/map/cardinality.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/map/map.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/map/map_concat.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/map/map_entries.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/map/map_extract.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/map/map_from_entries.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/map/map_keys_values.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/math/numeric.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/operators/bitwise.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/random/random.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/random/setseed.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/ascii.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/bar.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/chr.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/damerau_levenshtein.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/format_bytes.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/hamming.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/hex.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/instr.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/jaccard.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/jaro_winkler.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/left_right.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/levenshtein.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/pad.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/parse_path.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/printf.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/repeat.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/replace.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/reverse.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/starts_with.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/to_base.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/translate.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/trim.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/unicode.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/string/url_encode.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/struct/struct_insert.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/union/union_extract.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/union/union_tag.cpp delete mode 100644 src/duckdb/src/core_functions/scalar/union/union_value.cpp create mode 100644 src/duckdb/src/execution/operator/aggregate/physical_partitioned_aggregate.cpp create mode 100644 src/duckdb/src/execution/operator/csv_scanner/util/csv_validator.cpp rename src/duckdb/src/function/aggregate/distributive/{first.cpp => first_last_any.cpp} (94%) rename src/duckdb/src/{core_functions => function}/aggregate/distributive/minmax.cpp (95%) delete mode 100644 src/duckdb/src/function/aggregate/distributive_functions.cpp create mode 100644 src/duckdb/src/function/function_list.cpp rename src/duckdb/src/{core_functions/core_functions.cpp => function/register_function_list.cpp} (75%) delete mode 100644 src/duckdb/src/function/scalar/compressed_materialization_functions.cpp create mode 100644 src/duckdb/src/function/scalar/compressed_materialization_utils.cpp rename src/duckdb/src/{core_functions/scalar/blob => function/scalar}/create_sort_key.cpp (98%) rename src/duckdb/src/{core_functions => function}/scalar/date/strftime.cpp (98%) delete mode 100644 src/duckdb/src/function/scalar/generic/binning.cpp rename src/duckdb/src/{core_functions => function}/scalar/generic/error.cpp (90%) delete mode 100644 src/duckdb/src/function/scalar/generic_functions.cpp rename src/duckdb/src/{core_functions => function}/scalar/map/map_contains.cpp (97%) rename src/duckdb/src/function/scalar/{operators => operator}/add.cpp (100%) rename src/duckdb/src/function/scalar/{operators => operator}/arithmetic.cpp (91%) rename src/duckdb/src/function/scalar/{operators => operator}/multiply.cpp (100%) rename src/duckdb/src/function/scalar/{operators => operator}/subtract.cpp (100%) delete mode 100644 src/duckdb/src/function/scalar/operators.cpp delete mode 100644 src/duckdb/src/function/scalar/sequence_functions.cpp rename src/duckdb/src/{core_functions => function}/scalar/string/md5.cpp (96%) rename src/duckdb/src/{core_functions => function}/scalar/string/regexp_escape.cpp (77%) rename src/duckdb/src/{core_functions => function}/scalar/string/sha1.cpp (94%) rename src/duckdb/src/{core_functions => function}/scalar/string/sha256.cpp (94%) rename src/duckdb/src/{core_functions => function}/scalar/string/string_split.cpp (96%) delete mode 100644 src/duckdb/src/function/scalar/string_functions.cpp rename src/duckdb/src/{core_functions => function}/scalar/struct/struct_pack.cpp (98%) rename src/duckdb/src/include/duckdb/{core_functions/aggregate => common/enums}/quantile_enum.hpp (83%) delete mode 100644 src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/corr.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/covar.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/stddev.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/aggregate/distributive_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/aggregate/histogram_helpers.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/aggregate/holistic_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/aggregate/nested_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_helpers.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_sort_tree.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_state.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/aggregate/regression/regr_count.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/aggregate/regression/regr_slope.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/aggregate/regression_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/aggregate/sum_helpers.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/array_kernels.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/scalar/array_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/scalar/bit_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/scalar/blob_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/scalar/date_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/scalar/enum_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/scalar/generic_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/scalar/list_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/scalar/map_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/scalar/math_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/scalar/operators_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/scalar/random_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/scalar/string_functions.hpp delete mode 100644 src/duckdb/src/include/duckdb/core_functions/scalar/union_functions.hpp create mode 100644 src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_partitioned_aggregate.hpp create mode 100644 src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_validator.hpp create mode 100644 src/duckdb/src/include/duckdb/execution/partition_info.hpp create mode 100644 src/duckdb/src/include/duckdb/function/aggregate/distributive_function_utils.hpp rename src/duckdb/src/include/duckdb/{core_functions => function}/aggregate/minmax_n_helpers.hpp (99%) rename src/duckdb/src/include/duckdb/{core_functions => function}/aggregate/sort_key_helpers.hpp (93%) rename src/duckdb/src/include/duckdb/{core_functions => function}/create_sort_key.hpp (92%) rename src/duckdb/src/include/duckdb/{core_functions => function}/function_list.hpp (80%) rename src/duckdb/src/include/duckdb/{core_functions => function}/lambda_functions.hpp (99%) create mode 100644 src/duckdb/src/include/duckdb/function/scalar/compressed_materialization_utils.hpp create mode 100644 src/duckdb/src/include/duckdb/function/scalar/date_functions.hpp create mode 100644 src/duckdb/src/include/duckdb/function/scalar/generic_common.hpp create mode 100644 src/duckdb/src/include/duckdb/function/scalar/list_functions.hpp rename src/duckdb/src/include/duckdb/{core_functions/scalar/debug_functions.hpp => function/scalar/map_functions.hpp} (61%) create mode 100644 src/duckdb/src/include/duckdb/function/scalar/operator_functions.hpp create mode 100644 src/duckdb/src/include/duckdb/function/scalar/sequence_utils.hpp create mode 100644 src/duckdb/src/include/duckdb/function/scalar/string_common.hpp rename src/duckdb/src/include/duckdb/{core_functions => function}/scalar/struct_functions.hpp (50%) rename src/duckdb/src/include/duckdb/{core_functions/scalar/secret_functions.hpp => function/scalar/system_functions.hpp} (52%) rename src/duckdb/src/include/duckdb/{core_functions => function}/to_interval.hpp (94%) create mode 100644 src/duckdb/src/include/duckdb/optimizer/empty_result_pullup.hpp create mode 100644 src/duckdb/src/include/duckdb/optimizer/sampling_pushdown.hpp create mode 100644 src/duckdb/src/include/duckdb/planner/binding_alias.hpp create mode 100644 src/duckdb/src/include/duckdb/planner/filter/optional_filter.hpp rename src/duckdb/src/include/duckdb/{core_functions/core_functions.hpp => storage/storage_options.hpp} (50%) create mode 100644 src/duckdb/src/include/duckdb/transaction/undo_buffer_allocator.hpp create mode 100644 src/duckdb/src/main/relation.cpp.orig create mode 100644 src/duckdb/src/main/settings/autogenerated_settings.cpp create mode 100644 src/duckdb/src/main/settings/custom_settings.cpp delete mode 100644 src/duckdb/src/main/settings/settings.cpp create mode 100644 src/duckdb/src/optimizer/empty_result_pullup.cpp create mode 100644 src/duckdb/src/optimizer/pushdown/pushdown_unnest.cpp create mode 100644 src/duckdb/src/optimizer/sampling_pushdown.cpp create mode 100644 src/duckdb/src/parser/parsed_data/create_function_info.cpp create mode 100644 src/duckdb/src/parser/qualified_name.cpp create mode 100644 src/duckdb/src/planner/binding_alias.cpp create mode 100644 src/duckdb/src/planner/filter/optional_filter.cpp create mode 100644 src/duckdb/src/transaction/undo_buffer_allocator.cpp delete mode 100644 src/duckdb/third_party/parquet/parquet_constants.cpp delete mode 100644 src/duckdb/third_party/parquet/parquet_constants.h create mode 100644 src/duckdb/third_party/zstd/common/debug.cpp create mode 100644 src/duckdb/third_party/zstd/common/pool.cpp create mode 100644 src/duckdb/third_party/zstd/common/threading.cpp create mode 100644 src/duckdb/third_party/zstd/compress/zstdmt_compress.cpp create mode 100644 src/duckdb/third_party/zstd/deprecated/zbuff_common.cpp create mode 100644 src/duckdb/third_party/zstd/deprecated/zbuff_compress.cpp create mode 100644 src/duckdb/third_party/zstd/deprecated/zbuff_decompress.cpp create mode 100644 src/duckdb/third_party/zstd/dict/cover.cpp create mode 100644 src/duckdb/third_party/zstd/dict/divsufsort.cpp create mode 100644 src/duckdb/third_party/zstd/dict/fastcover.cpp create mode 100644 src/duckdb/third_party/zstd/dict/zdict.cpp create mode 100644 src/duckdb/third_party/zstd/include/zdict.h create mode 100644 src/duckdb/third_party/zstd/include/zstd/common/allocations.h create mode 100644 src/duckdb/third_party/zstd/include/zstd/common/bits.h create mode 100644 src/duckdb/third_party/zstd/include/zstd/common/cpu.h delete mode 100644 src/duckdb/third_party/zstd/include/zstd/common/fse_static.h delete mode 100644 src/duckdb/third_party/zstd/include/zstd/common/huf_static.h create mode 100644 src/duckdb/third_party/zstd/include/zstd/common/pool.h create mode 100644 src/duckdb/third_party/zstd/include/zstd/common/portability_macros.h create mode 100644 src/duckdb/third_party/zstd/include/zstd/common/threading.h rename src/duckdb/third_party/zstd/include/zstd/common/{xxhash.h => xxhash.hpp} (99%) rename src/duckdb/third_party/zstd/include/zstd/common/{xxhash_static.h => xxhash_static.hpp} (100%) create mode 100644 src/duckdb/third_party/zstd/include/zstd/common/zstd_deps.h create mode 100644 src/duckdb/third_party/zstd/include/zstd/common/zstd_trace.h create mode 100644 src/duckdb/third_party/zstd/include/zstd/compress/clevels.h create mode 100644 src/duckdb/third_party/zstd/include/zstd/compress/zstd_ldm_geartab.h create mode 100644 src/duckdb/third_party/zstd/include/zstd/compress/zstdmt_compress.h create mode 100644 src/duckdb/third_party/zstd/include/zstd/deprecated/zbuff.h create mode 100644 src/duckdb/third_party/zstd/include/zstd/dict/cover.h create mode 100644 src/duckdb/third_party/zstd/include/zstd/dict/divsufsort.h rename src/duckdb/third_party/zstd/include/{zstd/common => }/zstd_errors.h (73%) delete mode 100644 src/duckdb/third_party/zstd/include/zstd_static.h delete mode 100644 src/duckdb/ub_src_core_functions.cpp delete mode 100644 src/duckdb/ub_src_core_functions_aggregate_algebraic.cpp delete mode 100644 src/duckdb/ub_src_core_functions_aggregate_distributive.cpp delete mode 100644 src/duckdb/ub_src_core_functions_aggregate_holistic.cpp delete mode 100644 src/duckdb/ub_src_core_functions_aggregate_nested.cpp delete mode 100644 src/duckdb/ub_src_core_functions_aggregate_regression.cpp delete mode 100644 src/duckdb/ub_src_core_functions_scalar_array.cpp delete mode 100644 src/duckdb/ub_src_core_functions_scalar_bit.cpp delete mode 100644 src/duckdb/ub_src_core_functions_scalar_blob.cpp delete mode 100644 src/duckdb/ub_src_core_functions_scalar_date.cpp delete mode 100644 src/duckdb/ub_src_core_functions_scalar_debug.cpp delete mode 100644 src/duckdb/ub_src_core_functions_scalar_enum.cpp delete mode 100644 src/duckdb/ub_src_core_functions_scalar_generic.cpp delete mode 100644 src/duckdb/ub_src_core_functions_scalar_list.cpp delete mode 100644 src/duckdb/ub_src_core_functions_scalar_map.cpp delete mode 100644 src/duckdb/ub_src_core_functions_scalar_math.cpp delete mode 100644 src/duckdb/ub_src_core_functions_scalar_operators.cpp delete mode 100644 src/duckdb/ub_src_core_functions_scalar_random.cpp delete mode 100644 src/duckdb/ub_src_core_functions_scalar_string.cpp delete mode 100644 src/duckdb/ub_src_core_functions_scalar_struct.cpp delete mode 100644 src/duckdb/ub_src_core_functions_scalar_union.cpp create mode 100644 src/duckdb/ub_src_function_scalar_date.cpp create mode 100644 src/duckdb/ub_src_function_scalar_map.cpp create mode 100644 src/duckdb/ub_src_function_scalar_operator.cpp delete mode 100644 src/duckdb/ub_src_function_scalar_operators.cpp diff --git a/src/Makevars b/src/Makevars index 08c2ae4ae..2b50cfd18 100644 --- a/src/Makevars +++ b/src/Makevars @@ -15,5 +15,5 @@ include include/sources.mk include Makevars.duckdb CXX_STD = CXX17 -PKG_CPPFLAGS = -Iinclude -I../inst/include -DDUCKDB_DISABLE_PRINT -DDUCKDB_R_BUILD -DBROTLI_ENCODER_CLEANUP_ON_OOM -Iduckdb/src/include -Iduckdb/third_party/concurrentqueue -Iduckdb/third_party/fast_float -Iduckdb/third_party/fastpforlib -Iduckdb/third_party/fmt/include -Iduckdb/third_party/fsst -Iduckdb/third_party/httplib -Iduckdb/third_party/hyperloglog -Iduckdb/third_party/jaro_winkler -Iduckdb/third_party/jaro_winkler/details -Iduckdb/third_party/libpg_query -Iduckdb/third_party/libpg_query/include -Iduckdb/third_party/lz4 -Iduckdb/third_party/brotli/include -Iduckdb/third_party/brotli/common -Iduckdb/third_party/brotli/dec -Iduckdb/third_party/brotli/enc -Iduckdb/third_party/mbedtls -Iduckdb/third_party/mbedtls/include -Iduckdb/third_party/mbedtls/library -Iduckdb/third_party/miniz -Iduckdb/third_party/pcg -Iduckdb/third_party/re2 -Iduckdb/third_party/skiplist -Iduckdb/third_party/tdigest -Iduckdb/third_party/utf8proc -Iduckdb/third_party/utf8proc/include -Iduckdb/third_party/yyjson/include -Iduckdb/extension/parquet/include -Iduckdb/third_party/parquet -Iduckdb/third_party/thrift -Iduckdb/third_party/lz4 -Iduckdb/third_party/brotli/include -Iduckdb/third_party/brotli/common -Iduckdb/third_party/brotli/dec -Iduckdb/third_party/brotli/enc -Iduckdb/third_party/snappy -Iduckdb/third_party/zstd/include -Iduckdb/third_party/mbedtls -Iduckdb/third_party/mbedtls/include -I../inst/include -Iduckdb -DDUCKDB_EXTENSION_PARQUET_LINKED -DDUCKDB_BUILD_LIBRARY +PKG_CPPFLAGS = -Iinclude -I../inst/include -DDUCKDB_DISABLE_PRINT -DDUCKDB_R_BUILD -DBROTLI_ENCODER_CLEANUP_ON_OOM -Iduckdb/src/include -Iduckdb/third_party/concurrentqueue -Iduckdb/third_party/fast_float -Iduckdb/third_party/fastpforlib -Iduckdb/third_party/fmt/include -Iduckdb/third_party/fsst -Iduckdb/third_party/httplib -Iduckdb/third_party/hyperloglog -Iduckdb/third_party/jaro_winkler -Iduckdb/third_party/jaro_winkler/details -Iduckdb/third_party/libpg_query -Iduckdb/third_party/libpg_query/include -Iduckdb/third_party/lz4 -Iduckdb/third_party/brotli/include -Iduckdb/third_party/brotli/common -Iduckdb/third_party/brotli/dec -Iduckdb/third_party/brotli/enc -Iduckdb/third_party/mbedtls -Iduckdb/third_party/mbedtls/include -Iduckdb/third_party/mbedtls/library -Iduckdb/third_party/miniz -Iduckdb/third_party/pcg -Iduckdb/third_party/re2 -Iduckdb/third_party/skiplist -Iduckdb/third_party/tdigest -Iduckdb/third_party/utf8proc -Iduckdb/third_party/utf8proc/include -Iduckdb/third_party/yyjson/include -Iduckdb/third_party/zstd/include -Iduckdb/extension/parquet/include -Iduckdb/third_party/parquet -Iduckdb/third_party/thrift -Iduckdb/third_party/lz4 -Iduckdb/third_party/brotli/include -Iduckdb/third_party/brotli/common -Iduckdb/third_party/brotli/dec -Iduckdb/third_party/brotli/enc -Iduckdb/third_party/snappy -Iduckdb/third_party/mbedtls -Iduckdb/third_party/mbedtls/include -Iduckdb/third_party/zstd/include -I../inst/include -Iduckdb -DDUCKDB_EXTENSION_PARQUET_LINKED -DDUCKDB_BUILD_LIBRARY OBJECTS=rfuns.o database.o connection.o statement.o register.o relational.o scan.o signal.o transform.o utils.o reltoaltrep.o types.o cpp11.o $(SOURCES) diff --git a/src/Makevars.win b/src/Makevars.win index 2b183aa87..9e4967a8e 100644 --- a/src/Makevars.win +++ b/src/Makevars.win @@ -15,6 +15,6 @@ include include/sources.mk include Makevars.duckdb CXX_STD = CXX17 -PKG_CPPFLAGS = -Iinclude -I../inst/include -DDUCKDB_DISABLE_PRINT -DDUCKDB_R_BUILD -DBROTLI_ENCODER_CLEANUP_ON_OOM -Iduckdb/src/include -Iduckdb/third_party/concurrentqueue -Iduckdb/third_party/fast_float -Iduckdb/third_party/fastpforlib -Iduckdb/third_party/fmt/include -Iduckdb/third_party/fsst -Iduckdb/third_party/httplib -Iduckdb/third_party/hyperloglog -Iduckdb/third_party/jaro_winkler -Iduckdb/third_party/jaro_winkler/details -Iduckdb/third_party/libpg_query -Iduckdb/third_party/libpg_query/include -Iduckdb/third_party/lz4 -Iduckdb/third_party/brotli/include -Iduckdb/third_party/brotli/common -Iduckdb/third_party/brotli/dec -Iduckdb/third_party/brotli/enc -Iduckdb/third_party/mbedtls -Iduckdb/third_party/mbedtls/include -Iduckdb/third_party/mbedtls/library -Iduckdb/third_party/miniz -Iduckdb/third_party/pcg -Iduckdb/third_party/re2 -Iduckdb/third_party/skiplist -Iduckdb/third_party/tdigest -Iduckdb/third_party/utf8proc -Iduckdb/third_party/utf8proc/include -Iduckdb/third_party/yyjson/include -Iduckdb/extension/parquet/include -Iduckdb/third_party/parquet -Iduckdb/third_party/thrift -Iduckdb/third_party/lz4 -Iduckdb/third_party/brotli/include -Iduckdb/third_party/brotli/common -Iduckdb/third_party/brotli/dec -Iduckdb/third_party/brotli/enc -Iduckdb/third_party/snappy -Iduckdb/third_party/zstd/include -Iduckdb/third_party/mbedtls -Iduckdb/third_party/mbedtls/include -I../inst/include -Iduckdb -DDUCKDB_EXTENSION_PARQUET_LINKED -DDUCKDB_BUILD_LIBRARY -DDUCKDB_PLATFORM_RTOOLS=1 +PKG_CPPFLAGS = -Iinclude -I../inst/include -DDUCKDB_DISABLE_PRINT -DDUCKDB_R_BUILD -DBROTLI_ENCODER_CLEANUP_ON_OOM -Iduckdb/src/include -Iduckdb/third_party/concurrentqueue -Iduckdb/third_party/fast_float -Iduckdb/third_party/fastpforlib -Iduckdb/third_party/fmt/include -Iduckdb/third_party/fsst -Iduckdb/third_party/httplib -Iduckdb/third_party/hyperloglog -Iduckdb/third_party/jaro_winkler -Iduckdb/third_party/jaro_winkler/details -Iduckdb/third_party/libpg_query -Iduckdb/third_party/libpg_query/include -Iduckdb/third_party/lz4 -Iduckdb/third_party/brotli/include -Iduckdb/third_party/brotli/common -Iduckdb/third_party/brotli/dec -Iduckdb/third_party/brotli/enc -Iduckdb/third_party/mbedtls -Iduckdb/third_party/mbedtls/include -Iduckdb/third_party/mbedtls/library -Iduckdb/third_party/miniz -Iduckdb/third_party/pcg -Iduckdb/third_party/re2 -Iduckdb/third_party/skiplist -Iduckdb/third_party/tdigest -Iduckdb/third_party/utf8proc -Iduckdb/third_party/utf8proc/include -Iduckdb/third_party/yyjson/include -Iduckdb/third_party/zstd/include -Iduckdb/extension/parquet/include -Iduckdb/third_party/parquet -Iduckdb/third_party/thrift -Iduckdb/third_party/lz4 -Iduckdb/third_party/brotli/include -Iduckdb/third_party/brotli/common -Iduckdb/third_party/brotli/dec -Iduckdb/third_party/brotli/enc -Iduckdb/third_party/snappy -Iduckdb/third_party/mbedtls -Iduckdb/third_party/mbedtls/include -Iduckdb/third_party/zstd/include -I../inst/include -Iduckdb -DDUCKDB_EXTENSION_PARQUET_LINKED -DDUCKDB_BUILD_LIBRARY -DDUCKDB_PLATFORM_RTOOLS=1 OBJECTS=rfuns.o database.o connection.o statement.o register.o relational.o scan.o signal.o transform.o utils.o reltoaltrep.o types.o cpp11.o $(SOURCES) PKG_LIBS=-lws2_32 -L. -lrstrtmgr diff --git a/src/duckdb/extension/parquet/column_reader.cpp b/src/duckdb/extension/parquet/column_reader.cpp index 1b6d20632..72902d468 100644 --- a/src/duckdb/extension/parquet/column_reader.cpp +++ b/src/duckdb/extension/parquet/column_reader.cpp @@ -29,11 +29,11 @@ namespace duckdb { -using duckdb_parquet::format::CompressionCodec; -using duckdb_parquet::format::ConvertedType; -using duckdb_parquet::format::Encoding; -using duckdb_parquet::format::PageType; -using duckdb_parquet::format::Type; +using duckdb_parquet::CompressionCodec; +using duckdb_parquet::ConvertedType; +using duckdb_parquet::Encoding; +using duckdb_parquet::PageType; +using duckdb_parquet::Type; const uint64_t ParquetDecodeUtils::BITPACK_MASKS[] = {0, 1, @@ -108,7 +108,8 @@ const uint8_t ParquetDecodeUtils::BITPACK_DLEN = 8; ColumnReader::ColumnReader(ParquetReader &reader, LogicalType type_p, const SchemaElement &schema_p, idx_t file_idx_p, idx_t max_define_p, idx_t max_repeat_p) : schema(schema_p), file_idx(file_idx_p), max_define(max_define_p), max_repeat(max_repeat_p), reader(reader), - type(std::move(type_p)), page_rows_available(0) { + type(std::move(type_p)), page_rows_available(0), dictionary_selection_vector(STANDARD_VECTOR_SIZE), + dictionary_size(0) { // dummies for Skip() dummy_define.resize(reader.allocator, STANDARD_VECTOR_SIZE); @@ -189,19 +190,10 @@ unique_ptr ColumnReader::Stats(idx_t row_group_idx_p, const vect } void ColumnReader::Plain(shared_ptr plain_data, uint8_t *defines, idx_t num_values, // NOLINT - parquet_filter_t &filter, idx_t result_offset, Vector &result) { + parquet_filter_t *filter, idx_t result_offset, Vector &result) { throw NotImplementedException("Plain"); } -void ColumnReader::Dictionary(shared_ptr dictionary_data, idx_t num_entries) { // NOLINT - throw NotImplementedException("Dictionary"); -} - -void ColumnReader::Offsets(uint32_t *offsets, uint8_t *defines, idx_t num_values, parquet_filter_t &filter, - idx_t result_offset, Vector &result) { - throw NotImplementedException("Offsets"); -} - void ColumnReader::PrepareDeltaLengthByteArray(ResizeableBuffer &buffer) { throw std::runtime_error("DELTA_LENGTH_BYTE_ARRAY encoding is only supported for text or binary data"); } @@ -215,8 +207,6 @@ void ColumnReader::DeltaByteArray(uint8_t *defines, idx_t num_values, // NOLINT throw NotImplementedException("DeltaByteArray"); } -void ColumnReader::DictReference(Vector &result) { -} void ColumnReader::PlainReference(shared_ptr, Vector &result) { // NOLINT } @@ -247,6 +237,10 @@ void ColumnReader::PrepareRead(parquet_filter_t &filter) { block.reset(); PageHeader page_hdr; reader.Read(page_hdr, *protocol); + // some basic sanity check + if (page_hdr.compressed_page_size < 0 || page_hdr.uncompressed_page_size < 0) { + throw std::runtime_error("Page sizes can't be < 0"); + } switch (page_hdr.type) { case PageType::DATA_PAGE_V2: @@ -257,13 +251,25 @@ void ColumnReader::PrepareRead(parquet_filter_t &filter) { PreparePage(page_hdr); PrepareDataPage(page_hdr); break; - case PageType::DICTIONARY_PAGE: + case PageType::DICTIONARY_PAGE: { PreparePage(page_hdr); if (page_hdr.dictionary_page_header.num_values < 0) { throw std::runtime_error("Invalid dictionary page header (num_values < 0)"); } - Dictionary(std::move(block), page_hdr.dictionary_page_header.num_values); + auto old_dict_size = dictionary_size; + // we use the first value in the dictionary to keep a NULL + dictionary_size = page_hdr.dictionary_page_header.num_values; + if (!dictionary) { + dictionary = make_uniq(type, dictionary_size + 1); + } else if (dictionary_size > old_dict_size) { + dictionary->Resize(old_dict_size, dictionary_size + 1); + } + // we use the first entry as a NULL, dictionary vectors don't have a separate validity mask + FlatVector::Validity(*dictionary).SetInvalid(0); + PlainReference(block, *dictionary); + Plain(block, nullptr, dictionary_size, nullptr, 1, *dictionary); break; + } default: break; // ignore INDEX page type and any other custom extensions } @@ -275,7 +281,6 @@ void ColumnReader::ResetPage() { void ColumnReader::PreparePageV2(PageHeader &page_hdr) { D_ASSERT(page_hdr.type == PageType::DATA_PAGE_V2); - auto &trans = reinterpret_cast(*protocol->getTransport()); AllocateBlock(page_hdr.uncompressed_page_size + 1); @@ -297,6 +302,10 @@ void ColumnReader::PreparePageV2(PageHeader &page_hdr) { // copy repeats & defines as-is because FOR SOME REASON they are uncompressed auto uncompressed_bytes = page_hdr.data_page_header_v2.repetition_levels_byte_length + page_hdr.data_page_header_v2.definition_levels_byte_length; + if (uncompressed_bytes > page_hdr.uncompressed_page_size) { + throw std::runtime_error("Page header inconsistency, uncompressed_page_size needs to be larger than " + "repetition_levels_byte_length + definition_levels_byte_length"); + } trans.read(block->ptr, uncompressed_bytes); auto compressed_bytes = page_hdr.compressed_page_size - uncompressed_bytes; @@ -485,6 +494,31 @@ void ColumnReader::PrepareDataPage(PageHeader &page_hdr) { } } +void ColumnReader::ConvertDictToSelVec(uint32_t *offsets, uint8_t *defines, parquet_filter_t &filter, idx_t read_now, + idx_t result_offset) { + D_ASSERT(read_now <= STANDARD_VECTOR_SIZE); + idx_t offset_idx = 0; + for (idx_t row_idx = 0; row_idx < read_now; row_idx++) { + if (HasDefines() && defines[row_idx + result_offset] != max_define) { + dictionary_selection_vector.set_index(row_idx, 0); // dictionary entry 0 is NULL + continue; // we don't have a dict entry for NULLs + } + if (filter.test(row_idx + result_offset)) { + auto offset = offsets[offset_idx++]; + if (offset >= dictionary_size) { + throw std::runtime_error("Parquet file is likely corrupted, dictionary offset out of range"); + } + dictionary_selection_vector.set_index(row_idx, offset + 1); + } else { + dictionary_selection_vector.set_index(row_idx, 0); // just set NULL if the filter excludes this row + offset_idx++; + } + } +#ifdef DEBUG + dictionary_selection_vector.Verify(read_now, dictionary_size + 1); +#endif +} + idx_t ColumnReader::Read(uint64_t num_values, parquet_filter_t &filter, data_ptr_t define_out, data_ptr_t repeat_out, Vector &result) { // we need to reset the location because multiple column readers share the same protocol @@ -523,30 +557,42 @@ idx_t ColumnReader::Read(uint64_t num_values, parquet_filter_t &filter, data_ptr if ((dict_decoder || dbp_decoder || rle_decoder || bss_decoder) && HasDefines()) { // we need the null count because the dictionary offsets have no entries for nulls - for (idx_t i = 0; i < read_now; i++) { - if (define_out[i + result_offset] != max_define) { - null_count++; - } + for (idx_t i = result_offset; i < result_offset + read_now; i++) { + null_count += (define_out[i] != max_define); } } + if (result_offset != 0 && result.GetVectorType() != VectorType::FLAT_VECTOR) { + result.Flatten(result_offset); + result.Resize(result_offset, result_offset + read_now); + } + if (dict_decoder) { + if ((!dictionary || dictionary_size == 0) && null_count < read_now) { + throw std::runtime_error("Parquet file is likely corrupted, missing dictionary"); + } offset_buffer.resize(reader.allocator, sizeof(uint32_t) * (read_now - null_count)); dict_decoder->GetBatch(offset_buffer.ptr, read_now - null_count); - DictReference(result); - Offsets(reinterpret_cast(offset_buffer.ptr), define_out, read_now, filter, result_offset, - result); + ConvertDictToSelVec(reinterpret_cast(offset_buffer.ptr), + reinterpret_cast(define_out), filter, read_now, result_offset); + if (result_offset == 0) { + result.Slice(*dictionary, dictionary_selection_vector, read_now); + D_ASSERT(result.GetVectorType() == VectorType::DICTIONARY_VECTOR); + } else { + D_ASSERT(result.GetVectorType() == VectorType::FLAT_VECTOR); + VectorOperations::Copy(*dictionary, result, dictionary_selection_vector, read_now, 0, result_offset); + } } else if (dbp_decoder) { // TODO keep this in the state auto read_buf = make_shared_ptr(); switch (schema.type) { - case duckdb_parquet::format::Type::INT32: + case duckdb_parquet::Type::INT32: read_buf->resize(reader.allocator, sizeof(int32_t) * (read_now - null_count)); dbp_decoder->GetBatch(read_buf->ptr, read_now - null_count); break; - case duckdb_parquet::format::Type::INT64: + case duckdb_parquet::Type::INT64: read_buf->resize(reader.allocator, sizeof(int64_t) * (read_now - null_count)); dbp_decoder->GetBatch(read_buf->ptr, read_now - null_count); break; @@ -555,14 +601,14 @@ idx_t ColumnReader::Read(uint64_t num_values, parquet_filter_t &filter, data_ptr throw std::runtime_error("DELTA_BINARY_PACKED should only be INT32 or INT64"); } // Plain() will put NULLs in the right place - Plain(read_buf, define_out, read_now, filter, result_offset, result); + Plain(read_buf, define_out, read_now, &filter, result_offset, result); } else if (rle_decoder) { // RLE encoding for boolean D_ASSERT(type.id() == LogicalTypeId::BOOLEAN); auto read_buf = make_shared_ptr(); read_buf->resize(reader.allocator, sizeof(bool) * (read_now - null_count)); rle_decoder->GetBatch(read_buf->ptr, read_now - null_count); - PlainTemplated>(read_buf, define_out, read_now, filter, + PlainTemplated>(read_buf, define_out, read_now, &filter, result_offset, result); } else if (byte_array_data) { // DELTA_BYTE_ARRAY or DELTA_LENGTH_BYTE_ARRAY @@ -571,11 +617,11 @@ idx_t ColumnReader::Read(uint64_t num_values, parquet_filter_t &filter, data_ptr auto read_buf = make_shared_ptr(); switch (schema.type) { - case duckdb_parquet::format::Type::FLOAT: + case duckdb_parquet::Type::FLOAT: read_buf->resize(reader.allocator, sizeof(float) * (read_now - null_count)); bss_decoder->GetBatch(read_buf->ptr, read_now - null_count); break; - case duckdb_parquet::format::Type::DOUBLE: + case duckdb_parquet::Type::DOUBLE: read_buf->resize(reader.allocator, sizeof(double) * (read_now - null_count)); bss_decoder->GetBatch(read_buf->ptr, read_now - null_count); break; @@ -583,10 +629,10 @@ idx_t ColumnReader::Read(uint64_t num_values, parquet_filter_t &filter, data_ptr throw std::runtime_error("BYTE_STREAM_SPLIT encoding is only supported for FLOAT or DOUBLE data"); } - Plain(read_buf, define_out, read_now, filter, result_offset, result); + Plain(read_buf, define_out, read_now, &filter, result_offset, result); } else { PlainReference(block, result); - Plain(block, define_out, read_now, filter, result_offset, result); + Plain(block, define_out, read_now, &filter, result_offset, result); } result_offset += read_now; @@ -660,27 +706,6 @@ uint32_t StringColumnReader::VerifyString(const char *str_data, uint32_t str_len return VerifyString(str_data, str_len, Type() == LogicalTypeId::VARCHAR); } -void StringColumnReader::Dictionary(shared_ptr data, idx_t num_entries) { - dict = std::move(data); - dict_strings = unsafe_unique_ptr(new string_t[num_entries]); - for (idx_t dict_idx = 0; dict_idx < num_entries; dict_idx++) { - uint32_t str_len; - if (fixed_width_string_length == 0) { - // variable length string: read from dictionary - str_len = dict->read(); - } else { - // fixed length string - str_len = fixed_width_string_length; - } - dict->available(str_len); - - auto dict_str = reinterpret_cast(dict->ptr); - auto actual_str_len = VerifyString(dict_str, str_len); - dict_strings[dict_idx] = string_t(dict_str, actual_str_len); - dict->inc(str_len); - } -} - static shared_ptr ReadDbpData(Allocator &allocator, ResizeableBuffer &buffer, idx_t &value_count) { auto decoder = make_uniq(buffer.ptr, buffer.len); value_count = decoder->TotalValues(); @@ -707,6 +732,7 @@ void StringColumnReader::PrepareDeltaLengthByteArray(ResizeableBuffer &buffer) { auto string_data = FlatVector::GetData(*byte_array_data); for (idx_t i = 0; i < value_count; i++) { auto str_len = length_data[i]; + buffer.available(str_len); string_data[i] = StringVector::EmptyString(*byte_array_data, str_len); auto result_data = string_data[i].GetDataWriteable(); memcpy(result_data, buffer.ptr, length_data[i]); @@ -735,6 +761,7 @@ void StringColumnReader::PrepareDeltaByteArray(ResizeableBuffer &buffer) { auto string_data = FlatVector::GetData(*byte_array_data); for (idx_t i = 0; i < prefix_count; i++) { auto str_len = prefix_data[i] + suffix_data[i]; + buffer.available(suffix_data[i]); string_data[i] = StringVector::EmptyString(*byte_array_data, str_len); auto result_data = string_data[i].GetDataWriteable(); if (prefix_data[i] > 0) { @@ -786,17 +813,10 @@ class ParquetStringVectorBuffer : public VectorBuffer { shared_ptr buffer; }; -void StringColumnReader::DictReference(Vector &result) { - StringVector::AddBuffer(result, make_buffer(dict)); -} void StringColumnReader::PlainReference(shared_ptr plain_data, Vector &result) { StringVector::AddBuffer(result, make_buffer(std::move(plain_data))); } -string_t StringParquetValueConversion::DictRead(ByteBuffer &dict, uint32_t &offset, ColumnReader &reader) { - return reader.Cast().dict_strings[offset]; -} - string_t StringParquetValueConversion::PlainRead(ByteBuffer &plain_data, ColumnReader &reader) { auto &scr = reader.Cast(); uint32_t str_len = scr.fixed_width_string_length == 0 ? plain_data.read() : scr.fixed_width_string_length; @@ -1251,9 +1271,6 @@ idx_t StructColumnReader::GroupRowsAvailable() { //===--------------------------------------------------------------------===// template struct DecimalParquetValueConversion { - static DUCKDB_PHYSICAL_TYPE DictRead(ByteBuffer &dict, uint32_t &offset, ColumnReader &reader) { - return reinterpret_cast(dict.ptr)[offset]; - } static DUCKDB_PHYSICAL_TYPE PlainRead(ByteBuffer &plain_data, ColumnReader &reader) { idx_t byte_len; @@ -1303,14 +1320,6 @@ class DecimalColumnReader reader, std::move(type_p), schema_p, file_idx_p, max_define_p, max_repeat_p) {}; protected: - void Dictionary(shared_ptr dictionary_data, idx_t num_entries) { // NOLINT - BaseType::AllocateDict(num_entries * sizeof(DUCKDB_PHYSICAL_TYPE)); - auto dict_ptr = (DUCKDB_PHYSICAL_TYPE *)this->dict->ptr; - for (idx_t i = 0; i < num_entries; i++) { - dict_ptr[i] = - DecimalParquetValueConversion::PlainRead(*dictionary_data, *this); - } - } }; template @@ -1340,7 +1349,7 @@ static unique_ptr CreateDecimalReaderInternal(ParquetReader &reade template <> double ParquetDecimalUtils::ReadDecimalValue(const_data_ptr_t pointer, idx_t size, - const duckdb_parquet::format::SchemaElement &schema_ele) { + const duckdb_parquet::SchemaElement &schema_ele) { double res = 0; bool positive = (*pointer & 0x80) == 0; for (idx_t i = 0; i < size; i += 8) { @@ -1377,10 +1386,6 @@ unique_ptr ParquetDecimalUtils::CreateReader(ParquetReader &reader // UUID Column Reader //===--------------------------------------------------------------------===// struct UUIDValueConversion { - static hugeint_t DictRead(ByteBuffer &dict, uint32_t &offset, ColumnReader &reader) { - return reinterpret_cast(dict.ptr)[offset]; - } - static hugeint_t ReadParquetUUID(const_data_ptr_t input) { hugeint_t result; result.lower = 0; @@ -1428,15 +1433,6 @@ class UUIDColumnReader : public TemplatedColumnReader(reader, std::move(type_p), schema_p, file_idx_p, max_define_p, max_repeat_p) {}; - -protected: - void Dictionary(shared_ptr dictionary_data, idx_t num_entries) { // NOLINT - AllocateDict(num_entries * sizeof(hugeint_t)); - auto dict_ptr = reinterpret_cast(this->dict->ptr); - for (idx_t i = 0; i < num_entries; i++) { - dict_ptr[i] = UUIDValueConversion::PlainRead(*dictionary_data, *this); - } - } }; //===--------------------------------------------------------------------===// @@ -1445,10 +1441,6 @@ class UUIDColumnReader : public TemplatedColumnReader(dict.ptr)[offset]; - } - static interval_t ReadParquetInterval(const_data_ptr_t input) { interval_t result; result.months = Load(input); @@ -1488,15 +1480,6 @@ class IntervalColumnReader : public TemplatedColumnReader(reader, std::move(type_p), schema_p, file_idx_p, max_define_p, max_repeat_p) {}; - -protected: - void Dictionary(shared_ptr dictionary_data, idx_t num_entries) override { // NOLINT - AllocateDict(num_entries * sizeof(interval_t)); - auto dict_ptr = reinterpret_cast(this->dict->ptr); - for (idx_t i = 0; i < num_entries; i++) { - dict_ptr[i] = IntervalValueConversion::PlainRead(*dictionary_data, *this); - } - } }; //===--------------------------------------------------------------------===// diff --git a/src/duckdb/extension/parquet/column_writer.cpp b/src/duckdb/extension/parquet/column_writer.cpp index 0b1d867c8..26b8965e0 100644 --- a/src/duckdb/extension/parquet/column_writer.cpp +++ b/src/duckdb/extension/parquet/column_writer.cpp @@ -1,10 +1,11 @@ #include "column_writer.hpp" #include "duckdb.hpp" +#include "geo_parquet.hpp" +#include "parquet_dbp_encoder.hpp" #include "parquet_rle_bp_decoder.hpp" #include "parquet_rle_bp_encoder.hpp" #include "parquet_writer.hpp" -#include "geo_parquet.hpp" #ifndef DUCKDB_AMALGAMATION #include "duckdb/common/exception.hpp" #include "duckdb/common/operator/comparison_operators.hpp" @@ -19,49 +20,29 @@ #include "duckdb/execution/expression_executor.hpp" #endif +#include "brotli/encode.h" #include "lz4.hpp" #include "miniz_wrapper.hpp" #include "snappy.h" #include "zstd.h" -#include "brotli/encode.h" namespace duckdb { using namespace duckdb_parquet; // NOLINT using namespace duckdb_miniz; // NOLINT -using duckdb_parquet::format::CompressionCodec; -using duckdb_parquet::format::ConvertedType; -using duckdb_parquet::format::Encoding; -using duckdb_parquet::format::FieldRepetitionType; -using duckdb_parquet::format::FileMetaData; -using duckdb_parquet::format::PageHeader; -using duckdb_parquet::format::PageType; -using ParquetRowGroup = duckdb_parquet::format::RowGroup; -using duckdb_parquet::format::Type; +using duckdb_parquet::CompressionCodec; +using duckdb_parquet::ConvertedType; +using duckdb_parquet::Encoding; +using duckdb_parquet::FieldRepetitionType; +using duckdb_parquet::FileMetaData; +using duckdb_parquet::PageHeader; +using duckdb_parquet::PageType; +using ParquetRowGroup = duckdb_parquet::RowGroup; +using duckdb_parquet::Type; #define PARQUET_DEFINE_VALID 65535 -static void VarintEncode(uint32_t val, WriteStream &ser) { - do { - uint8_t byte = val & 127; - val >>= 7; - if (val != 0) { - byte |= 128; - } - ser.Write(byte); - } while (val != 0); -} - -static uint8_t GetVarintSize(uint32_t val) { - uint8_t res = 0; - do { - val >>= 7; - res++; - } while (val != 0); - return res; -} - //===--------------------------------------------------------------------===// // ColumnWriterStatistics //===--------------------------------------------------------------------===// @@ -106,7 +87,7 @@ void RleBpEncoder::BeginPrepare(uint32_t first_value) { void RleBpEncoder::FinishRun() { // last value, or value has changed // write out the current run - byte_count += GetVarintSize(current_run_count << 1) + byte_width; + byte_count += ParquetDecodeUtils::GetVarintSize(current_run_count << 1) + byte_width; current_run_count = 1; run_count++; } @@ -137,7 +118,7 @@ void RleBpEncoder::BeginWrite(WriteStream &writer, uint32_t first_value) { void RleBpEncoder::WriteRun(WriteStream &writer) { // write the header of the run - VarintEncode(current_run_count << 1, writer); + ParquetDecodeUtils::VarintEncode(current_run_count << 1, writer); // now write the value D_ASSERT(last_value >> (byte_width * 8) == 0); switch (byte_width) { @@ -224,16 +205,11 @@ void ColumnWriter::CompressPage(MemoryStream &temp_writer, size_t &compressed_si break; } case CompressionCodec::ZSTD: { - auto configured_compression = writer.CompressionLevel(); - int compress_level = ZSTD_CLEVEL_DEFAULT; - if (configured_compression.IsValid()) { - compress_level = static_cast(configured_compression.GetIndex()); - } compressed_size = duckdb_zstd::ZSTD_compressBound(temp_writer.GetPosition()); compressed_buf = unique_ptr(new data_t[compressed_size]); - compressed_size = - duckdb_zstd::ZSTD_compress((void *)compressed_buf.get(), compressed_size, - (const void *)temp_writer.GetData(), temp_writer.GetPosition(), compress_level); + compressed_size = duckdb_zstd::ZSTD_compress((void *)compressed_buf.get(), compressed_size, + (const void *)temp_writer.GetData(), temp_writer.GetPosition(), + writer.CompressionLevel()); compressed_data = compressed_buf.get(); break; } @@ -344,13 +320,13 @@ struct PageWriteInformation { class BasicColumnWriterState : public ColumnWriterState { public: - BasicColumnWriterState(duckdb_parquet::format::RowGroup &row_group, idx_t col_idx) + BasicColumnWriterState(duckdb_parquet::RowGroup &row_group, idx_t col_idx) : row_group(row_group), col_idx(col_idx) { page_info.emplace_back(); } ~BasicColumnWriterState() override = default; - duckdb_parquet::format::RowGroup &row_group; + duckdb_parquet::RowGroup &row_group; idx_t col_idx; vector page_info; vector write_info; @@ -387,7 +363,7 @@ class BasicColumnWriter : public ColumnWriter { static constexpr const idx_t STRING_LENGTH_SIZE = sizeof(uint32_t); public: - unique_ptr InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) override; + unique_ptr InitializeWriteState(duckdb_parquet::RowGroup &row_group) override; void Prepare(ColumnWriterState &state, ColumnWriterState *parent, Vector &vector, idx_t count) override; void BeginWrite(ColumnWriterState &state) override; void Write(ColumnWriterState &state, Vector &vector, idx_t count) override; @@ -397,7 +373,7 @@ class BasicColumnWriter : public ColumnWriter { static void WriteLevels(WriteStream &temp_writer, const unsafe_vector &levels, idx_t max_value, idx_t start_offset, idx_t count); - virtual duckdb_parquet::format::Encoding::type GetEncoding(BasicColumnWriterState &state); + virtual duckdb_parquet::Encoding::type GetEncoding(BasicColumnWriterState &state); void NextPage(BasicColumnWriterState &state); void FlushPage(BasicColumnWriterState &state); @@ -425,18 +401,18 @@ class BasicColumnWriter : public ColumnWriter { void WriteDictionary(BasicColumnWriterState &state, unique_ptr temp_writer, idx_t row_count); virtual void FlushDictionary(BasicColumnWriterState &state, ColumnWriterStatistics *stats); - void SetParquetStatistics(BasicColumnWriterState &state, duckdb_parquet::format::ColumnChunk &column); - void RegisterToRowGroup(duckdb_parquet::format::RowGroup &row_group); + void SetParquetStatistics(BasicColumnWriterState &state, duckdb_parquet::ColumnChunk &column); + void RegisterToRowGroup(duckdb_parquet::RowGroup &row_group); }; -unique_ptr BasicColumnWriter::InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) { +unique_ptr BasicColumnWriter::InitializeWriteState(duckdb_parquet::RowGroup &row_group) { auto result = make_uniq(row_group, row_group.columns.size()); RegisterToRowGroup(row_group); return std::move(result); } -void BasicColumnWriter::RegisterToRowGroup(duckdb_parquet::format::RowGroup &row_group) { - format::ColumnChunk column_chunk; +void BasicColumnWriter::RegisterToRowGroup(duckdb_parquet::RowGroup &row_group) { + duckdb_parquet::ColumnChunk column_chunk; column_chunk.__isset.meta_data = true; column_chunk.meta_data.codec = writer.GetCodec(); column_chunk.meta_data.path_in_schema = schema_path; @@ -486,7 +462,7 @@ void BasicColumnWriter::Prepare(ColumnWriterState &state_p, ColumnWriterState *p } } -duckdb_parquet::format::Encoding::type BasicColumnWriter::GetEncoding(BasicColumnWriterState &state) { +duckdb_parquet::Encoding::type BasicColumnWriter::GetEncoding(BasicColumnWriterState &state) { return Encoding::PLAIN; } @@ -646,8 +622,7 @@ void BasicColumnWriter::Write(ColumnWriterState &state_p, Vector &vector, idx_t } } -void BasicColumnWriter::SetParquetStatistics(BasicColumnWriterState &state, - duckdb_parquet::format::ColumnChunk &column_chunk) { +void BasicColumnWriter::SetParquetStatistics(BasicColumnWriterState &state, duckdb_parquet::ColumnChunk &column_chunk) { if (max_repeat == 0) { column_chunk.meta_data.statistics.null_count = NumericCast(state.null_count); column_chunk.meta_data.statistics.__isset.null_count = true; @@ -879,7 +854,7 @@ struct ParquetUhugeintOperator { template static void TemplatedWritePlain(Vector &col, ColumnWriterStatistics *stats, const idx_t chunk_start, - const idx_t chunk_end, ValidityMask &mask, WriteStream &ser) { + const idx_t chunk_end, const ValidityMask &mask, WriteStream &ser) { static constexpr idx_t WRITE_COMBINER_CAPACITY = 8; TGT write_combiner[WRITE_COMBINER_CAPACITY]; idx_t write_combiner_count = 0; @@ -900,6 +875,25 @@ static void TemplatedWritePlain(Vector &col, ColumnWriterStatistics *stats, cons ser.WriteData(const_data_ptr_cast(write_combiner), write_combiner_count * sizeof(TGT)); } +class StandardColumnWriterState : public BasicColumnWriterState { +public: + StandardColumnWriterState(duckdb_parquet::RowGroup &row_group, idx_t col_idx) + : BasicColumnWriterState(row_group, col_idx) { + } + ~StandardColumnWriterState() override = default; + + // analysis state for integer values for DELTA_BINARY_PACKED + idx_t total_value_count = 0; +}; + +class StandardWriterPageState : public ColumnWriterPageState { +public: + explicit StandardWriterPageState(const idx_t total_value_count) : encoder(total_value_count), initialized(false) { + } + DbpEncoder encoder; + bool initialized; +}; + template class StandardColumnWriter : public BasicColumnWriter { public: @@ -910,14 +904,103 @@ class StandardColumnWriter : public BasicColumnWriter { ~StandardColumnWriter() override = default; public: + unique_ptr InitializeWriteState(duckdb_parquet::RowGroup &row_group) override { + auto result = make_uniq(row_group, row_group.columns.size()); + RegisterToRowGroup(row_group); + return std::move(result); + } + + unique_ptr InitializePageState(BasicColumnWriterState &state_p) override { + auto &state = state_p.Cast(); + auto result = make_uniq(state.total_value_count); + return std::move(result); + } + + void FlushPageState(WriteStream &temp_writer, ColumnWriterPageState *state_p) override { + auto &page_state = state_p->Cast(); + if (!page_state.initialized) { + page_state.encoder.BeginWrite(temp_writer, 0); + } + page_state.encoder.FinishWrite(temp_writer); + } + + Encoding::type GetEncoding(BasicColumnWriterState &state) override { + return HasAnalyze() ? Encoding::DELTA_BINARY_PACKED : Encoding::PLAIN; + } + + bool HasAnalyze() override { + // We can only do DELTA_BINARY_PACKED if the target type is int32_t/int64_t + const auto type = writer.GetType(schema_idx); + return type == Type::type::INT32 || type == Type::type::INT64; + } + + void Analyze(ColumnWriterState &state_p, ColumnWriterState *parent, Vector &vector, idx_t count) override { + D_ASSERT(HasAnalyze()); + auto &state = state_p.Cast(); + + const bool check_parent_empty = parent && !parent->is_empty.empty(); + const idx_t parent_index = state.definition_levels.size(); + + const idx_t vcount = + check_parent_empty ? parent->definition_levels.size() - state.definition_levels.size() : count; + const auto &validity = FlatVector::Validity(vector); + + idx_t vector_index = 0; + for (idx_t i = 0; i < vcount; i++) { + if (check_parent_empty && parent->is_empty[parent_index + i]) { + continue; + } + + if (validity.RowIsValid(vector_index)) { + state.total_value_count++; + } + vector_index++; + } + } + + void FinalizeAnalyze(ColumnWriterState &state) override { + // NOP + } + unique_ptr InitializeStatsState() override { return OP::template InitializeStats(); } - void WriteVector(WriteStream &temp_writer, ColumnWriterStatistics *stats, ColumnWriterPageState *page_state, + void WriteVector(WriteStream &temp_writer, ColumnWriterStatistics *stats, ColumnWriterPageState *page_state_p, Vector &input_column, idx_t chunk_start, idx_t chunk_end) override { - auto &mask = FlatVector::Validity(input_column); - TemplatedWritePlain(input_column, stats, chunk_start, chunk_end, mask, temp_writer); + const auto &mask = FlatVector::Validity(input_column); + if (HasAnalyze()) { + auto &page_state = page_state_p->Cast(); + auto &encoder = page_state.encoder; + const auto *ptr = FlatVector::GetData(input_column); + + idx_t r = chunk_start; + if (!page_state.initialized) { + // find first non-null value + for (; r < chunk_end; r++) { + if (!mask.RowIsValid(r)) { + continue; + } + const TGT target_value = OP::template Operation(ptr[r]); + OP::template HandleStats(stats, ptr[r], target_value); + encoder.BeginWrite(temp_writer, target_value); + page_state.initialized = true; + r++; // skip over + break; + } + } + + for (; r < chunk_end; r++) { + if (!mask.RowIsValid(r)) { + continue; + } + const TGT target_value = OP::template Operation(ptr[r]); + OP::template HandleStats(stats, ptr[r], target_value); + encoder.WriteValue(temp_writer, target_value); + } + } else { + TemplatedWritePlain(input_column, stats, chunk_start, chunk_end, mask, temp_writer); + } } idx_t GetRowSize(const Vector &vector, const idx_t index, const BasicColumnWriterState &state) const override { @@ -1270,7 +1353,7 @@ class StringStatisticsState : public ColumnWriterStatistics { class StringColumnWriterState : public BasicColumnWriterState { public: - StringColumnWriterState(duckdb_parquet::format::RowGroup &row_group, idx_t col_idx) + StringColumnWriterState(duckdb_parquet::RowGroup &row_group, idx_t col_idx) : BasicColumnWriterState(row_group, col_idx) { } ~StringColumnWriterState() override = default; @@ -1320,7 +1403,7 @@ class StringColumnWriter : public BasicColumnWriter { return make_uniq(); } - unique_ptr InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) override { + unique_ptr InitializeWriteState(duckdb_parquet::RowGroup &row_group) override { auto result = make_uniq(row_group, row_group.columns.size()); RegisterToRowGroup(row_group); return std::move(result); @@ -1368,7 +1451,7 @@ class StringColumnWriter : public BasicColumnWriter { // if the value changed, we will encode it in the page if (last_value_index != found.first->second) { // we will add the value index size later, when we know the total number of keys - state.estimated_rle_pages_size += GetVarintSize(run_length); + state.estimated_rle_pages_size += ParquetDecodeUtils::GetVarintSize(run_length); run_length = 0; run_count++; last_value_index = found.first->second; @@ -1451,7 +1534,7 @@ class StringColumnWriter : public BasicColumnWriter { } } - duckdb_parquet::format::Encoding::type GetEncoding(BasicColumnWriterState &state_p) override { + duckdb_parquet::Encoding::type GetEncoding(BasicColumnWriterState &state_p) override { auto &state = state_p.Cast(); return state.IsDictionaryEncoded() ? Encoding::RLE_DICTIONARY : Encoding::PLAIN; } @@ -1529,7 +1612,7 @@ class StringColumnWriter : public BasicColumnWriter { // GeoParquet files. class WKBColumnWriterState final : public StringColumnWriterState { public: - WKBColumnWriterState(ClientContext &context, duckdb_parquet::format::RowGroup &row_group, idx_t col_idx) + WKBColumnWriterState(ClientContext &context, duckdb_parquet::RowGroup &row_group, idx_t col_idx) : StringColumnWriterState(row_group, col_idx), geo_data(), geo_data_writer(context) { } @@ -1547,7 +1630,7 @@ class WKBColumnWriter final : public StringColumnWriter { this->writer.GetGeoParquetData().RegisterGeometryColumn(column_name); } - unique_ptr InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) override { + unique_ptr InitializeWriteState(duckdb_parquet::RowGroup &row_group) override { auto result = make_uniq(context, row_group, row_group.columns.size()); RegisterToRowGroup(row_group); return std::move(result); @@ -1658,7 +1741,7 @@ class EnumColumnWriter : public BasicColumnWriter { page_state.encoder.FinishWrite(temp_writer); } - duckdb_parquet::format::Encoding::type GetEncoding(BasicColumnWriterState &state) override { + duckdb_parquet::Encoding::type GetEncoding(BasicColumnWriterState &state) override { return Encoding::RLE_DICTIONARY; } @@ -1710,7 +1793,7 @@ class StructColumnWriter : public ColumnWriter { vector> child_writers; public: - unique_ptr InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) override; + unique_ptr InitializeWriteState(duckdb_parquet::RowGroup &row_group) override; bool HasAnalyze() override; void Analyze(ColumnWriterState &state, ColumnWriterState *parent, Vector &vector, idx_t count) override; void FinalizeAnalyze(ColumnWriterState &state) override; @@ -1723,17 +1806,17 @@ class StructColumnWriter : public ColumnWriter { class StructColumnWriterState : public ColumnWriterState { public: - StructColumnWriterState(duckdb_parquet::format::RowGroup &row_group, idx_t col_idx) + StructColumnWriterState(duckdb_parquet::RowGroup &row_group, idx_t col_idx) : row_group(row_group), col_idx(col_idx) { } ~StructColumnWriterState() override = default; - duckdb_parquet::format::RowGroup &row_group; + duckdb_parquet::RowGroup &row_group; idx_t col_idx; vector> child_states; }; -unique_ptr StructColumnWriter::InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) { +unique_ptr StructColumnWriter::InitializeWriteState(duckdb_parquet::RowGroup &row_group) { auto result = make_uniq(row_group, row_group.columns.size()); result->child_states.reserve(child_writers.size()); @@ -1831,7 +1914,7 @@ class ListColumnWriter : public ColumnWriter { unique_ptr child_writer; public: - unique_ptr InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) override; + unique_ptr InitializeWriteState(duckdb_parquet::RowGroup &row_group) override; bool HasAnalyze() override; void Analyze(ColumnWriterState &state, ColumnWriterState *parent, Vector &vector, idx_t count) override; void FinalizeAnalyze(ColumnWriterState &state) override; @@ -1844,18 +1927,17 @@ class ListColumnWriter : public ColumnWriter { class ListColumnWriterState : public ColumnWriterState { public: - ListColumnWriterState(duckdb_parquet::format::RowGroup &row_group, idx_t col_idx) - : row_group(row_group), col_idx(col_idx) { + ListColumnWriterState(duckdb_parquet::RowGroup &row_group, idx_t col_idx) : row_group(row_group), col_idx(col_idx) { } ~ListColumnWriterState() override = default; - duckdb_parquet::format::RowGroup &row_group; + duckdb_parquet::RowGroup &row_group; idx_t col_idx; unique_ptr child_state; idx_t parent_index = 0; }; -unique_ptr ListColumnWriter::InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) { +unique_ptr ListColumnWriter::InitializeWriteState(duckdb_parquet::RowGroup &row_group) { auto result = make_uniq(row_group, row_group.columns.size()); result->child_state = child_writer->InitializeWriteState(row_group); return std::move(result); @@ -2083,7 +2165,7 @@ void ArrayColumnWriter::Write(ColumnWriterState &state_p, Vector &vector, idx_t //===--------------------------------------------------------------------===// unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &context, - vector &schemas, + vector &schemas, ParquetWriter &writer, const LogicalType &type, const string &name, vector schema_path, optional_ptr field_ids, @@ -2107,7 +2189,7 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont if (type.id() == LogicalTypeId::STRUCT || type.id() == LogicalTypeId::UNION) { auto &child_types = StructType::GetChildTypes(type); // set up the schema element for this struct - duckdb_parquet::format::SchemaElement schema_element; + duckdb_parquet::SchemaElement schema_element; schema_element.repetition_type = null_type; schema_element.num_children = UnsafeNumericCast(child_types.size()); schema_element.__isset.num_children = true; @@ -2137,7 +2219,7 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont // set up the two schema elements for the list // for some reason we only set the converted type in the OPTIONAL element // first an OPTIONAL element - duckdb_parquet::format::SchemaElement optional_element; + duckdb_parquet::SchemaElement optional_element; optional_element.repetition_type = null_type; optional_element.num_children = 1; optional_element.converted_type = ConvertedType::LIST; @@ -2154,7 +2236,7 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont schema_path.push_back(name); // then a REPEATED element - duckdb_parquet::format::SchemaElement repeated_element; + duckdb_parquet::SchemaElement repeated_element; repeated_element.repetition_type = FieldRepetitionType::REPEATED; repeated_element.num_children = 1; repeated_element.__isset.num_children = true; @@ -2184,7 +2266,7 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont // } // } // top map element - duckdb_parquet::format::SchemaElement top_element; + duckdb_parquet::SchemaElement top_element; top_element.repetition_type = null_type; top_element.num_children = 1; top_element.converted_type = ConvertedType::MAP; @@ -2201,7 +2283,7 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont schema_path.push_back(name); // key_value element - duckdb_parquet::format::SchemaElement kv_element; + duckdb_parquet::SchemaElement kv_element; kv_element.repetition_type = FieldRepetitionType::REPEATED; kv_element.num_children = 2; kv_element.__isset.repetition_type = true; @@ -2229,7 +2311,7 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont return make_uniq(writer, schema_idx, schema_path, max_repeat, max_define, std::move(struct_writer), can_have_nulls); } - duckdb_parquet::format::SchemaElement schema_element; + duckdb_parquet::SchemaElement schema_element; schema_element.type = ParquetWriter::DuckDBTypeToParquetType(type); schema_element.repetition_type = null_type; schema_element.__isset.num_children = false; diff --git a/src/duckdb/extension/parquet/geo_parquet.cpp b/src/duckdb/extension/parquet/geo_parquet.cpp index b82cd5028..ec252a50d 100644 --- a/src/duckdb/extension/parquet/geo_parquet.cpp +++ b/src/duckdb/extension/parquet/geo_parquet.cpp @@ -176,9 +176,8 @@ void GeoParquetColumnMetadataWriter::Update(GeoParquetColumnMetadata &meta, Vect // GeoParquetFileMetadata //------------------------------------------------------------------------------ -unique_ptr -GeoParquetFileMetadata::TryRead(const duckdb_parquet::format::FileMetaData &file_meta_data, - const ClientContext &context) { +unique_ptr GeoParquetFileMetadata::TryRead(const duckdb_parquet::FileMetaData &file_meta_data, + const ClientContext &context) { // Conversion not enabled, or spatial is not loaded! if (!IsGeoParquetConversionEnabled(context)) { @@ -289,7 +288,7 @@ void GeoParquetFileMetadata::FlushColumnMeta(const string &column_name, const Ge column.bbox.Combine(meta.bbox); } -void GeoParquetFileMetadata::Write(duckdb_parquet::format::FileMetaData &file_meta_data) const { +void GeoParquetFileMetadata::Write(duckdb_parquet::FileMetaData &file_meta_data) const { yyjson_mut_doc *doc = yyjson_mut_doc_new(nullptr); yyjson_mut_val *root = yyjson_mut_obj(doc); @@ -343,7 +342,7 @@ void GeoParquetFileMetadata::Write(duckdb_parquet::format::FileMetaData &file_me } // Create a string from the JSON - duckdb_parquet::format::KeyValue kv; + duckdb_parquet::KeyValue kv; kv.__set_key("geo"); kv.__set_value(string(json, len)); diff --git a/src/duckdb/extension/parquet/include/boolean_column_reader.hpp b/src/duckdb/extension/parquet/include/boolean_column_reader.hpp index 125c548dc..c37c62098 100644 --- a/src/duckdb/extension/parquet/include/boolean_column_reader.hpp +++ b/src/duckdb/extension/parquet/include/boolean_column_reader.hpp @@ -40,10 +40,6 @@ class BooleanColumnReader : public TemplatedColumnReader parquet_filter_t; @@ -72,7 +72,7 @@ class ColumnReader { template void PlainTemplated(shared_ptr plain_data, uint8_t *defines, uint64_t num_values, - parquet_filter_t &filter, idx_t result_offset, Vector &result) { + parquet_filter_t *filter, idx_t result_offset, Vector &result) { if (HasDefines()) { if (CONVERSION::PlainAvailable(*plain_data, num_values)) { PlainTemplatedInternal(*plain_data, defines, num_values, filter, @@ -95,13 +95,13 @@ class ColumnReader { private: template void PlainTemplatedInternal(ByteBuffer &plain_data, const uint8_t *__restrict defines, const uint64_t num_values, - const parquet_filter_t &filter, const idx_t result_offset, Vector &result) { + const parquet_filter_t *filter, const idx_t result_offset, Vector &result) { const auto result_ptr = FlatVector::GetData(result); auto &result_mask = FlatVector::Validity(result); for (idx_t row_idx = result_offset; row_idx < result_offset + num_values; row_idx++) { - if (HAS_DEFINES && defines[row_idx] != max_define) { + if (HAS_DEFINES && defines && defines[row_idx] != max_define) { result_mask.SetInvalid(row_idx); - } else if (filter.test(row_idx)) { + } else if (!filter || filter->test(row_idx)) { result_ptr[row_idx] = UNSAFE ? CONVERSION::UnsafePlainRead(plain_data, *this) : CONVERSION::PlainRead(plain_data, *this); } else { // there is still some data there that we have to skip over @@ -117,14 +117,9 @@ class ColumnReader { protected: Allocator &GetAllocator(); // readers that use the default Read() need to implement those - virtual void Plain(shared_ptr plain_data, uint8_t *defines, idx_t num_values, parquet_filter_t &filter, + virtual void Plain(shared_ptr plain_data, uint8_t *defines, idx_t num_values, parquet_filter_t *filter, idx_t result_offset, Vector &result); - virtual void Dictionary(shared_ptr dictionary_data, idx_t num_entries); - virtual void Offsets(uint32_t *offsets, uint8_t *defines, idx_t num_values, parquet_filter_t &filter, - idx_t result_offset, Vector &result); - // these are nops for most types, but not for strings - virtual void DictReference(Vector &result); virtual void PlainReference(shared_ptr, Vector &result); virtual void PrepareDeltaLengthByteArray(ResizeableBuffer &buffer); @@ -168,10 +163,11 @@ class ColumnReader { void PreparePageV2(PageHeader &page_hdr); void DecompressInternal(CompressionCodec::type codec, const_data_ptr_t src, idx_t src_size, data_ptr_t dst, idx_t dst_size); + void ConvertDictToSelVec(uint32_t *offsets, uint8_t *defines, parquet_filter_t &filter, idx_t read_now, + idx_t result_offset); + const ColumnChunk *chunk = nullptr; - const duckdb_parquet::format::ColumnChunk *chunk = nullptr; - - duckdb_apache::thrift::protocol::TProtocol *protocol; + TProtocol *protocol; idx_t page_rows_available; idx_t group_rows_available; idx_t chunk_read_offset; @@ -193,6 +189,10 @@ class ColumnReader { ResizeableBuffer dummy_define; ResizeableBuffer dummy_repeat; + SelectionVector dictionary_selection_vector; + idx_t dictionary_size; + unique_ptr dictionary; + public: template TARGET &Cast() { diff --git a/src/duckdb/extension/parquet/include/column_writer.hpp b/src/duckdb/extension/parquet/include/column_writer.hpp index 65f89e596..619370b6d 100644 --- a/src/duckdb/extension/parquet/include/column_writer.hpp +++ b/src/duckdb/extension/parquet/include/column_writer.hpp @@ -80,12 +80,12 @@ class ColumnWriter { public: //! Create the column writer for a specific type recursively static unique_ptr - CreateWriterRecursive(ClientContext &context, vector &schemas, - ParquetWriter &writer, const LogicalType &type, const string &name, - vector schema_path, optional_ptr field_ids, idx_t max_repeat = 0, - idx_t max_define = 1, bool can_have_nulls = true); + CreateWriterRecursive(ClientContext &context, vector &schemas, ParquetWriter &writer, + const LogicalType &type, const string &name, vector schema_path, + optional_ptr field_ids, idx_t max_repeat = 0, idx_t max_define = 1, + bool can_have_nulls = true); - virtual unique_ptr InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) = 0; + virtual unique_ptr InitializeWriteState(duckdb_parquet::RowGroup &row_group) = 0; //! indicates whether the write need to analyse the data before preparing it virtual bool HasAnalyze() { diff --git a/src/duckdb/extension/parquet/include/decode_utils.hpp b/src/duckdb/extension/parquet/include/decode_utils.hpp index 3b2829d61..431820949 100644 --- a/src/duckdb/extension/parquet/include/decode_utils.hpp +++ b/src/duckdb/extension/parquet/include/decode_utils.hpp @@ -1,42 +1,148 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// decode_utils.hpp +// +// +//===----------------------------------------------------------------------===// + #pragma once +#include "duckdb/common/bitpacking.hpp" #include "resizable_buffer.hpp" namespace duckdb { -class ParquetDecodeUtils { - -public: - template - static T ZigzagToInt(const uint64_t n) { - return T(n >> 1) ^ -T(n & 1); - } +class ParquetDecodeUtils { + //===--------------------------------------------------------------------===// + // Bitpacking + //===--------------------------------------------------------------------===// +private: static const uint64_t BITPACK_MASKS[]; static const uint64_t BITPACK_MASKS_SIZE; static const uint8_t BITPACK_DLEN; - template - static uint32_t BitUnpack(ByteBuffer &buffer, uint8_t &bitpack_pos, T *dest, uint32_t count, uint8_t width) { - if (width >= ParquetDecodeUtils::BITPACK_MASKS_SIZE) { + static void CheckWidth(const uint8_t width) { + if (width >= BITPACK_MASKS_SIZE) { throw InvalidInputException("The width (%d) of the bitpacked data exceeds the supported max width (%d), " "the file might be corrupted.", - width, ParquetDecodeUtils::BITPACK_MASKS_SIZE); + width, BITPACK_MASKS_SIZE); } - auto mask = BITPACK_MASKS[width]; + } - for (uint32_t i = 0; i < count; i++) { - T val = (buffer.get() >> bitpack_pos) & mask; +public: + template + static uint32_t BitUnpack(ByteBuffer &src, bitpacking_width_t &bitpack_pos, T *dst, const idx_t count, + const bitpacking_width_t width) { + CheckWidth(width); + const auto mask = BITPACK_MASKS[width]; + src.available(count * width / BITPACK_DLEN); // check if buffer has enough space available once + for (idx_t i = 0; i < count; i++) { + auto val = (src.unsafe_get() >> bitpack_pos) & mask; bitpack_pos += width; while (bitpack_pos > BITPACK_DLEN) { - buffer.inc(1); - val |= (T(buffer.get()) << T(BITPACK_DLEN - (bitpack_pos - width))) & mask; + src.unsafe_inc(1); + val |= (static_cast(src.unsafe_get()) + << static_cast(BITPACK_DLEN - (bitpack_pos - width))) & + mask; bitpack_pos -= BITPACK_DLEN; } - dest[i] = val; + dst[i] = val; } return count; } + template + static void BitPackAligned(T *src, data_ptr_t dst, const idx_t count, const bitpacking_width_t width) { + D_ASSERT(width < BITPACK_MASKS_SIZE); + D_ASSERT(count % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE == 0); + BitpackingPrimitives::PackBuffer(dst, src, count, width); + } + + template + static void BitUnpackAligned(ByteBuffer &src, T *dst, const idx_t count, const bitpacking_width_t width) { + CheckWidth(width); + if (count % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE != 0) { + throw InvalidInputException("Aligned bitpacking count must be a multiple of %llu", + BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE); + } + const auto read_size = count * width / BITPACK_DLEN; + src.available(read_size); // check if buffer has enough space available once + for (idx_t i = 0; i < count; i += BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE) { + // Buffer for alignment + T aligned_data[BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE]; + + // Copy over to aligned buffer + const auto next_read = BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE * width / 8; + memcpy(aligned_data, src.ptr, next_read); + src.unsafe_inc(next_read); + + // Unpack + BitpackingPrimitives::UnPackBlock(data_ptr_cast(dst), data_ptr_cast(aligned_data), width); + } + } + + //===--------------------------------------------------------------------===// + // Zigzag + //===--------------------------------------------------------------------===// +private: + //! https://lemire.me/blog/2022/11/25/making-all-your-integers-positive-with-zigzag-encoding/ + template + static typename std::enable_if::value, typename std::make_signed::type>::type + ZigzagToIntInternal(UNSIGNED x) { + return (x >> 1) ^ (-(x & 1)); + } + + template + static typename std::enable_if::value, typename std::make_unsigned::type>::type + IntToZigzagInternal(SIGNED x) { + using UNSIGNED = typename std::make_unsigned::type; + return (static_cast(x) << 1) ^ static_cast(x >> (sizeof(SIGNED) * 8 - 1)); + } + +public: + template + static typename std::enable_if::value, typename std::make_signed::type>::type + ZigzagToInt(UNSIGNED x) { + auto integer = ZigzagToIntInternal(x); + D_ASSERT(x == IntToZigzagInternal(integer)); // test roundtrip + return integer; + } + + template + static typename std::enable_if::value, typename std::make_unsigned::type>::type + IntToZigzag(SIGNED x) { + auto zigzag = IntToZigzagInternal(x); + D_ASSERT(x == ZigzagToIntInternal(zigzag)); // test roundtrip + return zigzag; + } + + //===--------------------------------------------------------------------===// + // Varint + //===--------------------------------------------------------------------===// +public: + template + static uint8_t GetVarintSize(T val) { + uint8_t res = 0; + do { + val >>= 7; + res++; + } while (val != 0); + return res; + } + + template + static void VarintEncode(T val, WriteStream &ser) { + do { + uint8_t byte = val & 127; + val >>= 7; + if (val != 0) { + byte |= 128; + } + ser.Write(byte); + } while (val != 0); + } + template static T VarintDecode(ByteBuffer &buf) { T result = 0; diff --git a/src/duckdb/extension/parquet/include/geo_parquet.hpp b/src/duckdb/extension/parquet/include/geo_parquet.hpp index e9b7ce484..0a9b0966f 100644 --- a/src/duckdb/extension/parquet/include/geo_parquet.hpp +++ b/src/duckdb/extension/parquet/include/geo_parquet.hpp @@ -119,15 +119,16 @@ class GeoParquetFileMetadata { public: // 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::format::FileMetaData &file_meta_data, + + static unique_ptr TryRead(const duckdb_parquet::FileMetaData &file_meta_data, const ClientContext &context); - void Write(duckdb_parquet::format::FileMetaData &file_meta_data) const; + void Write(duckdb_parquet::FileMetaData &file_meta_data) const; void FlushColumnMeta(const string &column_name, const GeoParquetColumnMetadata &meta); const unordered_map &GetColumnMeta() const; unique_ptr CreateColumnReader(ParquetReader &reader, const LogicalType &logical_type, - const duckdb_parquet::format::SchemaElement &s_ele, idx_t schema_idx_p, + const duckdb_parquet::SchemaElement &s_ele, idx_t schema_idx_p, idx_t max_define_p, idx_t max_repeat_p, ClientContext &context); bool IsGeometryColumn(const string &column_name) const; diff --git a/src/duckdb/extension/parquet/include/null_column_reader.hpp b/src/duckdb/extension/parquet/include/null_column_reader.hpp index 567efee3e..6d89c906b 100644 --- a/src/duckdb/extension/parquet/include/null_column_reader.hpp +++ b/src/duckdb/extension/parquet/include/null_column_reader.hpp @@ -25,20 +25,7 @@ class NullColumnReader : public ColumnReader { shared_ptr dict; public: - void Dictionary(shared_ptr data, idx_t num_entries) override { - dict = std::move(data); - } - - void Offsets(uint32_t *offsets, uint8_t *defines, uint64_t num_values, parquet_filter_t &filter, - idx_t result_offset, Vector &result) override { - auto &result_mask = FlatVector::Validity(result); - - for (idx_t row_idx = 0; row_idx < num_values; row_idx++) { - result_mask.SetInvalid(row_idx + result_offset); - } - } - - void Plain(shared_ptr plain_data, uint8_t *defines, uint64_t num_values, parquet_filter_t &filter, + void Plain(shared_ptr plain_data, uint8_t *defines, uint64_t num_values, parquet_filter_t *filter, idx_t result_offset, Vector &result) override { (void)defines; (void)plain_data; diff --git a/src/duckdb/extension/parquet/include/parquet_crypto.hpp b/src/duckdb/extension/parquet/include/parquet_crypto.hpp index b4aed9d0c..470648446 100644 --- a/src/duckdb/extension/parquet/include/parquet_crypto.hpp +++ b/src/duckdb/extension/parquet/include/parquet_crypto.hpp @@ -4,7 +4,7 @@ // parquet_crypto.hpp // // -//===----------------------------------------------------------------------===/ +//===----------------------------------------------------------------------===// #pragma once diff --git a/src/duckdb/extension/parquet/include/parquet_dbp_decoder.hpp b/src/duckdb/extension/parquet/include/parquet_dbp_decoder.hpp index c40c3c026..4925a0ff9 100644 --- a/src/duckdb/extension/parquet/include/parquet_dbp_decoder.hpp +++ b/src/duckdb/extension/parquet/include/parquet_dbp_decoder.hpp @@ -1,126 +1,137 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// parquet_dbp_deccoder.hpp +// +// +//===----------------------------------------------------------------------===// + #pragma once + #include "decode_utils.hpp" namespace duckdb { + class DbpDecoder { public: - DbpDecoder(data_ptr_t buffer, uint32_t buffer_len) : buffer_(buffer, buffer_len) { - // - // overall header - block_value_count = ParquetDecodeUtils::VarintDecode(buffer_); - miniblocks_per_block = ParquetDecodeUtils::VarintDecode(buffer_); - total_value_count = ParquetDecodeUtils::VarintDecode(buffer_); - start_value = ParquetDecodeUtils::ZigzagToInt(ParquetDecodeUtils::VarintDecode(buffer_)); - - // some derivatives - D_ASSERT(miniblocks_per_block > 0); - values_per_miniblock = block_value_count / miniblocks_per_block; - miniblock_bit_widths = unique_ptr(new data_t[miniblocks_per_block]); - - // init state to something sane - values_left_in_block = 0; - values_left_in_miniblock = 0; - miniblock_offset = 0; - min_delta = 0; - bitpack_pos = 0; - is_first_value = true; + DbpDecoder(const data_ptr_t buffer, const uint32_t buffer_len) + : buffer_(buffer, buffer_len), + // + block_size_in_values(ParquetDecodeUtils::VarintDecode(buffer_)), + number_of_miniblocks_per_block(ParquetDecodeUtils::VarintDecode(buffer_)), + number_of_values_in_a_miniblock(block_size_in_values / number_of_miniblocks_per_block), + total_value_count(ParquetDecodeUtils::VarintDecode(buffer_)), + previous_value(ParquetDecodeUtils::ZigzagToInt(ParquetDecodeUtils::VarintDecode(buffer_))), + // init state to something sane + is_first_value(true), read_values(0), min_delta(NumericLimits::Maximum()), + miniblock_index(number_of_miniblocks_per_block - 1), list_of_bitwidths_of_miniblocks(nullptr), + miniblock_offset(number_of_values_in_a_miniblock), + unpacked_data_offset(BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE) { + if (!(block_size_in_values % number_of_miniblocks_per_block == 0 && + number_of_values_in_a_miniblock % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE == 0)) { + throw InvalidInputException("Parquet file has invalid block sizes for DELTA_BINARY_PACKED"); + } }; - ByteBuffer BufferPtr() { - if (bitpack_pos != 0) { - buffer_.inc(1); - bitpack_pos = 0; - } + ByteBuffer BufferPtr() const { return buffer_; } + uint64_t TotalValues() const { + return total_value_count; + } + template - void GetBatch(data_ptr_t values_target_ptr, uint32_t batch_size) { - auto values = reinterpret_cast(values_target_ptr); + void GetBatch(const data_ptr_t target_values_ptr, const idx_t batch_size) { + if (read_values + batch_size > total_value_count) { + throw std::runtime_error("DBP decode did not find enough values"); + } + read_values += batch_size; + GetBatchInternal(target_values_ptr, batch_size); + } + + void Finalize() { + if (miniblock_offset == number_of_values_in_a_miniblock) { + return; + } + auto data = make_unsafe_uniq_array(number_of_values_in_a_miniblock); + GetBatchInternal(data_ptr_cast(data.get()), number_of_values_in_a_miniblock - miniblock_offset); + } +private: + template + void GetBatchInternal(const data_ptr_t target_values_ptr, const idx_t batch_size) { if (batch_size == 0) { return; } - idx_t value_offset = 0; + auto target_values = reinterpret_cast(target_values_ptr); + idx_t target_values_offset = 0; if (is_first_value) { - values[0] = start_value; - value_offset++; + target_values[0] = static_cast(previous_value); + target_values_offset++; is_first_value = false; } - if (total_value_count == 1) { // I guess it's a special case - if (batch_size > 1) { - throw std::runtime_error("DBP decode did not find enough values (have 1)"); - } - return; - } - - while (value_offset < batch_size) { - if (values_left_in_block == 0) { // need to open new block - if (bitpack_pos > 0) { // have to eat the leftovers if any - buffer_.inc(1); - } - min_delta = - ParquetDecodeUtils::ZigzagToInt(ParquetDecodeUtils::VarintDecode(buffer_)); - for (idx_t miniblock_idx = 0; miniblock_idx < miniblocks_per_block; miniblock_idx++) { - miniblock_bit_widths[miniblock_idx] = buffer_.read(); - // TODO what happens if width is 0? + while (target_values_offset < batch_size) { + // Copy over any remaining data + const idx_t next = MinValue(batch_size - target_values_offset, + BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE - unpacked_data_offset); + if (next != 0) { + for (idx_t i = 0; i < next; i++) { + auto &target = target_values[target_values_offset + i]; + const auto &unpacked_value = unpacked_data[unpacked_data_offset + i]; + target = static_cast(static_cast(previous_value) + static_cast(min_delta) + + unpacked_value); + previous_value = static_cast(target); } - values_left_in_block = block_value_count; - miniblock_offset = 0; - bitpack_pos = 0; - values_left_in_miniblock = values_per_miniblock; - } - if (values_left_in_miniblock == 0) { - miniblock_offset++; - values_left_in_miniblock = values_per_miniblock; + target_values_offset += next; + unpacked_data_offset += next; + continue; } - auto read_now = MinValue(values_left_in_miniblock, (idx_t)batch_size - value_offset); - ParquetDecodeUtils::BitUnpack(buffer_, bitpack_pos, &values[value_offset], read_now, - miniblock_bit_widths[miniblock_offset]); - for (idx_t i = value_offset; i < value_offset + read_now; i++) { - values[i] = T(uint64_t((i == 0) ? start_value : values[i - 1]) + min_delta + uint64_t(values[i])); + // Move to next miniblock / block + D_ASSERT(unpacked_data_offset == BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE); + D_ASSERT(miniblock_index < number_of_miniblocks_per_block); + D_ASSERT(miniblock_offset <= number_of_values_in_a_miniblock); + if (miniblock_offset == number_of_values_in_a_miniblock) { + miniblock_offset = 0; + if (++miniblock_index == number_of_miniblocks_per_block) { + // + min_delta = ParquetDecodeUtils::ZigzagToInt(ParquetDecodeUtils::VarintDecode(buffer_)); + buffer_.available(number_of_miniblocks_per_block); + list_of_bitwidths_of_miniblocks = buffer_.ptr; + buffer_.unsafe_inc(number_of_miniblocks_per_block); + miniblock_index = 0; + } } - value_offset += read_now; - values_left_in_miniblock -= read_now; - values_left_in_block -= read_now; - } - if (value_offset != batch_size) { - throw std::runtime_error("DBP decode did not find enough values"); - } - start_value = values[batch_size - 1]; - } - void Finalize() { - if (values_left_in_miniblock == 0) { - return; + // Unpack from current miniblock + ParquetDecodeUtils::BitUnpackAligned(buffer_, unpacked_data, + BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE, + list_of_bitwidths_of_miniblocks[miniblock_index]); + unpacked_data_offset = 0; + miniblock_offset += BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE; } - auto data = unique_ptr(new uint32_t[values_left_in_miniblock]); - GetBatch(data_ptr_cast(data.get()), values_left_in_miniblock); - } - - uint64_t TotalValues() { - return total_value_count; } private: ByteBuffer buffer_; - idx_t block_value_count; - idx_t miniblocks_per_block; - idx_t total_value_count; - int64_t start_value; - idx_t values_per_miniblock; - - unique_ptr miniblock_bit_widths; - idx_t values_left_in_block; - idx_t values_left_in_miniblock; - idx_t miniblock_offset; - int64_t min_delta; + const idx_t block_size_in_values; + const idx_t number_of_miniblocks_per_block; + const idx_t number_of_values_in_a_miniblock; + const idx_t total_value_count; + int64_t previous_value; bool is_first_value; + idx_t read_values; - uint8_t bitpack_pos; + //! Block stuff + int64_t min_delta; + idx_t miniblock_index; + bitpacking_width_t *list_of_bitwidths_of_miniblocks; + idx_t miniblock_offset; + uint64_t unpacked_data[BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE]; + idx_t unpacked_data_offset; }; } // namespace duckdb diff --git a/src/duckdb/extension/parquet/include/parquet_dbp_encoder.hpp b/src/duckdb/extension/parquet/include/parquet_dbp_encoder.hpp new file mode 100644 index 000000000..36cffb1a1 --- /dev/null +++ b/src/duckdb/extension/parquet/include/parquet_dbp_encoder.hpp @@ -0,0 +1,179 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// parquet_dbp_encoder.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "decode_utils.hpp" + +namespace duckdb { + +class DbpEncoder { +private: + static constexpr uint64_t BLOCK_SIZE_IN_VALUES = 2048; + static constexpr uint64_t NUMBER_OF_MINIBLOCKS_IN_A_BLOCK = 8; + static constexpr uint64_t NUMBER_OF_VALUES_IN_A_MINIBLOCK = BLOCK_SIZE_IN_VALUES / NUMBER_OF_MINIBLOCKS_IN_A_BLOCK; + +public: + explicit DbpEncoder(const idx_t total_value_count_p) : total_value_count(total_value_count_p), count(0) { + } + +public: + void BeginWrite(WriteStream &writer, const int64_t first_value) { + // + + // the block size is a multiple of 128; it is stored as a ULEB128 int + ParquetDecodeUtils::VarintEncode(BLOCK_SIZE_IN_VALUES, writer); + // the miniblock count per block is a divisor of the block size such that their quotient, + // the number of values in a miniblock, is a multiple of 32 + static_assert(BLOCK_SIZE_IN_VALUES % NUMBER_OF_MINIBLOCKS_IN_A_BLOCK == 0 && + NUMBER_OF_VALUES_IN_A_MINIBLOCK % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE == 0, + "invalid block sizes for DELTA_BINARY_PACKED"); + // it is stored as a ULEB128 int + ParquetDecodeUtils::VarintEncode(NUMBER_OF_MINIBLOCKS_IN_A_BLOCK, writer); + // the total value count is stored as a ULEB128 int + ParquetDecodeUtils::VarintEncode(total_value_count, writer); + // the first value is stored as a zigzag ULEB128 int + ParquetDecodeUtils::VarintEncode(ParquetDecodeUtils::IntToZigzag(first_value), writer); + + // initialize + if (total_value_count != 0) { + count++; + } + previous_value = first_value; + + min_delta = NumericLimits::Maximum(); + block_count = 0; + } + + void WriteValue(WriteStream &writer, const int64_t &value) { + // 1. Compute the differences between consecutive elements. For the first element in the block, + // use the last element in the previous block or, in the case of the first block, + // use the first value of the whole sequence, stored in the header. + + // Subtractions in steps 1) and 2) may incur signed arithmetic overflow, + // and so will the corresponding additions when decoding. + // Overflow should be allowed and handled as wrapping around in 2’s complement notation + // so that the original values are correctly restituted. + // This may require explicit care in some programming languages + // (for example by doing all arithmetic in the unsigned domain). + const auto delta = static_cast(static_cast(value) - static_cast(previous_value)); + previous_value = value; + // Compute the frame of reference (the minimum of the deltas in the block). + min_delta = MinValue(min_delta, delta); + // append. if block is full, write it out + data[block_count++] = delta; + if (block_count == BLOCK_SIZE_IN_VALUES) { + WriteBlock(writer); + } + } + + void FinishWrite(WriteStream &writer) { + if (count + block_count != total_value_count) { + throw InternalException("value count mismatch when writing DELTA_BINARY_PACKED"); + } + if (block_count != 0) { + WriteBlock(writer); + } + } + +private: + void WriteBlock(WriteStream &writer) { + D_ASSERT(count + block_count == total_value_count || block_count == BLOCK_SIZE_IN_VALUES); + const auto number_of_miniblocks = + (block_count + NUMBER_OF_VALUES_IN_A_MINIBLOCK - 1) / NUMBER_OF_VALUES_IN_A_MINIBLOCK; + for (idx_t miniblock_idx = 0; miniblock_idx < number_of_miniblocks; miniblock_idx++) { + for (idx_t i = 0; i < NUMBER_OF_VALUES_IN_A_MINIBLOCK; i++) { + const idx_t index = miniblock_idx * NUMBER_OF_VALUES_IN_A_MINIBLOCK + i; + auto &value = data[index]; + if (index < block_count) { + // 2. Compute the frame of reference (the minimum of the deltas in the block). + // Subtract this min delta from all deltas in the block. + // This guarantees that all values are non-negative. + D_ASSERT(min_delta <= value); + value = static_cast(static_cast(value) - static_cast(min_delta)); + } else { + // If there are not enough values to fill the last miniblock, we pad the miniblock + // so that its length is always the number of values in a full miniblock multiplied by the bit + // width. The values of the padding bits should be zero, but readers must accept paddings consisting + // of arbitrary bits as well. + value = 0; + } + } + } + + for (idx_t miniblock_idx = 0; miniblock_idx < NUMBER_OF_MINIBLOCKS_IN_A_BLOCK; miniblock_idx++) { + auto &width = list_of_bitwidths_of_miniblocks[miniblock_idx]; + if (miniblock_idx < number_of_miniblocks) { + const auto src = &data[miniblock_idx * NUMBER_OF_VALUES_IN_A_MINIBLOCK]; + width = BitpackingPrimitives::MinimumBitWidth(reinterpret_cast(src), + NUMBER_OF_VALUES_IN_A_MINIBLOCK); + D_ASSERT(width <= sizeof(int64_t) * 8); + } else { + // If, in the last block, less than miniblocks are needed to store the + // values, the bytes storing the bit widths of the unneeded miniblocks are still present, their value + // should be zero, but readers must accept arbitrary values as well. There are no additional padding + // bytes for the miniblock bodies though, as if their bit widths were 0 (regardless of the actual byte + // values). The reader knows when to stop reading by keeping track of the number of values read. + width = 0; + } + } + + // 3. Encode the frame of reference (min delta) as a zigzag ULEB128 int + // followed by the bit widths of the miniblocks + // and the delta values (minus the min delta) bit-packed per miniblock. + // + + // the min delta is a zigzag ULEB128 int (we compute a minimum as we need positive integers for bit packing) + ParquetDecodeUtils::VarintEncode(ParquetDecodeUtils::IntToZigzag(min_delta), writer); + // the bitwidth of each block is stored as a byte + writer.WriteData(list_of_bitwidths_of_miniblocks, NUMBER_OF_MINIBLOCKS_IN_A_BLOCK); + // each miniblock is a list of bit packed ints according to the bit width stored at the beginning of the block + for (idx_t miniblock_idx = 0; miniblock_idx < number_of_miniblocks; miniblock_idx++) { + const auto src = &data[miniblock_idx * NUMBER_OF_VALUES_IN_A_MINIBLOCK]; + const auto &width = list_of_bitwidths_of_miniblocks[miniblock_idx]; + memset(data_packed, 0, sizeof(data_packed)); + ParquetDecodeUtils::BitPackAligned(reinterpret_cast(src), data_packed, + NUMBER_OF_VALUES_IN_A_MINIBLOCK, width); + const auto write_size = NUMBER_OF_VALUES_IN_A_MINIBLOCK * width / 8; +#ifdef DEBUG + // immediately verify that unpacking yields the input data + int64_t verification_data[NUMBER_OF_VALUES_IN_A_MINIBLOCK]; + ByteBuffer byte_buffer(data_ptr_cast(data_packed), write_size); + bitpacking_width_t bitpack_pos = 0; + ParquetDecodeUtils::BitUnpack(byte_buffer, bitpack_pos, verification_data, NUMBER_OF_VALUES_IN_A_MINIBLOCK, + width); + for (idx_t i = 0; i < NUMBER_OF_VALUES_IN_A_MINIBLOCK; i++) { + D_ASSERT(src[i] == verification_data[i]); + } +#endif + writer.WriteData(data_packed, write_size); + } + + count += block_count; + + min_delta = NumericLimits::Maximum(); + block_count = 0; + } + +private: + //! Overall fields + const idx_t total_value_count; + idx_t count; + int64_t previous_value; + + //! Block-specific fields + int64_t min_delta; + int64_t data[BLOCK_SIZE_IN_VALUES]; + idx_t block_count; + + //! Bitpacking fields + bitpacking_width_t list_of_bitwidths_of_miniblocks[NUMBER_OF_MINIBLOCKS_IN_A_BLOCK]; + data_t data_packed[NUMBER_OF_VALUES_IN_A_MINIBLOCK * sizeof(int64_t)]; +}; + +} // namespace duckdb diff --git a/src/duckdb/extension/parquet/include/parquet_decimal_utils.hpp b/src/duckdb/extension/parquet/include/parquet_decimal_utils.hpp index 4f189bbcf..119ed5672 100644 --- a/src/duckdb/extension/parquet/include/parquet_decimal_utils.hpp +++ b/src/duckdb/extension/parquet/include/parquet_decimal_utils.hpp @@ -16,8 +16,7 @@ namespace duckdb { class ParquetDecimalUtils { public: template - static PHYSICAL_TYPE ReadDecimalValue(const_data_ptr_t pointer, idx_t size, - const duckdb_parquet::format::SchemaElement &) { + static PHYSICAL_TYPE ReadDecimalValue(const_data_ptr_t pointer, idx_t size, const duckdb_parquet::SchemaElement &) { PHYSICAL_TYPE res = 0; auto res_ptr = (uint8_t *)&res; @@ -54,6 +53,6 @@ class ParquetDecimalUtils { template <> double ParquetDecimalUtils::ReadDecimalValue(const_data_ptr_t pointer, idx_t size, - const duckdb_parquet::format::SchemaElement &schema_ele); + const duckdb_parquet::SchemaElement &schema_ele); } // namespace duckdb diff --git a/src/duckdb/extension/parquet/include/parquet_extension.hpp b/src/duckdb/extension/parquet/include/parquet_extension.hpp index 702adb382..413a104b6 100644 --- a/src/duckdb/extension/parquet/include/parquet_extension.hpp +++ b/src/duckdb/extension/parquet/include/parquet_extension.hpp @@ -1,3 +1,11 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// parquet_extension.hpp +// +// +//===----------------------------------------------------------------------===/ + #pragma once #include "duckdb.hpp" diff --git a/src/duckdb/extension/parquet/include/parquet_file_metadata_cache.hpp b/src/duckdb/extension/parquet/include/parquet_file_metadata_cache.hpp index 48b6448de..b7373056f 100644 --- a/src/duckdb/extension/parquet/include/parquet_file_metadata_cache.hpp +++ b/src/duckdb/extension/parquet/include/parquet_file_metadata_cache.hpp @@ -20,7 +20,7 @@ class ParquetFileMetadataCache : public ObjectCacheEntry { public: ParquetFileMetadataCache() : metadata(nullptr) { } - ParquetFileMetadataCache(unique_ptr file_metadata, time_t r_time, + ParquetFileMetadataCache(unique_ptr file_metadata, time_t r_time, unique_ptr geo_metadata) : metadata(std::move(file_metadata)), read_time(r_time), geo_metadata(std::move(geo_metadata)) { } @@ -28,7 +28,7 @@ class ParquetFileMetadataCache : public ObjectCacheEntry { ~ParquetFileMetadataCache() override = default; //! Parquet file metadata - unique_ptr metadata; + unique_ptr metadata; //! read time time_t read_time; diff --git a/src/duckdb/extension/parquet/include/parquet_reader.hpp b/src/duckdb/extension/parquet/include/parquet_reader.hpp index 6b536bbd5..62f2d845c 100644 --- a/src/duckdb/extension/parquet/include/parquet_reader.hpp +++ b/src/duckdb/extension/parquet/include/parquet_reader.hpp @@ -138,7 +138,7 @@ class ParquetReader { //! Index of the file_row_number column idx_t file_row_number_idx = DConstants::INVALID_INDEX; //! Parquet schema for the generated columns - vector generated_column_schema; + vector generated_column_schema; //! Table column names - set when using COPY tbl FROM file.parquet vector table_columns; @@ -167,7 +167,7 @@ class ParquetReader { idx_t NumRows(); idx_t NumRowGroups(); - const duckdb_parquet::format::FileMetaData *GetFileMetadata(); + const duckdb_parquet::FileMetaData *GetFileMetadata(); uint32_t Read(duckdb_apache::thrift::TBase &object, TProtocol &iprot); uint32_t ReadData(duckdb_apache::thrift::protocol::TProtocol &iprot, const data_ptr_t buffer, @@ -204,7 +204,7 @@ class ParquetReader { unique_ptr CreateReaderRecursive(ClientContext &context, idx_t depth, idx_t max_define, idx_t max_repeat, idx_t &next_schema_idx, idx_t &next_file_idx); - const duckdb_parquet::format::RowGroup &GetGroup(ParquetReaderScanState &state); + const duckdb_parquet::RowGroup &GetGroup(ParquetReaderScanState &state); uint64_t GetGroupCompressedSize(ParquetReaderScanState &state); idx_t GetGroupOffset(ParquetReaderScanState &state); // Group span is the distance between the min page offset and the max page offset plus the max page compressed size diff --git a/src/duckdb/extension/parquet/include/parquet_statistics.hpp b/src/duckdb/extension/parquet/include/parquet_statistics.hpp index 94ce194e2..43c47223f 100644 --- a/src/duckdb/extension/parquet/include/parquet_statistics.hpp +++ b/src/duckdb/extension/parquet/include/parquet_statistics.hpp @@ -1,3 +1,11 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// parquet_statistics.hpp +// +// +//===----------------------------------------------------------------------===/ + #pragma once #include "duckdb.hpp" @@ -8,8 +16,8 @@ namespace duckdb { -using duckdb_parquet::format::ColumnChunk; -using duckdb_parquet::format::SchemaElement; +using duckdb_parquet::ColumnChunk; +using duckdb_parquet::SchemaElement; struct LogicalType; class ColumnReader; @@ -19,7 +27,7 @@ struct ParquetStatisticsUtils { static unique_ptr TransformColumnStatistics(const ColumnReader &reader, const vector &columns); - static Value ConvertValue(const LogicalType &type, const duckdb_parquet::format::SchemaElement &schema_ele, + static Value ConvertValue(const LogicalType &type, const duckdb_parquet::SchemaElement &schema_ele, const std::string &stats); }; diff --git a/src/duckdb/extension/parquet/include/parquet_writer.hpp b/src/duckdb/extension/parquet/include/parquet_writer.hpp index 297d2efa6..7eb5bc85c 100644 --- a/src/duckdb/extension/parquet/include/parquet_writer.hpp +++ b/src/duckdb/extension/parquet/include/parquet_writer.hpp @@ -33,7 +33,7 @@ class Serializer; class Deserializer; struct PreparedRowGroup { - duckdb_parquet::format::RowGroup row_group; + duckdb_parquet::RowGroup row_group; vector> states; vector> heaps; }; @@ -64,10 +64,10 @@ struct FieldID { class ParquetWriter { public: ParquetWriter(ClientContext &context, FileSystem &fs, string file_name, vector types, - vector names, duckdb_parquet::format::CompressionCodec::type codec, ChildFieldIDs field_ids, + vector names, duckdb_parquet::CompressionCodec::type codec, ChildFieldIDs field_ids, const vector> &kv_metadata, shared_ptr encryption_config, double dictionary_compression_ratio_threshold, - optional_idx compression_level, bool debug_use_openssl); + int64_t compression_level, bool debug_use_openssl); public: void PrepareRowGroup(ColumnDataCollection &buffer, PreparedRowGroup &result); @@ -75,16 +75,16 @@ class ParquetWriter { void Flush(ColumnDataCollection &buffer); void Finalize(); - static duckdb_parquet::format::Type::type DuckDBTypeToParquetType(const LogicalType &duckdb_type); - static void SetSchemaProperties(const LogicalType &duckdb_type, duckdb_parquet::format::SchemaElement &schema_ele); + static duckdb_parquet::Type::type DuckDBTypeToParquetType(const LogicalType &duckdb_type); + static void SetSchemaProperties(const LogicalType &duckdb_type, duckdb_parquet::SchemaElement &schema_ele); duckdb_apache::thrift::protocol::TProtocol *GetProtocol() { return protocol.get(); } - duckdb_parquet::format::CompressionCodec::type GetCodec() { + duckdb_parquet::CompressionCodec::type GetCodec() { return codec; } - duckdb_parquet::format::Type::type GetType(idx_t schema_idx) { + duckdb_parquet::Type::type GetType(idx_t schema_idx) { return file_meta_data.schema[schema_idx].type; } LogicalType GetSQLType(idx_t schema_idx) const { @@ -100,7 +100,7 @@ class ParquetWriter { double DictionaryCompressionRatioThreshold() const { return dictionary_compression_ratio_threshold; } - optional_idx CompressionLevel() const { + int64_t CompressionLevel() const { return compression_level; } idx_t NumberOfRowGroups() { @@ -114,23 +114,23 @@ class ParquetWriter { GeoParquetFileMetadata &GetGeoParquetData(); static bool TryGetParquetType(const LogicalType &duckdb_type, - optional_ptr type = nullptr); + optional_ptr type = nullptr); private: string file_name; vector sql_types; vector column_names; - duckdb_parquet::format::CompressionCodec::type codec; + duckdb_parquet::CompressionCodec::type codec; ChildFieldIDs field_ids; shared_ptr encryption_config; double dictionary_compression_ratio_threshold; - optional_idx compression_level; + int64_t compression_level; bool debug_use_openssl; shared_ptr encryption_util; unique_ptr writer; std::shared_ptr protocol; - duckdb_parquet::format::FileMetaData file_meta_data; + duckdb_parquet::FileMetaData file_meta_data; std::mutex lock; vector> column_writers; diff --git a/src/duckdb/extension/parquet/include/resizable_buffer.hpp b/src/duckdb/extension/parquet/include/resizable_buffer.hpp index 65b639bab..14658ecee 100644 --- a/src/duckdb/extension/parquet/include/resizable_buffer.hpp +++ b/src/duckdb/extension/parquet/include/resizable_buffer.hpp @@ -5,6 +5,7 @@ // // //===----------------------------------------------------------------------===// + #pragma once #include "duckdb.hpp" diff --git a/src/duckdb/extension/parquet/include/string_column_reader.hpp b/src/duckdb/extension/parquet/include/string_column_reader.hpp index f67bbd9da..2ab96a296 100644 --- a/src/duckdb/extension/parquet/include/string_column_reader.hpp +++ b/src/duckdb/extension/parquet/include/string_column_reader.hpp @@ -13,11 +13,8 @@ namespace duckdb { struct StringParquetValueConversion { - static string_t DictRead(ByteBuffer &dict, uint32_t &offset, ColumnReader &reader); - static string_t PlainRead(ByteBuffer &plain_data, ColumnReader &reader); static void PlainSkip(ByteBuffer &plain_data, ColumnReader &reader); - static bool PlainAvailable(const ByteBuffer &plain_data, const idx_t count); static string_t UnsafePlainRead(ByteBuffer &plain_data, ColumnReader &reader); static void UnsafePlainSkip(ByteBuffer &plain_data, ColumnReader &reader); @@ -30,14 +27,10 @@ class StringColumnReader : public TemplatedColumnReader dict_strings; idx_t fixed_width_string_length; idx_t delta_offset = 0; public: - void Dictionary(shared_ptr dictionary_data, idx_t num_entries) override; - void PrepareDeltaLengthByteArray(ResizeableBuffer &buffer) override; void PrepareDeltaByteArray(ResizeableBuffer &buffer) override; void DeltaByteArray(uint8_t *defines, idx_t num_values, parquet_filter_t &filter, idx_t result_offset, @@ -46,7 +39,6 @@ class StringColumnReader : public TemplatedColumnReader plain_data, Vector &result) override; }; diff --git a/src/duckdb/extension/parquet/include/templated_column_reader.hpp b/src/duckdb/extension/parquet/include/templated_column_reader.hpp index f9311524f..d85865309 100644 --- a/src/duckdb/extension/parquet/include/templated_column_reader.hpp +++ b/src/duckdb/extension/parquet/include/templated_column_reader.hpp @@ -15,10 +15,6 @@ namespace duckdb { template struct TemplatedParquetValueConversion { - static VALUE_TYPE DictRead(ByteBuffer &dict, uint32_t &offset, ColumnReader &reader) { - D_ASSERT(offset < dict.len / sizeof(VALUE_TYPE)); - return ((VALUE_TYPE *)dict.ptr)[offset]; - } static VALUE_TYPE PlainRead(ByteBuffer &plain_data, ColumnReader &reader) { return plain_data.read(); @@ -62,53 +58,16 @@ class TemplatedColumnReader : public ColumnReader { } } - void Dictionary(shared_ptr data, idx_t num_entries) override { - dict = std::move(data); - } - - void Offsets(uint32_t *offsets, uint8_t *defines, uint64_t num_values, parquet_filter_t &filter, - idx_t result_offset, Vector &result) override { - if (HasDefines()) { - OffsetsInternal(*dict, offsets, defines, num_values, filter, result_offset, result); - } else { - OffsetsInternal(*dict, offsets, defines, num_values, filter, result_offset, result); - } - } - - void Plain(shared_ptr plain_data, uint8_t *defines, uint64_t num_values, parquet_filter_t &filter, + void Plain(shared_ptr plain_data, uint8_t *defines, uint64_t num_values, parquet_filter_t *filter, idx_t result_offset, Vector &result) override { PlainTemplated(std::move(plain_data), defines, num_values, filter, result_offset, result); } - -private: - template - void OffsetsInternal(ResizeableBuffer &dict_ref, uint32_t *__restrict offsets, const uint8_t *__restrict defines, - const uint64_t num_values, const parquet_filter_t &filter, const idx_t result_offset, - Vector &result) { - const auto result_ptr = FlatVector::GetData(result); - auto &result_mask = FlatVector::Validity(result); - idx_t offset_idx = 0; - for (idx_t row_idx = result_offset; row_idx < result_offset + num_values; row_idx++) { - if (HAS_DEFINES && defines[row_idx] != max_define) { - result_mask.SetInvalid(row_idx); - continue; - } - if (filter.test(row_idx)) { - result_ptr[row_idx] = VALUE_CONVERSION::DictRead(dict_ref, offsets[offset_idx++], *this); - } else { - offset_idx++; - } - } - } }; template struct CallbackParquetValueConversion { - static DUCKDB_PHYSICAL_TYPE DictRead(ByteBuffer &dict, uint32_t &offset, ColumnReader &reader) { - return TemplatedParquetValueConversion::DictRead(dict, offset, reader); - } static DUCKDB_PHYSICAL_TYPE PlainRead(ByteBuffer &plain_data, ColumnReader &reader) { return FUNC(plain_data.read()); diff --git a/src/duckdb/extension/parquet/include/thrift_tools.hpp b/src/duckdb/extension/parquet/include/thrift_tools.hpp index 2306aa30b..815841b98 100644 --- a/src/duckdb/extension/parquet/include/thrift_tools.hpp +++ b/src/duckdb/extension/parquet/include/thrift_tools.hpp @@ -1,4 +1,13 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// thrift_tools.hpp +// +// +//===----------------------------------------------------------------------===/ + #pragma once + #include #include "thrift/protocol/TCompactProtocol.h" #include "thrift/transport/TBufferTransports.h" diff --git a/src/duckdb/extension/parquet/include/zstd_file_system.hpp b/src/duckdb/extension/parquet/include/zstd_file_system.hpp index 230aef36d..5b132bc8a 100644 --- a/src/duckdb/extension/parquet/include/zstd_file_system.hpp +++ b/src/duckdb/extension/parquet/include/zstd_file_system.hpp @@ -26,6 +26,10 @@ class ZStdFileSystem : public CompressedFileSystem { unique_ptr CreateStream() override; idx_t InBufferSize() override; idx_t OutBufferSize() override; + + static int64_t DefaultCompressionLevel(); + static int64_t MinimumCompressionLevel(); + static int64_t MaximumCompressionLevel(); }; } // namespace duckdb diff --git a/src/duckdb/extension/parquet/parquet_extension.cpp b/src/duckdb/extension/parquet/parquet_extension.cpp index 617dc3cac..7325de6ae 100644 --- a/src/duckdb/extension/parquet/parquet_extension.cpp +++ b/src/duckdb/extension/parquet/parquet_extension.cpp @@ -180,9 +180,9 @@ struct ParquetReadGlobalState : public GlobalTableFunctionState { struct ParquetWriteBindData : public TableFunctionData { vector sql_types; vector column_names; - duckdb_parquet::format::CompressionCodec::type codec = duckdb_parquet::format::CompressionCodec::SNAPPY; + duckdb_parquet::CompressionCodec::type codec = duckdb_parquet::CompressionCodec::SNAPPY; vector> kv_metadata; - idx_t row_group_size = Storage::ROW_GROUP_SIZE; + idx_t row_group_size = DEFAULT_ROW_GROUP_SIZE; //! If row_group_size_bytes is not set, we default to row_group_size * BYTES_PER_ROW static constexpr const idx_t BYTES_PER_ROW = 1024; @@ -200,7 +200,7 @@ struct ParquetWriteBindData : public TableFunctionData { ChildFieldIDs field_ids; //! The compression level, higher value is more - optional_idx compression_level; + int64_t compression_level = ZStdFileSystem::DefaultCompressionLevel(); }; struct ParquetWriteGlobalState : public GlobalFunctionData { @@ -383,6 +383,11 @@ static bool GetBooleanArgument(const pair> &option) { return BooleanValue::Get(boolean_value); } +TablePartitionInfo ParquetGetPartitionInfo(ClientContext &context, TableFunctionPartitionInput &input) { + auto &parquet_bind = input.bind_data->Cast(); + return parquet_bind.multi_file_reader->GetPartitionInfo(context, parquet_bind.reader_bind, input); +} + class ParquetScanFunction { public: static TableFunctionSet GetFunctionSet() { @@ -401,7 +406,7 @@ class ParquetScanFunction { {"type", LogicalType::VARCHAR}, {"default_value", LogicalType::VARCHAR}}})); table_function.named_parameters["encryption_config"] = LogicalTypeId::ANY; - table_function.get_batch_index = ParquetScanGetBatchIndex; + table_function.get_partition_data = ParquetScanGetPartitionData; table_function.serialize = ParquetScanSerialize; table_function.deserialize = ParquetScanDeserialize; table_function.get_bind_info = ParquetGetBindInfo; @@ -409,6 +414,7 @@ class ParquetScanFunction { table_function.filter_pushdown = true; table_function.filter_prune = true; table_function.pushdown_complex_filter = ParquetComplexFilterPushdown; + table_function.get_partition_info = ParquetGetPartitionInfo; MultiFileReader::AddParameters(table_function); @@ -520,7 +526,7 @@ class ParquetScanFunction { static unique_ptr ParquetScanBindInternal(ClientContext &context, unique_ptr multi_file_reader, - unique_ptr file_list, + shared_ptr file_list, vector &return_types, vector &names, ParquetOptions parquet_options) { auto result = make_uniq(); @@ -778,11 +784,16 @@ class ParquetScanFunction { return std::move(result); } - static idx_t ParquetScanGetBatchIndex(ClientContext &context, const FunctionData *bind_data_p, - LocalTableFunctionState *local_state, - GlobalTableFunctionState *global_state) { - auto &data = local_state->Cast(); - return data.batch_index; + static OperatorPartitionData ParquetScanGetPartitionData(ClientContext &context, + TableFunctionGetPartitionInput &input) { + auto &bind_data = input.bind_data->CastNoConst(); + auto &data = input.local_state->Cast(); + auto &gstate = input.global_state->Cast(); + OperatorPartitionData partition_data(data.batch_index); + bind_data.multi_file_reader->GetPartitionData(context, bind_data.reader_bind, data.reader->reader_data, + gstate.multi_file_reader_state, input.partition_info, + partition_data); + return partition_data; } static void ParquetScanSerialize(Serializer &serializer, const optional_ptr bind_data_p, @@ -1189,6 +1200,7 @@ unique_ptr ParquetWriteBind(ClientContext &context, CopyFunctionBi const vector &names, const vector &sql_types) { D_ASSERT(names.size() == sql_types.size()); bool row_group_size_bytes_set = false; + bool compression_level_set = false; auto bind_data = make_uniq(); for (auto &option : input.info.options) { const auto loption = StringUtil::Lower(option.first); @@ -1211,19 +1223,19 @@ unique_ptr ParquetWriteBind(ClientContext &context, CopyFunctionBi } else if (loption == "compression" || loption == "codec") { const auto roption = StringUtil::Lower(option.second[0].ToString()); if (roption == "uncompressed") { - bind_data->codec = duckdb_parquet::format::CompressionCodec::UNCOMPRESSED; + bind_data->codec = duckdb_parquet::CompressionCodec::UNCOMPRESSED; } else if (roption == "snappy") { - bind_data->codec = duckdb_parquet::format::CompressionCodec::SNAPPY; + bind_data->codec = duckdb_parquet::CompressionCodec::SNAPPY; } else if (roption == "gzip") { - bind_data->codec = duckdb_parquet::format::CompressionCodec::GZIP; + bind_data->codec = duckdb_parquet::CompressionCodec::GZIP; } else if (roption == "zstd") { - bind_data->codec = duckdb_parquet::format::CompressionCodec::ZSTD; + bind_data->codec = duckdb_parquet::CompressionCodec::ZSTD; } else if (roption == "brotli") { - bind_data->codec = duckdb_parquet::format::CompressionCodec::BROTLI; + bind_data->codec = duckdb_parquet::CompressionCodec::BROTLI; } else if (roption == "lz4" || roption == "lz4_raw") { /* LZ4 is technically another compression scheme, but deprecated and arrow also uses them * interchangeably */ - bind_data->codec = duckdb_parquet::format::CompressionCodec::LZ4_RAW; + bind_data->codec = duckdb_parquet::CompressionCodec::LZ4_RAW; } else { throw BinderException("Expected %s argument to be either [uncompressed, brotli, gzip, snappy, or zstd]", loption); @@ -1284,7 +1296,14 @@ unique_ptr ParquetWriteBind(ClientContext &context, CopyFunctionBi throw BinderException("Expected debug_use_openssl to be a BOOLEAN"); } } else if (loption == "compression_level") { - bind_data->compression_level = option.second[0].GetValue(); + const auto val = option.second[0].GetValue(); + if (val < ZStdFileSystem::MinimumCompressionLevel() || val > ZStdFileSystem::MaximumCompressionLevel()) { + throw BinderException("Compression level must be between %lld and %lld", + ZStdFileSystem::MinimumCompressionLevel(), + ZStdFileSystem::MaximumCompressionLevel()); + } + bind_data->compression_level = val; + compression_level_set = true; } else { throw NotImplementedException("Unrecognized option for PARQUET: %s", option.first.c_str()); } @@ -1299,6 +1318,10 @@ unique_ptr ParquetWriteBind(ClientContext &context, CopyFunctionBi bind_data->row_group_size_bytes = bind_data->row_group_size * ParquetWriteBindData::BYTES_PER_ROW; } + if (compression_level_set && bind_data->codec != CompressionCodec::ZSTD) { + throw BinderException("Compression level is only supported for the ZSTD compression codec"); + } + bind_data->sql_types = sql_types; bind_data->column_names = names; return std::move(bind_data); @@ -1359,8 +1382,7 @@ unique_ptr ParquetWriteInitializeLocal(ExecutionContext &cont // FIXME: Have these be generated instead template <> -const char *EnumUtil::ToChars( - duckdb_parquet::format::CompressionCodec::type value) { +const char *EnumUtil::ToChars(duckdb_parquet::CompressionCodec::type value) { switch (value) { case CompressionCodec::UNCOMPRESSED: return "UNCOMPRESSED"; @@ -1392,8 +1414,7 @@ const char *EnumUtil::ToChars( } template <> -duckdb_parquet::format::CompressionCodec::type -EnumUtil::FromString(const char *value) { +duckdb_parquet::CompressionCodec::type EnumUtil::FromString(const char *value) { if (StringUtil::Equals(value, "UNCOMPRESSED")) { return CompressionCodec::UNCOMPRESSED; } @@ -1421,6 +1442,23 @@ EnumUtil::FromString(const char throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented", value)); } +static optional_idx SerializeCompressionLevel(const int64_t compression_level) { + return compression_level < 0 ? NumericLimits::Maximum() - NumericCast(AbsValue(compression_level)) + : NumericCast(compression_level); +} + +static int64_t DeserializeCompressionLevel(const optional_idx compression_level) { + // Was originally an optional_idx, now int64_t, so we still serialize as such + if (!compression_level.IsValid()) { + return ZStdFileSystem::DefaultCompressionLevel(); + } + if (compression_level.GetIndex() > NumericCast(ZStdFileSystem::MaximumCompressionLevel())) { + // restore the negative compression level + return -NumericCast(NumericLimits::Maximum() - compression_level.GetIndex()); + } + return NumericCast(compression_level.GetIndex()); +} + static void ParquetCopySerialize(Serializer &serializer, const FunctionData &bind_data_p, const CopyFunction &function) { auto &bind_data = bind_data_p.Cast(); @@ -1435,7 +1473,9 @@ static void ParquetCopySerialize(Serializer &serializer, const FunctionData &bin bind_data.encryption_config, nullptr); serializer.WriteProperty(108, "dictionary_compression_ratio_threshold", bind_data.dictionary_compression_ratio_threshold); - serializer.WritePropertyWithDefault(109, "compression_level", bind_data.compression_level); + const auto compression_level = SerializeCompressionLevel(bind_data.compression_level); + D_ASSERT(DeserializeCompressionLevel(compression_level) == bind_data.compression_level); + serializer.WritePropertyWithDefault(109, "compression_level", compression_level); serializer.WriteProperty(110, "row_groups_per_file", bind_data.row_groups_per_file); serializer.WriteProperty(111, "debug_use_openssl", bind_data.debug_use_openssl); } @@ -1444,7 +1484,7 @@ static unique_ptr ParquetCopyDeserialize(Deserializer &deserialize auto data = make_uniq(); data->sql_types = deserializer.ReadProperty>(100, "sql_types"); data->column_names = deserializer.ReadProperty>(101, "column_names"); - data->codec = deserializer.ReadProperty(102, "codec"); + data->codec = deserializer.ReadProperty(102, "codec"); data->row_group_size = deserializer.ReadProperty(103, "row_group_size"); data->row_group_size_bytes = deserializer.ReadProperty(104, "row_group_size_bytes"); data->kv_metadata = deserializer.ReadProperty>>(105, "kv_metadata"); @@ -1453,7 +1493,10 @@ static unique_ptr ParquetCopyDeserialize(Deserializer &deserialize data->encryption_config, nullptr); deserializer.ReadPropertyWithExplicitDefault(108, "dictionary_compression_ratio_threshold", data->dictionary_compression_ratio_threshold, 1.0); - deserializer.ReadPropertyWithDefault(109, "compression_level", data->compression_level); + optional_idx compression_level; + deserializer.ReadPropertyWithDefault(109, "compression_level", compression_level); + data->compression_level = DeserializeCompressionLevel(compression_level); + D_ASSERT(SerializeCompressionLevel(data->compression_level) == compression_level); data->row_groups_per_file = deserializer.ReadPropertyWithExplicitDefault(110, "row_groups_per_file", optional_idx::Invalid()); data->debug_use_openssl = deserializer.ReadPropertyWithExplicitDefault(111, "debug_use_openssl", true); @@ -1689,7 +1732,11 @@ void ParquetExtension::Load(DuckDB &db) { config.replacement_scans.emplace_back(ParquetScanReplacement); config.AddExtensionOption("binary_as_string", "In Parquet files, interpret binary data as a string.", LogicalType::BOOLEAN); - + config.AddExtensionOption("disable_parquet_prefetching", "Disable the prefetching mechanism in Parquet", + LogicalType::BOOLEAN, Value(false)); + config.AddExtensionOption("prefetch_all_parquet_files", + "Use the prefetching mechanism for all types of parquet files", LogicalType::BOOLEAN, + Value(false)); config.AddExtensionOption( "enable_geoparquet_conversion", "Attempt to decode/encode geometry data in/as GeoParquet files if the spatial extension is present.", diff --git a/src/duckdb/extension/parquet/parquet_metadata.cpp b/src/duckdb/extension/parquet/parquet_metadata.cpp index b1d70a543..2ddab818b 100644 --- a/src/duckdb/extension/parquet/parquet_metadata.cpp +++ b/src/duckdb/extension/parquet/parquet_metadata.cpp @@ -15,7 +15,7 @@ namespace duckdb { struct ParquetMetaDataBindData : public TableFunctionData { vector return_types; - unique_ptr file_list; + shared_ptr file_list; unique_ptr multi_file_reader; }; @@ -166,8 +166,8 @@ void ParquetMetaDataOperatorData::BindMetaData(vector &return_types return_types.emplace_back(LogicalType::MAP(LogicalType::BLOB, LogicalType::BLOB)); } -Value ConvertParquetStats(const LogicalType &type, const duckdb_parquet::format::SchemaElement &schema_ele, - bool stats_is_set, const std::string &stats) { +Value ConvertParquetStats(const LogicalType &type, const duckdb_parquet::SchemaElement &schema_ele, bool stats_is_set, + const std::string &stats) { if (!stats_is_set) { return Value(LogicalType::VARCHAR); } @@ -352,7 +352,7 @@ void ParquetMetaDataOperatorData::BindSchema(vector &return_types, return_types.emplace_back(LogicalType::VARCHAR); } -Value ParquetLogicalTypeToString(const duckdb_parquet::format::LogicalType &type, bool is_set) { +Value ParquetLogicalTypeToString(const duckdb_parquet::LogicalType &type, bool is_set) { if (!is_set) { return Value(); } diff --git a/src/duckdb/extension/parquet/parquet_reader.cpp b/src/duckdb/extension/parquet/parquet_reader.cpp index 7357767b7..0d3d8dac0 100644 --- a/src/duckdb/extension/parquet/parquet_reader.cpp +++ b/src/duckdb/extension/parquet/parquet_reader.cpp @@ -29,6 +29,7 @@ #include "duckdb/planner/filter/conjunction_filter.hpp" #include "duckdb/planner/filter/constant_filter.hpp" #include "duckdb/planner/filter/struct_filter.hpp" +#include "duckdb/planner/filter/optional_filter.hpp" #include "duckdb/planner/table_filter.hpp" #include "duckdb/storage/object_cache.hpp" #endif @@ -40,15 +41,15 @@ namespace duckdb { -using duckdb_parquet::format::ColumnChunk; -using duckdb_parquet::format::ConvertedType; -using duckdb_parquet::format::FieldRepetitionType; -using duckdb_parquet::format::FileCryptoMetaData; -using duckdb_parquet::format::FileMetaData; -using ParquetRowGroup = duckdb_parquet::format::RowGroup; -using duckdb_parquet::format::SchemaElement; -using duckdb_parquet::format::Statistics; -using duckdb_parquet::format::Type; +using duckdb_parquet::ColumnChunk; +using duckdb_parquet::ConvertedType; +using duckdb_parquet::FieldRepetitionType; +using duckdb_parquet::FileCryptoMetaData; +using duckdb_parquet::FileMetaData; +using ParquetRowGroup = duckdb_parquet::RowGroup; +using duckdb_parquet::SchemaElement; +using duckdb_parquet::Statistics; +using duckdb_parquet::Type; static unique_ptr CreateThriftFileProtocol(Allocator &allocator, FileHandle &file_handle, bool prefetch_mode) { @@ -147,6 +148,10 @@ LogicalType ParquetReader::DeriveLogicalType(const SchemaElement &s_ele, bool bi } } if (s_ele.__isset.converted_type) { + // Legacy NULL type, does no longer exist, but files are still around of course + if (static_cast(s_ele.converted_type) == 24) { + return LogicalTypeId::SQLNULL; + } switch (s_ele.converted_type) { case ConvertedType::INT_8: if (s_ele.type == Type::INT32) { @@ -251,8 +256,6 @@ LogicalType ParquetReader::DeriveLogicalType(const SchemaElement &s_ele, bool bi return LogicalType::INTERVAL; case ConvertedType::JSON: return LogicalType::JSON(); - case ConvertedType::NULL_TYPE: - return LogicalTypeId::SQLNULL; case ConvertedType::MAP: case ConvertedType::MAP_KEY_VALUE: case ConvertedType::LIST: @@ -793,7 +796,14 @@ void ParquetReader::InitializeScan(ClientContext &context, ParquetReaderScanStat if (!state.file_handle || state.file_handle->path != file_handle->path) { auto flags = FileFlags::FILE_FLAGS_READ; - if (!file_handle->OnDiskFile() && file_handle->CanSeek()) { + Value disable_prefetch = false; + Value prefetch_all_files = false; + context.TryGetCurrentSetting("disable_parquet_prefetching", disable_prefetch); + context.TryGetCurrentSetting("prefetch_all_parquet_files", prefetch_all_files); + bool should_prefetch = !file_handle->OnDiskFile() || prefetch_all_files.GetValue(); + bool can_prefetch = file_handle->CanSeek() && !disable_prefetch.GetValue(); + + if (should_prefetch && can_prefetch) { state.prefetch_mode = true; flags |= FileFlags::FILE_FLAGS_DIRECT_IO; } else { @@ -817,15 +827,16 @@ void FilterIsNull(Vector &v, parquet_filter_t &filter_mask, idx_t count) { } return; } - D_ASSERT(v.GetVectorType() == VectorType::FLAT_VECTOR); - auto &mask = FlatVector::Validity(v); - if (mask.AllValid()) { + UnifiedVectorFormat unified; + v.ToUnifiedFormat(count, unified); + + if (unified.validity.AllValid()) { filter_mask.reset(); } else { for (idx_t i = 0; i < count; i++) { if (filter_mask.test(i)) { - filter_mask.set(i, !mask.RowIsValid(i)); + filter_mask.set(i, !unified.validity.RowIsValid(unified.sel->get_index(i))); } } } @@ -839,13 +850,14 @@ void FilterIsNotNull(Vector &v, parquet_filter_t &filter_mask, idx_t count) { } return; } - D_ASSERT(v.GetVectorType() == VectorType::FLAT_VECTOR); - auto &mask = FlatVector::Validity(v); - if (!mask.AllValid()) { + UnifiedVectorFormat unified; + v.ToUnifiedFormat(count, unified); + + if (!unified.validity.AllValid()) { for (idx_t i = 0; i < count; i++) { if (filter_mask.test(i)) { - filter_mask.set(i, mask.RowIsValid(i)); + filter_mask.set(i, unified.validity.RowIsValid(unified.sel->get_index(i))); } } } @@ -865,20 +877,20 @@ void TemplatedFilterOperation(Vector &v, T constant, parquet_filter_t &filter_ma return; } - D_ASSERT(v.GetVectorType() == VectorType::FLAT_VECTOR); - auto v_ptr = FlatVector::GetData(v); - auto &mask = FlatVector::Validity(v); + UnifiedVectorFormat unified; + v.ToUnifiedFormat(count, unified); + auto data_ptr = UnifiedVectorFormat::GetData(unified); - if (!mask.AllValid()) { + if (!unified.validity.AllValid()) { for (idx_t i = 0; i < count; i++) { - if (filter_mask.test(i) && mask.RowIsValid(i)) { - filter_mask.set(i, OP::Operation(v_ptr[i], constant)); + if (filter_mask.test(i) && unified.validity.RowIsValid(unified.sel->get_index(i))) { + filter_mask.set(i, OP::Operation(data_ptr[unified.sel->get_index(i)], constant)); } } } else { for (idx_t i = 0; i < count; i++) { if (filter_mask.test(i)) { - filter_mask.set(i, OP::Operation(v_ptr[i], constant)); + filter_mask.set(i, OP::Operation(data_ptr[unified.sel->get_index(i)], constant)); } } } @@ -992,7 +1004,12 @@ static void ApplyFilter(Vector &v, TableFilter &filter, parquet_filter_t &filter auto &struct_filter = filter.Cast(); auto &child = StructVector::GetEntries(v)[struct_filter.child_idx]; ApplyFilter(*child, *struct_filter.child_filter, filter_mask, count); - } break; + } + case TableFilterType::OPTIONAL_FILTER: { + // we don't execute zone map filters here - we only consider them for zone map pruning + // do nothing to the mask. + break; + } default: D_ASSERT(0); break; @@ -1039,14 +1056,16 @@ bool ParquetReader::ScanInternal(ParquetReaderScanState &state, DataChunk &resul auto &group = GetGroup(state); if (state.prefetch_mode && state.group_offset != (idx_t)group.num_rows) { - uint64_t total_row_group_span = GetGroupSpan(state); double scan_percentage = (double)(to_scan_compressed_bytes) / static_cast(total_row_group_span); if (to_scan_compressed_bytes > total_row_group_span) { - throw InvalidInputException( - "Malformed parquet file: sum of total compressed bytes of columns seems incorrect"); + throw IOException( + "The parquet file '%s' seems to have incorrectly set page offsets. This interferes with DuckDB's " + "prefetching optimization. DuckDB may still be able to scan this file by manually disabling the " + "prefetching mechanism using: 'SET disable_parquet_prefetching=true'.", + file_name); } if (!reader_data.filters && diff --git a/src/duckdb/extension/parquet/parquet_statistics.cpp b/src/duckdb/extension/parquet/parquet_statistics.cpp index 26896c576..82acbacb8 100644 --- a/src/duckdb/extension/parquet/parquet_statistics.cpp +++ b/src/duckdb/extension/parquet/parquet_statistics.cpp @@ -14,12 +14,12 @@ namespace duckdb { -using duckdb_parquet::format::ConvertedType; -using duckdb_parquet::format::Type; +using duckdb_parquet::ConvertedType; +using duckdb_parquet::Type; static unique_ptr CreateNumericStats(const LogicalType &type, - const duckdb_parquet::format::SchemaElement &schema_ele, - const duckdb_parquet::format::Statistics &parquet_stats) { + const duckdb_parquet::SchemaElement &schema_ele, + const duckdb_parquet::Statistics &parquet_stats) { auto stats = NumericStats::CreateUnknown(type); // for reasons unknown to science, Parquet defines *both* `min` and `min_value` as well as `max` and @@ -45,8 +45,7 @@ static unique_ptr CreateNumericStats(const LogicalType &type, return stats.ToUnique(); } -Value ParquetStatisticsUtils::ConvertValue(const LogicalType &type, - const duckdb_parquet::format::SchemaElement &schema_ele, +Value ParquetStatisticsUtils::ConvertValue(const LogicalType &type, const duckdb_parquet::SchemaElement &schema_ele, const std::string &stats) { auto stats_data = const_data_ptr_cast(stats.c_str()); switch (type.id()) { @@ -180,7 +179,7 @@ Value ParquetStatisticsUtils::ConvertValue(const LogicalType &type, throw InternalException("Time logicalType is set but unit is not defined"); } } - if (schema_ele.converted_type == duckdb_parquet::format::ConvertedType::TIME_MILLIS) { + if (schema_ele.converted_type == duckdb_parquet::ConvertedType::TIME_MILLIS) { return Value::TIME(Time::FromTimeMs(val)); } else { return Value::TIME(dtime_t(val)); @@ -234,7 +233,7 @@ Value ParquetStatisticsUtils::ConvertValue(const LogicalType &type, } else { throw InternalException("Timestamp logicalType is set but unit is not defined"); } - } else if (schema_ele.converted_type == duckdb_parquet::format::ConvertedType::TIMESTAMP_MILLIS) { + } else if (schema_ele.converted_type == duckdb_parquet::ConvertedType::TIMESTAMP_MILLIS) { timestamp_value = Timestamp::FromEpochMs(val); } else { timestamp_value = timestamp_t(val); @@ -270,7 +269,7 @@ Value ParquetStatisticsUtils::ConvertValue(const LogicalType &type, } else { throw InternalException("Timestamp (NS) logicalType is set but unit is unknown"); } - } else if (schema_ele.converted_type == duckdb_parquet::format::ConvertedType::TIMESTAMP_MILLIS) { + } else if (schema_ele.converted_type == duckdb_parquet::ConvertedType::TIMESTAMP_MILLIS) { timestamp_value = ParquetTimestampMsToTimestampNs(val); } else { timestamp_value = ParquetTimestampUsToTimestampNs(val); diff --git a/src/duckdb/extension/parquet/parquet_writer.cpp b/src/duckdb/extension/parquet/parquet_writer.cpp index a7a847afb..d840ff18a 100644 --- a/src/duckdb/extension/parquet/parquet_writer.cpp +++ b/src/duckdb/extension/parquet/parquet_writer.cpp @@ -25,16 +25,16 @@ using namespace duckdb_apache::thrift; // NOLINT using namespace duckdb_apache::thrift::protocol; // NOLINT using namespace duckdb_apache::thrift::transport; // NOLINT -using duckdb_parquet::format::CompressionCodec; -using duckdb_parquet::format::ConvertedType; -using duckdb_parquet::format::Encoding; -using duckdb_parquet::format::FieldRepetitionType; -using duckdb_parquet::format::FileCryptoMetaData; -using duckdb_parquet::format::FileMetaData; -using duckdb_parquet::format::PageHeader; -using duckdb_parquet::format::PageType; -using ParquetRowGroup = duckdb_parquet::format::RowGroup; -using duckdb_parquet::format::Type; +using duckdb_parquet::CompressionCodec; +using duckdb_parquet::ConvertedType; +using duckdb_parquet::Encoding; +using duckdb_parquet::FieldRepetitionType; +using duckdb_parquet::FileCryptoMetaData; +using duckdb_parquet::FileMetaData; +using duckdb_parquet::PageHeader; +using duckdb_parquet::PageType; +using ParquetRowGroup = duckdb_parquet::RowGroup; +using duckdb_parquet::Type; ChildFieldIDs::ChildFieldIDs() : ids(make_uniq>()) { } @@ -167,8 +167,7 @@ Type::type ParquetWriter::DuckDBTypeToParquetType(const LogicalType &duckdb_type throw NotImplementedException("Unimplemented type for Parquet \"%s\"", duckdb_type.ToString()); } -void ParquetWriter::SetSchemaProperties(const LogicalType &duckdb_type, - duckdb_parquet::format::SchemaElement &schema_ele) { +void ParquetWriter::SetSchemaProperties(const LogicalType &duckdb_type, duckdb_parquet::SchemaElement &schema_ele) { if (duckdb_type.IsJSONType()) { schema_ele.converted_type = ConvertedType::JSON; schema_ele.__isset.converted_type = true; @@ -318,12 +317,12 @@ ParquetWriter::ParquetWriter(ClientContext &context, FileSystem &fs, string file vector names_p, CompressionCodec::type codec, ChildFieldIDs field_ids_p, const vector> &kv_metadata, shared_ptr encryption_config_p, - double dictionary_compression_ratio_threshold_p, optional_idx compression_level_p, + double dictionary_compression_ratio_threshold_p, int64_t compression_level_p, bool debug_use_openssl_p) : 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)), encryption_config(std::move(encryption_config_p)), dictionary_compression_ratio_threshold(dictionary_compression_ratio_threshold_p), - debug_use_openssl(debug_use_openssl_p) { + compression_level(compression_level_p), debug_use_openssl(debug_use_openssl_p) { // initialize the file writer writer = make_uniq(fs, file_name.c_str(), FileFlags::FILE_FLAGS_WRITE | FileFlags::FILE_FLAGS_FILE_CREATE_NEW); @@ -356,31 +355,18 @@ ParquetWriter::ParquetWriter(ClientContext &context, FileSystem &fs, string file file_meta_data.schema.resize(1); for (auto &kv_pair : kv_metadata) { - duckdb_parquet::format::KeyValue kv; + duckdb_parquet::KeyValue kv; kv.__set_key(kv_pair.first); kv.__set_value(kv_pair.second); file_meta_data.key_value_metadata.push_back(kv); file_meta_data.__isset.key_value_metadata = true; } - if (compression_level_p.IsValid()) { - idx_t level = compression_level_p.GetIndex(); - switch (codec) { - case CompressionCodec::ZSTD: - if (level < 1 || level > 22) { - throw BinderException("Compression level for ZSTD must be between 1 and 22"); - } - break; - default: - throw NotImplementedException("Compression level is only supported for the ZSTD compression codec"); - } - compression_level = level; - } // populate root schema object 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::format::FieldRepetitionType::REQUIRED; + file_meta_data.schema[0].repetition_type = duckdb_parquet::FieldRepetitionType::REQUIRED; file_meta_data.schema[0].__isset.repetition_type = true; auto &unique_names = column_names; @@ -539,8 +525,8 @@ void ParquetWriter::Finalize() { if (encryption_config) { // Crypto metadata is written unencrypted FileCryptoMetaData crypto_metadata; - duckdb_parquet::format::AesGcmV1 aes_gcm_v1; - duckdb_parquet::format::EncryptionAlgorithm alg; + duckdb_parquet::AesGcmV1 aes_gcm_v1; + duckdb_parquet::EncryptionAlgorithm alg; alg.__set_AES_GCM_V1(aes_gcm_v1); crypto_metadata.__set_encryption_algorithm(alg); crypto_metadata.write(protocol.get()); diff --git a/src/duckdb/extension/parquet/zstd_file_system.cpp b/src/duckdb/extension/parquet/zstd_file_system.cpp index 5a630b056..7204f3607 100644 --- a/src/duckdb/extension/parquet/zstd_file_system.cpp +++ b/src/duckdb/extension/parquet/zstd_file_system.cpp @@ -1,4 +1,5 @@ #include "zstd_file_system.hpp" + #include "zstd.h" namespace duckdb { @@ -184,4 +185,16 @@ idx_t ZStdFileSystem::OutBufferSize() { return duckdb_zstd::ZSTD_DStreamOutSize(); } +int64_t ZStdFileSystem::DefaultCompressionLevel() { + return duckdb_zstd::ZSTD_defaultCLevel(); +} + +int64_t ZStdFileSystem::MinimumCompressionLevel() { + return duckdb_zstd::ZSTD_minCLevel(); +} + +int64_t ZStdFileSystem::MaximumCompressionLevel() { + return duckdb_zstd::ZSTD_maxCLevel(); +} + } // namespace duckdb diff --git a/src/duckdb/src/catalog/catalog.cpp b/src/duckdb/src/catalog/catalog.cpp index 08a01d93d..cc2a9cd4e 100644 --- a/src/duckdb/src/catalog/catalog.cpp +++ b/src/duckdb/src/catalog/catalog.cpp @@ -71,7 +71,12 @@ Catalog &Catalog::GetSystemCatalog(ClientContext &context) { return Catalog::GetSystemCatalog(*context.db); } -optional_ptr Catalog::GetCatalogEntry(ClientContext &context, const string &catalog_name) { +const string &GetDefaultCatalog(CatalogEntryRetriever &retriever) { + return DatabaseManager::GetDefaultDatabase(retriever.GetContext()); +} + +optional_ptr Catalog::GetCatalogEntry(CatalogEntryRetriever &retriever, const string &catalog_name) { + auto &context = retriever.GetContext(); auto &db_manager = DatabaseManager::Get(context); if (catalog_name == TEMP_CATALOG) { return &ClientData::Get(context).temporary_objects->GetCatalog(); @@ -79,22 +84,32 @@ optional_ptr Catalog::GetCatalogEntry(ClientContext &context, const str if (catalog_name == SYSTEM_CATALOG) { return &GetSystemCatalog(context); } - auto entry = db_manager.GetDatabase( - context, IsInvalidCatalog(catalog_name) ? DatabaseManager::GetDefaultDatabase(context) : catalog_name); + auto entry = + db_manager.GetDatabase(context, IsInvalidCatalog(catalog_name) ? GetDefaultCatalog(retriever) : catalog_name); if (!entry) { return nullptr; } return &entry->GetCatalog(); } -Catalog &Catalog::GetCatalog(ClientContext &context, const string &catalog_name) { - auto catalog = Catalog::GetCatalogEntry(context, catalog_name); +optional_ptr Catalog::GetCatalogEntry(ClientContext &context, const string &catalog_name) { + CatalogEntryRetriever entry_retriever(context); + return GetCatalogEntry(entry_retriever, catalog_name); +} + +Catalog &Catalog::GetCatalog(CatalogEntryRetriever &retriever, const string &catalog_name) { + auto catalog = Catalog::GetCatalogEntry(retriever, catalog_name); if (!catalog) { throw BinderException("Catalog \"%s\" does not exist!", catalog_name); } return *catalog; } +Catalog &Catalog::GetCatalog(ClientContext &context, const string &catalog_name) { + CatalogEntryRetriever entry_retriever(context); + return GetCatalog(entry_retriever, catalog_name); +} + //===--------------------------------------------------------------------===// // Schema //===--------------------------------------------------------------------===// @@ -293,22 +308,13 @@ optional_ptr Catalog::CreateIndex(ClientContext &context, CreateIn // Lookup Structures //===--------------------------------------------------------------------===// struct CatalogLookup { - CatalogLookup(Catalog &catalog, string schema_p) : catalog(catalog), schema(std::move(schema_p)) { + CatalogLookup(Catalog &catalog, string schema_p, string name_p) + : catalog(catalog), schema(std::move(schema_p)), name(std::move(name_p)) { } Catalog &catalog; string schema; -}; - -//! Return value of Catalog::LookupEntry -struct CatalogEntryLookup { - optional_ptr schema; - optional_ptr entry; - ErrorData error; - - DUCKDB_API bool Found() const { - return entry; - } + string name; }; //===--------------------------------------------------------------------===// @@ -321,8 +327,8 @@ void Catalog::DropEntry(ClientContext &context, DropInfo &info) { return; } - auto lookup = LookupEntry(context, info.type, info.schema, info.name, info.if_not_found); - + CatalogEntryRetriever retriever(context); + auto lookup = LookupEntry(retriever, info.type, info.schema, info.name, info.if_not_found); if (!lookup.Found()) { return; } @@ -352,9 +358,10 @@ SchemaCatalogEntry &Catalog::GetSchema(CatalogTransaction transaction, const str //===--------------------------------------------------------------------===// // Lookup //===--------------------------------------------------------------------===// -SimilarCatalogEntry Catalog::SimilarEntryInSchemas(ClientContext &context, const string &entry_name, CatalogType type, - const reference_set_t &schemas) { - SimilarCatalogEntry result; +vector Catalog::SimilarEntriesInSchemas(ClientContext &context, const string &entry_name, + CatalogType type, + const reference_set_t &schemas) { + vector results; for (auto schema_ref : schemas) { auto &schema = schema_ref.get(); auto transaction = schema.catalog.GetCatalogTransaction(context); @@ -363,17 +370,23 @@ SimilarCatalogEntry Catalog::SimilarEntryInSchemas(ClientContext &context, const // no similar entry found continue; } - if (!result.Found() || result.score < entry.score) { - result = entry; - result.schema = &schema; + if (results.empty() || results[0].score <= entry.score) { + if (!results.empty() && results[0].score < entry.score) { + results.clear(); + } + + results.push_back(entry); + results.back().schema = &schema; } } - return result; + return results; } -vector GetCatalogEntries(ClientContext &context, const string &catalog, const string &schema) { +vector GetCatalogEntries(CatalogEntryRetriever &retriever, const string &catalog, + const string &schema) { + auto &context = retriever.GetContext(); vector entries; - auto &search_path = *context.client_data->catalog_search_path; + auto &search_path = retriever.GetSearchPath(); if (IsInvalidCatalog(catalog) && IsInvalidSchema(schema)) { // no catalog or schema provided - scan the entire search path entries = search_path.Get(); @@ -400,11 +413,11 @@ vector GetCatalogEntries(ClientContext &context, const strin return entries; } -void FindMinimalQualification(ClientContext &context, const string &catalog_name, const string &schema_name, +void FindMinimalQualification(CatalogEntryRetriever &retriever, const string &catalog_name, const string &schema_name, bool &qualify_database, bool &qualify_schema) { // check if we can we qualify ONLY the schema bool found = false; - auto entries = GetCatalogEntries(context, INVALID_CATALOG, schema_name); + auto entries = GetCatalogEntries(retriever, INVALID_CATALOG, schema_name); for (auto &entry : entries) { if (entry.catalog == catalog_name && entry.schema == schema_name) { found = true; @@ -418,7 +431,7 @@ void FindMinimalQualification(ClientContext &context, const string &catalog_name } // check if we can qualify ONLY the catalog found = false; - entries = GetCatalogEntries(context, catalog_name, INVALID_SCHEMA); + entries = GetCatalogEntries(retriever, catalog_name, INVALID_SCHEMA); for (auto &entry : entries) { if (entry.catalog == catalog_name && entry.schema == schema_name) { found = true; @@ -476,25 +489,38 @@ static bool IsAutoloadableFunction(CatalogType type) { type == CatalogType::AGGREGATE_FUNCTION_ENTRY || type == CatalogType::PRAGMA_FUNCTION_ENTRY); } +bool IsTableFunction(CatalogType type) { + switch (type) { + case CatalogType::TABLE_FUNCTION_ENTRY: + case CatalogType::TABLE_MACRO_ENTRY: + case CatalogType::PRAGMA_FUNCTION_ENTRY: + return true; + default: + return false; + } +} + +bool IsScalarFunction(CatalogType type) { + switch (type) { + case CatalogType::SCALAR_FUNCTION_ENTRY: + case CatalogType::AGGREGATE_FUNCTION_ENTRY: + case CatalogType::MACRO_ENTRY: + return true; + default: + return false; + } +} + static bool CompareCatalogTypes(CatalogType type_a, CatalogType type_b) { if (type_a == type_b) { // Types are same return true; } - if (!IsAutoloadableFunction(type_a)) { - D_ASSERT(IsAutoloadableFunction(type_b)); - // Make sure that `type_a` is an autoloadable function - return CompareCatalogTypes(type_b, type_a); - } - if (type_a == CatalogType::TABLE_FUNCTION_ENTRY) { - // These are all table functions - return type_b == CatalogType::TABLE_MACRO_ENTRY || type_b == CatalogType::PRAGMA_FUNCTION_ENTRY; - } else if (type_a == CatalogType::SCALAR_FUNCTION_ENTRY) { - // These are all scalar functions - return type_b == CatalogType::MACRO_ENTRY; - } else if (type_a == CatalogType::PRAGMA_FUNCTION_ENTRY) { - // These are all table functions - return type_b == CatalogType::TABLE_MACRO_ENTRY || type_b == CatalogType::TABLE_FUNCTION_ENTRY; + if (IsScalarFunction(type_a) && IsScalarFunction(type_b)) { + return true; + } + if (IsTableFunction(type_a) && IsTableFunction(type_b)) { + return true; } return false; } @@ -553,18 +579,19 @@ CatalogException Catalog::UnrecognizedConfigurationError(ClientContext &context, throw CatalogException::MissingEntry("configuration parameter", name, potential_names); } -CatalogException Catalog::CreateMissingEntryException(ClientContext &context, const string &entry_name, +CatalogException Catalog::CreateMissingEntryException(CatalogEntryRetriever &retriever, const string &entry_name, CatalogType type, const reference_set_t &schemas, QueryErrorContext error_context) { - auto entry = SimilarEntryInSchemas(context, entry_name, type, schemas); + auto &context = retriever.GetContext(); + auto entries = SimilarEntriesInSchemas(context, entry_name, type, schemas); reference_set_t unseen_schemas; auto &db_manager = DatabaseManager::Get(context); auto databases = db_manager.GetDatabases(context); auto &config = DBConfig::GetConfig(context); - auto max_schema_count = config.options.catalog_error_max_schemas; + auto max_schema_count = config.GetSetting(context); for (auto database : databases) { if (unseen_schemas.size() >= max_schema_count) { break; @@ -637,20 +664,36 @@ CatalogException Catalog::CreateMissingEntryException(ClientContext &context, co // entries in other schemas get a penalty // however, if there is an exact match in another schema, we will always show it static constexpr const double UNSEEN_PENALTY = 0.2; - auto unseen_entry = SimilarEntryInSchemas(context, entry_name, type, unseen_schemas); - string did_you_mean; - if (unseen_entry.Found() && (unseen_entry.score == 1.0 || unseen_entry.score - UNSEEN_PENALTY > entry.score)) { + auto unseen_entries = SimilarEntriesInSchemas(context, entry_name, type, unseen_schemas); + vector suggestions; + if (!unseen_entries.empty() && (unseen_entries[0].score == 1.0 || unseen_entries[0].score - UNSEEN_PENALTY > + (entries.empty() ? 0.0 : entries[0].score))) { // the closest matching entry requires qualification as it is not in the default search path // check how to minimally qualify this entry - auto catalog_name = unseen_entry.schema->catalog.GetName(); - auto schema_name = unseen_entry.schema->name; - bool qualify_database; - bool qualify_schema; - FindMinimalQualification(context, catalog_name, schema_name, qualify_database, qualify_schema); - did_you_mean = unseen_entry.GetQualifiedName(qualify_database, qualify_schema); - } else if (entry.Found()) { - did_you_mean = entry.name; + for (auto &unseen_entry : unseen_entries) { + auto catalog_name = unseen_entry.schema->catalog.GetName(); + auto schema_name = unseen_entry.schema->name; + bool qualify_database; + bool qualify_schema; + FindMinimalQualification(retriever, catalog_name, schema_name, qualify_database, qualify_schema); + suggestions.push_back(unseen_entry.GetQualifiedName(qualify_database, qualify_schema)); + } + } else if (!entries.empty()) { + for (auto &entry : entries) { + suggestions.push_back(entry.name); + } } + + string did_you_mean; + std::sort(suggestions.begin(), suggestions.end()); + if (suggestions.size() > 2) { + auto last = suggestions.back(); + suggestions.pop_back(); + did_you_mean = StringUtil::Join(suggestions, ", ") + ", or " + last; + } else { + did_you_mean = StringUtil::Join(suggestions, " or "); + } + return CatalogException::MissingEntry(type, entry_name, did_you_mean, error_context); } @@ -667,13 +710,14 @@ CatalogEntryLookup Catalog::TryLookupEntryInternal(CatalogTransaction transactio return {schema_entry, entry, ErrorData()}; } -CatalogEntryLookup Catalog::TryLookupEntry(ClientContext &context, CatalogType type, const string &schema, +CatalogEntryLookup Catalog::TryLookupEntry(CatalogEntryRetriever &retriever, CatalogType type, const string &schema, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context) { + auto &context = retriever.GetContext(); reference_set_t schemas; if (IsInvalidSchema(schema)) { // try all schemas for this catalog - auto entries = GetCatalogEntries(context, GetName(), INVALID_SCHEMA); + auto entries = GetCatalogEntries(retriever, GetName(), INVALID_SCHEMA); for (auto &entry : entries) { auto &candidate_schema = entry.schema; auto transaction = GetCatalogTransaction(context); @@ -699,15 +743,15 @@ CatalogEntryLookup Catalog::TryLookupEntry(ClientContext &context, CatalogType t if (if_not_found == OnEntryNotFound::RETURN_NULL) { return {nullptr, nullptr, ErrorData()}; } else { - auto except = CreateMissingEntryException(context, name, type, schemas, error_context); + auto except = CreateMissingEntryException(retriever, name, type, schemas, error_context); return {nullptr, nullptr, ErrorData(except)}; } } -CatalogEntryLookup Catalog::LookupEntry(ClientContext &context, CatalogType type, const string &schema, +CatalogEntryLookup Catalog::LookupEntry(CatalogEntryRetriever &retriever, CatalogType type, const string &schema, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context) { - auto res = TryLookupEntry(context, type, schema, name, if_not_found, error_context); + auto res = TryLookupEntry(retriever, type, schema, name, if_not_found, error_context); if (res.error.HasError()) { res.error.Throw(); @@ -716,13 +760,14 @@ CatalogEntryLookup Catalog::LookupEntry(ClientContext &context, CatalogType type return res; } -CatalogEntryLookup Catalog::TryLookupEntry(ClientContext &context, vector &lookups, CatalogType type, - const string &name, OnEntryNotFound if_not_found, +CatalogEntryLookup Catalog::TryLookupEntry(CatalogEntryRetriever &retriever, vector &lookups, + CatalogType type, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context) { + auto &context = retriever.GetContext(); reference_set_t schemas; for (auto &lookup : lookups) { auto transaction = lookup.catalog.GetCatalogTransaction(context); - auto result = lookup.catalog.TryLookupEntryInternal(transaction, type, lookup.schema, name); + auto result = lookup.catalog.TryLookupEntryInternal(transaction, type, lookup.schema, lookup.name); if (result.Found()) { return result; } @@ -734,24 +779,60 @@ CatalogEntryLookup Catalog::TryLookupEntry(ClientContext &context, vector catalog_by_name_lookups; + auto catalog_by_name = GetCatalogEntry(retriever, name); + if (catalog_by_name && catalog_by_name->HasDefaultTable()) { + catalog_by_name_lookups.emplace_back(*catalog_by_name, catalog_by_name->GetDefaultTableSchema(), + catalog_by_name->GetDefaultTable()); + } + + return TryLookupEntry(retriever, catalog_by_name_lookups, type, name, if_not_found, error_context); +} + +static void ThrowDefaultTableAmbiguityException(CatalogEntryLookup &base_lookup, CatalogEntryLookup &default_table, + const string &name) { + auto entry_type = CatalogTypeToString(base_lookup.entry->type); + string fully_qualified_name_hint; + if (base_lookup.schema) { + fully_qualified_name_hint = StringUtil::Format(": '%s.%s.%s'", base_lookup.schema->catalog.GetName(), + base_lookup.schema->name, base_lookup.entry->name); + } + string fully_qualified_catalog_name_hint = StringUtil::Format( + ": '%s.%s.%s'", default_table.schema->catalog.GetName(), default_table.schema->name, default_table.entry->name); + throw CatalogException( + "Ambiguity detected for '%s': this could either refer to the '%s' '%s', or the " + "attached catalog '%s' which has a default table. To avoid this error, either detach the catalog and " + "reattach under a different name, or use a fully qualified name for the '%s'%s or for the Catalog " + "Default Table%s.", + name, entry_type, name, name, entry_type, fully_qualified_name_hint, fully_qualified_catalog_name_hint); +} + +CatalogEntryLookup Catalog::TryLookupEntry(CatalogEntryRetriever &retriever, CatalogType type, const string &catalog, const string &schema, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context) { - auto entries = GetCatalogEntries(context, catalog, schema); + auto entries = GetCatalogEntries(retriever, catalog, schema); vector lookups; vector final_lookups; lookups.reserve(entries.size()); for (auto &entry : entries) { optional_ptr catalog_entry; if (if_not_found == OnEntryNotFound::RETURN_NULL) { - catalog_entry = Catalog::GetCatalogEntry(context, entry.catalog); + catalog_entry = Catalog::GetCatalogEntry(retriever, entry.catalog); } else { - catalog_entry = &Catalog::GetCatalog(context, entry.catalog); + catalog_entry = &Catalog::GetCatalog(retriever, entry.catalog); } if (!catalog_entry) { return {nullptr, nullptr, ErrorData()}; @@ -759,26 +840,46 @@ CatalogEntryLookup Catalog::TryLookupEntry(ClientContext &context, CatalogType t D_ASSERT(catalog_entry); auto lookup_behavior = catalog_entry->CatalogTypeLookupRule(type); if (lookup_behavior == CatalogLookupBehavior::STANDARD) { - lookups.emplace_back(*catalog_entry, entry.schema); + lookups.emplace_back(*catalog_entry, entry.schema, name); } else if (lookup_behavior == CatalogLookupBehavior::LOWER_PRIORITY) { - final_lookups.emplace_back(*catalog_entry, entry.schema); + final_lookups.emplace_back(*catalog_entry, entry.schema, name); } } + for (auto &lookup : final_lookups) { lookups.emplace_back(std::move(lookup)); } - return Catalog::TryLookupEntry(context, lookups, type, name, if_not_found, error_context); + + // Do the main lookup + auto lookup_result = TryLookupEntry(retriever, lookups, type, name, if_not_found, error_context); + + // Special case for tables: we do a second lookup searching for catalogs with default tables that also match this + // lookup + if (type == CatalogType::TABLE_ENTRY) { + auto lookup_result_default_table = + TryLookupDefaultTable(retriever, type, catalog, schema, name, if_not_found, error_context); + + if (lookup_result_default_table.Found() && lookup_result.Found()) { + ThrowDefaultTableAmbiguityException(lookup_result, lookup_result_default_table, name); + } + + if (lookup_result_default_table.Found()) { + return lookup_result_default_table; + } + } + + return lookup_result; } -optional_ptr Catalog::GetEntry(ClientContext &context, CatalogType type, const string &schema_name, - const string &name, OnEntryNotFound if_not_found, - QueryErrorContext error_context) { - auto lookup_entry = TryLookupEntry(context, type, schema_name, name, if_not_found, error_context); +optional_ptr Catalog::GetEntry(CatalogEntryRetriever &retriever, CatalogType type, + const string &schema_name, const string &name, + OnEntryNotFound if_not_found, QueryErrorContext error_context) { + auto lookup_entry = TryLookupEntry(retriever, type, schema_name, name, if_not_found, error_context); // Try autoloading extension to resolve lookup if (!lookup_entry.Found()) { - if (AutoLoadExtensionByCatalogEntry(*context.db, type, name)) { - lookup_entry = TryLookupEntry(context, type, schema_name, name, if_not_found, error_context); + if (AutoLoadExtensionByCatalogEntry(*retriever.GetContext().db, type, name)) { + lookup_entry = TryLookupEntry(retriever, type, schema_name, name, if_not_found, error_context); } } @@ -789,20 +890,27 @@ optional_ptr Catalog::GetEntry(ClientContext &context, CatalogType return lookup_entry.entry.get(); } +optional_ptr Catalog::GetEntry(ClientContext &context, CatalogType type, const string &schema_name, + const string &name, OnEntryNotFound if_not_found, + QueryErrorContext error_context) { + CatalogEntryRetriever retriever(context); + return GetEntry(retriever, type, schema_name, name, if_not_found, error_context); +} + CatalogEntry &Catalog::GetEntry(ClientContext &context, CatalogType type, const string &schema, const string &name, QueryErrorContext error_context) { return *Catalog::GetEntry(context, type, schema, name, OnEntryNotFound::THROW_EXCEPTION, error_context); } -optional_ptr Catalog::GetEntry(ClientContext &context, CatalogType type, const string &catalog, +optional_ptr Catalog::GetEntry(CatalogEntryRetriever &retriever, CatalogType type, const string &catalog, const string &schema, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context) { - auto result = TryLookupEntry(context, type, catalog, schema, name, if_not_found, error_context); + auto result = TryLookupEntry(retriever, type, catalog, schema, name, if_not_found, error_context); // Try autoloading extension to resolve lookup if (!result.Found()) { - if (AutoLoadExtensionByCatalogEntry(*context.db, type, name)) { - result = TryLookupEntry(context, type, catalog, schema, name, if_not_found, error_context); + if (AutoLoadExtensionByCatalogEntry(*retriever.GetContext().db, type, name)) { + result = TryLookupEntry(retriever, type, catalog, schema, name, if_not_found, error_context); } } @@ -816,20 +924,26 @@ optional_ptr Catalog::GetEntry(ClientContext &context, CatalogType } return result.entry.get(); } +optional_ptr Catalog::GetEntry(ClientContext &context, CatalogType type, const string &catalog, + const string &schema, const string &name, OnEntryNotFound if_not_found, + QueryErrorContext error_context) { + CatalogEntryRetriever retriever(context); + return GetEntry(retriever, type, catalog, schema, name, if_not_found, error_context); +} CatalogEntry &Catalog::GetEntry(ClientContext &context, CatalogType type, const string &catalog, const string &schema, const string &name, QueryErrorContext error_context) { return *Catalog::GetEntry(context, type, catalog, schema, name, OnEntryNotFound::THROW_EXCEPTION, error_context); } -optional_ptr Catalog::GetSchema(ClientContext &context, const string &catalog_name, +optional_ptr Catalog::GetSchema(CatalogEntryRetriever &retriever, const string &catalog_name, const string &schema_name, OnEntryNotFound if_not_found, QueryErrorContext error_context) { - auto entries = GetCatalogEntries(context, catalog_name, schema_name); + auto entries = GetCatalogEntries(retriever, catalog_name, schema_name); for (idx_t i = 0; i < entries.size(); i++) { auto on_not_found = i + 1 == entries.size() ? if_not_found : OnEntryNotFound::RETURN_NULL; - auto &catalog = Catalog::GetCatalog(context, entries[i].catalog); - auto result = catalog.GetSchema(context, schema_name, on_not_found, error_context); + auto &catalog = Catalog::GetCatalog(retriever, entries[i].catalog); + auto result = catalog.GetSchema(retriever.GetContext(), schema_name, on_not_found, error_context); if (result) { return result; } @@ -837,20 +951,28 @@ optional_ptr Catalog::GetSchema(ClientContext &context, cons return nullptr; } +optional_ptr Catalog::GetSchema(ClientContext &context, const string &catalog_name, + const string &schema_name, OnEntryNotFound if_not_found, + QueryErrorContext error_context) { + CatalogEntryRetriever retriever(context); + return GetSchema(retriever, catalog_name, schema_name, if_not_found, error_context); +} + vector> Catalog::GetSchemas(ClientContext &context) { vector> schemas; ScanSchemas(context, [&](SchemaCatalogEntry &entry) { schemas.push_back(entry); }); return schemas; } -vector> Catalog::GetSchemas(ClientContext &context, const string &catalog_name) { +vector> Catalog::GetSchemas(CatalogEntryRetriever &retriever, + const string &catalog_name) { vector> catalogs; if (IsInvalidCatalog(catalog_name)) { reference_set_t inserted_catalogs; - auto &search_path = *context.client_data->catalog_search_path; + auto &search_path = retriever.GetSearchPath(); for (auto &entry : search_path.Get()) { - auto &catalog = Catalog::GetCatalog(context, entry.catalog); + auto &catalog = Catalog::GetCatalog(retriever, entry.catalog); if (inserted_catalogs.find(catalog) != inserted_catalogs.end()) { continue; } @@ -858,16 +980,21 @@ vector> Catalog::GetSchemas(ClientContext &context catalogs.push_back(catalog); } } else { - catalogs.push_back(Catalog::GetCatalog(context, catalog_name)); + catalogs.push_back(Catalog::GetCatalog(retriever, catalog_name)); } vector> result; for (auto catalog : catalogs) { - auto schemas = catalog.get().GetSchemas(context); + auto schemas = catalog.get().GetSchemas(retriever.GetContext()); result.insert(result.end(), schemas.begin(), schemas.end()); } return result; } +vector> Catalog::GetSchemas(ClientContext &context, const string &catalog_name) { + CatalogEntryRetriever retriever(context); + return GetSchemas(retriever, catalog_name); +} + vector> Catalog::GetAllSchemas(ClientContext &context) { vector> result; @@ -896,8 +1023,8 @@ vector> Catalog::GetAllSchemas(ClientContext &cont void Catalog::Alter(CatalogTransaction transaction, AlterInfo &info) { if (transaction.HasContext()) { - auto lookup = - LookupEntry(transaction.GetContext(), info.GetCatalogType(), info.schema, info.name, info.if_not_found); + CatalogEntryRetriever retriever(transaction.GetContext()); + auto lookup = LookupEntry(retriever, info.GetCatalogType(), info.schema, info.name, info.if_not_found); if (!lookup.Found()) { return; } @@ -916,6 +1043,24 @@ vector Catalog::GetMetadataInfo(ClientContext &context) { return vector(); } +//! Whether this catalog has a default table. Catalogs with a default table can be queries by their catalog name +bool Catalog::HasDefaultTable() const { + return !default_table.empty(); +} + +void Catalog::SetDefaultTable(const string &schema, const string &name) { + default_table = name; + default_table_schema = schema; +} + +string Catalog::GetDefaultTable() const { + return default_table; +} + +string Catalog::GetDefaultTableSchema() const { + return !default_table_schema.empty() ? default_table_schema : DEFAULT_SCHEMA; +} + void Catalog::Verify() { } diff --git a/src/duckdb/src/catalog/catalog_entry.cpp b/src/duckdb/src/catalog/catalog_entry.cpp index 3c8f383ae..d6a96d6ec 100644 --- a/src/duckdb/src/catalog/catalog_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry.cpp @@ -109,6 +109,9 @@ unique_ptr CatalogEntry::Deserialize(Deserializer &deserializer) { void CatalogEntry::Verify(Catalog &catalog_p) { } +void CatalogEntry::Rollback(CatalogEntry &prev_entry) { +} + InCatalogEntry::InCatalogEntry(CatalogType type, Catalog &catalog, string name) : CatalogEntry(type, catalog, std::move(name)), catalog(catalog) { } diff --git a/src/duckdb/src/catalog/catalog_entry/duck_index_entry.cpp b/src/duckdb/src/catalog/catalog_entry/duck_index_entry.cpp index be047bfe3..c70984e53 100644 --- a/src/duckdb/src/catalog/catalog_entry/duck_index_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/duck_index_entry.cpp @@ -9,17 +9,20 @@ IndexDataTableInfo::IndexDataTableInfo(shared_ptr info_p, const s : info(std::move(info_p)), index_name(index_name_p) { } -IndexDataTableInfo::~IndexDataTableInfo() { +void DuckIndexEntry::Rollback(CatalogEntry &) { if (!info) { return; } - // FIXME: this should happen differently. - info->GetIndexes().RemoveIndex(index_name); + if (!info->info) { + return; + } + info->info->GetIndexes().RemoveIndex(name); } DuckIndexEntry::DuckIndexEntry(Catalog &catalog, SchemaCatalogEntry &schema, CreateIndexInfo &create_info, TableCatalogEntry &table_p) : IndexCatalogEntry(catalog, schema, create_info), initial_index_size(0) { + auto &table = table_p.Cast(); auto &storage = table.GetStorage(); info = make_shared_ptr(storage.GetDataTableInfo(), name); @@ -54,7 +57,9 @@ DataTableInfo &DuckIndexEntry::GetDataTableInfo() const { void DuckIndexEntry::CommitDrop() { D_ASSERT(info); - GetDataTableInfo().GetIndexes().CommitDrop(name); + auto &indexes = GetDataTableInfo().GetIndexes(); + indexes.CommitDrop(name); + indexes.RemoveIndex(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 f3c8684fb..f2d01e58a 100644 --- a/src/duckdb/src/catalog/catalog_entry/duck_schema_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/duck_schema_entry.cpp @@ -168,6 +168,9 @@ optional_ptr DuckSchemaEntry::CreateTable(CatalogTransaction trans auto &set = GetCatalogSet(CatalogType::TABLE_ENTRY); info.dependencies.AddDependency(*set.GetEntry(transaction, fk_info.name)); } + for (auto &dep : info.dependencies.Set()) { + table->dependencies.AddDependency(dep); + } auto entry = AddEntryInternal(transaction, std::move(table), info.Base().on_conflict, info.dependencies); if (!entry) { 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 be1041f9b..901a7120f 100644 --- a/src/duckdb/src/catalog/catalog_entry/duck_table_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/duck_table_entry.cpp @@ -20,72 +20,22 @@ #include "duckdb/planner/operator/logical_projection.hpp" #include "duckdb/planner/operator/logical_update.hpp" #include "duckdb/planner/parsed_data/bound_create_table_info.hpp" -#include "duckdb/planner/table_filter.hpp" #include "duckdb/storage/storage_manager.hpp" #include "duckdb/storage/table_storage_info.hpp" namespace duckdb { -void AddDataTableIndex(DataTable &storage, const ColumnList &columns, const vector &keys, - IndexConstraintType constraint_type, const IndexStorageInfo &info) { - - // fetch types and create expressions for the index from the columns - vector column_ids; - vector> unbound_expressions; - vector> bound_expressions; - idx_t key_nr = 0; - column_ids.reserve(keys.size()); - for (auto &physical_key : keys) { - auto &column = columns.GetColumn(physical_key); - D_ASSERT(!column.Generated()); - unbound_expressions.push_back( - make_uniq(column.Name(), column.Type(), ColumnBinding(0, column_ids.size()))); - - bound_expressions.push_back(make_uniq(column.Type(), key_nr++)); - column_ids.push_back(column.StorageOid()); - } - // create an adaptive radix tree around the expressions - auto art = make_uniq(info.name, constraint_type, column_ids, TableIOManager::Get(storage), - std::move(unbound_expressions), storage.db, nullptr, info); - if (!info.IsValid() && !info.name.empty() && !storage.IsRoot()) { - throw TransactionException("Transaction conflict: cannot add an index to a table that has been altered!"); - } - storage.AddIndex(std::move(art)); -} - -void AddDataTableIndex(DataTable &storage, const ColumnList &columns, vector &keys, - IndexConstraintType constraint_type, const IndexStorageInfo &info) { - vector new_keys; - new_keys.reserve(keys.size()); - for (auto &logical_key : keys) { - new_keys.push_back(columns.LogicalToPhysical(logical_key)); - } - AddDataTableIndex(storage, columns, new_keys, constraint_type, info); -} - -IndexStorageInfo GetIndexInfo(const IndexConstraintType &constraint_type, const bool v1_0_0_storage, - unique_ptr &create_info, const idx_t identifier) { +IndexStorageInfo GetIndexInfo(const IndexConstraintType type, const bool v1_0_0_storage, unique_ptr &info, + const idx_t id) { - auto &create_table_info = create_info->Cast(); - auto constraint_name = EnumUtil::ToString(constraint_type) + "_"; - auto name = constraint_name + create_table_info.table + "_" + to_string(identifier); - IndexStorageInfo info(name); + auto &table_info = info->Cast(); + auto constraint_name = EnumUtil::ToString(type) + "_"; + auto name = constraint_name + table_info.table + "_" + to_string(id); + IndexStorageInfo index_info(name); if (!v1_0_0_storage) { - info.options.emplace("v1_0_0_storage", v1_0_0_storage); - } - return info; -} - -vector GetUniqueConstraintKeys(const ColumnList &columns, const UniqueConstraint &constraint) { - vector indexes; - if (constraint.HasIndex()) { - indexes.push_back(columns.LogicalToPhysical(constraint.GetIndex())); - } else { - for (auto &keyname : constraint.GetColumnNames()) { - indexes.push_back(columns.GetColumn(keyname).Physical()); - } + index_info.options.emplace("v1_0_0_storage", v1_0_0_storage); } - return indexes; + return index_info; } DuckTableEntry::DuckTableEntry(Catalog &catalog, SchemaCatalogEntry &schema, BoundCreateTableInfo &info, @@ -101,28 +51,30 @@ DuckTableEntry::DuckTableEntry(Catalog &catalog, SchemaCatalogEntry &schema, Bou } // create the physical storage - vector storage_columns; + vector column_defs; for (auto &col_def : columns.Physical()) { - storage_columns.push_back(col_def.Copy()); + column_defs.push_back(col_def.Copy()); } storage = make_shared_ptr(catalog.GetAttached(), StorageManager::Get(catalog).GetTableIOManager(&info), - schema.name, name, std::move(storage_columns), std::move(info.data)); + schema.name, name, std::move(column_defs), std::move(info.data)); - // create the unique indexes for the UNIQUE and PRIMARY KEY and FOREIGN KEY constraints + // Create the unique indexes for the UNIQUE, PRIMARY KEY, and FOREIGN KEY constraints. idx_t indexes_idx = 0; for (idx_t i = 0; i < constraints.size(); i++) { auto &constraint = constraints[i]; if (constraint->type == ConstraintType::UNIQUE) { - // unique constraint: create a unique index + + // UNIQUE constraint: Create a unique index. auto &unique = constraint->Cast(); IndexConstraintType constraint_type = IndexConstraintType::UNIQUE; if (unique.is_primary_key) { constraint_type = IndexConstraintType::PRIMARY; } - auto unique_keys = GetUniqueConstraintKeys(columns, unique); + + auto column_indexes = unique.GetLogicalIndexes(columns); if (info.indexes.empty()) { - auto index_storage_info = GetIndexInfo(constraint_type, false, info.base, i); - AddDataTableIndex(*storage, columns, unique_keys, constraint_type, index_storage_info); + auto index_info = GetIndexInfo(constraint_type, false, info.base, i); + storage->AddIndex(columns, column_indexes, constraint_type, index_info); continue; } @@ -132,21 +84,27 @@ DuckTableEntry::DuckTableEntry(Catalog &catalog, SchemaCatalogEntry &schema, Bou info.indexes[indexes_idx].name = name_info.name; } - // now add the index - AddDataTableIndex(*storage, columns, unique_keys, constraint_type, info.indexes[indexes_idx++]); + // Now we can add the index. + storage->AddIndex(columns, column_indexes, constraint_type, info.indexes[indexes_idx++]); continue; } if (constraint->type == ConstraintType::FOREIGN_KEY) { - // foreign key constraint: create a foreign key index + // Create a FOREIGN KEY index. auto &bfk = constraint->Cast(); if (bfk.info.type == ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE || bfk.info.type == ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE) { + vector column_indexes; + for (const auto &physical_index : bfk.info.fk_keys) { + auto &col = columns.GetColumn(physical_index); + column_indexes.push_back(col.Logical()); + } + if (info.indexes.empty()) { auto constraint_type = IndexConstraintType::FOREIGN; - auto index_storage_info = GetIndexInfo(constraint_type, false, info.base, i); - AddDataTableIndex(*storage, columns, bfk.info.fk_keys, constraint_type, index_storage_info); + auto index_info = GetIndexInfo(constraint_type, false, info.base, i); + storage->AddIndex(columns, column_indexes, constraint_type, index_info); continue; } @@ -156,9 +114,8 @@ DuckTableEntry::DuckTableEntry(Catalog &catalog, SchemaCatalogEntry &schema, Bou info.indexes[indexes_idx].name = name_info.name; } - // now add the index - AddDataTableIndex(*storage, columns, bfk.info.fk_keys, IndexConstraintType::FOREIGN, - info.indexes[indexes_idx++]); + // Now we can add the index. + storage->AddIndex(columns, column_indexes, IndexConstraintType::FOREIGN, info.indexes[indexes_idx++]); } } } @@ -258,6 +215,10 @@ unique_ptr DuckTableEntry::AlterEntry(ClientContext &context, Alte auto &drop_not_null_info = table_info.Cast(); return DropNotNull(context, drop_not_null_info); } + case AlterTableType::ADD_CONSTRAINT: { + auto &add_constraint_info = table_info.Cast(); + return AddConstraint(context, add_constraint_info); + } default: throw InternalException("Unrecognized alter table type!"); } @@ -565,7 +526,6 @@ unique_ptr DuckTableEntry::SetDefault(ClientContext &context, SetD } unique_ptr DuckTableEntry::SetNotNull(ClientContext &context, SetNotNullInfo &info) { - auto create_info = make_uniq(schema, name); create_info->comment = comment; create_info->tags = tags; @@ -598,8 +558,9 @@ unique_ptr DuckTableEntry::SetNotNull(ClientContext &context, SetN } // Return with new storage info. Note that we need the bound column index here. - auto new_storage = make_shared_ptr( - context, *storage, make_uniq(columns.LogicalToPhysical(LogicalIndex(not_null_idx)))); + auto physical_columns = columns.LogicalToPhysical(LogicalIndex(not_null_idx)); + auto bound_constraint = make_uniq(physical_columns); + auto new_storage = make_shared_ptr(context, *storage, *bound_constraint); return make_uniq(catalog, schema, *bound_create_info, new_storage); } @@ -630,12 +591,24 @@ 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); + auto change_idx = GetColumnIndex(info.column_name); auto create_info = make_uniq(schema, name); create_info->temporary = temporary; create_info->comment = comment; create_info->tags = tags; + // Bind the USING expression. + vector bound_columns; + AlterBinder expr_binder(*binder, context, *this, bound_columns, info.target_type); + auto expression = info.expression->Copy(); + auto bound_expression = expr_binder.Bind(expression); + + // Infer the target_type from the USING expression, if not set explicitly. + if (info.target_type == LogicalType::UNKNOWN) { + info.target_type = bound_expression->return_type; + } + auto bound_constraints = binder->BindConstraints(constraints, name, columns); for (auto &col : columns.Logical()) { auto copy = col.Copy(); @@ -655,11 +628,11 @@ unique_ptr DuckTableEntry::ChangeColumnType(ClientContext &context create_info->columns.AddColumn(std::move(copy)); } - for (idx_t i = 0; i < constraints.size(); i++) { - auto constraint = constraints[i]->Copy(); + for (idx_t constr_idx = 0; constr_idx < constraints.size(); constr_idx++) { + auto constraint = constraints[constr_idx]->Copy(); switch (constraint->type) { case ConstraintType::CHECK: { - auto &bound_check = bound_constraints[i]->Cast(); + auto &bound_check = bound_constraints[constr_idx]->Cast(); auto physical_index = columns.LogicalToPhysical(change_idx); if (bound_check.bound_columns.find(physical_index) != bound_check.bound_columns.end()) { throw BinderException("Cannot change the type of a column that has a CHECK constraint specified"); @@ -669,22 +642,21 @@ unique_ptr DuckTableEntry::ChangeColumnType(ClientContext &context case ConstraintType::NOT_NULL: break; case ConstraintType::UNIQUE: { - auto &bound_unique = bound_constraints[i]->Cast(); - if (bound_unique.key_set.find(change_idx) != bound_unique.key_set.end()) { + auto &bound_unique = bound_constraints[constr_idx]->Cast(); + auto physical_index = columns.LogicalToPhysical(change_idx); + if (bound_unique.key_set.find(physical_index) != bound_unique.key_set.end()) { throw BinderException( "Cannot change the type of a column that has a UNIQUE or PRIMARY KEY constraint specified"); } break; } case ConstraintType::FOREIGN_KEY: { - auto &bfk = bound_constraints[i]->Cast(); + auto &bfk = bound_constraints[constr_idx]->Cast(); auto key_set = bfk.pk_key_set; if (bfk.info.type == ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE) { key_set = bfk.fk_key_set; } else if (bfk.info.type == ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE) { - for (idx_t i = 0; i < bfk.info.fk_keys.size(); i++) { - key_set.insert(bfk.info.fk_keys[i]); - } + key_set.insert(bfk.info.fk_keys.begin(), bfk.info.fk_keys.end()); } if (key_set.find(columns.LogicalToPhysical(change_idx)) != key_set.end()) { throw BinderException("Cannot change the type of a column that has a FOREIGN KEY constraint specified"); @@ -697,12 +669,8 @@ unique_ptr DuckTableEntry::ChangeColumnType(ClientContext &context create_info->constraints.push_back(std::move(constraint)); } - // bind the specified expression - vector bound_columns; - AlterBinder expr_binder(*binder, context, *this, bound_columns, info.target_type); - auto expression = info.expression->Copy(); - auto bound_expression = expr_binder.Bind(expression); auto bound_create_info = binder->BindCreateTableInfo(std::move(create_info), schema); + vector storage_oids; for (idx_t i = 0; i < bound_columns.size(); i++) { storage_oids.push_back(columns.LogicalToPhysical(bound_columns[i]).index); @@ -801,6 +769,84 @@ unique_ptr DuckTableEntry::DropForeignKeyConstraint(ClientContext return make_uniq(catalog, schema, *bound_create_info, storage); } +void DuckTableEntry::Rollback(CatalogEntry &prev_entry) { + if (prev_entry.type != CatalogType::TABLE_ENTRY) { + return; + } + + // Rolls back any physical index creation. + // FIXME: Currently only works for PKs. + // FIXME: Should be changed to work for any index-based constraint. + + auto &table = Cast(); + auto &prev_table = prev_entry.Cast(); + auto &prev_info = prev_table.GetStorage().GetDataTableInfo(); + auto &prev_indexes = prev_info->GetIndexes(); + + // Find all index-based constraints that exist in rollback_table, but not in table. + // Then, remove them. + + unordered_set names; + for (const auto &constraint : prev_table.GetConstraints()) { + if (constraint->type != ConstraintType::UNIQUE) { + continue; + } + const auto &unique = constraint->Cast(); + if (unique.is_primary_key) { + auto index_name = unique.GetName(prev_table.name); + names.insert(index_name); + } + } + + for (const auto &constraint : GetConstraints()) { + if (constraint->type != ConstraintType::UNIQUE) { + continue; + } + const auto &unique = constraint->Cast(); + if (!unique.IsPrimaryKey()) { + continue; + } + auto index_name = unique.GetName(table.name); + if (names.find(index_name) == names.end()) { + prev_indexes.RemoveIndex(index_name); + } + } +} + +unique_ptr DuckTableEntry::AddConstraint(ClientContext &context, AddConstraintInfo &info) { + auto create_info = make_uniq(schema, name); + create_info->comment = comment; + + // Copy all columns and constraints to the modified table. + create_info->columns = columns.Copy(); + for (const auto &constraint : constraints) { + create_info->constraints.push_back(constraint->Copy()); + } + + if (info.constraint->type == ConstraintType::UNIQUE) { + const auto &unique = info.constraint->Cast(); + const auto existing_pk = GetPrimaryKey(); + + if (unique.is_primary_key && existing_pk) { + auto existing_name = existing_pk->ToString(); + throw CatalogException("table \"%s\" can have only one primary key: %s", name, existing_name); + } + create_info->constraints.push_back(info.constraint->Copy()); + + } else { + throw InternalException("unsupported constraint type in ALTER TABLE statement"); + } + + // We create a physical table with a new constraint and a new unique index. + const auto binder = Binder::CreateBinder(context); + const auto bound_constraint = binder->BindConstraint(*info.constraint, create_info->table, create_info->columns); + const auto bound_create_info = binder->BindCreateTableInfo(std::move(create_info), schema); + + auto new_storage = make_shared_ptr(context, *storage, *bound_constraint); + auto new_entry = make_uniq(catalog, schema, *bound_create_info, new_storage); + return std::move(new_entry); +} + unique_ptr DuckTableEntry::Copy(ClientContext &context) const { auto create_info = make_uniq(schema, name); create_info->comment = comment; 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 865ac4734..cb927f98a 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 @@ -8,7 +8,7 @@ ScalarFunctionCatalogEntry::ScalarFunctionCatalogEntry(Catalog &catalog, SchemaC : FunctionEntry(CatalogType::SCALAR_FUNCTION_ENTRY, catalog, schema, info), functions(info.functions) { } -unique_ptr ScalarFunctionCatalogEntry::AlterEntry(ClientContext &context, AlterInfo &info) { +unique_ptr ScalarFunctionCatalogEntry::AlterEntry(CatalogTransaction transaction, AlterInfo &info) { if (info.type != AlterType::ALTER_SCALAR_FUNCTION) { throw InternalException("Attempting to alter ScalarFunctionCatalogEntry with unsupported alter type"); } @@ -20,10 +20,18 @@ unique_ptr ScalarFunctionCatalogEntry::AlterEntry(ClientContext &c auto &add_overloads = function_info.Cast(); ScalarFunctionSet new_set = functions; - if (!new_set.MergeFunctionSet(add_overloads.new_overloads)) { - throw BinderException("Failed to add new function overloads to function \"%s\": function already exists", name); + if (!new_set.MergeFunctionSet(add_overloads.new_overloads->functions, true)) { + throw BinderException( + "Failed to add new function overloads to function \"%s\": function overload already exists", name); } CreateScalarFunctionInfo new_info(std::move(new_set)); + new_info.internal = internal; + new_info.description = + add_overloads.new_overloads->description.empty() ? description : add_overloads.new_overloads->description; + new_info.parameter_names = add_overloads.new_overloads->parameter_names.empty() + ? parameter_names + : add_overloads.new_overloads->parameter_names; + new_info.example = add_overloads.new_overloads->example.empty() ? example : add_overloads.new_overloads->example; return make_uniq(catalog, schema, new_info); } 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 abb66b7e1..ce0078e50 100644 --- a/src/duckdb/src/catalog/catalog_entry/table_catalog_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/table_catalog_entry.cpp @@ -176,6 +176,24 @@ string TableCatalogEntry::ColumnsToSQL(const ColumnList &columns, const vector 0) { + ss << ", "; + } + ss << KeywordHelper::WriteOptionallyQuoted(column.Name()) << " "; + } + ss << ")"; + return ss.str(); +} + string TableCatalogEntry::ToSQL() const { auto create_info = GetInfo(); return create_info->ToString(); @@ -316,4 +334,20 @@ void TableCatalogEntry::BindUpdateConstraints(Binder &binder, LogicalGet &get, L } } +optional_ptr TableCatalogEntry::GetPrimaryKey() const { + for (const auto &constraint : GetConstraints()) { + if (constraint->type == ConstraintType::UNIQUE) { + auto &unique = constraint->Cast(); + if (unique.IsPrimaryKey()) { + return &unique; + } + } + } + return nullptr; +} + +bool TableCatalogEntry::HasPrimaryKey() const { + return GetPrimaryKey() != nullptr; +} + } // namespace duckdb 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 1b3b566ba..9b80a1d5d 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 @@ -9,7 +9,7 @@ TableFunctionCatalogEntry::TableFunctionCatalogEntry(Catalog &catalog, SchemaCat D_ASSERT(this->functions.Size() > 0); } -unique_ptr TableFunctionCatalogEntry::AlterEntry(ClientContext &context, AlterInfo &info) { +unique_ptr TableFunctionCatalogEntry::AlterEntry(CatalogTransaction transaction, AlterInfo &info) { if (info.type != AlterType::ALTER_TABLE_FUNCTION) { throw InternalException("Attempting to alter TableFunctionCatalogEntry with unsupported alter type"); } diff --git a/src/duckdb/src/catalog/catalog_entry_retriever.cpp b/src/duckdb/src/catalog/catalog_entry_retriever.cpp index db0d0d423..c37562d72 100644 --- a/src/duckdb/src/catalog/catalog_entry_retriever.cpp +++ b/src/duckdb/src/catalog/catalog_entry_retriever.cpp @@ -7,6 +7,7 @@ #include "duckdb/common/enums/catalog_type.hpp" #include "duckdb/common/optional_ptr.hpp" #include "duckdb/catalog/catalog_entry/type_catalog_entry.hpp" +#include "duckdb/main/client_data.hpp" namespace duckdb { @@ -36,14 +37,13 @@ optional_ptr CatalogEntryRetriever::GetEntry(CatalogType type, con const string &schema, const string &name, OnEntryNotFound on_entry_not_found, QueryErrorContext error_context) { - return GetEntryInternal( - [&]() { return Catalog::GetEntry(context, type, catalog, schema, name, on_entry_not_found, error_context); }); + return ReturnAndCallback(Catalog::GetEntry(*this, type, catalog, schema, name, on_entry_not_found, error_context)); } optional_ptr CatalogEntryRetriever::GetSchema(const string &catalog, const string &name, OnEntryNotFound on_entry_not_found, QueryErrorContext error_context) { - auto result = Catalog::GetSchema(context, catalog, name, on_entry_not_found, error_context); + auto result = Catalog::GetSchema(*this, catalog, name, on_entry_not_found, error_context); if (!result) { return result; } @@ -57,8 +57,63 @@ optional_ptr CatalogEntryRetriever::GetSchema(const string & optional_ptr CatalogEntryRetriever::GetEntry(CatalogType type, Catalog &catalog, const string &schema, const string &name, OnEntryNotFound on_entry_not_found, QueryErrorContext error_context) { - return GetEntryInternal( - [&]() { return catalog.GetEntry(context, type, schema, name, on_entry_not_found, error_context); }); + return ReturnAndCallback(catalog.GetEntry(*this, type, schema, name, on_entry_not_found, error_context)); +} + +optional_ptr CatalogEntryRetriever::ReturnAndCallback(optional_ptr result) { + if (!result) { + return result; + } + if (callback) { + // Call the callback if it's set + callback(*result); + } + return result; +} + +void CatalogEntryRetriever::Inherit(const CatalogEntryRetriever &parent) { + this->callback = parent.callback; + this->search_path = parent.search_path; +} + +CatalogSearchPath &CatalogEntryRetriever::GetSearchPath() { + if (search_path) { + return *search_path; + } + return *ClientData::Get(context).catalog_search_path; +} + +void CatalogEntryRetriever::SetSearchPath(vector entries) { + vector new_path; + for (auto &entry : entries) { + if (IsInvalidCatalog(entry.catalog) || entry.catalog == SYSTEM_CATALOG || entry.catalog == TEMP_CATALOG) { + continue; + } + new_path.push_back(std::move(entry)); + } + if (new_path.empty()) { + return; + } + + // push the set paths from the ClientContext behind the provided paths + auto &client_search_path = *ClientData::Get(context).catalog_search_path; + auto &set_paths = client_search_path.GetSetPaths(); + for (auto path : set_paths) { + if (IsInvalidCatalog(path.catalog)) { + path.catalog = DatabaseManager::GetDefaultDatabase(context); + } + new_path.push_back(std::move(path)); + } + + this->search_path = make_shared_ptr(context, std::move(new_path)); +} + +void CatalogEntryRetriever::SetCallback(catalog_entry_callback_t callback) { + this->callback = std::move(callback); +} + +catalog_entry_callback_t CatalogEntryRetriever::GetCallback() { + return callback; } } // namespace duckdb diff --git a/src/duckdb/src/catalog/catalog_search_path.cpp b/src/duckdb/src/catalog/catalog_search_path.cpp index 9368e300f..fe314dde7 100644 --- a/src/duckdb/src/catalog/catalog_search_path.cpp +++ b/src/duckdb/src/catalog/catalog_search_path.cpp @@ -123,13 +123,17 @@ vector CatalogSearchEntry::ParseList(const string &input) { return result; } -CatalogSearchPath::CatalogSearchPath(ClientContext &context_p) : context(context_p) { - Reset(); +CatalogSearchPath::CatalogSearchPath(ClientContext &context_p, vector entries) + : context(context_p) { + SetPathsInternal(std::move(entries)); +} + +CatalogSearchPath::CatalogSearchPath(ClientContext &context_p) : CatalogSearchPath(context_p, {}) { } void CatalogSearchPath::Reset() { vector empty; - SetPaths(empty); + SetPathsInternal(empty); } string CatalogSearchPath::GetSetName(CatalogSetPathType set_type) { @@ -176,8 +180,7 @@ void CatalogSearchPath::Set(vector new_paths, CatalogSetPath new_paths[0].catalog); } } - this->set_paths = std::move(new_paths); - SetPaths(set_paths); + SetPathsInternal(std::move(new_paths)); } void CatalogSearchPath::Set(CatalogSearchEntry new_value, CatalogSetPathType set_type) { @@ -239,12 +242,14 @@ const CatalogSearchEntry &CatalogSearchPath::GetDefault() { return paths[1]; } -void CatalogSearchPath::SetPaths(vector new_paths) { +void CatalogSearchPath::SetPathsInternal(vector new_paths) { + this->set_paths = std::move(new_paths); + paths.clear(); - paths.reserve(new_paths.size() + 3); + paths.reserve(set_paths.size() + 3); paths.emplace_back(TEMP_CATALOG, DEFAULT_SCHEMA); - for (auto &path : new_paths) { - paths.push_back(std::move(path)); + for (auto &path : set_paths) { + paths.push_back(path); } paths.emplace_back(INVALID_CATALOG, DEFAULT_SCHEMA); paths.emplace_back(SYSTEM_CATALOG, DEFAULT_SCHEMA); diff --git a/src/duckdb/src/catalog/catalog_set.cpp b/src/duckdb/src/catalog/catalog_set.cpp index f3f7ef1b9..310bef958 100644 --- a/src/duckdb/src/catalog/catalog_set.cpp +++ b/src/duckdb/src/catalog/catalog_set.cpp @@ -590,6 +590,7 @@ void CatalogSet::Undo(CatalogEntry &entry) { // i.e. we have to place (entry) as (entry->parent) again auto &to_be_removed_node = entry.Parent(); + to_be_removed_node.Rollback(entry); D_ASSERT(StringUtil::CIEquals(entry.name, to_be_removed_node.name)); if (!to_be_removed_node.HasParent()) { diff --git a/src/duckdb/src/catalog/default/default_functions.cpp b/src/duckdb/src/catalog/default/default_functions.cpp index f7f4634b9..247998363 100644 --- a/src/duckdb/src/catalog/default/default_functions.cpp +++ b/src/duckdb/src/catalog/default/default_functions.cpp @@ -27,10 +27,10 @@ static const DefaultMacro internal_macros[] = { {"pg_catalog", "pg_typeof", {"expression", nullptr}, {{nullptr, nullptr}}, "lower(typeof(expression))"}, // get the data type of any value - {"pg_catalog", "current_database", {nullptr}, {{nullptr, nullptr}}, "main.current_database()"}, // name of current database (called "catalog" in the SQL standard) - {"pg_catalog", "current_query", {nullptr}, {{nullptr, nullptr}}, "main.current_query()"}, // the currently executing query (NULL if not inside a plpgsql function) - {"pg_catalog", "current_schema", {nullptr}, {{nullptr, nullptr}}, "main.current_schema()"}, // name of current schema - {"pg_catalog", "current_schemas", {"include_implicit"}, {{nullptr, nullptr}}, "main.current_schemas(include_implicit)"}, // names of schemas in search path + {"pg_catalog", "current_database", {nullptr}, {{nullptr, nullptr}}, "system.main.current_database()"}, // name of current database (called "catalog" in the SQL standard) + {"pg_catalog", "current_query", {nullptr}, {{nullptr, nullptr}}, "system.main.current_query()"}, // the currently executing query (NULL if not inside a plpgsql function) + {"pg_catalog", "current_schema", {nullptr}, {{nullptr, nullptr}}, "system.main.current_schema()"}, // name of current schema + {"pg_catalog", "current_schemas", {"include_implicit"}, {{nullptr, nullptr}}, "system.main.current_schemas(include_implicit)"}, // names of schemas in search path // privilege functions {"pg_catalog", "has_any_column_privilege", {"table", "privilege", nullptr}, {{nullptr, nullptr}}, "true"}, //boolean //does current user have privilege for any column of table diff --git a/src/duckdb/src/catalog/dependency_manager.cpp b/src/duckdb/src/catalog/dependency_manager.cpp index 51c60d3ad..7cf3d0eca 100644 --- a/src/duckdb/src/catalog/dependency_manager.cpp +++ b/src/duckdb/src/catalog/dependency_manager.cpp @@ -485,6 +485,54 @@ void DependencyManager::DropObject(CatalogTransaction transaction, CatalogEntry } } +void DependencyManager::ReorderEntries(catalog_entry_vector_t &entries, ClientContext &context) { + auto transaction = catalog.GetCatalogTransaction(context); + // Read all the entries visible to this snapshot + ReorderEntries(entries, transaction); +} + +void DependencyManager::ReorderEntries(catalog_entry_vector_t &entries) { + // Read all committed entries + CatalogTransaction transaction(catalog.GetDatabase(), TRANSACTION_ID_START - 1, TRANSACTION_ID_START - 1); + ReorderEntries(entries, transaction); +} + +void DependencyManager::ReorderEntry(CatalogTransaction transaction, CatalogEntry &entry, catalog_entry_set_t &visited, + catalog_entry_vector_t &order) { + auto &catalog_entry = *LookupEntry(transaction, entry); + // We use this in CheckpointManager, it has the highest commit ID, allowing us to read any committed data + bool allow_internal = transaction.start_time == TRANSACTION_ID_START - 1; + if (visited.count(catalog_entry) || (!allow_internal && catalog_entry.internal)) { + // Already seen and ordered appropriately + return; + } + + // Check if there are any entries that this entry depends on, those are written first + catalog_entry_vector_t dependents; + auto info = GetLookupProperties(entry); + ScanSubjects(transaction, info, [&](DependencyEntry &dep) { dependents.push_back(dep); }); + for (auto &dep : dependents) { + ReorderEntry(transaction, dep, visited, order); + } + + // Then write the entry + visited.insert(catalog_entry); + order.push_back(catalog_entry); +} + +void DependencyManager::ReorderEntries(catalog_entry_vector_t &entries, CatalogTransaction transaction) { + catalog_entry_vector_t reordered; + catalog_entry_set_t visited; + for (auto &entry : entries) { + ReorderEntry(transaction, entry, visited, reordered); + } + // If this would fail, that means there are more entries that we somehow reached through the dependency manager + // but those entries should not actually be visible to this transaction + D_ASSERT(entries.size() == reordered.size()); + entries.clear(); + entries = reordered; +} + void DependencyManager::AlterObject(CatalogTransaction transaction, CatalogEntry &old_obj, CatalogEntry &new_obj, AlterInfo &alter_info) { if (IsSystemEntry(new_obj)) { diff --git a/src/duckdb/src/catalog/duck_catalog.cpp b/src/duckdb/src/catalog/duck_catalog.cpp index 920740c96..02264a027 100644 --- a/src/duckdb/src/catalog/duck_catalog.cpp +++ b/src/duckdb/src/catalog/duck_catalog.cpp @@ -8,9 +8,7 @@ #include "duckdb/function/built_in_functions.hpp" #include "duckdb/main/attached_database.hpp" #include "duckdb/transaction/duck_transaction_manager.hpp" -#ifndef DISABLE_CORE_FUNCTIONS_EXTENSION -#include "duckdb/core_functions/core_functions.hpp" -#endif +#include "duckdb/function/function_list.hpp" namespace duckdb { @@ -35,13 +33,11 @@ void DuckCatalog::Initialize(bool load_builtin) { CreateSchema(data, info); if (load_builtin) { - // initialize default functions BuiltinFunctions builtin(data, *this); builtin.Initialize(); -#ifndef DISABLE_CORE_FUNCTIONS_EXTENSION - CoreFunctions::RegisterFunctions(*this, data); -#endif + // initialize default functions + FunctionList::RegisterFunctions(*this, data); } Verify(); diff --git a/src/duckdb/src/common/arrow/arrow_merge_event.cpp b/src/duckdb/src/common/arrow/arrow_merge_event.cpp index 4dafac60f..1315ad1ad 100644 --- a/src/duckdb/src/common/arrow/arrow_merge_event.cpp +++ b/src/duckdb/src/common/arrow/arrow_merge_event.cpp @@ -87,7 +87,7 @@ void ArrowMergeEvent::Schedule() { idx_t tuples_for_task = 0; idx_t start_index = transformer.GetIndex(); idx_t end_index = start_index; - while (tuples_for_task < Storage::ROW_GROUP_SIZE) { + while (tuples_for_task < DEFAULT_ROW_GROUP_SIZE) { idx_t batch_size; if (!transformer.TryGetNextBatchSize(batch_size)) { finished = true; diff --git a/src/duckdb/src/common/enum_util.cpp b/src/duckdb/src/common/enum_util.cpp index 9a0db08f8..ff0432b2b 100644 --- a/src/duckdb/src/common/enum_util.cpp +++ b/src/duckdb/src/common/enum_util.cpp @@ -45,6 +45,7 @@ #include "duckdb/common/enums/physical_operator_type.hpp" #include "duckdb/common/enums/prepared_statement_mode.hpp" #include "duckdb/common/enums/profiler_format.hpp" +#include "duckdb/common/enums/quantile_enum.hpp" #include "duckdb/common/enums/relation_type.hpp" #include "duckdb/common/enums/scan_options.hpp" #include "duckdb/common/enums/set_operation_type.hpp" @@ -77,7 +78,6 @@ #include "duckdb/common/types/timestamp.hpp" #include "duckdb/common/types/vector.hpp" #include "duckdb/common/types/vector_buffer.hpp" -#include "duckdb/core_functions/aggregate/quantile_enum.hpp" #include "duckdb/execution/index/art/art.hpp" #include "duckdb/execution/index/art/node.hpp" #include "duckdb/execution/operator/csv_scanner/csv_option.hpp" @@ -88,7 +88,7 @@ #include "duckdb/function/copy_function.hpp" #include "duckdb/function/function.hpp" #include "duckdb/function/macro_function.hpp" -#include "duckdb/function/scalar/compressed_materialization_functions.hpp" +#include "duckdb/function/scalar/compressed_materialization_utils.hpp" #include "duckdb/function/scalar/strftime_format.hpp" #include "duckdb/function/table/arrow/enum/arrow_datetime_type.hpp" #include "duckdb/function/table/arrow/enum/arrow_type_info_type.hpp" @@ -139,8200 +139,3932 @@ #include "duckdb/storage/statistics/base_statistics.hpp" #include "duckdb/storage/table/chunk_info.hpp" #include "duckdb/storage/table/column_segment.hpp" +#include "duckdb/storage/temporary_file_manager.hpp" #include "duckdb/verification/statement_verifier.hpp" namespace duckdb { +const StringUtil::EnumStringLiteral *GetAccessModeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(AccessMode::UNDEFINED), "UNDEFINED" }, + { static_cast(AccessMode::AUTOMATIC), "AUTOMATIC" }, + { static_cast(AccessMode::READ_ONLY), "READ_ONLY" }, + { static_cast(AccessMode::READ_WRITE), "READ_WRITE" } + }; + return values; +} + template<> const char* EnumUtil::ToChars(AccessMode value) { - switch(value) { - case AccessMode::UNDEFINED: - return "UNDEFINED"; - case AccessMode::AUTOMATIC: - return "AUTOMATIC"; - case AccessMode::READ_ONLY: - return "READ_ONLY"; - case AccessMode::READ_WRITE: - return "READ_WRITE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetAccessModeValues(), 4, "AccessMode", static_cast(value)); } template<> AccessMode EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "UNDEFINED")) { - return AccessMode::UNDEFINED; - } - if (StringUtil::Equals(value, "AUTOMATIC")) { - return AccessMode::AUTOMATIC; - } - if (StringUtil::Equals(value, "READ_ONLY")) { - return AccessMode::READ_ONLY; - } - if (StringUtil::Equals(value, "READ_WRITE")) { - return AccessMode::READ_WRITE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetAccessModeValues(), 4, "AccessMode", value)); +} + +const StringUtil::EnumStringLiteral *GetAggregateCombineTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(AggregateCombineType::PRESERVE_INPUT), "PRESERVE_INPUT" }, + { static_cast(AggregateCombineType::ALLOW_DESTRUCTIVE), "ALLOW_DESTRUCTIVE" } + }; + return values; } template<> const char* EnumUtil::ToChars(AggregateCombineType value) { - switch(value) { - case AggregateCombineType::PRESERVE_INPUT: - return "PRESERVE_INPUT"; - case AggregateCombineType::ALLOW_DESTRUCTIVE: - return "ALLOW_DESTRUCTIVE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetAggregateCombineTypeValues(), 2, "AggregateCombineType", static_cast(value)); } template<> AggregateCombineType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "PRESERVE_INPUT")) { - return AggregateCombineType::PRESERVE_INPUT; - } - if (StringUtil::Equals(value, "ALLOW_DESTRUCTIVE")) { - return AggregateCombineType::ALLOW_DESTRUCTIVE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetAggregateCombineTypeValues(), 2, "AggregateCombineType", value)); +} + +const StringUtil::EnumStringLiteral *GetAggregateHandlingValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(AggregateHandling::STANDARD_HANDLING), "STANDARD_HANDLING" }, + { static_cast(AggregateHandling::NO_AGGREGATES_ALLOWED), "NO_AGGREGATES_ALLOWED" }, + { static_cast(AggregateHandling::FORCE_AGGREGATES), "FORCE_AGGREGATES" } + }; + return values; } template<> const char* EnumUtil::ToChars(AggregateHandling value) { - switch(value) { - case AggregateHandling::STANDARD_HANDLING: - return "STANDARD_HANDLING"; - case AggregateHandling::NO_AGGREGATES_ALLOWED: - return "NO_AGGREGATES_ALLOWED"; - case AggregateHandling::FORCE_AGGREGATES: - return "FORCE_AGGREGATES"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetAggregateHandlingValues(), 3, "AggregateHandling", static_cast(value)); } template<> AggregateHandling EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "STANDARD_HANDLING")) { - return AggregateHandling::STANDARD_HANDLING; - } - if (StringUtil::Equals(value, "NO_AGGREGATES_ALLOWED")) { - return AggregateHandling::NO_AGGREGATES_ALLOWED; - } - if (StringUtil::Equals(value, "FORCE_AGGREGATES")) { - return AggregateHandling::FORCE_AGGREGATES; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetAggregateHandlingValues(), 3, "AggregateHandling", value)); +} + +const StringUtil::EnumStringLiteral *GetAggregateOrderDependentValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(AggregateOrderDependent::ORDER_DEPENDENT), "ORDER_DEPENDENT" }, + { static_cast(AggregateOrderDependent::NOT_ORDER_DEPENDENT), "NOT_ORDER_DEPENDENT" } + }; + return values; } template<> const char* EnumUtil::ToChars(AggregateOrderDependent value) { - switch(value) { - case AggregateOrderDependent::ORDER_DEPENDENT: - return "ORDER_DEPENDENT"; - case AggregateOrderDependent::NOT_ORDER_DEPENDENT: - return "NOT_ORDER_DEPENDENT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetAggregateOrderDependentValues(), 2, "AggregateOrderDependent", static_cast(value)); } template<> AggregateOrderDependent EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "ORDER_DEPENDENT")) { - return AggregateOrderDependent::ORDER_DEPENDENT; - } - if (StringUtil::Equals(value, "NOT_ORDER_DEPENDENT")) { - return AggregateOrderDependent::NOT_ORDER_DEPENDENT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetAggregateOrderDependentValues(), 2, "AggregateOrderDependent", value)); +} + +const StringUtil::EnumStringLiteral *GetAggregateTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(AggregateType::NON_DISTINCT), "NON_DISTINCT" }, + { static_cast(AggregateType::DISTINCT), "DISTINCT" } + }; + return values; } template<> const char* EnumUtil::ToChars(AggregateType value) { - switch(value) { - case AggregateType::NON_DISTINCT: - return "NON_DISTINCT"; - case AggregateType::DISTINCT: - return "DISTINCT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetAggregateTypeValues(), 2, "AggregateType", static_cast(value)); } template<> AggregateType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NON_DISTINCT")) { - return AggregateType::NON_DISTINCT; - } - if (StringUtil::Equals(value, "DISTINCT")) { - return AggregateType::DISTINCT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetAggregateTypeValues(), 2, "AggregateType", value)); +} + +const StringUtil::EnumStringLiteral *GetAlterForeignKeyTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(AlterForeignKeyType::AFT_ADD), "AFT_ADD" }, + { static_cast(AlterForeignKeyType::AFT_DELETE), "AFT_DELETE" } + }; + return values; } template<> const char* EnumUtil::ToChars(AlterForeignKeyType value) { - switch(value) { - case AlterForeignKeyType::AFT_ADD: - return "AFT_ADD"; - case AlterForeignKeyType::AFT_DELETE: - return "AFT_DELETE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetAlterForeignKeyTypeValues(), 2, "AlterForeignKeyType", static_cast(value)); } template<> AlterForeignKeyType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "AFT_ADD")) { - return AlterForeignKeyType::AFT_ADD; - } - if (StringUtil::Equals(value, "AFT_DELETE")) { - return AlterForeignKeyType::AFT_DELETE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetAlterForeignKeyTypeValues(), 2, "AlterForeignKeyType", value)); +} + +const StringUtil::EnumStringLiteral *GetAlterScalarFunctionTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(AlterScalarFunctionType::INVALID), "INVALID" }, + { static_cast(AlterScalarFunctionType::ADD_FUNCTION_OVERLOADS), "ADD_FUNCTION_OVERLOADS" } + }; + return values; } template<> const char* EnumUtil::ToChars(AlterScalarFunctionType value) { - switch(value) { - case AlterScalarFunctionType::INVALID: - return "INVALID"; - case AlterScalarFunctionType::ADD_FUNCTION_OVERLOADS: - return "ADD_FUNCTION_OVERLOADS"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetAlterScalarFunctionTypeValues(), 2, "AlterScalarFunctionType", static_cast(value)); } template<> AlterScalarFunctionType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return AlterScalarFunctionType::INVALID; - } - if (StringUtil::Equals(value, "ADD_FUNCTION_OVERLOADS")) { - return AlterScalarFunctionType::ADD_FUNCTION_OVERLOADS; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetAlterScalarFunctionTypeValues(), 2, "AlterScalarFunctionType", value)); +} + +const StringUtil::EnumStringLiteral *GetAlterTableFunctionTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(AlterTableFunctionType::INVALID), "INVALID" }, + { static_cast(AlterTableFunctionType::ADD_FUNCTION_OVERLOADS), "ADD_FUNCTION_OVERLOADS" } + }; + return values; } template<> const char* EnumUtil::ToChars(AlterTableFunctionType value) { - switch(value) { - case AlterTableFunctionType::INVALID: - return "INVALID"; - case AlterTableFunctionType::ADD_FUNCTION_OVERLOADS: - return "ADD_FUNCTION_OVERLOADS"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetAlterTableFunctionTypeValues(), 2, "AlterTableFunctionType", static_cast(value)); } template<> AlterTableFunctionType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return AlterTableFunctionType::INVALID; - } - if (StringUtil::Equals(value, "ADD_FUNCTION_OVERLOADS")) { - return AlterTableFunctionType::ADD_FUNCTION_OVERLOADS; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetAlterTableFunctionTypeValues(), 2, "AlterTableFunctionType", value)); +} + +const StringUtil::EnumStringLiteral *GetAlterTableTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(AlterTableType::INVALID), "INVALID" }, + { static_cast(AlterTableType::RENAME_COLUMN), "RENAME_COLUMN" }, + { static_cast(AlterTableType::RENAME_TABLE), "RENAME_TABLE" }, + { static_cast(AlterTableType::ADD_COLUMN), "ADD_COLUMN" }, + { static_cast(AlterTableType::REMOVE_COLUMN), "REMOVE_COLUMN" }, + { static_cast(AlterTableType::ALTER_COLUMN_TYPE), "ALTER_COLUMN_TYPE" }, + { static_cast(AlterTableType::SET_DEFAULT), "SET_DEFAULT" }, + { static_cast(AlterTableType::FOREIGN_KEY_CONSTRAINT), "FOREIGN_KEY_CONSTRAINT" }, + { static_cast(AlterTableType::SET_NOT_NULL), "SET_NOT_NULL" }, + { static_cast(AlterTableType::DROP_NOT_NULL), "DROP_NOT_NULL" }, + { static_cast(AlterTableType::SET_COLUMN_COMMENT), "SET_COLUMN_COMMENT" }, + { static_cast(AlterTableType::ADD_CONSTRAINT), "ADD_CONSTRAINT" } + }; + return values; } template<> const char* EnumUtil::ToChars(AlterTableType value) { - switch(value) { - case AlterTableType::INVALID: - return "INVALID"; - case AlterTableType::RENAME_COLUMN: - return "RENAME_COLUMN"; - case AlterTableType::RENAME_TABLE: - return "RENAME_TABLE"; - case AlterTableType::ADD_COLUMN: - return "ADD_COLUMN"; - case AlterTableType::REMOVE_COLUMN: - return "REMOVE_COLUMN"; - case AlterTableType::ALTER_COLUMN_TYPE: - return "ALTER_COLUMN_TYPE"; - case AlterTableType::SET_DEFAULT: - return "SET_DEFAULT"; - case AlterTableType::FOREIGN_KEY_CONSTRAINT: - return "FOREIGN_KEY_CONSTRAINT"; - case AlterTableType::SET_NOT_NULL: - return "SET_NOT_NULL"; - case AlterTableType::DROP_NOT_NULL: - return "DROP_NOT_NULL"; - case AlterTableType::SET_COLUMN_COMMENT: - return "SET_COLUMN_COMMENT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetAlterTableTypeValues(), 12, "AlterTableType", static_cast(value)); } template<> AlterTableType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return AlterTableType::INVALID; - } - if (StringUtil::Equals(value, "RENAME_COLUMN")) { - return AlterTableType::RENAME_COLUMN; - } - if (StringUtil::Equals(value, "RENAME_TABLE")) { - return AlterTableType::RENAME_TABLE; - } - if (StringUtil::Equals(value, "ADD_COLUMN")) { - return AlterTableType::ADD_COLUMN; - } - if (StringUtil::Equals(value, "REMOVE_COLUMN")) { - return AlterTableType::REMOVE_COLUMN; - } - if (StringUtil::Equals(value, "ALTER_COLUMN_TYPE")) { - return AlterTableType::ALTER_COLUMN_TYPE; - } - if (StringUtil::Equals(value, "SET_DEFAULT")) { - return AlterTableType::SET_DEFAULT; - } - if (StringUtil::Equals(value, "FOREIGN_KEY_CONSTRAINT")) { - return AlterTableType::FOREIGN_KEY_CONSTRAINT; - } - if (StringUtil::Equals(value, "SET_NOT_NULL")) { - return AlterTableType::SET_NOT_NULL; - } - if (StringUtil::Equals(value, "DROP_NOT_NULL")) { - return AlterTableType::DROP_NOT_NULL; - } - if (StringUtil::Equals(value, "SET_COLUMN_COMMENT")) { - return AlterTableType::SET_COLUMN_COMMENT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetAlterTableTypeValues(), 12, "AlterTableType", value)); +} + +const StringUtil::EnumStringLiteral *GetAlterTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(AlterType::INVALID), "INVALID" }, + { static_cast(AlterType::ALTER_TABLE), "ALTER_TABLE" }, + { static_cast(AlterType::ALTER_VIEW), "ALTER_VIEW" }, + { static_cast(AlterType::ALTER_SEQUENCE), "ALTER_SEQUENCE" }, + { static_cast(AlterType::CHANGE_OWNERSHIP), "CHANGE_OWNERSHIP" }, + { static_cast(AlterType::ALTER_SCALAR_FUNCTION), "ALTER_SCALAR_FUNCTION" }, + { static_cast(AlterType::ALTER_TABLE_FUNCTION), "ALTER_TABLE_FUNCTION" }, + { static_cast(AlterType::SET_COMMENT), "SET_COMMENT" }, + { static_cast(AlterType::SET_COLUMN_COMMENT), "SET_COLUMN_COMMENT" } + }; + return values; } template<> const char* EnumUtil::ToChars(AlterType value) { - switch(value) { - case AlterType::INVALID: - return "INVALID"; - case AlterType::ALTER_TABLE: - return "ALTER_TABLE"; - case AlterType::ALTER_VIEW: - return "ALTER_VIEW"; - case AlterType::ALTER_SEQUENCE: - return "ALTER_SEQUENCE"; - case AlterType::CHANGE_OWNERSHIP: - return "CHANGE_OWNERSHIP"; - case AlterType::ALTER_SCALAR_FUNCTION: - return "ALTER_SCALAR_FUNCTION"; - case AlterType::ALTER_TABLE_FUNCTION: - return "ALTER_TABLE_FUNCTION"; - case AlterType::SET_COMMENT: - return "SET_COMMENT"; - case AlterType::SET_COLUMN_COMMENT: - return "SET_COLUMN_COMMENT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetAlterTypeValues(), 9, "AlterType", static_cast(value)); } template<> AlterType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return AlterType::INVALID; - } - if (StringUtil::Equals(value, "ALTER_TABLE")) { - return AlterType::ALTER_TABLE; - } - if (StringUtil::Equals(value, "ALTER_VIEW")) { - return AlterType::ALTER_VIEW; - } - if (StringUtil::Equals(value, "ALTER_SEQUENCE")) { - return AlterType::ALTER_SEQUENCE; - } - if (StringUtil::Equals(value, "CHANGE_OWNERSHIP")) { - return AlterType::CHANGE_OWNERSHIP; - } - if (StringUtil::Equals(value, "ALTER_SCALAR_FUNCTION")) { - return AlterType::ALTER_SCALAR_FUNCTION; - } - if (StringUtil::Equals(value, "ALTER_TABLE_FUNCTION")) { - return AlterType::ALTER_TABLE_FUNCTION; - } - if (StringUtil::Equals(value, "SET_COMMENT")) { - return AlterType::SET_COMMENT; - } - if (StringUtil::Equals(value, "SET_COLUMN_COMMENT")) { - return AlterType::SET_COLUMN_COMMENT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetAlterTypeValues(), 9, "AlterType", value)); +} + +const StringUtil::EnumStringLiteral *GetAlterViewTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(AlterViewType::INVALID), "INVALID" }, + { static_cast(AlterViewType::RENAME_VIEW), "RENAME_VIEW" } + }; + return values; } template<> const char* EnumUtil::ToChars(AlterViewType value) { - switch(value) { - case AlterViewType::INVALID: - return "INVALID"; - case AlterViewType::RENAME_VIEW: - return "RENAME_VIEW"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetAlterViewTypeValues(), 2, "AlterViewType", static_cast(value)); } template<> AlterViewType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return AlterViewType::INVALID; - } - if (StringUtil::Equals(value, "RENAME_VIEW")) { - return AlterViewType::RENAME_VIEW; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetAlterViewTypeValues(), 2, "AlterViewType", value)); +} + +const StringUtil::EnumStringLiteral *GetAppenderTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(AppenderType::LOGICAL), "LOGICAL" }, + { static_cast(AppenderType::PHYSICAL), "PHYSICAL" } + }; + return values; } template<> const char* EnumUtil::ToChars(AppenderType value) { - switch(value) { - case AppenderType::LOGICAL: - return "LOGICAL"; - case AppenderType::PHYSICAL: - return "PHYSICAL"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetAppenderTypeValues(), 2, "AppenderType", static_cast(value)); } template<> AppenderType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "LOGICAL")) { - return AppenderType::LOGICAL; - } - if (StringUtil::Equals(value, "PHYSICAL")) { - return AppenderType::PHYSICAL; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetAppenderTypeValues(), 2, "AppenderType", value)); +} + +const StringUtil::EnumStringLiteral *GetArrowDateTimeTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ArrowDateTimeType::MILLISECONDS), "MILLISECONDS" }, + { static_cast(ArrowDateTimeType::MICROSECONDS), "MICROSECONDS" }, + { static_cast(ArrowDateTimeType::NANOSECONDS), "NANOSECONDS" }, + { static_cast(ArrowDateTimeType::SECONDS), "SECONDS" }, + { static_cast(ArrowDateTimeType::DAYS), "DAYS" }, + { static_cast(ArrowDateTimeType::MONTHS), "MONTHS" }, + { static_cast(ArrowDateTimeType::MONTH_DAY_NANO), "MONTH_DAY_NANO" } + }; + return values; } template<> const char* EnumUtil::ToChars(ArrowDateTimeType value) { - switch(value) { - case ArrowDateTimeType::MILLISECONDS: - return "MILLISECONDS"; - case ArrowDateTimeType::MICROSECONDS: - return "MICROSECONDS"; - case ArrowDateTimeType::NANOSECONDS: - return "NANOSECONDS"; - case ArrowDateTimeType::SECONDS: - return "SECONDS"; - case ArrowDateTimeType::DAYS: - return "DAYS"; - case ArrowDateTimeType::MONTHS: - return "MONTHS"; - case ArrowDateTimeType::MONTH_DAY_NANO: - return "MONTH_DAY_NANO"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetArrowDateTimeTypeValues(), 7, "ArrowDateTimeType", static_cast(value)); } template<> ArrowDateTimeType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "MILLISECONDS")) { - return ArrowDateTimeType::MILLISECONDS; - } - if (StringUtil::Equals(value, "MICROSECONDS")) { - return ArrowDateTimeType::MICROSECONDS; - } - if (StringUtil::Equals(value, "NANOSECONDS")) { - return ArrowDateTimeType::NANOSECONDS; - } - if (StringUtil::Equals(value, "SECONDS")) { - return ArrowDateTimeType::SECONDS; - } - if (StringUtil::Equals(value, "DAYS")) { - return ArrowDateTimeType::DAYS; - } - if (StringUtil::Equals(value, "MONTHS")) { - return ArrowDateTimeType::MONTHS; - } - if (StringUtil::Equals(value, "MONTH_DAY_NANO")) { - return ArrowDateTimeType::MONTH_DAY_NANO; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetArrowDateTimeTypeValues(), 7, "ArrowDateTimeType", value)); +} + +const StringUtil::EnumStringLiteral *GetArrowOffsetSizeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ArrowOffsetSize::REGULAR), "REGULAR" }, + { static_cast(ArrowOffsetSize::LARGE), "LARGE" } + }; + return values; } template<> const char* EnumUtil::ToChars(ArrowOffsetSize value) { - switch(value) { - case ArrowOffsetSize::REGULAR: - return "REGULAR"; - case ArrowOffsetSize::LARGE: - return "LARGE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetArrowOffsetSizeValues(), 2, "ArrowOffsetSize", static_cast(value)); } template<> ArrowOffsetSize EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "REGULAR")) { - return ArrowOffsetSize::REGULAR; - } - if (StringUtil::Equals(value, "LARGE")) { - return ArrowOffsetSize::LARGE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetArrowOffsetSizeValues(), 2, "ArrowOffsetSize", value)); +} + +const StringUtil::EnumStringLiteral *GetArrowTypeInfoTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ArrowTypeInfoType::LIST), "LIST" }, + { static_cast(ArrowTypeInfoType::STRUCT), "STRUCT" }, + { static_cast(ArrowTypeInfoType::DATE_TIME), "DATE_TIME" }, + { static_cast(ArrowTypeInfoType::STRING), "STRING" }, + { static_cast(ArrowTypeInfoType::ARRAY), "ARRAY" } + }; + return values; } template<> const char* EnumUtil::ToChars(ArrowTypeInfoType value) { - switch(value) { - case ArrowTypeInfoType::LIST: - return "LIST"; - case ArrowTypeInfoType::STRUCT: - return "STRUCT"; - case ArrowTypeInfoType::DATE_TIME: - return "DATE_TIME"; - case ArrowTypeInfoType::STRING: - return "STRING"; - case ArrowTypeInfoType::ARRAY: - return "ARRAY"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetArrowTypeInfoTypeValues(), 5, "ArrowTypeInfoType", static_cast(value)); } template<> ArrowTypeInfoType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "LIST")) { - return ArrowTypeInfoType::LIST; - } - if (StringUtil::Equals(value, "STRUCT")) { - return ArrowTypeInfoType::STRUCT; - } - if (StringUtil::Equals(value, "DATE_TIME")) { - return ArrowTypeInfoType::DATE_TIME; - } - if (StringUtil::Equals(value, "STRING")) { - return ArrowTypeInfoType::STRING; - } - if (StringUtil::Equals(value, "ARRAY")) { - return ArrowTypeInfoType::ARRAY; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetArrowTypeInfoTypeValues(), 5, "ArrowTypeInfoType", value)); +} + +const StringUtil::EnumStringLiteral *GetArrowVariableSizeTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ArrowVariableSizeType::NORMAL), "NORMAL" }, + { static_cast(ArrowVariableSizeType::FIXED_SIZE), "FIXED_SIZE" }, + { static_cast(ArrowVariableSizeType::SUPER_SIZE), "SUPER_SIZE" }, + { static_cast(ArrowVariableSizeType::VIEW), "VIEW" } + }; + return values; } template<> const char* EnumUtil::ToChars(ArrowVariableSizeType value) { - switch(value) { - case ArrowVariableSizeType::NORMAL: - return "NORMAL"; - case ArrowVariableSizeType::FIXED_SIZE: - return "FIXED_SIZE"; - case ArrowVariableSizeType::SUPER_SIZE: - return "SUPER_SIZE"; - case ArrowVariableSizeType::VIEW: - return "VIEW"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetArrowVariableSizeTypeValues(), 4, "ArrowVariableSizeType", static_cast(value)); } template<> ArrowVariableSizeType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NORMAL")) { - return ArrowVariableSizeType::NORMAL; - } - if (StringUtil::Equals(value, "FIXED_SIZE")) { - return ArrowVariableSizeType::FIXED_SIZE; - } - if (StringUtil::Equals(value, "SUPER_SIZE")) { - return ArrowVariableSizeType::SUPER_SIZE; - } - if (StringUtil::Equals(value, "VIEW")) { - return ArrowVariableSizeType::VIEW; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetArrowVariableSizeTypeValues(), 4, "ArrowVariableSizeType", value)); +} + +const StringUtil::EnumStringLiteral *GetBinderTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(BinderType::REGULAR_BINDER), "REGULAR_BINDER" }, + { static_cast(BinderType::VIEW_BINDER), "VIEW_BINDER" } + }; + return values; } template<> const char* EnumUtil::ToChars(BinderType value) { - switch(value) { - case BinderType::REGULAR_BINDER: - return "REGULAR_BINDER"; - case BinderType::VIEW_BINDER: - return "VIEW_BINDER"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetBinderTypeValues(), 2, "BinderType", static_cast(value)); } template<> BinderType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "REGULAR_BINDER")) { - return BinderType::REGULAR_BINDER; - } - if (StringUtil::Equals(value, "VIEW_BINDER")) { - return BinderType::VIEW_BINDER; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetBinderTypeValues(), 2, "BinderType", value)); +} + +const StringUtil::EnumStringLiteral *GetBindingModeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(BindingMode::STANDARD_BINDING), "STANDARD_BINDING" }, + { static_cast(BindingMode::EXTRACT_NAMES), "EXTRACT_NAMES" }, + { static_cast(BindingMode::EXTRACT_REPLACEMENT_SCANS), "EXTRACT_REPLACEMENT_SCANS" } + }; + return values; } template<> const char* EnumUtil::ToChars(BindingMode value) { - switch(value) { - case BindingMode::STANDARD_BINDING: - return "STANDARD_BINDING"; - case BindingMode::EXTRACT_NAMES: - return "EXTRACT_NAMES"; - case BindingMode::EXTRACT_REPLACEMENT_SCANS: - return "EXTRACT_REPLACEMENT_SCANS"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetBindingModeValues(), 3, "BindingMode", static_cast(value)); } template<> BindingMode EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "STANDARD_BINDING")) { - return BindingMode::STANDARD_BINDING; - } - if (StringUtil::Equals(value, "EXTRACT_NAMES")) { - return BindingMode::EXTRACT_NAMES; - } - if (StringUtil::Equals(value, "EXTRACT_REPLACEMENT_SCANS")) { - return BindingMode::EXTRACT_REPLACEMENT_SCANS; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetBindingModeValues(), 3, "BindingMode", value)); +} + +const StringUtil::EnumStringLiteral *GetBitpackingModeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(BitpackingMode::INVALID), "INVALID" }, + { static_cast(BitpackingMode::AUTO), "AUTO" }, + { static_cast(BitpackingMode::CONSTANT), "CONSTANT" }, + { static_cast(BitpackingMode::CONSTANT_DELTA), "CONSTANT_DELTA" }, + { static_cast(BitpackingMode::DELTA_FOR), "DELTA_FOR" }, + { static_cast(BitpackingMode::FOR), "FOR" } + }; + return values; } template<> const char* EnumUtil::ToChars(BitpackingMode value) { - switch(value) { - case BitpackingMode::INVALID: - return "INVALID"; - 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(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetBitpackingModeValues(), 6, "BitpackingMode", static_cast(value)); } template<> BitpackingMode EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return BitpackingMode::INVALID; - } - if (StringUtil::Equals(value, "AUTO")) { - return BitpackingMode::AUTO; - } - if (StringUtil::Equals(value, "CONSTANT")) { - return BitpackingMode::CONSTANT; - } - if (StringUtil::Equals(value, "CONSTANT_DELTA")) { - return BitpackingMode::CONSTANT_DELTA; - } - if (StringUtil::Equals(value, "DELTA_FOR")) { - return BitpackingMode::DELTA_FOR; - } - if (StringUtil::Equals(value, "FOR")) { - return BitpackingMode::FOR; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetBitpackingModeValues(), 6, "BitpackingMode", value)); +} + +const StringUtil::EnumStringLiteral *GetBlockStateValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(BlockState::BLOCK_UNLOADED), "BLOCK_UNLOADED" }, + { static_cast(BlockState::BLOCK_LOADED), "BLOCK_LOADED" } + }; + return values; } template<> const char* EnumUtil::ToChars(BlockState value) { - switch(value) { - case BlockState::BLOCK_UNLOADED: - return "BLOCK_UNLOADED"; - case BlockState::BLOCK_LOADED: - return "BLOCK_LOADED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetBlockStateValues(), 2, "BlockState", static_cast(value)); } template<> BlockState EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "BLOCK_UNLOADED")) { - return BlockState::BLOCK_UNLOADED; - } - if (StringUtil::Equals(value, "BLOCK_LOADED")) { - return BlockState::BLOCK_LOADED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetBlockStateValues(), 2, "BlockState", value)); +} + +const StringUtil::EnumStringLiteral *GetCAPIResultSetTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(CAPIResultSetType::CAPI_RESULT_TYPE_NONE), "CAPI_RESULT_TYPE_NONE" }, + { static_cast(CAPIResultSetType::CAPI_RESULT_TYPE_MATERIALIZED), "CAPI_RESULT_TYPE_MATERIALIZED" }, + { static_cast(CAPIResultSetType::CAPI_RESULT_TYPE_STREAMING), "CAPI_RESULT_TYPE_STREAMING" }, + { static_cast(CAPIResultSetType::CAPI_RESULT_TYPE_DEPRECATED), "CAPI_RESULT_TYPE_DEPRECATED" } + }; + return values; } template<> const char* EnumUtil::ToChars(CAPIResultSetType value) { - switch(value) { - case CAPIResultSetType::CAPI_RESULT_TYPE_NONE: - return "CAPI_RESULT_TYPE_NONE"; - case CAPIResultSetType::CAPI_RESULT_TYPE_MATERIALIZED: - return "CAPI_RESULT_TYPE_MATERIALIZED"; - case CAPIResultSetType::CAPI_RESULT_TYPE_STREAMING: - return "CAPI_RESULT_TYPE_STREAMING"; - case CAPIResultSetType::CAPI_RESULT_TYPE_DEPRECATED: - return "CAPI_RESULT_TYPE_DEPRECATED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetCAPIResultSetTypeValues(), 4, "CAPIResultSetType", static_cast(value)); } template<> CAPIResultSetType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "CAPI_RESULT_TYPE_NONE")) { - return CAPIResultSetType::CAPI_RESULT_TYPE_NONE; - } - if (StringUtil::Equals(value, "CAPI_RESULT_TYPE_MATERIALIZED")) { - return CAPIResultSetType::CAPI_RESULT_TYPE_MATERIALIZED; - } - if (StringUtil::Equals(value, "CAPI_RESULT_TYPE_STREAMING")) { - return CAPIResultSetType::CAPI_RESULT_TYPE_STREAMING; - } - if (StringUtil::Equals(value, "CAPI_RESULT_TYPE_DEPRECATED")) { - return CAPIResultSetType::CAPI_RESULT_TYPE_DEPRECATED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetCAPIResultSetTypeValues(), 4, "CAPIResultSetType", value)); +} + +const StringUtil::EnumStringLiteral *GetCSVStateValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(CSVState::STANDARD), "STANDARD" }, + { static_cast(CSVState::DELIMITER), "DELIMITER" }, + { static_cast(CSVState::RECORD_SEPARATOR), "RECORD_SEPARATOR" }, + { static_cast(CSVState::CARRIAGE_RETURN), "CARRIAGE_RETURN" }, + { static_cast(CSVState::QUOTED), "QUOTED" }, + { static_cast(CSVState::UNQUOTED), "UNQUOTED" }, + { static_cast(CSVState::ESCAPE), "ESCAPE" }, + { static_cast(CSVState::INVALID), "INVALID" }, + { static_cast(CSVState::NOT_SET), "NOT_SET" }, + { static_cast(CSVState::QUOTED_NEW_LINE), "QUOTED_NEW_LINE" }, + { static_cast(CSVState::EMPTY_SPACE), "EMPTY_SPACE" }, + { static_cast(CSVState::COMMENT), "COMMENT" }, + { static_cast(CSVState::STANDARD_NEWLINE), "STANDARD_NEWLINE" } + }; + return values; } template<> const char* EnumUtil::ToChars(CSVState value) { - switch(value) { - case CSVState::STANDARD: - return "STANDARD"; - case CSVState::DELIMITER: - return "DELIMITER"; - case CSVState::RECORD_SEPARATOR: - return "RECORD_SEPARATOR"; - case CSVState::CARRIAGE_RETURN: - return "CARRIAGE_RETURN"; - case CSVState::QUOTED: - return "QUOTED"; - case CSVState::UNQUOTED: - return "UNQUOTED"; - case CSVState::ESCAPE: - return "ESCAPE"; - case CSVState::INVALID: - return "INVALID"; - case CSVState::NOT_SET: - return "NOT_SET"; - case CSVState::QUOTED_NEW_LINE: - return "QUOTED_NEW_LINE"; - case CSVState::EMPTY_SPACE: - return "EMPTY_SPACE"; - case CSVState::COMMENT: - return "COMMENT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetCSVStateValues(), 13, "CSVState", static_cast(value)); } template<> CSVState EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "STANDARD")) { - return CSVState::STANDARD; - } - if (StringUtil::Equals(value, "DELIMITER")) { - return CSVState::DELIMITER; - } - if (StringUtil::Equals(value, "RECORD_SEPARATOR")) { - return CSVState::RECORD_SEPARATOR; - } - if (StringUtil::Equals(value, "CARRIAGE_RETURN")) { - return CSVState::CARRIAGE_RETURN; - } - if (StringUtil::Equals(value, "QUOTED")) { - return CSVState::QUOTED; - } - if (StringUtil::Equals(value, "UNQUOTED")) { - return CSVState::UNQUOTED; - } - if (StringUtil::Equals(value, "ESCAPE")) { - return CSVState::ESCAPE; - } - if (StringUtil::Equals(value, "INVALID")) { - return CSVState::INVALID; - } - if (StringUtil::Equals(value, "NOT_SET")) { - return CSVState::NOT_SET; - } - if (StringUtil::Equals(value, "QUOTED_NEW_LINE")) { - return CSVState::QUOTED_NEW_LINE; - } - if (StringUtil::Equals(value, "EMPTY_SPACE")) { - return CSVState::EMPTY_SPACE; - } - if (StringUtil::Equals(value, "COMMENT")) { - return CSVState::COMMENT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetCSVStateValues(), 13, "CSVState", value)); +} + +const StringUtil::EnumStringLiteral *GetCTEMaterializeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(CTEMaterialize::CTE_MATERIALIZE_DEFAULT), "CTE_MATERIALIZE_DEFAULT" }, + { static_cast(CTEMaterialize::CTE_MATERIALIZE_ALWAYS), "CTE_MATERIALIZE_ALWAYS" }, + { static_cast(CTEMaterialize::CTE_MATERIALIZE_NEVER), "CTE_MATERIALIZE_NEVER" } + }; + return values; } template<> const char* EnumUtil::ToChars(CTEMaterialize value) { - switch(value) { - case CTEMaterialize::CTE_MATERIALIZE_DEFAULT: - return "CTE_MATERIALIZE_DEFAULT"; - case CTEMaterialize::CTE_MATERIALIZE_ALWAYS: - return "CTE_MATERIALIZE_ALWAYS"; - case CTEMaterialize::CTE_MATERIALIZE_NEVER: - return "CTE_MATERIALIZE_NEVER"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetCTEMaterializeValues(), 3, "CTEMaterialize", static_cast(value)); } template<> CTEMaterialize EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "CTE_MATERIALIZE_DEFAULT")) { - return CTEMaterialize::CTE_MATERIALIZE_DEFAULT; - } - if (StringUtil::Equals(value, "CTE_MATERIALIZE_ALWAYS")) { - return CTEMaterialize::CTE_MATERIALIZE_ALWAYS; - } - if (StringUtil::Equals(value, "CTE_MATERIALIZE_NEVER")) { - return CTEMaterialize::CTE_MATERIALIZE_NEVER; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetCTEMaterializeValues(), 3, "CTEMaterialize", value)); +} + +const StringUtil::EnumStringLiteral *GetCatalogLookupBehaviorValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(CatalogLookupBehavior::STANDARD), "STANDARD" }, + { static_cast(CatalogLookupBehavior::LOWER_PRIORITY), "LOWER_PRIORITY" }, + { static_cast(CatalogLookupBehavior::NEVER_LOOKUP), "NEVER_LOOKUP" } + }; + return values; } template<> const char* EnumUtil::ToChars(CatalogLookupBehavior value) { - switch(value) { - case CatalogLookupBehavior::STANDARD: - return "STANDARD"; - case CatalogLookupBehavior::LOWER_PRIORITY: - return "LOWER_PRIORITY"; - case CatalogLookupBehavior::NEVER_LOOKUP: - return "NEVER_LOOKUP"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetCatalogLookupBehaviorValues(), 3, "CatalogLookupBehavior", static_cast(value)); } template<> CatalogLookupBehavior EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "STANDARD")) { - return CatalogLookupBehavior::STANDARD; - } - if (StringUtil::Equals(value, "LOWER_PRIORITY")) { - return CatalogLookupBehavior::LOWER_PRIORITY; - } - if (StringUtil::Equals(value, "NEVER_LOOKUP")) { - return CatalogLookupBehavior::NEVER_LOOKUP; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetCatalogLookupBehaviorValues(), 3, "CatalogLookupBehavior", value)); +} + +const StringUtil::EnumStringLiteral *GetCatalogTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(CatalogType::INVALID), "INVALID" }, + { static_cast(CatalogType::TABLE_ENTRY), "TABLE_ENTRY" }, + { static_cast(CatalogType::SCHEMA_ENTRY), "SCHEMA_ENTRY" }, + { static_cast(CatalogType::VIEW_ENTRY), "VIEW_ENTRY" }, + { static_cast(CatalogType::INDEX_ENTRY), "INDEX_ENTRY" }, + { static_cast(CatalogType::PREPARED_STATEMENT), "PREPARED_STATEMENT" }, + { static_cast(CatalogType::SEQUENCE_ENTRY), "SEQUENCE_ENTRY" }, + { static_cast(CatalogType::COLLATION_ENTRY), "COLLATION_ENTRY" }, + { static_cast(CatalogType::TYPE_ENTRY), "TYPE_ENTRY" }, + { static_cast(CatalogType::DATABASE_ENTRY), "DATABASE_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" }, + { static_cast(CatalogType::PRAGMA_FUNCTION_ENTRY), "PRAGMA_FUNCTION_ENTRY" }, + { static_cast(CatalogType::COPY_FUNCTION_ENTRY), "COPY_FUNCTION_ENTRY" }, + { static_cast(CatalogType::MACRO_ENTRY), "MACRO_ENTRY" }, + { static_cast(CatalogType::TABLE_MACRO_ENTRY), "TABLE_MACRO_ENTRY" }, + { static_cast(CatalogType::DELETED_ENTRY), "DELETED_ENTRY" }, + { static_cast(CatalogType::RENAMED_ENTRY), "RENAMED_ENTRY" }, + { static_cast(CatalogType::SECRET_ENTRY), "SECRET_ENTRY" }, + { static_cast(CatalogType::SECRET_TYPE_ENTRY), "SECRET_TYPE_ENTRY" }, + { static_cast(CatalogType::SECRET_FUNCTION_ENTRY), "SECRET_FUNCTION_ENTRY" }, + { static_cast(CatalogType::DEPENDENCY_ENTRY), "DEPENDENCY_ENTRY" } + }; + return values; } template<> const char* EnumUtil::ToChars(CatalogType value) { - switch(value) { - case CatalogType::INVALID: - return "INVALID"; - case CatalogType::TABLE_ENTRY: - return "TABLE_ENTRY"; - case CatalogType::SCHEMA_ENTRY: - return "SCHEMA_ENTRY"; - case CatalogType::VIEW_ENTRY: - return "VIEW_ENTRY"; - case CatalogType::INDEX_ENTRY: - return "INDEX_ENTRY"; - case CatalogType::PREPARED_STATEMENT: - return "PREPARED_STATEMENT"; - case CatalogType::SEQUENCE_ENTRY: - return "SEQUENCE_ENTRY"; - case CatalogType::COLLATION_ENTRY: - return "COLLATION_ENTRY"; - case CatalogType::TYPE_ENTRY: - return "TYPE_ENTRY"; - case CatalogType::DATABASE_ENTRY: - return "DATABASE_ENTRY"; - case CatalogType::TABLE_FUNCTION_ENTRY: - return "TABLE_FUNCTION_ENTRY"; - case CatalogType::SCALAR_FUNCTION_ENTRY: - return "SCALAR_FUNCTION_ENTRY"; - case CatalogType::AGGREGATE_FUNCTION_ENTRY: - return "AGGREGATE_FUNCTION_ENTRY"; - case CatalogType::PRAGMA_FUNCTION_ENTRY: - return "PRAGMA_FUNCTION_ENTRY"; - case CatalogType::COPY_FUNCTION_ENTRY: - return "COPY_FUNCTION_ENTRY"; - case CatalogType::MACRO_ENTRY: - return "MACRO_ENTRY"; - case CatalogType::TABLE_MACRO_ENTRY: - return "TABLE_MACRO_ENTRY"; - case CatalogType::DELETED_ENTRY: - return "DELETED_ENTRY"; - case CatalogType::RENAMED_ENTRY: - return "RENAMED_ENTRY"; - case CatalogType::SECRET_ENTRY: - return "SECRET_ENTRY"; - case CatalogType::SECRET_TYPE_ENTRY: - return "SECRET_TYPE_ENTRY"; - case CatalogType::SECRET_FUNCTION_ENTRY: - return "SECRET_FUNCTION_ENTRY"; - case CatalogType::DEPENDENCY_ENTRY: - return "DEPENDENCY_ENTRY"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetCatalogTypeValues(), 23, "CatalogType", static_cast(value)); } template<> CatalogType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return CatalogType::INVALID; - } - if (StringUtil::Equals(value, "TABLE_ENTRY")) { - return CatalogType::TABLE_ENTRY; - } - if (StringUtil::Equals(value, "SCHEMA_ENTRY")) { - return CatalogType::SCHEMA_ENTRY; - } - if (StringUtil::Equals(value, "VIEW_ENTRY")) { - return CatalogType::VIEW_ENTRY; - } - if (StringUtil::Equals(value, "INDEX_ENTRY")) { - return CatalogType::INDEX_ENTRY; - } - if (StringUtil::Equals(value, "PREPARED_STATEMENT")) { - return CatalogType::PREPARED_STATEMENT; - } - if (StringUtil::Equals(value, "SEQUENCE_ENTRY")) { - return CatalogType::SEQUENCE_ENTRY; - } - if (StringUtil::Equals(value, "COLLATION_ENTRY")) { - return CatalogType::COLLATION_ENTRY; - } - if (StringUtil::Equals(value, "TYPE_ENTRY")) { - return CatalogType::TYPE_ENTRY; - } - if (StringUtil::Equals(value, "DATABASE_ENTRY")) { - return CatalogType::DATABASE_ENTRY; - } - if (StringUtil::Equals(value, "TABLE_FUNCTION_ENTRY")) { - return CatalogType::TABLE_FUNCTION_ENTRY; - } - if (StringUtil::Equals(value, "SCALAR_FUNCTION_ENTRY")) { - return CatalogType::SCALAR_FUNCTION_ENTRY; - } - if (StringUtil::Equals(value, "AGGREGATE_FUNCTION_ENTRY")) { - return CatalogType::AGGREGATE_FUNCTION_ENTRY; - } - if (StringUtil::Equals(value, "PRAGMA_FUNCTION_ENTRY")) { - return CatalogType::PRAGMA_FUNCTION_ENTRY; - } - if (StringUtil::Equals(value, "COPY_FUNCTION_ENTRY")) { - return CatalogType::COPY_FUNCTION_ENTRY; - } - if (StringUtil::Equals(value, "MACRO_ENTRY")) { - return CatalogType::MACRO_ENTRY; - } - if (StringUtil::Equals(value, "TABLE_MACRO_ENTRY")) { - return CatalogType::TABLE_MACRO_ENTRY; - } - if (StringUtil::Equals(value, "DELETED_ENTRY")) { - return CatalogType::DELETED_ENTRY; - } - if (StringUtil::Equals(value, "RENAMED_ENTRY")) { - return CatalogType::RENAMED_ENTRY; - } - if (StringUtil::Equals(value, "SECRET_ENTRY")) { - return CatalogType::SECRET_ENTRY; - } - if (StringUtil::Equals(value, "SECRET_TYPE_ENTRY")) { - return CatalogType::SECRET_TYPE_ENTRY; - } - if (StringUtil::Equals(value, "SECRET_FUNCTION_ENTRY")) { - return CatalogType::SECRET_FUNCTION_ENTRY; - } - if (StringUtil::Equals(value, "DEPENDENCY_ENTRY")) { - return CatalogType::DEPENDENCY_ENTRY; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetCatalogTypeValues(), 23, "CatalogType", value)); +} + +const StringUtil::EnumStringLiteral *GetCheckpointAbortValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(CheckpointAbort::NO_ABORT), "NONE" }, + { static_cast(CheckpointAbort::DEBUG_ABORT_BEFORE_TRUNCATE), "BEFORE_TRUNCATE" }, + { static_cast(CheckpointAbort::DEBUG_ABORT_BEFORE_HEADER), "BEFORE_HEADER" }, + { static_cast(CheckpointAbort::DEBUG_ABORT_AFTER_FREE_LIST_WRITE), "AFTER_FREE_LIST_WRITE" } + }; + return values; } template<> const char* EnumUtil::ToChars(CheckpointAbort value) { - switch(value) { - case CheckpointAbort::NO_ABORT: - return "NO_ABORT"; - case CheckpointAbort::DEBUG_ABORT_BEFORE_TRUNCATE: - return "DEBUG_ABORT_BEFORE_TRUNCATE"; - case CheckpointAbort::DEBUG_ABORT_BEFORE_HEADER: - return "DEBUG_ABORT_BEFORE_HEADER"; - case CheckpointAbort::DEBUG_ABORT_AFTER_FREE_LIST_WRITE: - return "DEBUG_ABORT_AFTER_FREE_LIST_WRITE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetCheckpointAbortValues(), 4, "CheckpointAbort", static_cast(value)); } template<> CheckpointAbort EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NO_ABORT")) { - return CheckpointAbort::NO_ABORT; - } - if (StringUtil::Equals(value, "DEBUG_ABORT_BEFORE_TRUNCATE")) { - return CheckpointAbort::DEBUG_ABORT_BEFORE_TRUNCATE; - } - if (StringUtil::Equals(value, "DEBUG_ABORT_BEFORE_HEADER")) { - return CheckpointAbort::DEBUG_ABORT_BEFORE_HEADER; - } - if (StringUtil::Equals(value, "DEBUG_ABORT_AFTER_FREE_LIST_WRITE")) { - return CheckpointAbort::DEBUG_ABORT_AFTER_FREE_LIST_WRITE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetCheckpointAbortValues(), 4, "CheckpointAbort", value)); +} + +const StringUtil::EnumStringLiteral *GetChunkInfoTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ChunkInfoType::CONSTANT_INFO), "CONSTANT_INFO" }, + { static_cast(ChunkInfoType::VECTOR_INFO), "VECTOR_INFO" }, + { static_cast(ChunkInfoType::EMPTY_INFO), "EMPTY_INFO" } + }; + return values; } template<> const char* EnumUtil::ToChars(ChunkInfoType value) { - switch(value) { - case ChunkInfoType::CONSTANT_INFO: - return "CONSTANT_INFO"; - case ChunkInfoType::VECTOR_INFO: - return "VECTOR_INFO"; - case ChunkInfoType::EMPTY_INFO: - return "EMPTY_INFO"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetChunkInfoTypeValues(), 3, "ChunkInfoType", static_cast(value)); } template<> ChunkInfoType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "CONSTANT_INFO")) { - return ChunkInfoType::CONSTANT_INFO; - } - if (StringUtil::Equals(value, "VECTOR_INFO")) { - return ChunkInfoType::VECTOR_INFO; - } - if (StringUtil::Equals(value, "EMPTY_INFO")) { - return ChunkInfoType::EMPTY_INFO; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetChunkInfoTypeValues(), 3, "ChunkInfoType", value)); +} + +const StringUtil::EnumStringLiteral *GetColumnDataAllocatorTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ColumnDataAllocatorType::BUFFER_MANAGER_ALLOCATOR), "BUFFER_MANAGER_ALLOCATOR" }, + { static_cast(ColumnDataAllocatorType::IN_MEMORY_ALLOCATOR), "IN_MEMORY_ALLOCATOR" }, + { static_cast(ColumnDataAllocatorType::HYBRID), "HYBRID" } + }; + return values; } template<> const char* EnumUtil::ToChars(ColumnDataAllocatorType value) { - switch(value) { - case ColumnDataAllocatorType::BUFFER_MANAGER_ALLOCATOR: - return "BUFFER_MANAGER_ALLOCATOR"; - case ColumnDataAllocatorType::IN_MEMORY_ALLOCATOR: - return "IN_MEMORY_ALLOCATOR"; - case ColumnDataAllocatorType::HYBRID: - return "HYBRID"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetColumnDataAllocatorTypeValues(), 3, "ColumnDataAllocatorType", static_cast(value)); } template<> ColumnDataAllocatorType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "BUFFER_MANAGER_ALLOCATOR")) { - return ColumnDataAllocatorType::BUFFER_MANAGER_ALLOCATOR; - } - if (StringUtil::Equals(value, "IN_MEMORY_ALLOCATOR")) { - return ColumnDataAllocatorType::IN_MEMORY_ALLOCATOR; - } - if (StringUtil::Equals(value, "HYBRID")) { - return ColumnDataAllocatorType::HYBRID; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetColumnDataAllocatorTypeValues(), 3, "ColumnDataAllocatorType", value)); +} + +const StringUtil::EnumStringLiteral *GetColumnDataScanPropertiesValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ColumnDataScanProperties::INVALID), "INVALID" }, + { static_cast(ColumnDataScanProperties::ALLOW_ZERO_COPY), "ALLOW_ZERO_COPY" }, + { static_cast(ColumnDataScanProperties::DISALLOW_ZERO_COPY), "DISALLOW_ZERO_COPY" } + }; + return values; } template<> const char* EnumUtil::ToChars(ColumnDataScanProperties value) { - switch(value) { - case ColumnDataScanProperties::INVALID: - return "INVALID"; - case ColumnDataScanProperties::ALLOW_ZERO_COPY: - return "ALLOW_ZERO_COPY"; - case ColumnDataScanProperties::DISALLOW_ZERO_COPY: - return "DISALLOW_ZERO_COPY"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetColumnDataScanPropertiesValues(), 3, "ColumnDataScanProperties", static_cast(value)); } template<> ColumnDataScanProperties EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return ColumnDataScanProperties::INVALID; - } - if (StringUtil::Equals(value, "ALLOW_ZERO_COPY")) { - return ColumnDataScanProperties::ALLOW_ZERO_COPY; - } - if (StringUtil::Equals(value, "DISALLOW_ZERO_COPY")) { - return ColumnDataScanProperties::DISALLOW_ZERO_COPY; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetColumnDataScanPropertiesValues(), 3, "ColumnDataScanProperties", value)); +} + +const StringUtil::EnumStringLiteral *GetColumnSegmentTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ColumnSegmentType::TRANSIENT), "TRANSIENT" }, + { static_cast(ColumnSegmentType::PERSISTENT), "PERSISTENT" } + }; + return values; } template<> const char* EnumUtil::ToChars(ColumnSegmentType value) { - switch(value) { - case ColumnSegmentType::TRANSIENT: - return "TRANSIENT"; - case ColumnSegmentType::PERSISTENT: - return "PERSISTENT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetColumnSegmentTypeValues(), 2, "ColumnSegmentType", static_cast(value)); } template<> ColumnSegmentType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "TRANSIENT")) { - return ColumnSegmentType::TRANSIENT; - } - if (StringUtil::Equals(value, "PERSISTENT")) { - return ColumnSegmentType::PERSISTENT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetColumnSegmentTypeValues(), 2, "ColumnSegmentType", value)); +} + +const StringUtil::EnumStringLiteral *GetCompressedMaterializationDirectionValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(CompressedMaterializationDirection::INVALID), "INVALID" }, + { static_cast(CompressedMaterializationDirection::COMPRESS), "COMPRESS" }, + { static_cast(CompressedMaterializationDirection::DECOMPRESS), "DECOMPRESS" } + }; + return values; } template<> const char* EnumUtil::ToChars(CompressedMaterializationDirection value) { - switch(value) { - case CompressedMaterializationDirection::INVALID: - return "INVALID"; - case CompressedMaterializationDirection::COMPRESS: - return "COMPRESS"; - case CompressedMaterializationDirection::DECOMPRESS: - return "DECOMPRESS"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetCompressedMaterializationDirectionValues(), 3, "CompressedMaterializationDirection", static_cast(value)); } template<> CompressedMaterializationDirection EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return CompressedMaterializationDirection::INVALID; - } - if (StringUtil::Equals(value, "COMPRESS")) { - return CompressedMaterializationDirection::COMPRESS; - } - if (StringUtil::Equals(value, "DECOMPRESS")) { - return CompressedMaterializationDirection::DECOMPRESS; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetCompressedMaterializationDirectionValues(), 3, "CompressedMaterializationDirection", value)); +} + +const StringUtil::EnumStringLiteral *GetCompressionTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(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_COUNT), "COMPRESSION_COUNT" } + }; + return values; } template<> const char* EnumUtil::ToChars(CompressionType value) { - switch(value) { - case CompressionType::COMPRESSION_AUTO: - return "COMPRESSION_AUTO"; - case CompressionType::COMPRESSION_UNCOMPRESSED: - return "COMPRESSION_UNCOMPRESSED"; - case CompressionType::COMPRESSION_CONSTANT: - return "COMPRESSION_CONSTANT"; - case CompressionType::COMPRESSION_RLE: - return "COMPRESSION_RLE"; - case CompressionType::COMPRESSION_DICTIONARY: - return "COMPRESSION_DICTIONARY"; - case CompressionType::COMPRESSION_PFOR_DELTA: - return "COMPRESSION_PFOR_DELTA"; - case CompressionType::COMPRESSION_BITPACKING: - return "COMPRESSION_BITPACKING"; - case CompressionType::COMPRESSION_FSST: - return "COMPRESSION_FSST"; - case CompressionType::COMPRESSION_CHIMP: - return "COMPRESSION_CHIMP"; - case CompressionType::COMPRESSION_PATAS: - return "COMPRESSION_PATAS"; - case CompressionType::COMPRESSION_ALP: - return "COMPRESSION_ALP"; - case CompressionType::COMPRESSION_ALPRD: - return "COMPRESSION_ALPRD"; - case CompressionType::COMPRESSION_COUNT: - return "COMPRESSION_COUNT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetCompressionTypeValues(), 13, "CompressionType", static_cast(value)); } template<> CompressionType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "COMPRESSION_AUTO")) { - return CompressionType::COMPRESSION_AUTO; - } - if (StringUtil::Equals(value, "COMPRESSION_UNCOMPRESSED")) { - return CompressionType::COMPRESSION_UNCOMPRESSED; - } - if (StringUtil::Equals(value, "COMPRESSION_CONSTANT")) { - return CompressionType::COMPRESSION_CONSTANT; - } - if (StringUtil::Equals(value, "COMPRESSION_RLE")) { - return CompressionType::COMPRESSION_RLE; - } - if (StringUtil::Equals(value, "COMPRESSION_DICTIONARY")) { - return CompressionType::COMPRESSION_DICTIONARY; - } - if (StringUtil::Equals(value, "COMPRESSION_PFOR_DELTA")) { - return CompressionType::COMPRESSION_PFOR_DELTA; - } - if (StringUtil::Equals(value, "COMPRESSION_BITPACKING")) { - return CompressionType::COMPRESSION_BITPACKING; - } - if (StringUtil::Equals(value, "COMPRESSION_FSST")) { - return CompressionType::COMPRESSION_FSST; - } - if (StringUtil::Equals(value, "COMPRESSION_CHIMP")) { - return CompressionType::COMPRESSION_CHIMP; - } - if (StringUtil::Equals(value, "COMPRESSION_PATAS")) { - return CompressionType::COMPRESSION_PATAS; - } - if (StringUtil::Equals(value, "COMPRESSION_ALP")) { - return CompressionType::COMPRESSION_ALP; - } - if (StringUtil::Equals(value, "COMPRESSION_ALPRD")) { - return CompressionType::COMPRESSION_ALPRD; - } - if (StringUtil::Equals(value, "COMPRESSION_COUNT")) { - return CompressionType::COMPRESSION_COUNT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetCompressionTypeValues(), 13, "CompressionType", value)); +} + +const StringUtil::EnumStringLiteral *GetConflictManagerModeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ConflictManagerMode::SCAN), "SCAN" }, + { static_cast(ConflictManagerMode::THROW), "THROW" } + }; + return values; } template<> const char* EnumUtil::ToChars(ConflictManagerMode value) { - switch(value) { - case ConflictManagerMode::SCAN: - return "SCAN"; - case ConflictManagerMode::THROW: - return "THROW"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetConflictManagerModeValues(), 2, "ConflictManagerMode", static_cast(value)); } template<> ConflictManagerMode EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "SCAN")) { - return ConflictManagerMode::SCAN; - } - if (StringUtil::Equals(value, "THROW")) { - return ConflictManagerMode::THROW; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetConflictManagerModeValues(), 2, "ConflictManagerMode", value)); +} + +const StringUtil::EnumStringLiteral *GetConstraintTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ConstraintType::INVALID), "INVALID" }, + { static_cast(ConstraintType::NOT_NULL), "NOT_NULL" }, + { static_cast(ConstraintType::CHECK), "CHECK" }, + { static_cast(ConstraintType::UNIQUE), "UNIQUE" }, + { static_cast(ConstraintType::FOREIGN_KEY), "FOREIGN_KEY" } + }; + return values; } template<> const char* EnumUtil::ToChars(ConstraintType value) { - switch(value) { - case ConstraintType::INVALID: - return "INVALID"; - case ConstraintType::NOT_NULL: - return "NOT_NULL"; - case ConstraintType::CHECK: - return "CHECK"; - case ConstraintType::UNIQUE: - return "UNIQUE"; - case ConstraintType::FOREIGN_KEY: - return "FOREIGN_KEY"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetConstraintTypeValues(), 5, "ConstraintType", static_cast(value)); } template<> ConstraintType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return ConstraintType::INVALID; - } - if (StringUtil::Equals(value, "NOT_NULL")) { - return ConstraintType::NOT_NULL; - } - if (StringUtil::Equals(value, "CHECK")) { - return ConstraintType::CHECK; - } - if (StringUtil::Equals(value, "UNIQUE")) { - return ConstraintType::UNIQUE; - } - if (StringUtil::Equals(value, "FOREIGN_KEY")) { - return ConstraintType::FOREIGN_KEY; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetConstraintTypeValues(), 5, "ConstraintType", value)); +} + +const StringUtil::EnumStringLiteral *GetCopyFunctionReturnTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(CopyFunctionReturnType::CHANGED_ROWS), "CHANGED_ROWS" }, + { static_cast(CopyFunctionReturnType::CHANGED_ROWS_AND_FILE_LIST), "CHANGED_ROWS_AND_FILE_LIST" } + }; + return values; } template<> const char* EnumUtil::ToChars(CopyFunctionReturnType value) { - switch(value) { - case CopyFunctionReturnType::CHANGED_ROWS: - return "CHANGED_ROWS"; - case CopyFunctionReturnType::CHANGED_ROWS_AND_FILE_LIST: - return "CHANGED_ROWS_AND_FILE_LIST"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetCopyFunctionReturnTypeValues(), 2, "CopyFunctionReturnType", static_cast(value)); } template<> CopyFunctionReturnType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "CHANGED_ROWS")) { - return CopyFunctionReturnType::CHANGED_ROWS; - } - if (StringUtil::Equals(value, "CHANGED_ROWS_AND_FILE_LIST")) { - return CopyFunctionReturnType::CHANGED_ROWS_AND_FILE_LIST; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetCopyFunctionReturnTypeValues(), 2, "CopyFunctionReturnType", value)); +} + +const StringUtil::EnumStringLiteral *GetCopyOverwriteModeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(CopyOverwriteMode::COPY_ERROR_ON_CONFLICT), "COPY_ERROR_ON_CONFLICT" }, + { static_cast(CopyOverwriteMode::COPY_OVERWRITE), "COPY_OVERWRITE" }, + { static_cast(CopyOverwriteMode::COPY_OVERWRITE_OR_IGNORE), "COPY_OVERWRITE_OR_IGNORE" }, + { static_cast(CopyOverwriteMode::COPY_APPEND), "COPY_APPEND" } + }; + return values; } template<> const char* EnumUtil::ToChars(CopyOverwriteMode value) { - switch(value) { - case CopyOverwriteMode::COPY_ERROR_ON_CONFLICT: - return "COPY_ERROR_ON_CONFLICT"; - case CopyOverwriteMode::COPY_OVERWRITE: - return "COPY_OVERWRITE"; - case CopyOverwriteMode::COPY_OVERWRITE_OR_IGNORE: - return "COPY_OVERWRITE_OR_IGNORE"; - case CopyOverwriteMode::COPY_APPEND: - return "COPY_APPEND"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetCopyOverwriteModeValues(), 4, "CopyOverwriteMode", static_cast(value)); } template<> CopyOverwriteMode EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "COPY_ERROR_ON_CONFLICT")) { - return CopyOverwriteMode::COPY_ERROR_ON_CONFLICT; - } - if (StringUtil::Equals(value, "COPY_OVERWRITE")) { - return CopyOverwriteMode::COPY_OVERWRITE; - } - if (StringUtil::Equals(value, "COPY_OVERWRITE_OR_IGNORE")) { - return CopyOverwriteMode::COPY_OVERWRITE_OR_IGNORE; - } - if (StringUtil::Equals(value, "COPY_APPEND")) { - return CopyOverwriteMode::COPY_APPEND; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetCopyOverwriteModeValues(), 4, "CopyOverwriteMode", value)); +} + +const StringUtil::EnumStringLiteral *GetCopyToTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(CopyToType::COPY_TO_FILE), "COPY_TO_FILE" }, + { static_cast(CopyToType::EXPORT_DATABASE), "EXPORT_DATABASE" } + }; + return values; } template<> const char* EnumUtil::ToChars(CopyToType value) { - switch(value) { - case CopyToType::COPY_TO_FILE: - return "COPY_TO_FILE"; - case CopyToType::EXPORT_DATABASE: - return "EXPORT_DATABASE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetCopyToTypeValues(), 2, "CopyToType", static_cast(value)); } template<> CopyToType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "COPY_TO_FILE")) { - return CopyToType::COPY_TO_FILE; - } - if (StringUtil::Equals(value, "EXPORT_DATABASE")) { - return CopyToType::EXPORT_DATABASE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetCopyToTypeValues(), 2, "CopyToType", value)); +} + +const StringUtil::EnumStringLiteral *GetDataFileTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(DataFileType::FILE_DOES_NOT_EXIST), "FILE_DOES_NOT_EXIST" }, + { static_cast(DataFileType::DUCKDB_FILE), "DUCKDB_FILE" }, + { static_cast(DataFileType::SQLITE_FILE), "SQLITE_FILE" }, + { static_cast(DataFileType::PARQUET_FILE), "PARQUET_FILE" } + }; + return values; } template<> const char* EnumUtil::ToChars(DataFileType value) { - switch(value) { - case DataFileType::FILE_DOES_NOT_EXIST: - return "FILE_DOES_NOT_EXIST"; - case DataFileType::DUCKDB_FILE: - return "DUCKDB_FILE"; - case DataFileType::SQLITE_FILE: - return "SQLITE_FILE"; - case DataFileType::PARQUET_FILE: - return "PARQUET_FILE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetDataFileTypeValues(), 4, "DataFileType", static_cast(value)); } template<> DataFileType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "FILE_DOES_NOT_EXIST")) { - return DataFileType::FILE_DOES_NOT_EXIST; - } - if (StringUtil::Equals(value, "DUCKDB_FILE")) { - return DataFileType::DUCKDB_FILE; - } - if (StringUtil::Equals(value, "SQLITE_FILE")) { - return DataFileType::SQLITE_FILE; - } - if (StringUtil::Equals(value, "PARQUET_FILE")) { - return DataFileType::PARQUET_FILE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetDataFileTypeValues(), 4, "DataFileType", value)); +} + +const StringUtil::EnumStringLiteral *GetDatePartSpecifierValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(DatePartSpecifier::YEAR), "YEAR" }, + { static_cast(DatePartSpecifier::MONTH), "MONTH" }, + { static_cast(DatePartSpecifier::DAY), "DAY" }, + { static_cast(DatePartSpecifier::DECADE), "DECADE" }, + { static_cast(DatePartSpecifier::CENTURY), "CENTURY" }, + { static_cast(DatePartSpecifier::MILLENNIUM), "MILLENNIUM" }, + { static_cast(DatePartSpecifier::MICROSECONDS), "MICROSECONDS" }, + { static_cast(DatePartSpecifier::MILLISECONDS), "MILLISECONDS" }, + { static_cast(DatePartSpecifier::SECOND), "SECOND" }, + { static_cast(DatePartSpecifier::MINUTE), "MINUTE" }, + { static_cast(DatePartSpecifier::HOUR), "HOUR" }, + { static_cast(DatePartSpecifier::DOW), "DOW" }, + { static_cast(DatePartSpecifier::ISODOW), "ISODOW" }, + { static_cast(DatePartSpecifier::WEEK), "WEEK" }, + { static_cast(DatePartSpecifier::ISOYEAR), "ISOYEAR" }, + { static_cast(DatePartSpecifier::QUARTER), "QUARTER" }, + { static_cast(DatePartSpecifier::DOY), "DOY" }, + { static_cast(DatePartSpecifier::YEARWEEK), "YEARWEEK" }, + { static_cast(DatePartSpecifier::ERA), "ERA" }, + { static_cast(DatePartSpecifier::TIMEZONE), "TIMEZONE" }, + { static_cast(DatePartSpecifier::TIMEZONE_HOUR), "TIMEZONE_HOUR" }, + { static_cast(DatePartSpecifier::TIMEZONE_MINUTE), "TIMEZONE_MINUTE" }, + { static_cast(DatePartSpecifier::EPOCH), "EPOCH" }, + { static_cast(DatePartSpecifier::JULIAN_DAY), "JULIAN_DAY" }, + { static_cast(DatePartSpecifier::INVALID), "INVALID" } + }; + return values; } template<> const char* EnumUtil::ToChars(DatePartSpecifier value) { - switch(value) { - case DatePartSpecifier::YEAR: - return "YEAR"; - case DatePartSpecifier::MONTH: - return "MONTH"; - case DatePartSpecifier::DAY: - return "DAY"; - case DatePartSpecifier::DECADE: - return "DECADE"; - case DatePartSpecifier::CENTURY: - return "CENTURY"; - case DatePartSpecifier::MILLENNIUM: - return "MILLENNIUM"; - case DatePartSpecifier::MICROSECONDS: - return "MICROSECONDS"; - case DatePartSpecifier::MILLISECONDS: - return "MILLISECONDS"; - case DatePartSpecifier::SECOND: - return "SECOND"; - case DatePartSpecifier::MINUTE: - return "MINUTE"; - case DatePartSpecifier::HOUR: - return "HOUR"; - case DatePartSpecifier::DOW: - return "DOW"; - case DatePartSpecifier::ISODOW: - return "ISODOW"; - case DatePartSpecifier::WEEK: - return "WEEK"; - case DatePartSpecifier::ISOYEAR: - return "ISOYEAR"; - case DatePartSpecifier::QUARTER: - return "QUARTER"; - case DatePartSpecifier::DOY: - return "DOY"; - case DatePartSpecifier::YEARWEEK: - return "YEARWEEK"; - case DatePartSpecifier::ERA: - return "ERA"; - case DatePartSpecifier::TIMEZONE: - return "TIMEZONE"; - case DatePartSpecifier::TIMEZONE_HOUR: - return "TIMEZONE_HOUR"; - case DatePartSpecifier::TIMEZONE_MINUTE: - return "TIMEZONE_MINUTE"; - case DatePartSpecifier::EPOCH: - return "EPOCH"; - case DatePartSpecifier::JULIAN_DAY: - return "JULIAN_DAY"; - case DatePartSpecifier::INVALID: - return "INVALID"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetDatePartSpecifierValues(), 25, "DatePartSpecifier", static_cast(value)); } template<> DatePartSpecifier EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "YEAR")) { - return DatePartSpecifier::YEAR; - } - if (StringUtil::Equals(value, "MONTH")) { - return DatePartSpecifier::MONTH; - } - if (StringUtil::Equals(value, "DAY")) { - return DatePartSpecifier::DAY; - } - if (StringUtil::Equals(value, "DECADE")) { - return DatePartSpecifier::DECADE; - } - if (StringUtil::Equals(value, "CENTURY")) { - return DatePartSpecifier::CENTURY; - } - if (StringUtil::Equals(value, "MILLENNIUM")) { - return DatePartSpecifier::MILLENNIUM; - } - if (StringUtil::Equals(value, "MICROSECONDS")) { - return DatePartSpecifier::MICROSECONDS; - } - if (StringUtil::Equals(value, "MILLISECONDS")) { - return DatePartSpecifier::MILLISECONDS; - } - if (StringUtil::Equals(value, "SECOND")) { - return DatePartSpecifier::SECOND; - } - if (StringUtil::Equals(value, "MINUTE")) { - return DatePartSpecifier::MINUTE; - } - if (StringUtil::Equals(value, "HOUR")) { - return DatePartSpecifier::HOUR; - } - if (StringUtil::Equals(value, "DOW")) { - return DatePartSpecifier::DOW; - } - if (StringUtil::Equals(value, "ISODOW")) { - return DatePartSpecifier::ISODOW; - } - if (StringUtil::Equals(value, "WEEK")) { - return DatePartSpecifier::WEEK; - } - if (StringUtil::Equals(value, "ISOYEAR")) { - return DatePartSpecifier::ISOYEAR; - } - if (StringUtil::Equals(value, "QUARTER")) { - return DatePartSpecifier::QUARTER; - } - if (StringUtil::Equals(value, "DOY")) { - return DatePartSpecifier::DOY; - } - if (StringUtil::Equals(value, "YEARWEEK")) { - return DatePartSpecifier::YEARWEEK; - } - if (StringUtil::Equals(value, "ERA")) { - return DatePartSpecifier::ERA; - } - if (StringUtil::Equals(value, "TIMEZONE")) { - return DatePartSpecifier::TIMEZONE; - } - if (StringUtil::Equals(value, "TIMEZONE_HOUR")) { - return DatePartSpecifier::TIMEZONE_HOUR; - } - if (StringUtil::Equals(value, "TIMEZONE_MINUTE")) { - return DatePartSpecifier::TIMEZONE_MINUTE; - } - if (StringUtil::Equals(value, "EPOCH")) { - return DatePartSpecifier::EPOCH; - } - if (StringUtil::Equals(value, "JULIAN_DAY")) { - return DatePartSpecifier::JULIAN_DAY; - } - if (StringUtil::Equals(value, "INVALID")) { - return DatePartSpecifier::INVALID; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetDatePartSpecifierValues(), 25, "DatePartSpecifier", value)); +} + +const StringUtil::EnumStringLiteral *GetDebugInitializeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(DebugInitialize::NO_INITIALIZE), "NO_INITIALIZE" }, + { static_cast(DebugInitialize::DEBUG_ZERO_INITIALIZE), "DEBUG_ZERO_INITIALIZE" }, + { static_cast(DebugInitialize::DEBUG_ONE_INITIALIZE), "DEBUG_ONE_INITIALIZE" } + }; + return values; } template<> const char* EnumUtil::ToChars(DebugInitialize value) { - switch(value) { - case DebugInitialize::NO_INITIALIZE: - return "NO_INITIALIZE"; - case DebugInitialize::DEBUG_ZERO_INITIALIZE: - return "DEBUG_ZERO_INITIALIZE"; - case DebugInitialize::DEBUG_ONE_INITIALIZE: - return "DEBUG_ONE_INITIALIZE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetDebugInitializeValues(), 3, "DebugInitialize", static_cast(value)); } template<> DebugInitialize EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NO_INITIALIZE")) { - return DebugInitialize::NO_INITIALIZE; - } - if (StringUtil::Equals(value, "DEBUG_ZERO_INITIALIZE")) { - return DebugInitialize::DEBUG_ZERO_INITIALIZE; - } - if (StringUtil::Equals(value, "DEBUG_ONE_INITIALIZE")) { - return DebugInitialize::DEBUG_ONE_INITIALIZE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetDebugInitializeValues(), 3, "DebugInitialize", value)); +} + +const StringUtil::EnumStringLiteral *GetDefaultOrderByNullTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(DefaultOrderByNullType::INVALID), "INVALID" }, + { static_cast(DefaultOrderByNullType::NULLS_FIRST), "NULLS_FIRST" }, + { static_cast(DefaultOrderByNullType::NULLS_LAST), "NULLS_LAST" }, + { static_cast(DefaultOrderByNullType::NULLS_FIRST_ON_ASC_LAST_ON_DESC), "NULLS_FIRST_ON_ASC_LAST_ON_DESC" }, + { static_cast(DefaultOrderByNullType::NULLS_LAST_ON_ASC_FIRST_ON_DESC), "NULLS_LAST_ON_ASC_FIRST_ON_DESC" } + }; + return values; } template<> const char* EnumUtil::ToChars(DefaultOrderByNullType value) { - switch(value) { - case DefaultOrderByNullType::INVALID: - return "INVALID"; - case DefaultOrderByNullType::NULLS_FIRST: - return "NULLS_FIRST"; - case DefaultOrderByNullType::NULLS_LAST: - return "NULLS_LAST"; - case DefaultOrderByNullType::NULLS_FIRST_ON_ASC_LAST_ON_DESC: - return "NULLS_FIRST_ON_ASC_LAST_ON_DESC"; - case DefaultOrderByNullType::NULLS_LAST_ON_ASC_FIRST_ON_DESC: - return "NULLS_LAST_ON_ASC_FIRST_ON_DESC"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetDefaultOrderByNullTypeValues(), 5, "DefaultOrderByNullType", static_cast(value)); } template<> DefaultOrderByNullType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return DefaultOrderByNullType::INVALID; - } - if (StringUtil::Equals(value, "NULLS_FIRST")) { - return DefaultOrderByNullType::NULLS_FIRST; - } - if (StringUtil::Equals(value, "NULLS_LAST")) { - return DefaultOrderByNullType::NULLS_LAST; - } - if (StringUtil::Equals(value, "NULLS_FIRST_ON_ASC_LAST_ON_DESC")) { - return DefaultOrderByNullType::NULLS_FIRST_ON_ASC_LAST_ON_DESC; - } - if (StringUtil::Equals(value, "NULLS_LAST_ON_ASC_FIRST_ON_DESC")) { - return DefaultOrderByNullType::NULLS_LAST_ON_ASC_FIRST_ON_DESC; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetDefaultOrderByNullTypeValues(), 5, "DefaultOrderByNullType", value)); +} + +const StringUtil::EnumStringLiteral *GetDependencyEntryTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(DependencyEntryType::SUBJECT), "SUBJECT" }, + { static_cast(DependencyEntryType::DEPENDENT), "DEPENDENT" } + }; + return values; } template<> const char* EnumUtil::ToChars(DependencyEntryType value) { - switch(value) { - case DependencyEntryType::SUBJECT: - return "SUBJECT"; - case DependencyEntryType::DEPENDENT: - return "DEPENDENT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetDependencyEntryTypeValues(), 2, "DependencyEntryType", static_cast(value)); } template<> DependencyEntryType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "SUBJECT")) { - return DependencyEntryType::SUBJECT; - } - if (StringUtil::Equals(value, "DEPENDENT")) { - return DependencyEntryType::DEPENDENT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetDependencyEntryTypeValues(), 2, "DependencyEntryType", value)); +} + +const StringUtil::EnumStringLiteral *GetDeprecatedIndexTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(DeprecatedIndexType::INVALID), "INVALID" }, + { static_cast(DeprecatedIndexType::ART), "ART" }, + { static_cast(DeprecatedIndexType::EXTENSION), "EXTENSION" } + }; + return values; } template<> const char* EnumUtil::ToChars(DeprecatedIndexType value) { - switch(value) { - case DeprecatedIndexType::INVALID: - return "INVALID"; - case DeprecatedIndexType::ART: - return "ART"; - case DeprecatedIndexType::EXTENSION: - return "EXTENSION"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetDeprecatedIndexTypeValues(), 3, "DeprecatedIndexType", static_cast(value)); } template<> DeprecatedIndexType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return DeprecatedIndexType::INVALID; - } - if (StringUtil::Equals(value, "ART")) { - return DeprecatedIndexType::ART; - } - if (StringUtil::Equals(value, "EXTENSION")) { - return DeprecatedIndexType::EXTENSION; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetDeprecatedIndexTypeValues(), 3, "DeprecatedIndexType", value)); +} + +const StringUtil::EnumStringLiteral *GetDestroyBufferUponValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(DestroyBufferUpon::BLOCK), "BLOCK" }, + { static_cast(DestroyBufferUpon::EVICTION), "EVICTION" }, + { static_cast(DestroyBufferUpon::UNPIN), "UNPIN" } + }; + return values; } template<> const char* EnumUtil::ToChars(DestroyBufferUpon value) { - switch(value) { - case DestroyBufferUpon::BLOCK: - return "BLOCK"; - case DestroyBufferUpon::EVICTION: - return "EVICTION"; - case DestroyBufferUpon::UNPIN: - return "UNPIN"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetDestroyBufferUponValues(), 3, "DestroyBufferUpon", static_cast(value)); } template<> DestroyBufferUpon EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "BLOCK")) { - return DestroyBufferUpon::BLOCK; - } - if (StringUtil::Equals(value, "EVICTION")) { - return DestroyBufferUpon::EVICTION; - } - if (StringUtil::Equals(value, "UNPIN")) { - return DestroyBufferUpon::UNPIN; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetDestroyBufferUponValues(), 3, "DestroyBufferUpon", value)); +} + +const StringUtil::EnumStringLiteral *GetDistinctTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(DistinctType::DISTINCT), "DISTINCT" }, + { static_cast(DistinctType::DISTINCT_ON), "DISTINCT_ON" } + }; + return values; } template<> const char* EnumUtil::ToChars(DistinctType value) { - switch(value) { - case DistinctType::DISTINCT: - return "DISTINCT"; - case DistinctType::DISTINCT_ON: - return "DISTINCT_ON"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetDistinctTypeValues(), 2, "DistinctType", static_cast(value)); } template<> DistinctType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "DISTINCT")) { - return DistinctType::DISTINCT; - } - if (StringUtil::Equals(value, "DISTINCT_ON")) { - return DistinctType::DISTINCT_ON; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetDistinctTypeValues(), 2, "DistinctType", value)); +} + +const StringUtil::EnumStringLiteral *GetErrorTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ErrorType::UNSIGNED_EXTENSION), "UNSIGNED_EXTENSION" }, + { static_cast(ErrorType::INVALIDATED_TRANSACTION), "INVALIDATED_TRANSACTION" }, + { static_cast(ErrorType::INVALIDATED_DATABASE), "INVALIDATED_DATABASE" }, + { static_cast(ErrorType::ERROR_COUNT), "ERROR_COUNT" }, + { static_cast(ErrorType::INVALID), "INVALID" } + }; + return values; } template<> const char* EnumUtil::ToChars(ErrorType value) { - switch(value) { - case ErrorType::UNSIGNED_EXTENSION: - return "UNSIGNED_EXTENSION"; - case ErrorType::INVALIDATED_TRANSACTION: - return "INVALIDATED_TRANSACTION"; - case ErrorType::INVALIDATED_DATABASE: - return "INVALIDATED_DATABASE"; - case ErrorType::ERROR_COUNT: - return "ERROR_COUNT"; - case ErrorType::INVALID: - return "INVALID"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetErrorTypeValues(), 5, "ErrorType", static_cast(value)); } template<> ErrorType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "UNSIGNED_EXTENSION")) { - return ErrorType::UNSIGNED_EXTENSION; - } - if (StringUtil::Equals(value, "INVALIDATED_TRANSACTION")) { - return ErrorType::INVALIDATED_TRANSACTION; - } - if (StringUtil::Equals(value, "INVALIDATED_DATABASE")) { - return ErrorType::INVALIDATED_DATABASE; - } - if (StringUtil::Equals(value, "ERROR_COUNT")) { - return ErrorType::ERROR_COUNT; - } - if (StringUtil::Equals(value, "INVALID")) { - return ErrorType::INVALID; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetErrorTypeValues(), 5, "ErrorType", value)); +} + +const StringUtil::EnumStringLiteral *GetExceptionFormatValueTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ExceptionFormatValueType::FORMAT_VALUE_TYPE_DOUBLE), "FORMAT_VALUE_TYPE_DOUBLE" }, + { static_cast(ExceptionFormatValueType::FORMAT_VALUE_TYPE_INTEGER), "FORMAT_VALUE_TYPE_INTEGER" }, + { static_cast(ExceptionFormatValueType::FORMAT_VALUE_TYPE_STRING), "FORMAT_VALUE_TYPE_STRING" } + }; + return values; } template<> const char* EnumUtil::ToChars(ExceptionFormatValueType value) { - switch(value) { - case ExceptionFormatValueType::FORMAT_VALUE_TYPE_DOUBLE: - return "FORMAT_VALUE_TYPE_DOUBLE"; - case ExceptionFormatValueType::FORMAT_VALUE_TYPE_INTEGER: - return "FORMAT_VALUE_TYPE_INTEGER"; - case ExceptionFormatValueType::FORMAT_VALUE_TYPE_STRING: - return "FORMAT_VALUE_TYPE_STRING"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetExceptionFormatValueTypeValues(), 3, "ExceptionFormatValueType", static_cast(value)); } template<> ExceptionFormatValueType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "FORMAT_VALUE_TYPE_DOUBLE")) { - return ExceptionFormatValueType::FORMAT_VALUE_TYPE_DOUBLE; - } - if (StringUtil::Equals(value, "FORMAT_VALUE_TYPE_INTEGER")) { - return ExceptionFormatValueType::FORMAT_VALUE_TYPE_INTEGER; - } - if (StringUtil::Equals(value, "FORMAT_VALUE_TYPE_STRING")) { - return ExceptionFormatValueType::FORMAT_VALUE_TYPE_STRING; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetExceptionFormatValueTypeValues(), 3, "ExceptionFormatValueType", value)); +} + +const StringUtil::EnumStringLiteral *GetExceptionTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ExceptionType::INVALID), "INVALID" }, + { static_cast(ExceptionType::OUT_OF_RANGE), "OUT_OF_RANGE" }, + { static_cast(ExceptionType::CONVERSION), "CONVERSION" }, + { static_cast(ExceptionType::UNKNOWN_TYPE), "UNKNOWN_TYPE" }, + { static_cast(ExceptionType::DECIMAL), "DECIMAL" }, + { static_cast(ExceptionType::MISMATCH_TYPE), "MISMATCH_TYPE" }, + { static_cast(ExceptionType::DIVIDE_BY_ZERO), "DIVIDE_BY_ZERO" }, + { static_cast(ExceptionType::OBJECT_SIZE), "OBJECT_SIZE" }, + { static_cast(ExceptionType::INVALID_TYPE), "INVALID_TYPE" }, + { static_cast(ExceptionType::SERIALIZATION), "SERIALIZATION" }, + { static_cast(ExceptionType::TRANSACTION), "TRANSACTION" }, + { static_cast(ExceptionType::NOT_IMPLEMENTED), "NOT_IMPLEMENTED" }, + { static_cast(ExceptionType::EXPRESSION), "EXPRESSION" }, + { static_cast(ExceptionType::CATALOG), "CATALOG" }, + { static_cast(ExceptionType::PARSER), "PARSER" }, + { static_cast(ExceptionType::PLANNER), "PLANNER" }, + { static_cast(ExceptionType::SCHEDULER), "SCHEDULER" }, + { static_cast(ExceptionType::EXECUTOR), "EXECUTOR" }, + { static_cast(ExceptionType::CONSTRAINT), "CONSTRAINT" }, + { static_cast(ExceptionType::INDEX), "INDEX" }, + { static_cast(ExceptionType::STAT), "STAT" }, + { static_cast(ExceptionType::CONNECTION), "CONNECTION" }, + { static_cast(ExceptionType::SYNTAX), "SYNTAX" }, + { static_cast(ExceptionType::SETTINGS), "SETTINGS" }, + { static_cast(ExceptionType::BINDER), "BINDER" }, + { static_cast(ExceptionType::NETWORK), "NETWORK" }, + { static_cast(ExceptionType::OPTIMIZER), "OPTIMIZER" }, + { static_cast(ExceptionType::NULL_POINTER), "NULL_POINTER" }, + { static_cast(ExceptionType::IO), "IO" }, + { static_cast(ExceptionType::INTERRUPT), "INTERRUPT" }, + { static_cast(ExceptionType::FATAL), "FATAL" }, + { static_cast(ExceptionType::INTERNAL), "INTERNAL" }, + { static_cast(ExceptionType::INVALID_INPUT), "INVALID_INPUT" }, + { static_cast(ExceptionType::OUT_OF_MEMORY), "OUT_OF_MEMORY" }, + { static_cast(ExceptionType::PERMISSION), "PERMISSION" }, + { static_cast(ExceptionType::PARAMETER_NOT_RESOLVED), "PARAMETER_NOT_RESOLVED" }, + { static_cast(ExceptionType::PARAMETER_NOT_ALLOWED), "PARAMETER_NOT_ALLOWED" }, + { static_cast(ExceptionType::DEPENDENCY), "DEPENDENCY" }, + { static_cast(ExceptionType::HTTP), "HTTP" }, + { static_cast(ExceptionType::MISSING_EXTENSION), "MISSING_EXTENSION" }, + { static_cast(ExceptionType::AUTOLOAD), "AUTOLOAD" }, + { static_cast(ExceptionType::SEQUENCE), "SEQUENCE" }, + { static_cast(ExceptionType::INVALID_CONFIGURATION), "INVALID_CONFIGURATION" } + }; + return values; } template<> const char* EnumUtil::ToChars(ExceptionType value) { - switch(value) { - case ExceptionType::INVALID: - return "INVALID"; - case ExceptionType::OUT_OF_RANGE: - return "OUT_OF_RANGE"; - case ExceptionType::CONVERSION: - return "CONVERSION"; - case ExceptionType::UNKNOWN_TYPE: - return "UNKNOWN_TYPE"; - case ExceptionType::DECIMAL: - return "DECIMAL"; - case ExceptionType::MISMATCH_TYPE: - return "MISMATCH_TYPE"; - case ExceptionType::DIVIDE_BY_ZERO: - return "DIVIDE_BY_ZERO"; - case ExceptionType::OBJECT_SIZE: - return "OBJECT_SIZE"; - case ExceptionType::INVALID_TYPE: - return "INVALID_TYPE"; - case ExceptionType::SERIALIZATION: - return "SERIALIZATION"; - case ExceptionType::TRANSACTION: - return "TRANSACTION"; - case ExceptionType::NOT_IMPLEMENTED: - return "NOT_IMPLEMENTED"; - case ExceptionType::EXPRESSION: - return "EXPRESSION"; - case ExceptionType::CATALOG: - return "CATALOG"; - case ExceptionType::PARSER: - return "PARSER"; - case ExceptionType::PLANNER: - return "PLANNER"; - case ExceptionType::SCHEDULER: - return "SCHEDULER"; - case ExceptionType::EXECUTOR: - return "EXECUTOR"; - case ExceptionType::CONSTRAINT: - return "CONSTRAINT"; - case ExceptionType::INDEX: - return "INDEX"; - case ExceptionType::STAT: - return "STAT"; - case ExceptionType::CONNECTION: - return "CONNECTION"; - case ExceptionType::SYNTAX: - return "SYNTAX"; - case ExceptionType::SETTINGS: - return "SETTINGS"; - case ExceptionType::BINDER: - return "BINDER"; - case ExceptionType::NETWORK: - return "NETWORK"; - case ExceptionType::OPTIMIZER: - return "OPTIMIZER"; - case ExceptionType::NULL_POINTER: - return "NULL_POINTER"; - case ExceptionType::IO: - return "IO"; - case ExceptionType::INTERRUPT: - return "INTERRUPT"; - case ExceptionType::FATAL: - return "FATAL"; - case ExceptionType::INTERNAL: - return "INTERNAL"; - case ExceptionType::INVALID_INPUT: - return "INVALID_INPUT"; - case ExceptionType::OUT_OF_MEMORY: - return "OUT_OF_MEMORY"; - case ExceptionType::PERMISSION: - return "PERMISSION"; - case ExceptionType::PARAMETER_NOT_RESOLVED: - return "PARAMETER_NOT_RESOLVED"; - case ExceptionType::PARAMETER_NOT_ALLOWED: - return "PARAMETER_NOT_ALLOWED"; - case ExceptionType::DEPENDENCY: - return "DEPENDENCY"; - case ExceptionType::HTTP: - return "HTTP"; - case ExceptionType::MISSING_EXTENSION: - return "MISSING_EXTENSION"; - case ExceptionType::AUTOLOAD: - return "AUTOLOAD"; - case ExceptionType::SEQUENCE: - return "SEQUENCE"; - case ExceptionType::INVALID_CONFIGURATION: - return "INVALID_CONFIGURATION"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetExceptionTypeValues(), 43, "ExceptionType", static_cast(value)); } template<> ExceptionType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return ExceptionType::INVALID; - } - if (StringUtil::Equals(value, "OUT_OF_RANGE")) { - return ExceptionType::OUT_OF_RANGE; - } - if (StringUtil::Equals(value, "CONVERSION")) { - return ExceptionType::CONVERSION; - } - if (StringUtil::Equals(value, "UNKNOWN_TYPE")) { - return ExceptionType::UNKNOWN_TYPE; - } - if (StringUtil::Equals(value, "DECIMAL")) { - return ExceptionType::DECIMAL; - } - if (StringUtil::Equals(value, "MISMATCH_TYPE")) { - return ExceptionType::MISMATCH_TYPE; - } - if (StringUtil::Equals(value, "DIVIDE_BY_ZERO")) { - return ExceptionType::DIVIDE_BY_ZERO; - } - if (StringUtil::Equals(value, "OBJECT_SIZE")) { - return ExceptionType::OBJECT_SIZE; - } - if (StringUtil::Equals(value, "INVALID_TYPE")) { - return ExceptionType::INVALID_TYPE; - } - if (StringUtil::Equals(value, "SERIALIZATION")) { - return ExceptionType::SERIALIZATION; - } - if (StringUtil::Equals(value, "TRANSACTION")) { - return ExceptionType::TRANSACTION; - } - if (StringUtil::Equals(value, "NOT_IMPLEMENTED")) { - return ExceptionType::NOT_IMPLEMENTED; - } - if (StringUtil::Equals(value, "EXPRESSION")) { - return ExceptionType::EXPRESSION; - } - if (StringUtil::Equals(value, "CATALOG")) { - return ExceptionType::CATALOG; - } - if (StringUtil::Equals(value, "PARSER")) { - return ExceptionType::PARSER; - } - if (StringUtil::Equals(value, "PLANNER")) { - return ExceptionType::PLANNER; - } - if (StringUtil::Equals(value, "SCHEDULER")) { - return ExceptionType::SCHEDULER; - } - if (StringUtil::Equals(value, "EXECUTOR")) { - return ExceptionType::EXECUTOR; - } - if (StringUtil::Equals(value, "CONSTRAINT")) { - return ExceptionType::CONSTRAINT; - } - if (StringUtil::Equals(value, "INDEX")) { - return ExceptionType::INDEX; - } - if (StringUtil::Equals(value, "STAT")) { - return ExceptionType::STAT; - } - if (StringUtil::Equals(value, "CONNECTION")) { - return ExceptionType::CONNECTION; - } - if (StringUtil::Equals(value, "SYNTAX")) { - return ExceptionType::SYNTAX; - } - if (StringUtil::Equals(value, "SETTINGS")) { - return ExceptionType::SETTINGS; - } - if (StringUtil::Equals(value, "BINDER")) { - return ExceptionType::BINDER; - } - if (StringUtil::Equals(value, "NETWORK")) { - return ExceptionType::NETWORK; - } - if (StringUtil::Equals(value, "OPTIMIZER")) { - return ExceptionType::OPTIMIZER; - } - if (StringUtil::Equals(value, "NULL_POINTER")) { - return ExceptionType::NULL_POINTER; - } - if (StringUtil::Equals(value, "IO")) { - return ExceptionType::IO; - } - if (StringUtil::Equals(value, "INTERRUPT")) { - return ExceptionType::INTERRUPT; - } - if (StringUtil::Equals(value, "FATAL")) { - return ExceptionType::FATAL; - } - if (StringUtil::Equals(value, "INTERNAL")) { - return ExceptionType::INTERNAL; - } - if (StringUtil::Equals(value, "INVALID_INPUT")) { - return ExceptionType::INVALID_INPUT; - } - if (StringUtil::Equals(value, "OUT_OF_MEMORY")) { - return ExceptionType::OUT_OF_MEMORY; - } - if (StringUtil::Equals(value, "PERMISSION")) { - return ExceptionType::PERMISSION; - } - if (StringUtil::Equals(value, "PARAMETER_NOT_RESOLVED")) { - return ExceptionType::PARAMETER_NOT_RESOLVED; - } - if (StringUtil::Equals(value, "PARAMETER_NOT_ALLOWED")) { - return ExceptionType::PARAMETER_NOT_ALLOWED; - } - if (StringUtil::Equals(value, "DEPENDENCY")) { - return ExceptionType::DEPENDENCY; - } - if (StringUtil::Equals(value, "HTTP")) { - return ExceptionType::HTTP; - } - if (StringUtil::Equals(value, "MISSING_EXTENSION")) { - return ExceptionType::MISSING_EXTENSION; - } - if (StringUtil::Equals(value, "AUTOLOAD")) { - return ExceptionType::AUTOLOAD; - } - if (StringUtil::Equals(value, "SEQUENCE")) { - return ExceptionType::SEQUENCE; - } - if (StringUtil::Equals(value, "INVALID_CONFIGURATION")) { - return ExceptionType::INVALID_CONFIGURATION; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetExceptionTypeValues(), 43, "ExceptionType", value)); +} + +const StringUtil::EnumStringLiteral *GetExplainFormatValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ExplainFormat::DEFAULT), "DEFAULT" }, + { static_cast(ExplainFormat::TEXT), "TEXT" }, + { static_cast(ExplainFormat::JSON), "JSON" }, + { static_cast(ExplainFormat::HTML), "HTML" }, + { static_cast(ExplainFormat::GRAPHVIZ), "GRAPHVIZ" } + }; + return values; } template<> const char* EnumUtil::ToChars(ExplainFormat value) { - switch(value) { - case ExplainFormat::DEFAULT: - return "DEFAULT"; - case ExplainFormat::TEXT: - return "TEXT"; - case ExplainFormat::JSON: - return "JSON"; - case ExplainFormat::HTML: - return "HTML"; - case ExplainFormat::GRAPHVIZ: - return "GRAPHVIZ"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetExplainFormatValues(), 5, "ExplainFormat", static_cast(value)); } template<> ExplainFormat EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "DEFAULT")) { - return ExplainFormat::DEFAULT; - } - if (StringUtil::Equals(value, "TEXT")) { - return ExplainFormat::TEXT; - } - if (StringUtil::Equals(value, "JSON")) { - return ExplainFormat::JSON; - } - if (StringUtil::Equals(value, "HTML")) { - return ExplainFormat::HTML; - } - if (StringUtil::Equals(value, "GRAPHVIZ")) { - return ExplainFormat::GRAPHVIZ; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetExplainFormatValues(), 5, "ExplainFormat", value)); +} + +const StringUtil::EnumStringLiteral *GetExplainOutputTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ExplainOutputType::ALL), "ALL" }, + { static_cast(ExplainOutputType::OPTIMIZED_ONLY), "OPTIMIZED_ONLY" }, + { static_cast(ExplainOutputType::PHYSICAL_ONLY), "PHYSICAL_ONLY" } + }; + return values; } template<> const char* EnumUtil::ToChars(ExplainOutputType value) { - switch(value) { - case ExplainOutputType::ALL: - return "ALL"; - case ExplainOutputType::OPTIMIZED_ONLY: - return "OPTIMIZED_ONLY"; - case ExplainOutputType::PHYSICAL_ONLY: - return "PHYSICAL_ONLY"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetExplainOutputTypeValues(), 3, "ExplainOutputType", static_cast(value)); } template<> ExplainOutputType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "ALL")) { - return ExplainOutputType::ALL; - } - if (StringUtil::Equals(value, "OPTIMIZED_ONLY")) { - return ExplainOutputType::OPTIMIZED_ONLY; - } - if (StringUtil::Equals(value, "PHYSICAL_ONLY")) { - return ExplainOutputType::PHYSICAL_ONLY; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetExplainOutputTypeValues(), 3, "ExplainOutputType", value)); +} + +const StringUtil::EnumStringLiteral *GetExplainTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ExplainType::EXPLAIN_STANDARD), "EXPLAIN_STANDARD" }, + { static_cast(ExplainType::EXPLAIN_ANALYZE), "EXPLAIN_ANALYZE" } + }; + return values; } template<> const char* EnumUtil::ToChars(ExplainType value) { - switch(value) { - case ExplainType::EXPLAIN_STANDARD: - return "EXPLAIN_STANDARD"; - case ExplainType::EXPLAIN_ANALYZE: - return "EXPLAIN_ANALYZE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetExplainTypeValues(), 2, "ExplainType", static_cast(value)); } template<> ExplainType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "EXPLAIN_STANDARD")) { - return ExplainType::EXPLAIN_STANDARD; - } - if (StringUtil::Equals(value, "EXPLAIN_ANALYZE")) { - return ExplainType::EXPLAIN_ANALYZE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetExplainTypeValues(), 2, "ExplainType", value)); +} + +const StringUtil::EnumStringLiteral *GetExponentTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ExponentType::NONE), "NONE" }, + { static_cast(ExponentType::POSITIVE), "POSITIVE" }, + { static_cast(ExponentType::NEGATIVE), "NEGATIVE" } + }; + return values; } template<> const char* EnumUtil::ToChars(ExponentType value) { - switch(value) { - case ExponentType::NONE: - return "NONE"; - case ExponentType::POSITIVE: - return "POSITIVE"; - case ExponentType::NEGATIVE: - return "NEGATIVE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetExponentTypeValues(), 3, "ExponentType", static_cast(value)); } template<> ExponentType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NONE")) { - return ExponentType::NONE; - } - if (StringUtil::Equals(value, "POSITIVE")) { - return ExponentType::POSITIVE; - } - if (StringUtil::Equals(value, "NEGATIVE")) { - return ExponentType::NEGATIVE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetExponentTypeValues(), 3, "ExponentType", value)); +} + +const StringUtil::EnumStringLiteral *GetExpressionClassValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ExpressionClass::INVALID), "INVALID" }, + { static_cast(ExpressionClass::AGGREGATE), "AGGREGATE" }, + { static_cast(ExpressionClass::CASE), "CASE" }, + { static_cast(ExpressionClass::CAST), "CAST" }, + { static_cast(ExpressionClass::COLUMN_REF), "COLUMN_REF" }, + { static_cast(ExpressionClass::COMPARISON), "COMPARISON" }, + { static_cast(ExpressionClass::CONJUNCTION), "CONJUNCTION" }, + { static_cast(ExpressionClass::CONSTANT), "CONSTANT" }, + { static_cast(ExpressionClass::DEFAULT), "DEFAULT" }, + { static_cast(ExpressionClass::FUNCTION), "FUNCTION" }, + { static_cast(ExpressionClass::OPERATOR), "OPERATOR" }, + { static_cast(ExpressionClass::STAR), "STAR" }, + { static_cast(ExpressionClass::SUBQUERY), "SUBQUERY" }, + { static_cast(ExpressionClass::WINDOW), "WINDOW" }, + { static_cast(ExpressionClass::PARAMETER), "PARAMETER" }, + { static_cast(ExpressionClass::COLLATE), "COLLATE" }, + { static_cast(ExpressionClass::LAMBDA), "LAMBDA" }, + { static_cast(ExpressionClass::POSITIONAL_REFERENCE), "POSITIONAL_REFERENCE" }, + { static_cast(ExpressionClass::BETWEEN), "BETWEEN" }, + { static_cast(ExpressionClass::LAMBDA_REF), "LAMBDA_REF" }, + { static_cast(ExpressionClass::BOUND_AGGREGATE), "BOUND_AGGREGATE" }, + { static_cast(ExpressionClass::BOUND_CASE), "BOUND_CASE" }, + { static_cast(ExpressionClass::BOUND_CAST), "BOUND_CAST" }, + { static_cast(ExpressionClass::BOUND_COLUMN_REF), "BOUND_COLUMN_REF" }, + { static_cast(ExpressionClass::BOUND_COMPARISON), "BOUND_COMPARISON" }, + { static_cast(ExpressionClass::BOUND_CONJUNCTION), "BOUND_CONJUNCTION" }, + { static_cast(ExpressionClass::BOUND_CONSTANT), "BOUND_CONSTANT" }, + { static_cast(ExpressionClass::BOUND_DEFAULT), "BOUND_DEFAULT" }, + { static_cast(ExpressionClass::BOUND_FUNCTION), "BOUND_FUNCTION" }, + { static_cast(ExpressionClass::BOUND_OPERATOR), "BOUND_OPERATOR" }, + { static_cast(ExpressionClass::BOUND_PARAMETER), "BOUND_PARAMETER" }, + { static_cast(ExpressionClass::BOUND_REF), "BOUND_REF" }, + { static_cast(ExpressionClass::BOUND_SUBQUERY), "BOUND_SUBQUERY" }, + { static_cast(ExpressionClass::BOUND_WINDOW), "BOUND_WINDOW" }, + { static_cast(ExpressionClass::BOUND_BETWEEN), "BOUND_BETWEEN" }, + { static_cast(ExpressionClass::BOUND_UNNEST), "BOUND_UNNEST" }, + { static_cast(ExpressionClass::BOUND_LAMBDA), "BOUND_LAMBDA" }, + { static_cast(ExpressionClass::BOUND_LAMBDA_REF), "BOUND_LAMBDA_REF" }, + { static_cast(ExpressionClass::BOUND_EXPRESSION), "BOUND_EXPRESSION" }, + { static_cast(ExpressionClass::BOUND_EXPANDED), "BOUND_EXPANDED" } + }; + return values; } template<> const char* EnumUtil::ToChars(ExpressionClass value) { - switch(value) { - case ExpressionClass::INVALID: - return "INVALID"; - case ExpressionClass::AGGREGATE: - return "AGGREGATE"; - case ExpressionClass::CASE: - return "CASE"; - case ExpressionClass::CAST: - return "CAST"; - case ExpressionClass::COLUMN_REF: - return "COLUMN_REF"; - case ExpressionClass::COMPARISON: - return "COMPARISON"; - case ExpressionClass::CONJUNCTION: - return "CONJUNCTION"; - case ExpressionClass::CONSTANT: - return "CONSTANT"; - case ExpressionClass::DEFAULT: - return "DEFAULT"; - case ExpressionClass::FUNCTION: - return "FUNCTION"; - case ExpressionClass::OPERATOR: - return "OPERATOR"; - case ExpressionClass::STAR: - return "STAR"; - case ExpressionClass::SUBQUERY: - return "SUBQUERY"; - case ExpressionClass::WINDOW: - return "WINDOW"; - case ExpressionClass::PARAMETER: - return "PARAMETER"; - case ExpressionClass::COLLATE: - return "COLLATE"; - case ExpressionClass::LAMBDA: - return "LAMBDA"; - case ExpressionClass::POSITIONAL_REFERENCE: - return "POSITIONAL_REFERENCE"; - case ExpressionClass::BETWEEN: - return "BETWEEN"; - case ExpressionClass::LAMBDA_REF: - return "LAMBDA_REF"; - case ExpressionClass::BOUND_AGGREGATE: - return "BOUND_AGGREGATE"; - case ExpressionClass::BOUND_CASE: - return "BOUND_CASE"; - case ExpressionClass::BOUND_CAST: - return "BOUND_CAST"; - case ExpressionClass::BOUND_COLUMN_REF: - return "BOUND_COLUMN_REF"; - case ExpressionClass::BOUND_COMPARISON: - return "BOUND_COMPARISON"; - case ExpressionClass::BOUND_CONJUNCTION: - return "BOUND_CONJUNCTION"; - case ExpressionClass::BOUND_CONSTANT: - return "BOUND_CONSTANT"; - case ExpressionClass::BOUND_DEFAULT: - return "BOUND_DEFAULT"; - case ExpressionClass::BOUND_FUNCTION: - return "BOUND_FUNCTION"; - case ExpressionClass::BOUND_OPERATOR: - return "BOUND_OPERATOR"; - case ExpressionClass::BOUND_PARAMETER: - return "BOUND_PARAMETER"; - case ExpressionClass::BOUND_REF: - return "BOUND_REF"; - case ExpressionClass::BOUND_SUBQUERY: - return "BOUND_SUBQUERY"; - case ExpressionClass::BOUND_WINDOW: - return "BOUND_WINDOW"; - case ExpressionClass::BOUND_BETWEEN: - return "BOUND_BETWEEN"; - case ExpressionClass::BOUND_UNNEST: - return "BOUND_UNNEST"; - case ExpressionClass::BOUND_LAMBDA: - return "BOUND_LAMBDA"; - case ExpressionClass::BOUND_LAMBDA_REF: - return "BOUND_LAMBDA_REF"; - case ExpressionClass::BOUND_EXPRESSION: - return "BOUND_EXPRESSION"; - case ExpressionClass::BOUND_EXPANDED: - return "BOUND_EXPANDED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetExpressionClassValues(), 40, "ExpressionClass", static_cast(value)); } template<> ExpressionClass EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return ExpressionClass::INVALID; - } - if (StringUtil::Equals(value, "AGGREGATE")) { - return ExpressionClass::AGGREGATE; - } - if (StringUtil::Equals(value, "CASE")) { - return ExpressionClass::CASE; - } - if (StringUtil::Equals(value, "CAST")) { - return ExpressionClass::CAST; - } - if (StringUtil::Equals(value, "COLUMN_REF")) { - return ExpressionClass::COLUMN_REF; - } - if (StringUtil::Equals(value, "COMPARISON")) { - return ExpressionClass::COMPARISON; - } - if (StringUtil::Equals(value, "CONJUNCTION")) { - return ExpressionClass::CONJUNCTION; - } - if (StringUtil::Equals(value, "CONSTANT")) { - return ExpressionClass::CONSTANT; - } - if (StringUtil::Equals(value, "DEFAULT")) { - return ExpressionClass::DEFAULT; - } - if (StringUtil::Equals(value, "FUNCTION")) { - return ExpressionClass::FUNCTION; - } - if (StringUtil::Equals(value, "OPERATOR")) { - return ExpressionClass::OPERATOR; - } - if (StringUtil::Equals(value, "STAR")) { - return ExpressionClass::STAR; - } - if (StringUtil::Equals(value, "SUBQUERY")) { - return ExpressionClass::SUBQUERY; - } - if (StringUtil::Equals(value, "WINDOW")) { - return ExpressionClass::WINDOW; - } - if (StringUtil::Equals(value, "PARAMETER")) { - return ExpressionClass::PARAMETER; - } - if (StringUtil::Equals(value, "COLLATE")) { - return ExpressionClass::COLLATE; - } - if (StringUtil::Equals(value, "LAMBDA")) { - return ExpressionClass::LAMBDA; - } - if (StringUtil::Equals(value, "POSITIONAL_REFERENCE")) { - return ExpressionClass::POSITIONAL_REFERENCE; - } - if (StringUtil::Equals(value, "BETWEEN")) { - return ExpressionClass::BETWEEN; - } - if (StringUtil::Equals(value, "LAMBDA_REF")) { - return ExpressionClass::LAMBDA_REF; - } - if (StringUtil::Equals(value, "BOUND_AGGREGATE")) { - return ExpressionClass::BOUND_AGGREGATE; - } - if (StringUtil::Equals(value, "BOUND_CASE")) { - return ExpressionClass::BOUND_CASE; - } - if (StringUtil::Equals(value, "BOUND_CAST")) { - return ExpressionClass::BOUND_CAST; - } - if (StringUtil::Equals(value, "BOUND_COLUMN_REF")) { - return ExpressionClass::BOUND_COLUMN_REF; - } - if (StringUtil::Equals(value, "BOUND_COMPARISON")) { - return ExpressionClass::BOUND_COMPARISON; - } - if (StringUtil::Equals(value, "BOUND_CONJUNCTION")) { - return ExpressionClass::BOUND_CONJUNCTION; - } - if (StringUtil::Equals(value, "BOUND_CONSTANT")) { - return ExpressionClass::BOUND_CONSTANT; - } - if (StringUtil::Equals(value, "BOUND_DEFAULT")) { - return ExpressionClass::BOUND_DEFAULT; - } - if (StringUtil::Equals(value, "BOUND_FUNCTION")) { - return ExpressionClass::BOUND_FUNCTION; - } - if (StringUtil::Equals(value, "BOUND_OPERATOR")) { - return ExpressionClass::BOUND_OPERATOR; - } - if (StringUtil::Equals(value, "BOUND_PARAMETER")) { - return ExpressionClass::BOUND_PARAMETER; - } - if (StringUtil::Equals(value, "BOUND_REF")) { - return ExpressionClass::BOUND_REF; - } - if (StringUtil::Equals(value, "BOUND_SUBQUERY")) { - return ExpressionClass::BOUND_SUBQUERY; - } - if (StringUtil::Equals(value, "BOUND_WINDOW")) { - return ExpressionClass::BOUND_WINDOW; - } - if (StringUtil::Equals(value, "BOUND_BETWEEN")) { - return ExpressionClass::BOUND_BETWEEN; - } - if (StringUtil::Equals(value, "BOUND_UNNEST")) { - return ExpressionClass::BOUND_UNNEST; - } - if (StringUtil::Equals(value, "BOUND_LAMBDA")) { - return ExpressionClass::BOUND_LAMBDA; - } - if (StringUtil::Equals(value, "BOUND_LAMBDA_REF")) { - return ExpressionClass::BOUND_LAMBDA_REF; - } - if (StringUtil::Equals(value, "BOUND_EXPRESSION")) { - return ExpressionClass::BOUND_EXPRESSION; - } - if (StringUtil::Equals(value, "BOUND_EXPANDED")) { - return ExpressionClass::BOUND_EXPANDED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetExpressionClassValues(), 40, "ExpressionClass", value)); +} + +const StringUtil::EnumStringLiteral *GetExpressionTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ExpressionType::INVALID), "INVALID" }, + { static_cast(ExpressionType::OPERATOR_CAST), "OPERATOR_CAST" }, + { static_cast(ExpressionType::OPERATOR_NOT), "OPERATOR_NOT" }, + { static_cast(ExpressionType::OPERATOR_IS_NULL), "OPERATOR_IS_NULL" }, + { static_cast(ExpressionType::OPERATOR_IS_NOT_NULL), "OPERATOR_IS_NOT_NULL" }, + { static_cast(ExpressionType::COMPARE_EQUAL), "COMPARE_EQUAL" }, + { static_cast(ExpressionType::COMPARE_NOTEQUAL), "COMPARE_NOTEQUAL" }, + { static_cast(ExpressionType::COMPARE_LESSTHAN), "COMPARE_LESSTHAN" }, + { static_cast(ExpressionType::COMPARE_GREATERTHAN), "COMPARE_GREATERTHAN" }, + { static_cast(ExpressionType::COMPARE_LESSTHANOREQUALTO), "COMPARE_LESSTHANOREQUALTO" }, + { static_cast(ExpressionType::COMPARE_GREATERTHANOREQUALTO), "COMPARE_GREATERTHANOREQUALTO" }, + { static_cast(ExpressionType::COMPARE_IN), "COMPARE_IN" }, + { static_cast(ExpressionType::COMPARE_NOT_IN), "COMPARE_NOT_IN" }, + { static_cast(ExpressionType::COMPARE_DISTINCT_FROM), "COMPARE_DISTINCT_FROM" }, + { static_cast(ExpressionType::COMPARE_BETWEEN), "COMPARE_BETWEEN" }, + { static_cast(ExpressionType::COMPARE_NOT_BETWEEN), "COMPARE_NOT_BETWEEN" }, + { static_cast(ExpressionType::COMPARE_NOT_DISTINCT_FROM), "COMPARE_NOT_DISTINCT_FROM" }, + { static_cast(ExpressionType::CONJUNCTION_AND), "CONJUNCTION_AND" }, + { static_cast(ExpressionType::CONJUNCTION_OR), "CONJUNCTION_OR" }, + { static_cast(ExpressionType::VALUE_CONSTANT), "VALUE_CONSTANT" }, + { static_cast(ExpressionType::VALUE_PARAMETER), "VALUE_PARAMETER" }, + { static_cast(ExpressionType::VALUE_TUPLE), "VALUE_TUPLE" }, + { static_cast(ExpressionType::VALUE_TUPLE_ADDRESS), "VALUE_TUPLE_ADDRESS" }, + { static_cast(ExpressionType::VALUE_NULL), "VALUE_NULL" }, + { static_cast(ExpressionType::VALUE_VECTOR), "VALUE_VECTOR" }, + { static_cast(ExpressionType::VALUE_SCALAR), "VALUE_SCALAR" }, + { static_cast(ExpressionType::VALUE_DEFAULT), "VALUE_DEFAULT" }, + { static_cast(ExpressionType::AGGREGATE), "AGGREGATE" }, + { static_cast(ExpressionType::BOUND_AGGREGATE), "BOUND_AGGREGATE" }, + { static_cast(ExpressionType::GROUPING_FUNCTION), "GROUPING_FUNCTION" }, + { static_cast(ExpressionType::WINDOW_AGGREGATE), "WINDOW_AGGREGATE" }, + { static_cast(ExpressionType::WINDOW_RANK), "WINDOW_RANK" }, + { static_cast(ExpressionType::WINDOW_RANK_DENSE), "WINDOW_RANK_DENSE" }, + { static_cast(ExpressionType::WINDOW_NTILE), "WINDOW_NTILE" }, + { static_cast(ExpressionType::WINDOW_PERCENT_RANK), "WINDOW_PERCENT_RANK" }, + { static_cast(ExpressionType::WINDOW_CUME_DIST), "WINDOW_CUME_DIST" }, + { static_cast(ExpressionType::WINDOW_ROW_NUMBER), "WINDOW_ROW_NUMBER" }, + { static_cast(ExpressionType::WINDOW_FIRST_VALUE), "WINDOW_FIRST_VALUE" }, + { static_cast(ExpressionType::WINDOW_LAST_VALUE), "WINDOW_LAST_VALUE" }, + { static_cast(ExpressionType::WINDOW_LEAD), "WINDOW_LEAD" }, + { static_cast(ExpressionType::WINDOW_LAG), "WINDOW_LAG" }, + { static_cast(ExpressionType::WINDOW_NTH_VALUE), "WINDOW_NTH_VALUE" }, + { static_cast(ExpressionType::FUNCTION), "FUNCTION" }, + { static_cast(ExpressionType::BOUND_FUNCTION), "BOUND_FUNCTION" }, + { static_cast(ExpressionType::CASE_EXPR), "CASE_EXPR" }, + { static_cast(ExpressionType::OPERATOR_NULLIF), "OPERATOR_NULLIF" }, + { static_cast(ExpressionType::OPERATOR_COALESCE), "OPERATOR_COALESCE" }, + { static_cast(ExpressionType::ARRAY_EXTRACT), "ARRAY_EXTRACT" }, + { static_cast(ExpressionType::ARRAY_SLICE), "ARRAY_SLICE" }, + { static_cast(ExpressionType::STRUCT_EXTRACT), "STRUCT_EXTRACT" }, + { static_cast(ExpressionType::ARRAY_CONSTRUCTOR), "ARRAY_CONSTRUCTOR" }, + { static_cast(ExpressionType::ARROW), "ARROW" }, + { static_cast(ExpressionType::SUBQUERY), "SUBQUERY" }, + { static_cast(ExpressionType::STAR), "STAR" }, + { static_cast(ExpressionType::TABLE_STAR), "TABLE_STAR" }, + { static_cast(ExpressionType::PLACEHOLDER), "PLACEHOLDER" }, + { static_cast(ExpressionType::COLUMN_REF), "COLUMN_REF" }, + { static_cast(ExpressionType::FUNCTION_REF), "FUNCTION_REF" }, + { static_cast(ExpressionType::TABLE_REF), "TABLE_REF" }, + { static_cast(ExpressionType::LAMBDA_REF), "LAMBDA_REF" }, + { static_cast(ExpressionType::CAST), "CAST" }, + { static_cast(ExpressionType::BOUND_REF), "BOUND_REF" }, + { static_cast(ExpressionType::BOUND_COLUMN_REF), "BOUND_COLUMN_REF" }, + { static_cast(ExpressionType::BOUND_UNNEST), "BOUND_UNNEST" }, + { static_cast(ExpressionType::COLLATE), "COLLATE" }, + { static_cast(ExpressionType::LAMBDA), "LAMBDA" }, + { static_cast(ExpressionType::POSITIONAL_REFERENCE), "POSITIONAL_REFERENCE" }, + { static_cast(ExpressionType::BOUND_LAMBDA_REF), "BOUND_LAMBDA_REF" }, + { static_cast(ExpressionType::BOUND_EXPANDED), "BOUND_EXPANDED" } + }; + return values; } template<> const char* EnumUtil::ToChars(ExpressionType value) { - switch(value) { - case ExpressionType::INVALID: - return "INVALID"; - case ExpressionType::OPERATOR_CAST: - return "OPERATOR_CAST"; - case ExpressionType::OPERATOR_NOT: - return "OPERATOR_NOT"; - case ExpressionType::OPERATOR_IS_NULL: - return "OPERATOR_IS_NULL"; - case ExpressionType::OPERATOR_IS_NOT_NULL: - return "OPERATOR_IS_NOT_NULL"; - case ExpressionType::COMPARE_EQUAL: - return "COMPARE_EQUAL"; - case ExpressionType::COMPARE_NOTEQUAL: - return "COMPARE_NOTEQUAL"; - case ExpressionType::COMPARE_LESSTHAN: - return "COMPARE_LESSTHAN"; - case ExpressionType::COMPARE_GREATERTHAN: - return "COMPARE_GREATERTHAN"; - case ExpressionType::COMPARE_LESSTHANOREQUALTO: - return "COMPARE_LESSTHANOREQUALTO"; - case ExpressionType::COMPARE_GREATERTHANOREQUALTO: - return "COMPARE_GREATERTHANOREQUALTO"; - case ExpressionType::COMPARE_IN: - return "COMPARE_IN"; - case ExpressionType::COMPARE_NOT_IN: - return "COMPARE_NOT_IN"; - case ExpressionType::COMPARE_DISTINCT_FROM: - return "COMPARE_DISTINCT_FROM"; - case ExpressionType::COMPARE_BETWEEN: - return "COMPARE_BETWEEN"; - case ExpressionType::COMPARE_NOT_BETWEEN: - return "COMPARE_NOT_BETWEEN"; - case ExpressionType::COMPARE_NOT_DISTINCT_FROM: - return "COMPARE_NOT_DISTINCT_FROM"; - case ExpressionType::CONJUNCTION_AND: - return "CONJUNCTION_AND"; - case ExpressionType::CONJUNCTION_OR: - return "CONJUNCTION_OR"; - case ExpressionType::VALUE_CONSTANT: - return "VALUE_CONSTANT"; - case ExpressionType::VALUE_PARAMETER: - return "VALUE_PARAMETER"; - case ExpressionType::VALUE_TUPLE: - return "VALUE_TUPLE"; - case ExpressionType::VALUE_TUPLE_ADDRESS: - return "VALUE_TUPLE_ADDRESS"; - case ExpressionType::VALUE_NULL: - return "VALUE_NULL"; - case ExpressionType::VALUE_VECTOR: - return "VALUE_VECTOR"; - case ExpressionType::VALUE_SCALAR: - return "VALUE_SCALAR"; - case ExpressionType::VALUE_DEFAULT: - return "VALUE_DEFAULT"; - case ExpressionType::AGGREGATE: - return "AGGREGATE"; - case ExpressionType::BOUND_AGGREGATE: - return "BOUND_AGGREGATE"; - case ExpressionType::GROUPING_FUNCTION: - return "GROUPING_FUNCTION"; - case ExpressionType::WINDOW_AGGREGATE: - return "WINDOW_AGGREGATE"; - case ExpressionType::WINDOW_RANK: - return "WINDOW_RANK"; - case ExpressionType::WINDOW_RANK_DENSE: - return "WINDOW_RANK_DENSE"; - case ExpressionType::WINDOW_NTILE: - return "WINDOW_NTILE"; - case ExpressionType::WINDOW_PERCENT_RANK: - return "WINDOW_PERCENT_RANK"; - case ExpressionType::WINDOW_CUME_DIST: - return "WINDOW_CUME_DIST"; - case ExpressionType::WINDOW_ROW_NUMBER: - return "WINDOW_ROW_NUMBER"; - case ExpressionType::WINDOW_FIRST_VALUE: - return "WINDOW_FIRST_VALUE"; - case ExpressionType::WINDOW_LAST_VALUE: - return "WINDOW_LAST_VALUE"; - case ExpressionType::WINDOW_LEAD: - return "WINDOW_LEAD"; - case ExpressionType::WINDOW_LAG: - return "WINDOW_LAG"; - case ExpressionType::WINDOW_NTH_VALUE: - return "WINDOW_NTH_VALUE"; - case ExpressionType::FUNCTION: - return "FUNCTION"; - case ExpressionType::BOUND_FUNCTION: - return "BOUND_FUNCTION"; - case ExpressionType::CASE_EXPR: - return "CASE_EXPR"; - case ExpressionType::OPERATOR_NULLIF: - return "OPERATOR_NULLIF"; - case ExpressionType::OPERATOR_COALESCE: - return "OPERATOR_COALESCE"; - case ExpressionType::ARRAY_EXTRACT: - return "ARRAY_EXTRACT"; - case ExpressionType::ARRAY_SLICE: - return "ARRAY_SLICE"; - case ExpressionType::STRUCT_EXTRACT: - return "STRUCT_EXTRACT"; - case ExpressionType::ARRAY_CONSTRUCTOR: - return "ARRAY_CONSTRUCTOR"; - case ExpressionType::ARROW: - return "ARROW"; - case ExpressionType::SUBQUERY: - return "SUBQUERY"; - case ExpressionType::STAR: - return "STAR"; - case ExpressionType::TABLE_STAR: - return "TABLE_STAR"; - case ExpressionType::PLACEHOLDER: - return "PLACEHOLDER"; - case ExpressionType::COLUMN_REF: - return "COLUMN_REF"; - case ExpressionType::FUNCTION_REF: - return "FUNCTION_REF"; - case ExpressionType::TABLE_REF: - return "TABLE_REF"; - case ExpressionType::LAMBDA_REF: - return "LAMBDA_REF"; - case ExpressionType::CAST: - return "CAST"; - case ExpressionType::BOUND_REF: - return "BOUND_REF"; - case ExpressionType::BOUND_COLUMN_REF: - return "BOUND_COLUMN_REF"; - case ExpressionType::BOUND_UNNEST: - return "BOUND_UNNEST"; - case ExpressionType::COLLATE: - return "COLLATE"; - case ExpressionType::LAMBDA: - return "LAMBDA"; - case ExpressionType::POSITIONAL_REFERENCE: - return "POSITIONAL_REFERENCE"; - case ExpressionType::BOUND_LAMBDA_REF: - return "BOUND_LAMBDA_REF"; - case ExpressionType::BOUND_EXPANDED: - return "BOUND_EXPANDED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetExpressionTypeValues(), 69, "ExpressionType", static_cast(value)); } template<> ExpressionType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return ExpressionType::INVALID; - } - if (StringUtil::Equals(value, "OPERATOR_CAST")) { - return ExpressionType::OPERATOR_CAST; - } - if (StringUtil::Equals(value, "OPERATOR_NOT")) { - return ExpressionType::OPERATOR_NOT; - } - if (StringUtil::Equals(value, "OPERATOR_IS_NULL")) { - return ExpressionType::OPERATOR_IS_NULL; - } - if (StringUtil::Equals(value, "OPERATOR_IS_NOT_NULL")) { - return ExpressionType::OPERATOR_IS_NOT_NULL; - } - if (StringUtil::Equals(value, "COMPARE_EQUAL")) { - return ExpressionType::COMPARE_EQUAL; - } - if (StringUtil::Equals(value, "COMPARE_NOTEQUAL")) { - return ExpressionType::COMPARE_NOTEQUAL; - } - if (StringUtil::Equals(value, "COMPARE_LESSTHAN")) { - return ExpressionType::COMPARE_LESSTHAN; - } - if (StringUtil::Equals(value, "COMPARE_GREATERTHAN")) { - return ExpressionType::COMPARE_GREATERTHAN; - } - if (StringUtil::Equals(value, "COMPARE_LESSTHANOREQUALTO")) { - return ExpressionType::COMPARE_LESSTHANOREQUALTO; - } - if (StringUtil::Equals(value, "COMPARE_GREATERTHANOREQUALTO")) { - return ExpressionType::COMPARE_GREATERTHANOREQUALTO; - } - if (StringUtil::Equals(value, "COMPARE_IN")) { - return ExpressionType::COMPARE_IN; - } - if (StringUtil::Equals(value, "COMPARE_NOT_IN")) { - return ExpressionType::COMPARE_NOT_IN; - } - if (StringUtil::Equals(value, "COMPARE_DISTINCT_FROM")) { - return ExpressionType::COMPARE_DISTINCT_FROM; - } - if (StringUtil::Equals(value, "COMPARE_BETWEEN")) { - return ExpressionType::COMPARE_BETWEEN; - } - if (StringUtil::Equals(value, "COMPARE_NOT_BETWEEN")) { - return ExpressionType::COMPARE_NOT_BETWEEN; - } - if (StringUtil::Equals(value, "COMPARE_NOT_DISTINCT_FROM")) { - return ExpressionType::COMPARE_NOT_DISTINCT_FROM; - } - if (StringUtil::Equals(value, "CONJUNCTION_AND")) { - return ExpressionType::CONJUNCTION_AND; - } - if (StringUtil::Equals(value, "CONJUNCTION_OR")) { - return ExpressionType::CONJUNCTION_OR; - } - if (StringUtil::Equals(value, "VALUE_CONSTANT")) { - return ExpressionType::VALUE_CONSTANT; - } - if (StringUtil::Equals(value, "VALUE_PARAMETER")) { - return ExpressionType::VALUE_PARAMETER; - } - if (StringUtil::Equals(value, "VALUE_TUPLE")) { - return ExpressionType::VALUE_TUPLE; - } - if (StringUtil::Equals(value, "VALUE_TUPLE_ADDRESS")) { - return ExpressionType::VALUE_TUPLE_ADDRESS; - } - if (StringUtil::Equals(value, "VALUE_NULL")) { - return ExpressionType::VALUE_NULL; - } - if (StringUtil::Equals(value, "VALUE_VECTOR")) { - return ExpressionType::VALUE_VECTOR; - } - if (StringUtil::Equals(value, "VALUE_SCALAR")) { - return ExpressionType::VALUE_SCALAR; - } - if (StringUtil::Equals(value, "VALUE_DEFAULT")) { - return ExpressionType::VALUE_DEFAULT; - } - if (StringUtil::Equals(value, "AGGREGATE")) { - return ExpressionType::AGGREGATE; - } - if (StringUtil::Equals(value, "BOUND_AGGREGATE")) { - return ExpressionType::BOUND_AGGREGATE; - } - if (StringUtil::Equals(value, "GROUPING_FUNCTION")) { - return ExpressionType::GROUPING_FUNCTION; - } - if (StringUtil::Equals(value, "WINDOW_AGGREGATE")) { - return ExpressionType::WINDOW_AGGREGATE; - } - if (StringUtil::Equals(value, "WINDOW_RANK")) { - return ExpressionType::WINDOW_RANK; - } - if (StringUtil::Equals(value, "WINDOW_RANK_DENSE")) { - return ExpressionType::WINDOW_RANK_DENSE; - } - if (StringUtil::Equals(value, "WINDOW_NTILE")) { - return ExpressionType::WINDOW_NTILE; - } - if (StringUtil::Equals(value, "WINDOW_PERCENT_RANK")) { - return ExpressionType::WINDOW_PERCENT_RANK; - } - if (StringUtil::Equals(value, "WINDOW_CUME_DIST")) { - return ExpressionType::WINDOW_CUME_DIST; - } - if (StringUtil::Equals(value, "WINDOW_ROW_NUMBER")) { - return ExpressionType::WINDOW_ROW_NUMBER; - } - if (StringUtil::Equals(value, "WINDOW_FIRST_VALUE")) { - return ExpressionType::WINDOW_FIRST_VALUE; - } - if (StringUtil::Equals(value, "WINDOW_LAST_VALUE")) { - return ExpressionType::WINDOW_LAST_VALUE; - } - if (StringUtil::Equals(value, "WINDOW_LEAD")) { - return ExpressionType::WINDOW_LEAD; - } - if (StringUtil::Equals(value, "WINDOW_LAG")) { - return ExpressionType::WINDOW_LAG; - } - if (StringUtil::Equals(value, "WINDOW_NTH_VALUE")) { - return ExpressionType::WINDOW_NTH_VALUE; - } - if (StringUtil::Equals(value, "FUNCTION")) { - return ExpressionType::FUNCTION; - } - if (StringUtil::Equals(value, "BOUND_FUNCTION")) { - return ExpressionType::BOUND_FUNCTION; - } - if (StringUtil::Equals(value, "CASE_EXPR")) { - return ExpressionType::CASE_EXPR; - } - if (StringUtil::Equals(value, "OPERATOR_NULLIF")) { - return ExpressionType::OPERATOR_NULLIF; - } - if (StringUtil::Equals(value, "OPERATOR_COALESCE")) { - return ExpressionType::OPERATOR_COALESCE; - } - if (StringUtil::Equals(value, "ARRAY_EXTRACT")) { - return ExpressionType::ARRAY_EXTRACT; - } - if (StringUtil::Equals(value, "ARRAY_SLICE")) { - return ExpressionType::ARRAY_SLICE; - } - if (StringUtil::Equals(value, "STRUCT_EXTRACT")) { - return ExpressionType::STRUCT_EXTRACT; - } - if (StringUtil::Equals(value, "ARRAY_CONSTRUCTOR")) { - return ExpressionType::ARRAY_CONSTRUCTOR; - } - if (StringUtil::Equals(value, "ARROW")) { - return ExpressionType::ARROW; - } - if (StringUtil::Equals(value, "SUBQUERY")) { - return ExpressionType::SUBQUERY; - } - if (StringUtil::Equals(value, "STAR")) { - return ExpressionType::STAR; - } - if (StringUtil::Equals(value, "TABLE_STAR")) { - return ExpressionType::TABLE_STAR; - } - if (StringUtil::Equals(value, "PLACEHOLDER")) { - return ExpressionType::PLACEHOLDER; - } - if (StringUtil::Equals(value, "COLUMN_REF")) { - return ExpressionType::COLUMN_REF; - } - if (StringUtil::Equals(value, "FUNCTION_REF")) { - return ExpressionType::FUNCTION_REF; - } - if (StringUtil::Equals(value, "TABLE_REF")) { - return ExpressionType::TABLE_REF; - } - if (StringUtil::Equals(value, "LAMBDA_REF")) { - return ExpressionType::LAMBDA_REF; - } - if (StringUtil::Equals(value, "CAST")) { - return ExpressionType::CAST; - } - if (StringUtil::Equals(value, "BOUND_REF")) { - return ExpressionType::BOUND_REF; - } - if (StringUtil::Equals(value, "BOUND_COLUMN_REF")) { - return ExpressionType::BOUND_COLUMN_REF; - } - if (StringUtil::Equals(value, "BOUND_UNNEST")) { - return ExpressionType::BOUND_UNNEST; - } - if (StringUtil::Equals(value, "COLLATE")) { - return ExpressionType::COLLATE; - } - if (StringUtil::Equals(value, "LAMBDA")) { - return ExpressionType::LAMBDA; - } - if (StringUtil::Equals(value, "POSITIONAL_REFERENCE")) { - return ExpressionType::POSITIONAL_REFERENCE; - } - if (StringUtil::Equals(value, "BOUND_LAMBDA_REF")) { - return ExpressionType::BOUND_LAMBDA_REF; - } - if (StringUtil::Equals(value, "BOUND_EXPANDED")) { - return ExpressionType::BOUND_EXPANDED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetExpressionTypeValues(), 69, "ExpressionType", value)); +} + +const StringUtil::EnumStringLiteral *GetExtensionABITypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ExtensionABIType::UNKNOWN), "UNKNOWN" }, + { static_cast(ExtensionABIType::CPP), "CPP" }, + { static_cast(ExtensionABIType::C_STRUCT), "C_STRUCT" } + }; + return values; } template<> const char* EnumUtil::ToChars(ExtensionABIType value) { - switch(value) { - case ExtensionABIType::UNKNOWN: - return "UNKNOWN"; - case ExtensionABIType::CPP: - return "CPP"; - case ExtensionABIType::C_STRUCT: - return "C_STRUCT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetExtensionABITypeValues(), 3, "ExtensionABIType", static_cast(value)); } template<> ExtensionABIType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "UNKNOWN")) { - return ExtensionABIType::UNKNOWN; - } - if (StringUtil::Equals(value, "CPP")) { - return ExtensionABIType::CPP; - } - if (StringUtil::Equals(value, "C_STRUCT")) { - return ExtensionABIType::C_STRUCT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetExtensionABITypeValues(), 3, "ExtensionABIType", value)); +} + +const StringUtil::EnumStringLiteral *GetExtensionInstallModeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ExtensionInstallMode::UNKNOWN), "UNKNOWN" }, + { static_cast(ExtensionInstallMode::REPOSITORY), "REPOSITORY" }, + { static_cast(ExtensionInstallMode::CUSTOM_PATH), "CUSTOM_PATH" }, + { static_cast(ExtensionInstallMode::STATICALLY_LINKED), "STATICALLY_LINKED" }, + { static_cast(ExtensionInstallMode::NOT_INSTALLED), "NOT_INSTALLED" } + }; + return values; } template<> const char* EnumUtil::ToChars(ExtensionInstallMode value) { - switch(value) { - case ExtensionInstallMode::UNKNOWN: - return "UNKNOWN"; - case ExtensionInstallMode::REPOSITORY: - return "REPOSITORY"; - case ExtensionInstallMode::CUSTOM_PATH: - return "CUSTOM_PATH"; - case ExtensionInstallMode::STATICALLY_LINKED: - return "STATICALLY_LINKED"; - case ExtensionInstallMode::NOT_INSTALLED: - return "NOT_INSTALLED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetExtensionInstallModeValues(), 5, "ExtensionInstallMode", static_cast(value)); } template<> ExtensionInstallMode EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "UNKNOWN")) { - return ExtensionInstallMode::UNKNOWN; - } - if (StringUtil::Equals(value, "REPOSITORY")) { - return ExtensionInstallMode::REPOSITORY; - } - if (StringUtil::Equals(value, "CUSTOM_PATH")) { - return ExtensionInstallMode::CUSTOM_PATH; - } - if (StringUtil::Equals(value, "STATICALLY_LINKED")) { - return ExtensionInstallMode::STATICALLY_LINKED; - } - if (StringUtil::Equals(value, "NOT_INSTALLED")) { - return ExtensionInstallMode::NOT_INSTALLED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetExtensionInstallModeValues(), 5, "ExtensionInstallMode", value)); +} + +const StringUtil::EnumStringLiteral *GetExtensionLoadResultValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ExtensionLoadResult::LOADED_EXTENSION), "LOADED_EXTENSION" }, + { static_cast(ExtensionLoadResult::EXTENSION_UNKNOWN), "EXTENSION_UNKNOWN" }, + { static_cast(ExtensionLoadResult::NOT_LOADED), "NOT_LOADED" } + }; + return values; } template<> const char* EnumUtil::ToChars(ExtensionLoadResult value) { - switch(value) { - case ExtensionLoadResult::LOADED_EXTENSION: - return "LOADED_EXTENSION"; - case ExtensionLoadResult::EXTENSION_UNKNOWN: - return "EXTENSION_UNKNOWN"; - case ExtensionLoadResult::NOT_LOADED: - return "NOT_LOADED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetExtensionLoadResultValues(), 3, "ExtensionLoadResult", static_cast(value)); } template<> ExtensionLoadResult EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "LOADED_EXTENSION")) { - return ExtensionLoadResult::LOADED_EXTENSION; - } - if (StringUtil::Equals(value, "EXTENSION_UNKNOWN")) { - return ExtensionLoadResult::EXTENSION_UNKNOWN; - } - if (StringUtil::Equals(value, "NOT_LOADED")) { - return ExtensionLoadResult::NOT_LOADED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetExtensionLoadResultValues(), 3, "ExtensionLoadResult", value)); +} + +const StringUtil::EnumStringLiteral *GetExtensionUpdateResultTagValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ExtensionUpdateResultTag::UNKNOWN), "UNKNOWN" }, + { static_cast(ExtensionUpdateResultTag::NO_UPDATE_AVAILABLE), "NO_UPDATE_AVAILABLE" }, + { static_cast(ExtensionUpdateResultTag::NOT_A_REPOSITORY), "NOT_A_REPOSITORY" }, + { static_cast(ExtensionUpdateResultTag::NOT_INSTALLED), "NOT_INSTALLED" }, + { static_cast(ExtensionUpdateResultTag::STATICALLY_LOADED), "STATICALLY_LOADED" }, + { static_cast(ExtensionUpdateResultTag::MISSING_INSTALL_INFO), "MISSING_INSTALL_INFO" }, + { static_cast(ExtensionUpdateResultTag::REDOWNLOADED), "REDOWNLOADED" }, + { static_cast(ExtensionUpdateResultTag::UPDATED), "UPDATED" } + }; + return values; } template<> const char* EnumUtil::ToChars(ExtensionUpdateResultTag value) { - switch(value) { - case ExtensionUpdateResultTag::UNKNOWN: - return "UNKNOWN"; - case ExtensionUpdateResultTag::NO_UPDATE_AVAILABLE: - return "NO_UPDATE_AVAILABLE"; - case ExtensionUpdateResultTag::NOT_A_REPOSITORY: - return "NOT_A_REPOSITORY"; - case ExtensionUpdateResultTag::NOT_INSTALLED: - return "NOT_INSTALLED"; - case ExtensionUpdateResultTag::STATICALLY_LOADED: - return "STATICALLY_LOADED"; - case ExtensionUpdateResultTag::MISSING_INSTALL_INFO: - return "MISSING_INSTALL_INFO"; - case ExtensionUpdateResultTag::REDOWNLOADED: - return "REDOWNLOADED"; - case ExtensionUpdateResultTag::UPDATED: - return "UPDATED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetExtensionUpdateResultTagValues(), 8, "ExtensionUpdateResultTag", static_cast(value)); } template<> ExtensionUpdateResultTag EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "UNKNOWN")) { - return ExtensionUpdateResultTag::UNKNOWN; - } - if (StringUtil::Equals(value, "NO_UPDATE_AVAILABLE")) { - return ExtensionUpdateResultTag::NO_UPDATE_AVAILABLE; - } - if (StringUtil::Equals(value, "NOT_A_REPOSITORY")) { - return ExtensionUpdateResultTag::NOT_A_REPOSITORY; - } - if (StringUtil::Equals(value, "NOT_INSTALLED")) { - return ExtensionUpdateResultTag::NOT_INSTALLED; - } - if (StringUtil::Equals(value, "STATICALLY_LOADED")) { - return ExtensionUpdateResultTag::STATICALLY_LOADED; - } - if (StringUtil::Equals(value, "MISSING_INSTALL_INFO")) { - return ExtensionUpdateResultTag::MISSING_INSTALL_INFO; - } - if (StringUtil::Equals(value, "REDOWNLOADED")) { - return ExtensionUpdateResultTag::REDOWNLOADED; - } - if (StringUtil::Equals(value, "UPDATED")) { - return ExtensionUpdateResultTag::UPDATED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetExtensionUpdateResultTagValues(), 8, "ExtensionUpdateResultTag", value)); +} + +const StringUtil::EnumStringLiteral *GetExtraDropInfoTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ExtraDropInfoType::INVALID), "INVALID" }, + { static_cast(ExtraDropInfoType::SECRET_INFO), "SECRET_INFO" } + }; + return values; } template<> const char* EnumUtil::ToChars(ExtraDropInfoType value) { - switch(value) { - case ExtraDropInfoType::INVALID: - return "INVALID"; - case ExtraDropInfoType::SECRET_INFO: - return "SECRET_INFO"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetExtraDropInfoTypeValues(), 2, "ExtraDropInfoType", static_cast(value)); } template<> ExtraDropInfoType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return ExtraDropInfoType::INVALID; - } - if (StringUtil::Equals(value, "SECRET_INFO")) { - return ExtraDropInfoType::SECRET_INFO; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetExtraDropInfoTypeValues(), 2, "ExtraDropInfoType", value)); +} + +const StringUtil::EnumStringLiteral *GetExtraTypeInfoTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ExtraTypeInfoType::INVALID_TYPE_INFO), "INVALID_TYPE_INFO" }, + { static_cast(ExtraTypeInfoType::GENERIC_TYPE_INFO), "GENERIC_TYPE_INFO" }, + { static_cast(ExtraTypeInfoType::DECIMAL_TYPE_INFO), "DECIMAL_TYPE_INFO" }, + { static_cast(ExtraTypeInfoType::STRING_TYPE_INFO), "STRING_TYPE_INFO" }, + { 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::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" }, + { static_cast(ExtraTypeInfoType::INTEGER_LITERAL_TYPE_INFO), "INTEGER_LITERAL_TYPE_INFO" } + }; + return values; } template<> const char* EnumUtil::ToChars(ExtraTypeInfoType value) { - switch(value) { - case ExtraTypeInfoType::INVALID_TYPE_INFO: - return "INVALID_TYPE_INFO"; - case ExtraTypeInfoType::GENERIC_TYPE_INFO: - return "GENERIC_TYPE_INFO"; - case ExtraTypeInfoType::DECIMAL_TYPE_INFO: - return "DECIMAL_TYPE_INFO"; - case ExtraTypeInfoType::STRING_TYPE_INFO: - return "STRING_TYPE_INFO"; - case ExtraTypeInfoType::LIST_TYPE_INFO: - return "LIST_TYPE_INFO"; - case ExtraTypeInfoType::STRUCT_TYPE_INFO: - return "STRUCT_TYPE_INFO"; - case ExtraTypeInfoType::ENUM_TYPE_INFO: - return "ENUM_TYPE_INFO"; - case ExtraTypeInfoType::USER_TYPE_INFO: - return "USER_TYPE_INFO"; - case ExtraTypeInfoType::AGGREGATE_STATE_TYPE_INFO: - return "AGGREGATE_STATE_TYPE_INFO"; - case ExtraTypeInfoType::ARRAY_TYPE_INFO: - return "ARRAY_TYPE_INFO"; - case ExtraTypeInfoType::ANY_TYPE_INFO: - return "ANY_TYPE_INFO"; - case ExtraTypeInfoType::INTEGER_LITERAL_TYPE_INFO: - return "INTEGER_LITERAL_TYPE_INFO"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetExtraTypeInfoTypeValues(), 12, "ExtraTypeInfoType", static_cast(value)); } template<> ExtraTypeInfoType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID_TYPE_INFO")) { - return ExtraTypeInfoType::INVALID_TYPE_INFO; - } - if (StringUtil::Equals(value, "GENERIC_TYPE_INFO")) { - return ExtraTypeInfoType::GENERIC_TYPE_INFO; - } - if (StringUtil::Equals(value, "DECIMAL_TYPE_INFO")) { - return ExtraTypeInfoType::DECIMAL_TYPE_INFO; - } - if (StringUtil::Equals(value, "STRING_TYPE_INFO")) { - return ExtraTypeInfoType::STRING_TYPE_INFO; - } - if (StringUtil::Equals(value, "LIST_TYPE_INFO")) { - return ExtraTypeInfoType::LIST_TYPE_INFO; - } - if (StringUtil::Equals(value, "STRUCT_TYPE_INFO")) { - return ExtraTypeInfoType::STRUCT_TYPE_INFO; - } - if (StringUtil::Equals(value, "ENUM_TYPE_INFO")) { - return ExtraTypeInfoType::ENUM_TYPE_INFO; - } - if (StringUtil::Equals(value, "USER_TYPE_INFO")) { - return ExtraTypeInfoType::USER_TYPE_INFO; - } - if (StringUtil::Equals(value, "AGGREGATE_STATE_TYPE_INFO")) { - return ExtraTypeInfoType::AGGREGATE_STATE_TYPE_INFO; - } - if (StringUtil::Equals(value, "ARRAY_TYPE_INFO")) { - return ExtraTypeInfoType::ARRAY_TYPE_INFO; - } - if (StringUtil::Equals(value, "ANY_TYPE_INFO")) { - return ExtraTypeInfoType::ANY_TYPE_INFO; - } - if (StringUtil::Equals(value, "INTEGER_LITERAL_TYPE_INFO")) { - return ExtraTypeInfoType::INTEGER_LITERAL_TYPE_INFO; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetExtraTypeInfoTypeValues(), 12, "ExtraTypeInfoType", value)); +} + +const StringUtil::EnumStringLiteral *GetFileBufferTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(FileBufferType::BLOCK), "BLOCK" }, + { static_cast(FileBufferType::MANAGED_BUFFER), "MANAGED_BUFFER" }, + { static_cast(FileBufferType::TINY_BUFFER), "TINY_BUFFER" } + }; + return values; } template<> const char* EnumUtil::ToChars(FileBufferType value) { - switch(value) { - case FileBufferType::BLOCK: - return "BLOCK"; - case FileBufferType::MANAGED_BUFFER: - return "MANAGED_BUFFER"; - case FileBufferType::TINY_BUFFER: - return "TINY_BUFFER"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetFileBufferTypeValues(), 3, "FileBufferType", static_cast(value)); } template<> FileBufferType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "BLOCK")) { - return FileBufferType::BLOCK; - } - if (StringUtil::Equals(value, "MANAGED_BUFFER")) { - return FileBufferType::MANAGED_BUFFER; - } - if (StringUtil::Equals(value, "TINY_BUFFER")) { - return FileBufferType::TINY_BUFFER; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetFileBufferTypeValues(), 3, "FileBufferType", value)); +} + +const StringUtil::EnumStringLiteral *GetFileCompressionTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(FileCompressionType::AUTO_DETECT), "AUTO_DETECT" }, + { static_cast(FileCompressionType::UNCOMPRESSED), "UNCOMPRESSED" }, + { static_cast(FileCompressionType::GZIP), "GZIP" }, + { static_cast(FileCompressionType::ZSTD), "ZSTD" } + }; + return values; } template<> const char* EnumUtil::ToChars(FileCompressionType value) { - switch(value) { - case FileCompressionType::AUTO_DETECT: - return "AUTO_DETECT"; - case FileCompressionType::UNCOMPRESSED: - return "UNCOMPRESSED"; - case FileCompressionType::GZIP: - return "GZIP"; - case FileCompressionType::ZSTD: - return "ZSTD"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetFileCompressionTypeValues(), 4, "FileCompressionType", static_cast(value)); } template<> FileCompressionType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "AUTO_DETECT")) { - return FileCompressionType::AUTO_DETECT; - } - if (StringUtil::Equals(value, "UNCOMPRESSED")) { - return FileCompressionType::UNCOMPRESSED; - } - if (StringUtil::Equals(value, "GZIP")) { - return FileCompressionType::GZIP; - } - if (StringUtil::Equals(value, "ZSTD")) { - return FileCompressionType::ZSTD; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetFileCompressionTypeValues(), 4, "FileCompressionType", value)); +} + +const StringUtil::EnumStringLiteral *GetFileExpandResultValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(FileExpandResult::NO_FILES), "NO_FILES" }, + { static_cast(FileExpandResult::SINGLE_FILE), "SINGLE_FILE" }, + { static_cast(FileExpandResult::MULTIPLE_FILES), "MULTIPLE_FILES" } + }; + return values; } template<> const char* EnumUtil::ToChars(FileExpandResult value) { - switch(value) { - case FileExpandResult::NO_FILES: - return "NO_FILES"; - case FileExpandResult::SINGLE_FILE: - return "SINGLE_FILE"; - case FileExpandResult::MULTIPLE_FILES: - return "MULTIPLE_FILES"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetFileExpandResultValues(), 3, "FileExpandResult", static_cast(value)); } template<> FileExpandResult EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NO_FILES")) { - return FileExpandResult::NO_FILES; - } - if (StringUtil::Equals(value, "SINGLE_FILE")) { - return FileExpandResult::SINGLE_FILE; - } - if (StringUtil::Equals(value, "MULTIPLE_FILES")) { - return FileExpandResult::MULTIPLE_FILES; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetFileExpandResultValues(), 3, "FileExpandResult", value)); +} + +const StringUtil::EnumStringLiteral *GetFileGlobOptionsValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(FileGlobOptions::DISALLOW_EMPTY), "DISALLOW_EMPTY" }, + { static_cast(FileGlobOptions::ALLOW_EMPTY), "ALLOW_EMPTY" } + }; + return values; } template<> const char* EnumUtil::ToChars(FileGlobOptions value) { - switch(value) { - case FileGlobOptions::DISALLOW_EMPTY: - return "DISALLOW_EMPTY"; - case FileGlobOptions::ALLOW_EMPTY: - return "ALLOW_EMPTY"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetFileGlobOptionsValues(), 2, "FileGlobOptions", static_cast(value)); } template<> FileGlobOptions EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "DISALLOW_EMPTY")) { - return FileGlobOptions::DISALLOW_EMPTY; - } - if (StringUtil::Equals(value, "ALLOW_EMPTY")) { - return FileGlobOptions::ALLOW_EMPTY; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetFileGlobOptionsValues(), 2, "FileGlobOptions", value)); +} + +const StringUtil::EnumStringLiteral *GetFileLockTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(FileLockType::NO_LOCK), "NO_LOCK" }, + { static_cast(FileLockType::READ_LOCK), "READ_LOCK" }, + { static_cast(FileLockType::WRITE_LOCK), "WRITE_LOCK" } + }; + return values; } template<> const char* EnumUtil::ToChars(FileLockType value) { - switch(value) { - case FileLockType::NO_LOCK: - return "NO_LOCK"; - case FileLockType::READ_LOCK: - return "READ_LOCK"; - case FileLockType::WRITE_LOCK: - return "WRITE_LOCK"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetFileLockTypeValues(), 3, "FileLockType", static_cast(value)); } template<> FileLockType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NO_LOCK")) { - return FileLockType::NO_LOCK; - } - if (StringUtil::Equals(value, "READ_LOCK")) { - return FileLockType::READ_LOCK; - } - if (StringUtil::Equals(value, "WRITE_LOCK")) { - return FileLockType::WRITE_LOCK; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetFileLockTypeValues(), 3, "FileLockType", value)); +} + +const StringUtil::EnumStringLiteral *GetFilterPropagateResultValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(FilterPropagateResult::NO_PRUNING_POSSIBLE), "NO_PRUNING_POSSIBLE" }, + { static_cast(FilterPropagateResult::FILTER_ALWAYS_TRUE), "FILTER_ALWAYS_TRUE" }, + { static_cast(FilterPropagateResult::FILTER_ALWAYS_FALSE), "FILTER_ALWAYS_FALSE" }, + { static_cast(FilterPropagateResult::FILTER_TRUE_OR_NULL), "FILTER_TRUE_OR_NULL" }, + { static_cast(FilterPropagateResult::FILTER_FALSE_OR_NULL), "FILTER_FALSE_OR_NULL" } + }; + return values; } template<> const char* EnumUtil::ToChars(FilterPropagateResult value) { - switch(value) { - case FilterPropagateResult::NO_PRUNING_POSSIBLE: - return "NO_PRUNING_POSSIBLE"; - case FilterPropagateResult::FILTER_ALWAYS_TRUE: - return "FILTER_ALWAYS_TRUE"; - case FilterPropagateResult::FILTER_ALWAYS_FALSE: - return "FILTER_ALWAYS_FALSE"; - case FilterPropagateResult::FILTER_TRUE_OR_NULL: - return "FILTER_TRUE_OR_NULL"; - case FilterPropagateResult::FILTER_FALSE_OR_NULL: - return "FILTER_FALSE_OR_NULL"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetFilterPropagateResultValues(), 5, "FilterPropagateResult", static_cast(value)); } template<> FilterPropagateResult EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NO_PRUNING_POSSIBLE")) { - return FilterPropagateResult::NO_PRUNING_POSSIBLE; - } - if (StringUtil::Equals(value, "FILTER_ALWAYS_TRUE")) { - return FilterPropagateResult::FILTER_ALWAYS_TRUE; - } - if (StringUtil::Equals(value, "FILTER_ALWAYS_FALSE")) { - return FilterPropagateResult::FILTER_ALWAYS_FALSE; - } - if (StringUtil::Equals(value, "FILTER_TRUE_OR_NULL")) { - return FilterPropagateResult::FILTER_TRUE_OR_NULL; - } - if (StringUtil::Equals(value, "FILTER_FALSE_OR_NULL")) { - return FilterPropagateResult::FILTER_FALSE_OR_NULL; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetFilterPropagateResultValues(), 5, "FilterPropagateResult", value)); +} + +const StringUtil::EnumStringLiteral *GetForeignKeyTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ForeignKeyType::FK_TYPE_PRIMARY_KEY_TABLE), "FK_TYPE_PRIMARY_KEY_TABLE" }, + { static_cast(ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE), "FK_TYPE_FOREIGN_KEY_TABLE" }, + { static_cast(ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE), "FK_TYPE_SELF_REFERENCE_TABLE" } + }; + return values; } template<> const char* EnumUtil::ToChars(ForeignKeyType value) { - switch(value) { - case ForeignKeyType::FK_TYPE_PRIMARY_KEY_TABLE: - return "FK_TYPE_PRIMARY_KEY_TABLE"; - case ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE: - return "FK_TYPE_FOREIGN_KEY_TABLE"; - case ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE: - return "FK_TYPE_SELF_REFERENCE_TABLE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetForeignKeyTypeValues(), 3, "ForeignKeyType", static_cast(value)); } template<> ForeignKeyType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "FK_TYPE_PRIMARY_KEY_TABLE")) { - return ForeignKeyType::FK_TYPE_PRIMARY_KEY_TABLE; - } - if (StringUtil::Equals(value, "FK_TYPE_FOREIGN_KEY_TABLE")) { - return ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE; - } - if (StringUtil::Equals(value, "FK_TYPE_SELF_REFERENCE_TABLE")) { - return ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetForeignKeyTypeValues(), 3, "ForeignKeyType", value)); +} + +const StringUtil::EnumStringLiteral *GetFunctionNullHandlingValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(FunctionNullHandling::DEFAULT_NULL_HANDLING), "DEFAULT_NULL_HANDLING" }, + { static_cast(FunctionNullHandling::SPECIAL_HANDLING), "SPECIAL_HANDLING" } + }; + return values; } template<> const char* EnumUtil::ToChars(FunctionNullHandling value) { - switch(value) { - case FunctionNullHandling::DEFAULT_NULL_HANDLING: - return "DEFAULT_NULL_HANDLING"; - case FunctionNullHandling::SPECIAL_HANDLING: - return "SPECIAL_HANDLING"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetFunctionNullHandlingValues(), 2, "FunctionNullHandling", static_cast(value)); } template<> FunctionNullHandling EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "DEFAULT_NULL_HANDLING")) { - return FunctionNullHandling::DEFAULT_NULL_HANDLING; - } - if (StringUtil::Equals(value, "SPECIAL_HANDLING")) { - return FunctionNullHandling::SPECIAL_HANDLING; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetFunctionNullHandlingValues(), 2, "FunctionNullHandling", value)); +} + +const StringUtil::EnumStringLiteral *GetFunctionStabilityValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(FunctionStability::CONSISTENT), "CONSISTENT" }, + { static_cast(FunctionStability::VOLATILE), "VOLATILE" }, + { static_cast(FunctionStability::CONSISTENT_WITHIN_QUERY), "CONSISTENT_WITHIN_QUERY" } + }; + return values; } template<> const char* EnumUtil::ToChars(FunctionStability value) { - switch(value) { - case FunctionStability::CONSISTENT: - return "CONSISTENT"; - case FunctionStability::VOLATILE: - return "VOLATILE"; - case FunctionStability::CONSISTENT_WITHIN_QUERY: - return "CONSISTENT_WITHIN_QUERY"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetFunctionStabilityValues(), 3, "FunctionStability", static_cast(value)); } template<> FunctionStability EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "CONSISTENT")) { - return FunctionStability::CONSISTENT; - } - if (StringUtil::Equals(value, "VOLATILE")) { - return FunctionStability::VOLATILE; - } - if (StringUtil::Equals(value, "CONSISTENT_WITHIN_QUERY")) { - return FunctionStability::CONSISTENT_WITHIN_QUERY; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetFunctionStabilityValues(), 3, "FunctionStability", value)); +} + +const StringUtil::EnumStringLiteral *GetGateStatusValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(GateStatus::GATE_NOT_SET), "GATE_NOT_SET" }, + { static_cast(GateStatus::GATE_SET), "GATE_SET" } + }; + return values; } template<> const char* EnumUtil::ToChars(GateStatus value) { - switch(value) { - case GateStatus::GATE_NOT_SET: - return "GATE_NOT_SET"; - case GateStatus::GATE_SET: - return "GATE_SET"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetGateStatusValues(), 2, "GateStatus", static_cast(value)); } template<> GateStatus EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "GATE_NOT_SET")) { - return GateStatus::GATE_NOT_SET; - } - if (StringUtil::Equals(value, "GATE_SET")) { - return GateStatus::GATE_SET; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetGateStatusValues(), 2, "GateStatus", value)); +} + +const StringUtil::EnumStringLiteral *GetHLLStorageTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(HLLStorageType::HLL_V1), "HLL_V1" }, + { static_cast(HLLStorageType::HLL_V2), "HLL_V2" } + }; + return values; } template<> const char* EnumUtil::ToChars(HLLStorageType value) { - switch(value) { - case HLLStorageType::HLL_V1: - return "HLL_V1"; - case HLLStorageType::HLL_V2: - return "HLL_V2"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetHLLStorageTypeValues(), 2, "HLLStorageType", static_cast(value)); } template<> HLLStorageType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "HLL_V1")) { - return HLLStorageType::HLL_V1; - } - if (StringUtil::Equals(value, "HLL_V2")) { - return HLLStorageType::HLL_V2; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetHLLStorageTypeValues(), 2, "HLLStorageType", value)); +} + +const StringUtil::EnumStringLiteral *GetIndexConstraintTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(IndexConstraintType::NONE), "NONE" }, + { static_cast(IndexConstraintType::UNIQUE), "UNIQUE" }, + { static_cast(IndexConstraintType::PRIMARY), "PRIMARY" }, + { static_cast(IndexConstraintType::FOREIGN), "FOREIGN" } + }; + return values; } template<> const char* EnumUtil::ToChars(IndexConstraintType value) { - switch(value) { - case IndexConstraintType::NONE: - return "NONE"; - case IndexConstraintType::UNIQUE: - return "UNIQUE"; - case IndexConstraintType::PRIMARY: - return "PRIMARY"; - case IndexConstraintType::FOREIGN: - return "FOREIGN"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetIndexConstraintTypeValues(), 4, "IndexConstraintType", static_cast(value)); } template<> IndexConstraintType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NONE")) { - return IndexConstraintType::NONE; - } - if (StringUtil::Equals(value, "UNIQUE")) { - return IndexConstraintType::UNIQUE; - } - if (StringUtil::Equals(value, "PRIMARY")) { - return IndexConstraintType::PRIMARY; - } - if (StringUtil::Equals(value, "FOREIGN")) { - return IndexConstraintType::FOREIGN; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetIndexConstraintTypeValues(), 4, "IndexConstraintType", value)); +} + +const StringUtil::EnumStringLiteral *GetInsertColumnOrderValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(InsertColumnOrder::INSERT_BY_POSITION), "INSERT_BY_POSITION" }, + { static_cast(InsertColumnOrder::INSERT_BY_NAME), "INSERT_BY_NAME" } + }; + return values; } template<> const char* EnumUtil::ToChars(InsertColumnOrder value) { - switch(value) { - case InsertColumnOrder::INSERT_BY_POSITION: - return "INSERT_BY_POSITION"; - case InsertColumnOrder::INSERT_BY_NAME: - return "INSERT_BY_NAME"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetInsertColumnOrderValues(), 2, "InsertColumnOrder", static_cast(value)); } template<> InsertColumnOrder EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INSERT_BY_POSITION")) { - return InsertColumnOrder::INSERT_BY_POSITION; - } - if (StringUtil::Equals(value, "INSERT_BY_NAME")) { - return InsertColumnOrder::INSERT_BY_NAME; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetInsertColumnOrderValues(), 2, "InsertColumnOrder", value)); +} + +const StringUtil::EnumStringLiteral *GetInterruptModeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(InterruptMode::NO_INTERRUPTS), "NO_INTERRUPTS" }, + { static_cast(InterruptMode::TASK), "TASK" }, + { static_cast(InterruptMode::BLOCKING), "BLOCKING" } + }; + return values; } template<> const char* EnumUtil::ToChars(InterruptMode value) { - switch(value) { - case InterruptMode::NO_INTERRUPTS: - return "NO_INTERRUPTS"; - case InterruptMode::TASK: - return "TASK"; - case InterruptMode::BLOCKING: - return "BLOCKING"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetInterruptModeValues(), 3, "InterruptMode", static_cast(value)); } template<> InterruptMode EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NO_INTERRUPTS")) { - return InterruptMode::NO_INTERRUPTS; - } - if (StringUtil::Equals(value, "TASK")) { - return InterruptMode::TASK; - } - if (StringUtil::Equals(value, "BLOCKING")) { - return InterruptMode::BLOCKING; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetInterruptModeValues(), 3, "InterruptMode", value)); +} + +const StringUtil::EnumStringLiteral *GetJoinRefTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(JoinRefType::REGULAR), "REGULAR" }, + { static_cast(JoinRefType::NATURAL), "NATURAL" }, + { static_cast(JoinRefType::CROSS), "CROSS" }, + { static_cast(JoinRefType::POSITIONAL), "POSITIONAL" }, + { static_cast(JoinRefType::ASOF), "ASOF" }, + { static_cast(JoinRefType::DEPENDENT), "DEPENDENT" } + }; + return values; } template<> const char* EnumUtil::ToChars(JoinRefType value) { - switch(value) { - case JoinRefType::REGULAR: - return "REGULAR"; - case JoinRefType::NATURAL: - return "NATURAL"; - case JoinRefType::CROSS: - return "CROSS"; - case JoinRefType::POSITIONAL: - return "POSITIONAL"; - case JoinRefType::ASOF: - return "ASOF"; - case JoinRefType::DEPENDENT: - return "DEPENDENT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetJoinRefTypeValues(), 6, "JoinRefType", static_cast(value)); } template<> JoinRefType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "REGULAR")) { - return JoinRefType::REGULAR; - } - if (StringUtil::Equals(value, "NATURAL")) { - return JoinRefType::NATURAL; - } - if (StringUtil::Equals(value, "CROSS")) { - return JoinRefType::CROSS; - } - if (StringUtil::Equals(value, "POSITIONAL")) { - return JoinRefType::POSITIONAL; - } - if (StringUtil::Equals(value, "ASOF")) { - return JoinRefType::ASOF; - } - if (StringUtil::Equals(value, "DEPENDENT")) { - return JoinRefType::DEPENDENT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetJoinRefTypeValues(), 6, "JoinRefType", value)); +} + +const StringUtil::EnumStringLiteral *GetJoinTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(JoinType::INVALID), "INVALID" }, + { static_cast(JoinType::LEFT), "LEFT" }, + { static_cast(JoinType::RIGHT), "RIGHT" }, + { static_cast(JoinType::INNER), "INNER" }, + { static_cast(JoinType::OUTER), "FULL" }, + { static_cast(JoinType::SEMI), "SEMI" }, + { static_cast(JoinType::ANTI), "ANTI" }, + { static_cast(JoinType::MARK), "MARK" }, + { static_cast(JoinType::SINGLE), "SINGLE" }, + { static_cast(JoinType::RIGHT_SEMI), "RIGHT_SEMI" }, + { static_cast(JoinType::RIGHT_ANTI), "RIGHT_ANTI" } + }; + return values; } template<> const char* EnumUtil::ToChars(JoinType value) { - switch(value) { - case JoinType::INVALID: - return "INVALID"; - case JoinType::LEFT: - return "LEFT"; - case JoinType::RIGHT: - return "RIGHT"; - case JoinType::INNER: - return "INNER"; - case JoinType::OUTER: - return "FULL"; - case JoinType::SEMI: - return "SEMI"; - case JoinType::ANTI: - return "ANTI"; - case JoinType::MARK: - return "MARK"; - case JoinType::SINGLE: - return "SINGLE"; - case JoinType::RIGHT_SEMI: - return "RIGHT_SEMI"; - case JoinType::RIGHT_ANTI: - return "RIGHT_ANTI"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetJoinTypeValues(), 11, "JoinType", static_cast(value)); } template<> JoinType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return JoinType::INVALID; - } - if (StringUtil::Equals(value, "LEFT")) { - return JoinType::LEFT; - } - if (StringUtil::Equals(value, "RIGHT")) { - return JoinType::RIGHT; - } - if (StringUtil::Equals(value, "INNER")) { - return JoinType::INNER; - } - if (StringUtil::Equals(value, "FULL")) { - return JoinType::OUTER; - } - if (StringUtil::Equals(value, "SEMI")) { - return JoinType::SEMI; - } - if (StringUtil::Equals(value, "ANTI")) { - return JoinType::ANTI; - } - if (StringUtil::Equals(value, "MARK")) { - return JoinType::MARK; - } - if (StringUtil::Equals(value, "SINGLE")) { - return JoinType::SINGLE; - } - if (StringUtil::Equals(value, "RIGHT_SEMI")) { - return JoinType::RIGHT_SEMI; - } - if (StringUtil::Equals(value, "RIGHT_ANTI")) { - return JoinType::RIGHT_ANTI; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetJoinTypeValues(), 11, "JoinType", value)); +} + +const StringUtil::EnumStringLiteral *GetKeywordCategoryValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(KeywordCategory::KEYWORD_RESERVED), "KEYWORD_RESERVED" }, + { static_cast(KeywordCategory::KEYWORD_UNRESERVED), "KEYWORD_UNRESERVED" }, + { static_cast(KeywordCategory::KEYWORD_TYPE_FUNC), "KEYWORD_TYPE_FUNC" }, + { static_cast(KeywordCategory::KEYWORD_COL_NAME), "KEYWORD_COL_NAME" }, + { static_cast(KeywordCategory::KEYWORD_NONE), "KEYWORD_NONE" } + }; + return values; } template<> const char* EnumUtil::ToChars(KeywordCategory value) { - switch(value) { - case KeywordCategory::KEYWORD_RESERVED: - return "KEYWORD_RESERVED"; - case KeywordCategory::KEYWORD_UNRESERVED: - return "KEYWORD_UNRESERVED"; - case KeywordCategory::KEYWORD_TYPE_FUNC: - return "KEYWORD_TYPE_FUNC"; - case KeywordCategory::KEYWORD_COL_NAME: - return "KEYWORD_COL_NAME"; - case KeywordCategory::KEYWORD_NONE: - return "KEYWORD_NONE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetKeywordCategoryValues(), 5, "KeywordCategory", static_cast(value)); } template<> KeywordCategory EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "KEYWORD_RESERVED")) { - return KeywordCategory::KEYWORD_RESERVED; - } - if (StringUtil::Equals(value, "KEYWORD_UNRESERVED")) { - return KeywordCategory::KEYWORD_UNRESERVED; - } - if (StringUtil::Equals(value, "KEYWORD_TYPE_FUNC")) { - return KeywordCategory::KEYWORD_TYPE_FUNC; - } - if (StringUtil::Equals(value, "KEYWORD_COL_NAME")) { - return KeywordCategory::KEYWORD_COL_NAME; - } - if (StringUtil::Equals(value, "KEYWORD_NONE")) { - return KeywordCategory::KEYWORD_NONE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetKeywordCategoryValues(), 5, "KeywordCategory", value)); +} + +const StringUtil::EnumStringLiteral *GetLimitNodeTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(LimitNodeType::UNSET), "UNSET" }, + { static_cast(LimitNodeType::CONSTANT_VALUE), "CONSTANT_VALUE" }, + { static_cast(LimitNodeType::CONSTANT_PERCENTAGE), "CONSTANT_PERCENTAGE" }, + { static_cast(LimitNodeType::EXPRESSION_VALUE), "EXPRESSION_VALUE" }, + { static_cast(LimitNodeType::EXPRESSION_PERCENTAGE), "EXPRESSION_PERCENTAGE" } + }; + return values; } template<> const char* EnumUtil::ToChars(LimitNodeType value) { - switch(value) { - case LimitNodeType::UNSET: - return "UNSET"; - case LimitNodeType::CONSTANT_VALUE: - return "CONSTANT_VALUE"; - case LimitNodeType::CONSTANT_PERCENTAGE: - return "CONSTANT_PERCENTAGE"; - case LimitNodeType::EXPRESSION_VALUE: - return "EXPRESSION_VALUE"; - case LimitNodeType::EXPRESSION_PERCENTAGE: - return "EXPRESSION_PERCENTAGE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetLimitNodeTypeValues(), 5, "LimitNodeType", static_cast(value)); } template<> LimitNodeType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "UNSET")) { - return LimitNodeType::UNSET; - } - if (StringUtil::Equals(value, "CONSTANT_VALUE")) { - return LimitNodeType::CONSTANT_VALUE; - } - if (StringUtil::Equals(value, "CONSTANT_PERCENTAGE")) { - return LimitNodeType::CONSTANT_PERCENTAGE; - } - if (StringUtil::Equals(value, "EXPRESSION_VALUE")) { - return LimitNodeType::EXPRESSION_VALUE; - } - if (StringUtil::Equals(value, "EXPRESSION_PERCENTAGE")) { - return LimitNodeType::EXPRESSION_PERCENTAGE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetLimitNodeTypeValues(), 5, "LimitNodeType", value)); +} + +const StringUtil::EnumStringLiteral *GetLoadTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(LoadType::LOAD), "LOAD" }, + { static_cast(LoadType::INSTALL), "INSTALL" }, + { static_cast(LoadType::FORCE_INSTALL), "FORCE_INSTALL" } + }; + return values; } template<> const char* EnumUtil::ToChars(LoadType value) { - switch(value) { - case LoadType::LOAD: - return "LOAD"; - case LoadType::INSTALL: - return "INSTALL"; - case LoadType::FORCE_INSTALL: - return "FORCE_INSTALL"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetLoadTypeValues(), 3, "LoadType", static_cast(value)); } template<> LoadType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "LOAD")) { - return LoadType::LOAD; - } - if (StringUtil::Equals(value, "INSTALL")) { - return LoadType::INSTALL; - } - if (StringUtil::Equals(value, "FORCE_INSTALL")) { - return LoadType::FORCE_INSTALL; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetLoadTypeValues(), 3, "LoadType", value)); +} + +const StringUtil::EnumStringLiteral *GetLogicalOperatorTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(LogicalOperatorType::LOGICAL_INVALID), "LOGICAL_INVALID" }, + { static_cast(LogicalOperatorType::LOGICAL_PROJECTION), "LOGICAL_PROJECTION" }, + { static_cast(LogicalOperatorType::LOGICAL_FILTER), "LOGICAL_FILTER" }, + { static_cast(LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY), "LOGICAL_AGGREGATE_AND_GROUP_BY" }, + { static_cast(LogicalOperatorType::LOGICAL_WINDOW), "LOGICAL_WINDOW" }, + { static_cast(LogicalOperatorType::LOGICAL_UNNEST), "LOGICAL_UNNEST" }, + { static_cast(LogicalOperatorType::LOGICAL_LIMIT), "LOGICAL_LIMIT" }, + { static_cast(LogicalOperatorType::LOGICAL_ORDER_BY), "LOGICAL_ORDER_BY" }, + { static_cast(LogicalOperatorType::LOGICAL_TOP_N), "LOGICAL_TOP_N" }, + { static_cast(LogicalOperatorType::LOGICAL_COPY_TO_FILE), "LOGICAL_COPY_TO_FILE" }, + { static_cast(LogicalOperatorType::LOGICAL_DISTINCT), "LOGICAL_DISTINCT" }, + { static_cast(LogicalOperatorType::LOGICAL_SAMPLE), "LOGICAL_SAMPLE" }, + { static_cast(LogicalOperatorType::LOGICAL_PIVOT), "LOGICAL_PIVOT" }, + { static_cast(LogicalOperatorType::LOGICAL_COPY_DATABASE), "LOGICAL_COPY_DATABASE" }, + { static_cast(LogicalOperatorType::LOGICAL_GET), "LOGICAL_GET" }, + { static_cast(LogicalOperatorType::LOGICAL_CHUNK_GET), "LOGICAL_CHUNK_GET" }, + { static_cast(LogicalOperatorType::LOGICAL_DELIM_GET), "LOGICAL_DELIM_GET" }, + { static_cast(LogicalOperatorType::LOGICAL_EXPRESSION_GET), "LOGICAL_EXPRESSION_GET" }, + { static_cast(LogicalOperatorType::LOGICAL_DUMMY_SCAN), "LOGICAL_DUMMY_SCAN" }, + { static_cast(LogicalOperatorType::LOGICAL_EMPTY_RESULT), "LOGICAL_EMPTY_RESULT" }, + { static_cast(LogicalOperatorType::LOGICAL_CTE_REF), "LOGICAL_CTE_REF" }, + { static_cast(LogicalOperatorType::LOGICAL_JOIN), "LOGICAL_JOIN" }, + { static_cast(LogicalOperatorType::LOGICAL_DELIM_JOIN), "LOGICAL_DELIM_JOIN" }, + { static_cast(LogicalOperatorType::LOGICAL_COMPARISON_JOIN), "LOGICAL_COMPARISON_JOIN" }, + { static_cast(LogicalOperatorType::LOGICAL_ANY_JOIN), "LOGICAL_ANY_JOIN" }, + { static_cast(LogicalOperatorType::LOGICAL_CROSS_PRODUCT), "LOGICAL_CROSS_PRODUCT" }, + { static_cast(LogicalOperatorType::LOGICAL_POSITIONAL_JOIN), "LOGICAL_POSITIONAL_JOIN" }, + { static_cast(LogicalOperatorType::LOGICAL_ASOF_JOIN), "LOGICAL_ASOF_JOIN" }, + { static_cast(LogicalOperatorType::LOGICAL_DEPENDENT_JOIN), "LOGICAL_DEPENDENT_JOIN" }, + { static_cast(LogicalOperatorType::LOGICAL_UNION), "LOGICAL_UNION" }, + { static_cast(LogicalOperatorType::LOGICAL_EXCEPT), "LOGICAL_EXCEPT" }, + { static_cast(LogicalOperatorType::LOGICAL_INTERSECT), "LOGICAL_INTERSECT" }, + { static_cast(LogicalOperatorType::LOGICAL_RECURSIVE_CTE), "LOGICAL_RECURSIVE_CTE" }, + { static_cast(LogicalOperatorType::LOGICAL_MATERIALIZED_CTE), "LOGICAL_MATERIALIZED_CTE" }, + { static_cast(LogicalOperatorType::LOGICAL_INSERT), "LOGICAL_INSERT" }, + { static_cast(LogicalOperatorType::LOGICAL_DELETE), "LOGICAL_DELETE" }, + { static_cast(LogicalOperatorType::LOGICAL_UPDATE), "LOGICAL_UPDATE" }, + { static_cast(LogicalOperatorType::LOGICAL_ALTER), "LOGICAL_ALTER" }, + { static_cast(LogicalOperatorType::LOGICAL_CREATE_TABLE), "LOGICAL_CREATE_TABLE" }, + { static_cast(LogicalOperatorType::LOGICAL_CREATE_INDEX), "LOGICAL_CREATE_INDEX" }, + { static_cast(LogicalOperatorType::LOGICAL_CREATE_SEQUENCE), "LOGICAL_CREATE_SEQUENCE" }, + { static_cast(LogicalOperatorType::LOGICAL_CREATE_VIEW), "LOGICAL_CREATE_VIEW" }, + { static_cast(LogicalOperatorType::LOGICAL_CREATE_SCHEMA), "LOGICAL_CREATE_SCHEMA" }, + { static_cast(LogicalOperatorType::LOGICAL_CREATE_MACRO), "LOGICAL_CREATE_MACRO" }, + { static_cast(LogicalOperatorType::LOGICAL_DROP), "LOGICAL_DROP" }, + { static_cast(LogicalOperatorType::LOGICAL_PRAGMA), "LOGICAL_PRAGMA" }, + { static_cast(LogicalOperatorType::LOGICAL_TRANSACTION), "LOGICAL_TRANSACTION" }, + { static_cast(LogicalOperatorType::LOGICAL_CREATE_TYPE), "LOGICAL_CREATE_TYPE" }, + { static_cast(LogicalOperatorType::LOGICAL_ATTACH), "LOGICAL_ATTACH" }, + { static_cast(LogicalOperatorType::LOGICAL_DETACH), "LOGICAL_DETACH" }, + { static_cast(LogicalOperatorType::LOGICAL_EXPLAIN), "LOGICAL_EXPLAIN" }, + { static_cast(LogicalOperatorType::LOGICAL_PREPARE), "LOGICAL_PREPARE" }, + { static_cast(LogicalOperatorType::LOGICAL_EXECUTE), "LOGICAL_EXECUTE" }, + { static_cast(LogicalOperatorType::LOGICAL_EXPORT), "LOGICAL_EXPORT" }, + { static_cast(LogicalOperatorType::LOGICAL_VACUUM), "LOGICAL_VACUUM" }, + { static_cast(LogicalOperatorType::LOGICAL_SET), "LOGICAL_SET" }, + { static_cast(LogicalOperatorType::LOGICAL_LOAD), "LOGICAL_LOAD" }, + { static_cast(LogicalOperatorType::LOGICAL_RESET), "LOGICAL_RESET" }, + { static_cast(LogicalOperatorType::LOGICAL_UPDATE_EXTENSIONS), "LOGICAL_UPDATE_EXTENSIONS" }, + { static_cast(LogicalOperatorType::LOGICAL_CREATE_SECRET), "LOGICAL_CREATE_SECRET" }, + { static_cast(LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR), "LOGICAL_EXTENSION_OPERATOR" } + }; + return values; } template<> const char* EnumUtil::ToChars(LogicalOperatorType value) { - switch(value) { - case LogicalOperatorType::LOGICAL_INVALID: - return "LOGICAL_INVALID"; - case LogicalOperatorType::LOGICAL_PROJECTION: - return "LOGICAL_PROJECTION"; - case LogicalOperatorType::LOGICAL_FILTER: - return "LOGICAL_FILTER"; - case LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY: - return "LOGICAL_AGGREGATE_AND_GROUP_BY"; - case LogicalOperatorType::LOGICAL_WINDOW: - return "LOGICAL_WINDOW"; - case LogicalOperatorType::LOGICAL_UNNEST: - return "LOGICAL_UNNEST"; - case LogicalOperatorType::LOGICAL_LIMIT: - return "LOGICAL_LIMIT"; - case LogicalOperatorType::LOGICAL_ORDER_BY: - return "LOGICAL_ORDER_BY"; - case LogicalOperatorType::LOGICAL_TOP_N: - return "LOGICAL_TOP_N"; - case LogicalOperatorType::LOGICAL_COPY_TO_FILE: - return "LOGICAL_COPY_TO_FILE"; - case LogicalOperatorType::LOGICAL_DISTINCT: - return "LOGICAL_DISTINCT"; - case LogicalOperatorType::LOGICAL_SAMPLE: - return "LOGICAL_SAMPLE"; - case LogicalOperatorType::LOGICAL_PIVOT: - return "LOGICAL_PIVOT"; - case LogicalOperatorType::LOGICAL_COPY_DATABASE: - return "LOGICAL_COPY_DATABASE"; - case LogicalOperatorType::LOGICAL_GET: - return "LOGICAL_GET"; - case LogicalOperatorType::LOGICAL_CHUNK_GET: - return "LOGICAL_CHUNK_GET"; - case LogicalOperatorType::LOGICAL_DELIM_GET: - return "LOGICAL_DELIM_GET"; - case LogicalOperatorType::LOGICAL_EXPRESSION_GET: - return "LOGICAL_EXPRESSION_GET"; - case LogicalOperatorType::LOGICAL_DUMMY_SCAN: - return "LOGICAL_DUMMY_SCAN"; - case LogicalOperatorType::LOGICAL_EMPTY_RESULT: - return "LOGICAL_EMPTY_RESULT"; - case LogicalOperatorType::LOGICAL_CTE_REF: - return "LOGICAL_CTE_REF"; - case LogicalOperatorType::LOGICAL_JOIN: - return "LOGICAL_JOIN"; - case LogicalOperatorType::LOGICAL_DELIM_JOIN: - return "LOGICAL_DELIM_JOIN"; - case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: - return "LOGICAL_COMPARISON_JOIN"; - case LogicalOperatorType::LOGICAL_ANY_JOIN: - return "LOGICAL_ANY_JOIN"; - case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: - return "LOGICAL_CROSS_PRODUCT"; - case LogicalOperatorType::LOGICAL_POSITIONAL_JOIN: - return "LOGICAL_POSITIONAL_JOIN"; - case LogicalOperatorType::LOGICAL_ASOF_JOIN: - return "LOGICAL_ASOF_JOIN"; - case LogicalOperatorType::LOGICAL_DEPENDENT_JOIN: - return "LOGICAL_DEPENDENT_JOIN"; - case LogicalOperatorType::LOGICAL_UNION: - return "LOGICAL_UNION"; - case LogicalOperatorType::LOGICAL_EXCEPT: - return "LOGICAL_EXCEPT"; - case LogicalOperatorType::LOGICAL_INTERSECT: - return "LOGICAL_INTERSECT"; - case LogicalOperatorType::LOGICAL_RECURSIVE_CTE: - return "LOGICAL_RECURSIVE_CTE"; - case LogicalOperatorType::LOGICAL_MATERIALIZED_CTE: - return "LOGICAL_MATERIALIZED_CTE"; - case LogicalOperatorType::LOGICAL_INSERT: - return "LOGICAL_INSERT"; - case LogicalOperatorType::LOGICAL_DELETE: - return "LOGICAL_DELETE"; - case LogicalOperatorType::LOGICAL_UPDATE: - return "LOGICAL_UPDATE"; - case LogicalOperatorType::LOGICAL_ALTER: - return "LOGICAL_ALTER"; - case LogicalOperatorType::LOGICAL_CREATE_TABLE: - return "LOGICAL_CREATE_TABLE"; - case LogicalOperatorType::LOGICAL_CREATE_INDEX: - return "LOGICAL_CREATE_INDEX"; - case LogicalOperatorType::LOGICAL_CREATE_SEQUENCE: - return "LOGICAL_CREATE_SEQUENCE"; - case LogicalOperatorType::LOGICAL_CREATE_VIEW: - return "LOGICAL_CREATE_VIEW"; - case LogicalOperatorType::LOGICAL_CREATE_SCHEMA: - return "LOGICAL_CREATE_SCHEMA"; - case LogicalOperatorType::LOGICAL_CREATE_MACRO: - return "LOGICAL_CREATE_MACRO"; - case LogicalOperatorType::LOGICAL_DROP: - return "LOGICAL_DROP"; - case LogicalOperatorType::LOGICAL_PRAGMA: - return "LOGICAL_PRAGMA"; - case LogicalOperatorType::LOGICAL_TRANSACTION: - return "LOGICAL_TRANSACTION"; - case LogicalOperatorType::LOGICAL_CREATE_TYPE: - return "LOGICAL_CREATE_TYPE"; - case LogicalOperatorType::LOGICAL_ATTACH: - return "LOGICAL_ATTACH"; - case LogicalOperatorType::LOGICAL_DETACH: - return "LOGICAL_DETACH"; - case LogicalOperatorType::LOGICAL_EXPLAIN: - return "LOGICAL_EXPLAIN"; - case LogicalOperatorType::LOGICAL_PREPARE: - return "LOGICAL_PREPARE"; - case LogicalOperatorType::LOGICAL_EXECUTE: - return "LOGICAL_EXECUTE"; - case LogicalOperatorType::LOGICAL_EXPORT: - return "LOGICAL_EXPORT"; - case LogicalOperatorType::LOGICAL_VACUUM: - return "LOGICAL_VACUUM"; - case LogicalOperatorType::LOGICAL_SET: - return "LOGICAL_SET"; - case LogicalOperatorType::LOGICAL_LOAD: - return "LOGICAL_LOAD"; - case LogicalOperatorType::LOGICAL_RESET: - return "LOGICAL_RESET"; - case LogicalOperatorType::LOGICAL_UPDATE_EXTENSIONS: - return "LOGICAL_UPDATE_EXTENSIONS"; - case LogicalOperatorType::LOGICAL_CREATE_SECRET: - return "LOGICAL_CREATE_SECRET"; - case LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR: - return "LOGICAL_EXTENSION_OPERATOR"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetLogicalOperatorTypeValues(), 61, "LogicalOperatorType", static_cast(value)); } template<> LogicalOperatorType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "LOGICAL_INVALID")) { - return LogicalOperatorType::LOGICAL_INVALID; - } - if (StringUtil::Equals(value, "LOGICAL_PROJECTION")) { - return LogicalOperatorType::LOGICAL_PROJECTION; - } - if (StringUtil::Equals(value, "LOGICAL_FILTER")) { - return LogicalOperatorType::LOGICAL_FILTER; - } - if (StringUtil::Equals(value, "LOGICAL_AGGREGATE_AND_GROUP_BY")) { - return LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY; - } - if (StringUtil::Equals(value, "LOGICAL_WINDOW")) { - return LogicalOperatorType::LOGICAL_WINDOW; - } - if (StringUtil::Equals(value, "LOGICAL_UNNEST")) { - return LogicalOperatorType::LOGICAL_UNNEST; - } - if (StringUtil::Equals(value, "LOGICAL_LIMIT")) { - return LogicalOperatorType::LOGICAL_LIMIT; - } - if (StringUtil::Equals(value, "LOGICAL_ORDER_BY")) { - return LogicalOperatorType::LOGICAL_ORDER_BY; - } - if (StringUtil::Equals(value, "LOGICAL_TOP_N")) { - return LogicalOperatorType::LOGICAL_TOP_N; - } - if (StringUtil::Equals(value, "LOGICAL_COPY_TO_FILE")) { - return LogicalOperatorType::LOGICAL_COPY_TO_FILE; - } - if (StringUtil::Equals(value, "LOGICAL_DISTINCT")) { - return LogicalOperatorType::LOGICAL_DISTINCT; - } - if (StringUtil::Equals(value, "LOGICAL_SAMPLE")) { - return LogicalOperatorType::LOGICAL_SAMPLE; - } - if (StringUtil::Equals(value, "LOGICAL_PIVOT")) { - return LogicalOperatorType::LOGICAL_PIVOT; - } - if (StringUtil::Equals(value, "LOGICAL_COPY_DATABASE")) { - return LogicalOperatorType::LOGICAL_COPY_DATABASE; - } - if (StringUtil::Equals(value, "LOGICAL_GET")) { - return LogicalOperatorType::LOGICAL_GET; - } - if (StringUtil::Equals(value, "LOGICAL_CHUNK_GET")) { - return LogicalOperatorType::LOGICAL_CHUNK_GET; - } - if (StringUtil::Equals(value, "LOGICAL_DELIM_GET")) { - return LogicalOperatorType::LOGICAL_DELIM_GET; - } - if (StringUtil::Equals(value, "LOGICAL_EXPRESSION_GET")) { - return LogicalOperatorType::LOGICAL_EXPRESSION_GET; - } - if (StringUtil::Equals(value, "LOGICAL_DUMMY_SCAN")) { - return LogicalOperatorType::LOGICAL_DUMMY_SCAN; - } - if (StringUtil::Equals(value, "LOGICAL_EMPTY_RESULT")) { - return LogicalOperatorType::LOGICAL_EMPTY_RESULT; - } - if (StringUtil::Equals(value, "LOGICAL_CTE_REF")) { - return LogicalOperatorType::LOGICAL_CTE_REF; - } - if (StringUtil::Equals(value, "LOGICAL_JOIN")) { - return LogicalOperatorType::LOGICAL_JOIN; - } - if (StringUtil::Equals(value, "LOGICAL_DELIM_JOIN")) { - return LogicalOperatorType::LOGICAL_DELIM_JOIN; - } - if (StringUtil::Equals(value, "LOGICAL_COMPARISON_JOIN")) { - return LogicalOperatorType::LOGICAL_COMPARISON_JOIN; - } - if (StringUtil::Equals(value, "LOGICAL_ANY_JOIN")) { - return LogicalOperatorType::LOGICAL_ANY_JOIN; - } - if (StringUtil::Equals(value, "LOGICAL_CROSS_PRODUCT")) { - return LogicalOperatorType::LOGICAL_CROSS_PRODUCT; - } - if (StringUtil::Equals(value, "LOGICAL_POSITIONAL_JOIN")) { - return LogicalOperatorType::LOGICAL_POSITIONAL_JOIN; - } - if (StringUtil::Equals(value, "LOGICAL_ASOF_JOIN")) { - return LogicalOperatorType::LOGICAL_ASOF_JOIN; - } - if (StringUtil::Equals(value, "LOGICAL_DEPENDENT_JOIN")) { - return LogicalOperatorType::LOGICAL_DEPENDENT_JOIN; - } - if (StringUtil::Equals(value, "LOGICAL_UNION")) { - return LogicalOperatorType::LOGICAL_UNION; - } - if (StringUtil::Equals(value, "LOGICAL_EXCEPT")) { - return LogicalOperatorType::LOGICAL_EXCEPT; - } - if (StringUtil::Equals(value, "LOGICAL_INTERSECT")) { - return LogicalOperatorType::LOGICAL_INTERSECT; - } - if (StringUtil::Equals(value, "LOGICAL_RECURSIVE_CTE")) { - return LogicalOperatorType::LOGICAL_RECURSIVE_CTE; - } - if (StringUtil::Equals(value, "LOGICAL_MATERIALIZED_CTE")) { - return LogicalOperatorType::LOGICAL_MATERIALIZED_CTE; - } - if (StringUtil::Equals(value, "LOGICAL_INSERT")) { - return LogicalOperatorType::LOGICAL_INSERT; - } - if (StringUtil::Equals(value, "LOGICAL_DELETE")) { - return LogicalOperatorType::LOGICAL_DELETE; - } - if (StringUtil::Equals(value, "LOGICAL_UPDATE")) { - return LogicalOperatorType::LOGICAL_UPDATE; - } - if (StringUtil::Equals(value, "LOGICAL_ALTER")) { - return LogicalOperatorType::LOGICAL_ALTER; - } - if (StringUtil::Equals(value, "LOGICAL_CREATE_TABLE")) { - return LogicalOperatorType::LOGICAL_CREATE_TABLE; - } - if (StringUtil::Equals(value, "LOGICAL_CREATE_INDEX")) { - return LogicalOperatorType::LOGICAL_CREATE_INDEX; - } - if (StringUtil::Equals(value, "LOGICAL_CREATE_SEQUENCE")) { - return LogicalOperatorType::LOGICAL_CREATE_SEQUENCE; - } - if (StringUtil::Equals(value, "LOGICAL_CREATE_VIEW")) { - return LogicalOperatorType::LOGICAL_CREATE_VIEW; - } - if (StringUtil::Equals(value, "LOGICAL_CREATE_SCHEMA")) { - return LogicalOperatorType::LOGICAL_CREATE_SCHEMA; - } - if (StringUtil::Equals(value, "LOGICAL_CREATE_MACRO")) { - return LogicalOperatorType::LOGICAL_CREATE_MACRO; - } - if (StringUtil::Equals(value, "LOGICAL_DROP")) { - return LogicalOperatorType::LOGICAL_DROP; - } - if (StringUtil::Equals(value, "LOGICAL_PRAGMA")) { - return LogicalOperatorType::LOGICAL_PRAGMA; - } - if (StringUtil::Equals(value, "LOGICAL_TRANSACTION")) { - return LogicalOperatorType::LOGICAL_TRANSACTION; - } - if (StringUtil::Equals(value, "LOGICAL_CREATE_TYPE")) { - return LogicalOperatorType::LOGICAL_CREATE_TYPE; - } - if (StringUtil::Equals(value, "LOGICAL_ATTACH")) { - return LogicalOperatorType::LOGICAL_ATTACH; - } - if (StringUtil::Equals(value, "LOGICAL_DETACH")) { - return LogicalOperatorType::LOGICAL_DETACH; - } - if (StringUtil::Equals(value, "LOGICAL_EXPLAIN")) { - return LogicalOperatorType::LOGICAL_EXPLAIN; - } - if (StringUtil::Equals(value, "LOGICAL_PREPARE")) { - return LogicalOperatorType::LOGICAL_PREPARE; - } - if (StringUtil::Equals(value, "LOGICAL_EXECUTE")) { - return LogicalOperatorType::LOGICAL_EXECUTE; - } - if (StringUtil::Equals(value, "LOGICAL_EXPORT")) { - return LogicalOperatorType::LOGICAL_EXPORT; - } - if (StringUtil::Equals(value, "LOGICAL_VACUUM")) { - return LogicalOperatorType::LOGICAL_VACUUM; - } - if (StringUtil::Equals(value, "LOGICAL_SET")) { - return LogicalOperatorType::LOGICAL_SET; - } - if (StringUtil::Equals(value, "LOGICAL_LOAD")) { - return LogicalOperatorType::LOGICAL_LOAD; - } - if (StringUtil::Equals(value, "LOGICAL_RESET")) { - return LogicalOperatorType::LOGICAL_RESET; - } - if (StringUtil::Equals(value, "LOGICAL_UPDATE_EXTENSIONS")) { - return LogicalOperatorType::LOGICAL_UPDATE_EXTENSIONS; - } - if (StringUtil::Equals(value, "LOGICAL_CREATE_SECRET")) { - return LogicalOperatorType::LOGICAL_CREATE_SECRET; - } - if (StringUtil::Equals(value, "LOGICAL_EXTENSION_OPERATOR")) { - return LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetLogicalOperatorTypeValues(), 61, "LogicalOperatorType", value)); +} + +const StringUtil::EnumStringLiteral *GetLogicalTypeIdValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(LogicalTypeId::INVALID), "INVALID" }, + { static_cast(LogicalTypeId::SQLNULL), "NULL" }, + { static_cast(LogicalTypeId::UNKNOWN), "UNKNOWN" }, + { static_cast(LogicalTypeId::ANY), "ANY" }, + { static_cast(LogicalTypeId::USER), "USER" }, + { static_cast(LogicalTypeId::BOOLEAN), "BOOLEAN" }, + { static_cast(LogicalTypeId::TINYINT), "TINYINT" }, + { static_cast(LogicalTypeId::SMALLINT), "SMALLINT" }, + { static_cast(LogicalTypeId::INTEGER), "INTEGER" }, + { static_cast(LogicalTypeId::BIGINT), "BIGINT" }, + { static_cast(LogicalTypeId::DATE), "DATE" }, + { static_cast(LogicalTypeId::TIME), "TIME" }, + { static_cast(LogicalTypeId::TIMESTAMP_SEC), "TIMESTAMP_S" }, + { static_cast(LogicalTypeId::TIMESTAMP_MS), "TIMESTAMP_MS" }, + { static_cast(LogicalTypeId::TIMESTAMP), "TIMESTAMP" }, + { static_cast(LogicalTypeId::TIMESTAMP_NS), "TIMESTAMP_NS" }, + { static_cast(LogicalTypeId::DECIMAL), "DECIMAL" }, + { static_cast(LogicalTypeId::FLOAT), "FLOAT" }, + { static_cast(LogicalTypeId::DOUBLE), "DOUBLE" }, + { static_cast(LogicalTypeId::CHAR), "CHAR" }, + { static_cast(LogicalTypeId::VARCHAR), "VARCHAR" }, + { static_cast(LogicalTypeId::BLOB), "BLOB" }, + { static_cast(LogicalTypeId::INTERVAL), "INTERVAL" }, + { static_cast(LogicalTypeId::UTINYINT), "UTINYINT" }, + { static_cast(LogicalTypeId::USMALLINT), "USMALLINT" }, + { static_cast(LogicalTypeId::UINTEGER), "UINTEGER" }, + { static_cast(LogicalTypeId::UBIGINT), "UBIGINT" }, + { static_cast(LogicalTypeId::TIMESTAMP_TZ), "TIMESTAMP WITH TIME ZONE" }, + { static_cast(LogicalTypeId::TIME_TZ), "TIME WITH TIME ZONE" }, + { static_cast(LogicalTypeId::BIT), "BIT" }, + { static_cast(LogicalTypeId::STRING_LITERAL), "STRING_LITERAL" }, + { static_cast(LogicalTypeId::INTEGER_LITERAL), "INTEGER_LITERAL" }, + { static_cast(LogicalTypeId::VARINT), "VARINT" }, + { static_cast(LogicalTypeId::UHUGEINT), "UHUGEINT" }, + { static_cast(LogicalTypeId::HUGEINT), "HUGEINT" }, + { static_cast(LogicalTypeId::POINTER), "POINTER" }, + { static_cast(LogicalTypeId::VALIDITY), "VALIDITY" }, + { static_cast(LogicalTypeId::UUID), "UUID" }, + { static_cast(LogicalTypeId::STRUCT), "STRUCT" }, + { static_cast(LogicalTypeId::LIST), "LIST" }, + { static_cast(LogicalTypeId::MAP), "MAP" }, + { static_cast(LogicalTypeId::TABLE), "TABLE" }, + { static_cast(LogicalTypeId::ENUM), "ENUM" }, + { static_cast(LogicalTypeId::AGGREGATE_STATE), "AGGREGATE_STATE" }, + { static_cast(LogicalTypeId::LAMBDA), "LAMBDA" }, + { static_cast(LogicalTypeId::UNION), "UNION" }, + { static_cast(LogicalTypeId::ARRAY), "ARRAY" } + }; + return values; } template<> const char* EnumUtil::ToChars(LogicalTypeId value) { - switch(value) { - case LogicalTypeId::INVALID: - return "INVALID"; - case LogicalTypeId::SQLNULL: - return "NULL"; - case LogicalTypeId::UNKNOWN: - return "UNKNOWN"; - case LogicalTypeId::ANY: - return "ANY"; - case LogicalTypeId::USER: - return "USER"; - case LogicalTypeId::BOOLEAN: - return "BOOLEAN"; - case LogicalTypeId::TINYINT: - return "TINYINT"; - case LogicalTypeId::SMALLINT: - return "SMALLINT"; - case LogicalTypeId::INTEGER: - return "INTEGER"; - case LogicalTypeId::BIGINT: - return "BIGINT"; - case LogicalTypeId::DATE: - return "DATE"; - case LogicalTypeId::TIME: - return "TIME"; - case LogicalTypeId::TIMESTAMP_SEC: - return "TIMESTAMP_S"; - case LogicalTypeId::TIMESTAMP_MS: - return "TIMESTAMP_MS"; - case LogicalTypeId::TIMESTAMP: - return "TIMESTAMP"; - case LogicalTypeId::TIMESTAMP_NS: - return "TIMESTAMP_NS"; - case LogicalTypeId::DECIMAL: - return "DECIMAL"; - case LogicalTypeId::FLOAT: - return "FLOAT"; - case LogicalTypeId::DOUBLE: - return "DOUBLE"; - case LogicalTypeId::CHAR: - return "CHAR"; - case LogicalTypeId::VARCHAR: - return "VARCHAR"; - case LogicalTypeId::BLOB: - return "BLOB"; - case LogicalTypeId::INTERVAL: - return "INTERVAL"; - case LogicalTypeId::UTINYINT: - return "UTINYINT"; - case LogicalTypeId::USMALLINT: - return "USMALLINT"; - case LogicalTypeId::UINTEGER: - return "UINTEGER"; - case LogicalTypeId::UBIGINT: - return "UBIGINT"; - case LogicalTypeId::TIMESTAMP_TZ: - return "TIMESTAMP WITH TIME ZONE"; - case LogicalTypeId::TIME_TZ: - return "TIME WITH TIME ZONE"; - case LogicalTypeId::BIT: - return "BIT"; - case LogicalTypeId::STRING_LITERAL: - return "STRING_LITERAL"; - case LogicalTypeId::INTEGER_LITERAL: - return "INTEGER_LITERAL"; - case LogicalTypeId::VARINT: - return "VARINT"; - case LogicalTypeId::UHUGEINT: - return "UHUGEINT"; - case LogicalTypeId::HUGEINT: - return "HUGEINT"; - case LogicalTypeId::POINTER: - return "POINTER"; - case LogicalTypeId::VALIDITY: - return "VALIDITY"; - case LogicalTypeId::UUID: - return "UUID"; - case LogicalTypeId::STRUCT: - return "STRUCT"; - case LogicalTypeId::LIST: - return "LIST"; - case LogicalTypeId::MAP: - return "MAP"; - case LogicalTypeId::TABLE: - return "TABLE"; - case LogicalTypeId::ENUM: - return "ENUM"; - case LogicalTypeId::AGGREGATE_STATE: - return "AGGREGATE_STATE"; - case LogicalTypeId::LAMBDA: - return "LAMBDA"; - case LogicalTypeId::UNION: - return "UNION"; - case LogicalTypeId::ARRAY: - return "ARRAY"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetLogicalTypeIdValues(), 47, "LogicalTypeId", static_cast(value)); } template<> LogicalTypeId EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return LogicalTypeId::INVALID; - } - if (StringUtil::Equals(value, "NULL")) { - return LogicalTypeId::SQLNULL; - } - if (StringUtil::Equals(value, "UNKNOWN")) { - return LogicalTypeId::UNKNOWN; - } - if (StringUtil::Equals(value, "ANY")) { - return LogicalTypeId::ANY; - } - if (StringUtil::Equals(value, "USER")) { - return LogicalTypeId::USER; - } - if (StringUtil::Equals(value, "BOOLEAN")) { - return LogicalTypeId::BOOLEAN; - } - if (StringUtil::Equals(value, "TINYINT")) { - return LogicalTypeId::TINYINT; - } - if (StringUtil::Equals(value, "SMALLINT")) { - return LogicalTypeId::SMALLINT; - } - if (StringUtil::Equals(value, "INTEGER")) { - return LogicalTypeId::INTEGER; - } - if (StringUtil::Equals(value, "BIGINT")) { - return LogicalTypeId::BIGINT; - } - if (StringUtil::Equals(value, "DATE")) { - return LogicalTypeId::DATE; - } - if (StringUtil::Equals(value, "TIME")) { - return LogicalTypeId::TIME; - } - if (StringUtil::Equals(value, "TIMESTAMP_S")) { - return LogicalTypeId::TIMESTAMP_SEC; - } - if (StringUtil::Equals(value, "TIMESTAMP_MS")) { - return LogicalTypeId::TIMESTAMP_MS; - } - if (StringUtil::Equals(value, "TIMESTAMP")) { - return LogicalTypeId::TIMESTAMP; - } - if (StringUtil::Equals(value, "TIMESTAMP_NS")) { - return LogicalTypeId::TIMESTAMP_NS; - } - if (StringUtil::Equals(value, "DECIMAL")) { - return LogicalTypeId::DECIMAL; - } - if (StringUtil::Equals(value, "FLOAT")) { - return LogicalTypeId::FLOAT; - } - if (StringUtil::Equals(value, "DOUBLE")) { - return LogicalTypeId::DOUBLE; - } - if (StringUtil::Equals(value, "CHAR")) { - return LogicalTypeId::CHAR; - } - if (StringUtil::Equals(value, "VARCHAR")) { - return LogicalTypeId::VARCHAR; - } - if (StringUtil::Equals(value, "BLOB")) { - return LogicalTypeId::BLOB; - } - if (StringUtil::Equals(value, "INTERVAL")) { - return LogicalTypeId::INTERVAL; - } - if (StringUtil::Equals(value, "UTINYINT")) { - return LogicalTypeId::UTINYINT; - } - if (StringUtil::Equals(value, "USMALLINT")) { - return LogicalTypeId::USMALLINT; - } - if (StringUtil::Equals(value, "UINTEGER")) { - return LogicalTypeId::UINTEGER; - } - if (StringUtil::Equals(value, "UBIGINT")) { - return LogicalTypeId::UBIGINT; - } - if (StringUtil::Equals(value, "TIMESTAMP WITH TIME ZONE")) { - return LogicalTypeId::TIMESTAMP_TZ; - } - if (StringUtil::Equals(value, "TIME WITH TIME ZONE")) { - return LogicalTypeId::TIME_TZ; - } - if (StringUtil::Equals(value, "BIT")) { - return LogicalTypeId::BIT; - } - if (StringUtil::Equals(value, "STRING_LITERAL")) { - return LogicalTypeId::STRING_LITERAL; - } - if (StringUtil::Equals(value, "INTEGER_LITERAL")) { - return LogicalTypeId::INTEGER_LITERAL; - } - if (StringUtil::Equals(value, "VARINT")) { - return LogicalTypeId::VARINT; - } - if (StringUtil::Equals(value, "UHUGEINT")) { - return LogicalTypeId::UHUGEINT; - } - if (StringUtil::Equals(value, "HUGEINT")) { - return LogicalTypeId::HUGEINT; - } - if (StringUtil::Equals(value, "POINTER")) { - return LogicalTypeId::POINTER; - } - if (StringUtil::Equals(value, "VALIDITY")) { - return LogicalTypeId::VALIDITY; - } - if (StringUtil::Equals(value, "UUID")) { - return LogicalTypeId::UUID; - } - if (StringUtil::Equals(value, "STRUCT")) { - return LogicalTypeId::STRUCT; - } - if (StringUtil::Equals(value, "LIST")) { - return LogicalTypeId::LIST; - } - if (StringUtil::Equals(value, "MAP")) { - return LogicalTypeId::MAP; - } - if (StringUtil::Equals(value, "TABLE")) { - return LogicalTypeId::TABLE; - } - if (StringUtil::Equals(value, "ENUM")) { - return LogicalTypeId::ENUM; - } - if (StringUtil::Equals(value, "AGGREGATE_STATE")) { - return LogicalTypeId::AGGREGATE_STATE; - } - if (StringUtil::Equals(value, "LAMBDA")) { - return LogicalTypeId::LAMBDA; - } - if (StringUtil::Equals(value, "UNION")) { - return LogicalTypeId::UNION; - } - if (StringUtil::Equals(value, "ARRAY")) { - return LogicalTypeId::ARRAY; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetLogicalTypeIdValues(), 47, "LogicalTypeId", value)); +} + +const StringUtil::EnumStringLiteral *GetLookupResultTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(LookupResultType::LOOKUP_MISS), "LOOKUP_MISS" }, + { static_cast(LookupResultType::LOOKUP_HIT), "LOOKUP_HIT" }, + { static_cast(LookupResultType::LOOKUP_NULL), "LOOKUP_NULL" } + }; + return values; } template<> const char* EnumUtil::ToChars(LookupResultType value) { - switch(value) { - case LookupResultType::LOOKUP_MISS: - return "LOOKUP_MISS"; - case LookupResultType::LOOKUP_HIT: - return "LOOKUP_HIT"; - case LookupResultType::LOOKUP_NULL: - return "LOOKUP_NULL"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetLookupResultTypeValues(), 3, "LookupResultType", static_cast(value)); } template<> LookupResultType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "LOOKUP_MISS")) { - return LookupResultType::LOOKUP_MISS; - } - if (StringUtil::Equals(value, "LOOKUP_HIT")) { - return LookupResultType::LOOKUP_HIT; - } - if (StringUtil::Equals(value, "LOOKUP_NULL")) { - return LookupResultType::LOOKUP_NULL; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetLookupResultTypeValues(), 3, "LookupResultType", value)); +} + +const StringUtil::EnumStringLiteral *GetMacroTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(MacroType::VOID_MACRO), "VOID_MACRO" }, + { static_cast(MacroType::TABLE_MACRO), "TABLE_MACRO" }, + { static_cast(MacroType::SCALAR_MACRO), "SCALAR_MACRO" } + }; + return values; } template<> const char* EnumUtil::ToChars(MacroType value) { - switch(value) { - case MacroType::VOID_MACRO: - return "VOID_MACRO"; - case MacroType::TABLE_MACRO: - return "TABLE_MACRO"; - case MacroType::SCALAR_MACRO: - return "SCALAR_MACRO"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetMacroTypeValues(), 3, "MacroType", static_cast(value)); } template<> MacroType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "VOID_MACRO")) { - return MacroType::VOID_MACRO; - } - if (StringUtil::Equals(value, "TABLE_MACRO")) { - return MacroType::TABLE_MACRO; - } - if (StringUtil::Equals(value, "SCALAR_MACRO")) { - return MacroType::SCALAR_MACRO; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetMacroTypeValues(), 3, "MacroType", value)); +} + +const StringUtil::EnumStringLiteral *GetMapInvalidReasonValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(MapInvalidReason::VALID), "VALID" }, + { static_cast(MapInvalidReason::NULL_KEY), "NULL_KEY" }, + { static_cast(MapInvalidReason::DUPLICATE_KEY), "DUPLICATE_KEY" }, + { static_cast(MapInvalidReason::NOT_ALIGNED), "NOT_ALIGNED" }, + { static_cast(MapInvalidReason::INVALID_PARAMS), "INVALID_PARAMS" } + }; + return values; } template<> const char* EnumUtil::ToChars(MapInvalidReason value) { - switch(value) { - case MapInvalidReason::VALID: - return "VALID"; - case MapInvalidReason::NULL_KEY: - return "NULL_KEY"; - case MapInvalidReason::DUPLICATE_KEY: - return "DUPLICATE_KEY"; - case MapInvalidReason::NOT_ALIGNED: - return "NOT_ALIGNED"; - case MapInvalidReason::INVALID_PARAMS: - return "INVALID_PARAMS"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetMapInvalidReasonValues(), 5, "MapInvalidReason", static_cast(value)); } template<> MapInvalidReason EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "VALID")) { - return MapInvalidReason::VALID; - } - if (StringUtil::Equals(value, "NULL_KEY")) { - return MapInvalidReason::NULL_KEY; - } - if (StringUtil::Equals(value, "DUPLICATE_KEY")) { - return MapInvalidReason::DUPLICATE_KEY; - } - if (StringUtil::Equals(value, "NOT_ALIGNED")) { - return MapInvalidReason::NOT_ALIGNED; - } - if (StringUtil::Equals(value, "INVALID_PARAMS")) { - return MapInvalidReason::INVALID_PARAMS; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetMapInvalidReasonValues(), 5, "MapInvalidReason", value)); +} + +const StringUtil::EnumStringLiteral *GetMemoryTagValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(MemoryTag::BASE_TABLE), "BASE_TABLE" }, + { static_cast(MemoryTag::HASH_TABLE), "HASH_TABLE" }, + { static_cast(MemoryTag::PARQUET_READER), "PARQUET_READER" }, + { static_cast(MemoryTag::CSV_READER), "CSV_READER" }, + { static_cast(MemoryTag::ORDER_BY), "ORDER_BY" }, + { static_cast(MemoryTag::ART_INDEX), "ART_INDEX" }, + { static_cast(MemoryTag::COLUMN_DATA), "COLUMN_DATA" }, + { static_cast(MemoryTag::METADATA), "METADATA" }, + { static_cast(MemoryTag::OVERFLOW_STRINGS), "OVERFLOW_STRINGS" }, + { static_cast(MemoryTag::IN_MEMORY_TABLE), "IN_MEMORY_TABLE" }, + { static_cast(MemoryTag::ALLOCATOR), "ALLOCATOR" }, + { static_cast(MemoryTag::EXTENSION), "EXTENSION" }, + { static_cast(MemoryTag::TRANSACTION), "TRANSACTION" } + }; + return values; } template<> const char* EnumUtil::ToChars(MemoryTag value) { - switch(value) { - case MemoryTag::BASE_TABLE: - return "BASE_TABLE"; - case MemoryTag::HASH_TABLE: - return "HASH_TABLE"; - case MemoryTag::PARQUET_READER: - return "PARQUET_READER"; - case MemoryTag::CSV_READER: - return "CSV_READER"; - case MemoryTag::ORDER_BY: - return "ORDER_BY"; - case MemoryTag::ART_INDEX: - return "ART_INDEX"; - case MemoryTag::COLUMN_DATA: - return "COLUMN_DATA"; - case MemoryTag::METADATA: - return "METADATA"; - case MemoryTag::OVERFLOW_STRINGS: - return "OVERFLOW_STRINGS"; - case MemoryTag::IN_MEMORY_TABLE: - return "IN_MEMORY_TABLE"; - case MemoryTag::ALLOCATOR: - return "ALLOCATOR"; - case MemoryTag::EXTENSION: - return "EXTENSION"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetMemoryTagValues(), 13, "MemoryTag", static_cast(value)); } template<> MemoryTag EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "BASE_TABLE")) { - return MemoryTag::BASE_TABLE; - } - if (StringUtil::Equals(value, "HASH_TABLE")) { - return MemoryTag::HASH_TABLE; - } - if (StringUtil::Equals(value, "PARQUET_READER")) { - return MemoryTag::PARQUET_READER; - } - if (StringUtil::Equals(value, "CSV_READER")) { - return MemoryTag::CSV_READER; - } - if (StringUtil::Equals(value, "ORDER_BY")) { - return MemoryTag::ORDER_BY; - } - if (StringUtil::Equals(value, "ART_INDEX")) { - return MemoryTag::ART_INDEX; - } - if (StringUtil::Equals(value, "COLUMN_DATA")) { - return MemoryTag::COLUMN_DATA; - } - if (StringUtil::Equals(value, "METADATA")) { - return MemoryTag::METADATA; - } - if (StringUtil::Equals(value, "OVERFLOW_STRINGS")) { - return MemoryTag::OVERFLOW_STRINGS; - } - if (StringUtil::Equals(value, "IN_MEMORY_TABLE")) { - return MemoryTag::IN_MEMORY_TABLE; - } - if (StringUtil::Equals(value, "ALLOCATOR")) { - return MemoryTag::ALLOCATOR; - } - if (StringUtil::Equals(value, "EXTENSION")) { - return MemoryTag::EXTENSION; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetMemoryTagValues(), 13, "MemoryTag", value)); +} + +const StringUtil::EnumStringLiteral *GetMetaPipelineTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(MetaPipelineType::REGULAR), "REGULAR" }, + { static_cast(MetaPipelineType::JOIN_BUILD), "JOIN_BUILD" } + }; + return values; } template<> const char* EnumUtil::ToChars(MetaPipelineType value) { - switch(value) { - case MetaPipelineType::REGULAR: - return "REGULAR"; - case MetaPipelineType::JOIN_BUILD: - return "JOIN_BUILD"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetMetaPipelineTypeValues(), 2, "MetaPipelineType", static_cast(value)); } template<> MetaPipelineType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "REGULAR")) { - return MetaPipelineType::REGULAR; - } - if (StringUtil::Equals(value, "JOIN_BUILD")) { - return MetaPipelineType::JOIN_BUILD; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetMetaPipelineTypeValues(), 2, "MetaPipelineType", value)); +} + +const StringUtil::EnumStringLiteral *GetMetricsTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(MetricsType::QUERY_NAME), "QUERY_NAME" }, + { static_cast(MetricsType::BLOCKED_THREAD_TIME), "BLOCKED_THREAD_TIME" }, + { static_cast(MetricsType::CPU_TIME), "CPU_TIME" }, + { static_cast(MetricsType::EXTRA_INFO), "EXTRA_INFO" }, + { static_cast(MetricsType::CUMULATIVE_CARDINALITY), "CUMULATIVE_CARDINALITY" }, + { static_cast(MetricsType::OPERATOR_TYPE), "OPERATOR_TYPE" }, + { static_cast(MetricsType::OPERATOR_CARDINALITY), "OPERATOR_CARDINALITY" }, + { static_cast(MetricsType::CUMULATIVE_ROWS_SCANNED), "CUMULATIVE_ROWS_SCANNED" }, + { static_cast(MetricsType::OPERATOR_ROWS_SCANNED), "OPERATOR_ROWS_SCANNED" }, + { static_cast(MetricsType::OPERATOR_TIMING), "OPERATOR_TIMING" }, + { static_cast(MetricsType::LATENCY), "LATENCY" }, + { static_cast(MetricsType::ROWS_RETURNED), "ROWS_RETURNED" }, + { static_cast(MetricsType::RESULT_SET_SIZE), "RESULT_SET_SIZE" }, + { static_cast(MetricsType::ALL_OPTIMIZERS), "ALL_OPTIMIZERS" }, + { static_cast(MetricsType::CUMULATIVE_OPTIMIZER_TIMING), "CUMULATIVE_OPTIMIZER_TIMING" }, + { static_cast(MetricsType::PLANNER), "PLANNER" }, + { static_cast(MetricsType::PLANNER_BINDING), "PLANNER_BINDING" }, + { static_cast(MetricsType::PHYSICAL_PLANNER), "PHYSICAL_PLANNER" }, + { static_cast(MetricsType::PHYSICAL_PLANNER_COLUMN_BINDING), "PHYSICAL_PLANNER_COLUMN_BINDING" }, + { static_cast(MetricsType::PHYSICAL_PLANNER_RESOLVE_TYPES), "PHYSICAL_PLANNER_RESOLVE_TYPES" }, + { static_cast(MetricsType::PHYSICAL_PLANNER_CREATE_PLAN), "PHYSICAL_PLANNER_CREATE_PLAN" }, + { static_cast(MetricsType::OPTIMIZER_EXPRESSION_REWRITER), "OPTIMIZER_EXPRESSION_REWRITER" }, + { static_cast(MetricsType::OPTIMIZER_FILTER_PULLUP), "OPTIMIZER_FILTER_PULLUP" }, + { static_cast(MetricsType::OPTIMIZER_FILTER_PUSHDOWN), "OPTIMIZER_FILTER_PUSHDOWN" }, + { static_cast(MetricsType::OPTIMIZER_CTE_FILTER_PUSHER), "OPTIMIZER_CTE_FILTER_PUSHER" }, + { static_cast(MetricsType::OPTIMIZER_REGEX_RANGE), "OPTIMIZER_REGEX_RANGE" }, + { static_cast(MetricsType::OPTIMIZER_IN_CLAUSE), "OPTIMIZER_IN_CLAUSE" }, + { static_cast(MetricsType::OPTIMIZER_JOIN_ORDER), "OPTIMIZER_JOIN_ORDER" }, + { static_cast(MetricsType::OPTIMIZER_DELIMINATOR), "OPTIMIZER_DELIMINATOR" }, + { static_cast(MetricsType::OPTIMIZER_UNNEST_REWRITER), "OPTIMIZER_UNNEST_REWRITER" }, + { static_cast(MetricsType::OPTIMIZER_UNUSED_COLUMNS), "OPTIMIZER_UNUSED_COLUMNS" }, + { static_cast(MetricsType::OPTIMIZER_STATISTICS_PROPAGATION), "OPTIMIZER_STATISTICS_PROPAGATION" }, + { static_cast(MetricsType::OPTIMIZER_COMMON_SUBEXPRESSIONS), "OPTIMIZER_COMMON_SUBEXPRESSIONS" }, + { static_cast(MetricsType::OPTIMIZER_COMMON_AGGREGATE), "OPTIMIZER_COMMON_AGGREGATE" }, + { static_cast(MetricsType::OPTIMIZER_COLUMN_LIFETIME), "OPTIMIZER_COLUMN_LIFETIME" }, + { static_cast(MetricsType::OPTIMIZER_BUILD_SIDE_PROBE_SIDE), "OPTIMIZER_BUILD_SIDE_PROBE_SIDE" }, + { static_cast(MetricsType::OPTIMIZER_LIMIT_PUSHDOWN), "OPTIMIZER_LIMIT_PUSHDOWN" }, + { static_cast(MetricsType::OPTIMIZER_SAMPLING_PUSHDOWN), "OPTIMIZER_SAMPLING_PUSHDOWN" }, + { static_cast(MetricsType::OPTIMIZER_TOP_N), "OPTIMIZER_TOP_N" }, + { static_cast(MetricsType::OPTIMIZER_COMPRESSED_MATERIALIZATION), "OPTIMIZER_COMPRESSED_MATERIALIZATION" }, + { static_cast(MetricsType::OPTIMIZER_DUPLICATE_GROUPS), "OPTIMIZER_DUPLICATE_GROUPS" }, + { static_cast(MetricsType::OPTIMIZER_REORDER_FILTER), "OPTIMIZER_REORDER_FILTER" }, + { static_cast(MetricsType::OPTIMIZER_JOIN_FILTER_PUSHDOWN), "OPTIMIZER_JOIN_FILTER_PUSHDOWN" }, + { static_cast(MetricsType::OPTIMIZER_EXTENSION), "OPTIMIZER_EXTENSION" }, + { static_cast(MetricsType::OPTIMIZER_MATERIALIZED_CTE), "OPTIMIZER_MATERIALIZED_CTE" }, + { static_cast(MetricsType::OPTIMIZER_EMPTY_RESULT_PULLUP), "OPTIMIZER_EMPTY_RESULT_PULLUP" } + }; + return values; } template<> const char* EnumUtil::ToChars(MetricsType value) { - switch(value) { - case MetricsType::QUERY_NAME: - return "QUERY_NAME"; - case MetricsType::BLOCKED_THREAD_TIME: - return "BLOCKED_THREAD_TIME"; - case MetricsType::CPU_TIME: - return "CPU_TIME"; - case MetricsType::EXTRA_INFO: - return "EXTRA_INFO"; - case MetricsType::CUMULATIVE_CARDINALITY: - return "CUMULATIVE_CARDINALITY"; - case MetricsType::OPERATOR_TYPE: - return "OPERATOR_TYPE"; - case MetricsType::OPERATOR_CARDINALITY: - return "OPERATOR_CARDINALITY"; - case MetricsType::CUMULATIVE_ROWS_SCANNED: - return "CUMULATIVE_ROWS_SCANNED"; - case MetricsType::OPERATOR_ROWS_SCANNED: - return "OPERATOR_ROWS_SCANNED"; - case MetricsType::OPERATOR_TIMING: - return "OPERATOR_TIMING"; - case MetricsType::LATENCY: - return "LATENCY"; - case MetricsType::ROWS_RETURNED: - return "ROWS_RETURNED"; - case MetricsType::RESULT_SET_SIZE: - return "RESULT_SET_SIZE"; - case MetricsType::ALL_OPTIMIZERS: - return "ALL_OPTIMIZERS"; - case MetricsType::CUMULATIVE_OPTIMIZER_TIMING: - return "CUMULATIVE_OPTIMIZER_TIMING"; - case MetricsType::PLANNER: - return "PLANNER"; - case MetricsType::PLANNER_BINDING: - return "PLANNER_BINDING"; - case MetricsType::PHYSICAL_PLANNER: - return "PHYSICAL_PLANNER"; - case MetricsType::PHYSICAL_PLANNER_COLUMN_BINDING: - return "PHYSICAL_PLANNER_COLUMN_BINDING"; - case MetricsType::PHYSICAL_PLANNER_RESOLVE_TYPES: - return "PHYSICAL_PLANNER_RESOLVE_TYPES"; - case MetricsType::PHYSICAL_PLANNER_CREATE_PLAN: - return "PHYSICAL_PLANNER_CREATE_PLAN"; - case MetricsType::OPTIMIZER_EXPRESSION_REWRITER: - return "OPTIMIZER_EXPRESSION_REWRITER"; - case MetricsType::OPTIMIZER_FILTER_PULLUP: - return "OPTIMIZER_FILTER_PULLUP"; - case MetricsType::OPTIMIZER_FILTER_PUSHDOWN: - return "OPTIMIZER_FILTER_PUSHDOWN"; - case MetricsType::OPTIMIZER_CTE_FILTER_PUSHER: - return "OPTIMIZER_CTE_FILTER_PUSHER"; - case MetricsType::OPTIMIZER_REGEX_RANGE: - return "OPTIMIZER_REGEX_RANGE"; - case MetricsType::OPTIMIZER_IN_CLAUSE: - return "OPTIMIZER_IN_CLAUSE"; - case MetricsType::OPTIMIZER_JOIN_ORDER: - return "OPTIMIZER_JOIN_ORDER"; - case MetricsType::OPTIMIZER_DELIMINATOR: - return "OPTIMIZER_DELIMINATOR"; - case MetricsType::OPTIMIZER_UNNEST_REWRITER: - return "OPTIMIZER_UNNEST_REWRITER"; - case MetricsType::OPTIMIZER_UNUSED_COLUMNS: - return "OPTIMIZER_UNUSED_COLUMNS"; - case MetricsType::OPTIMIZER_STATISTICS_PROPAGATION: - return "OPTIMIZER_STATISTICS_PROPAGATION"; - case MetricsType::OPTIMIZER_COMMON_SUBEXPRESSIONS: - return "OPTIMIZER_COMMON_SUBEXPRESSIONS"; - case MetricsType::OPTIMIZER_COMMON_AGGREGATE: - return "OPTIMIZER_COMMON_AGGREGATE"; - case MetricsType::OPTIMIZER_COLUMN_LIFETIME: - return "OPTIMIZER_COLUMN_LIFETIME"; - case MetricsType::OPTIMIZER_BUILD_SIDE_PROBE_SIDE: - return "OPTIMIZER_BUILD_SIDE_PROBE_SIDE"; - case MetricsType::OPTIMIZER_LIMIT_PUSHDOWN: - return "OPTIMIZER_LIMIT_PUSHDOWN"; - case MetricsType::OPTIMIZER_TOP_N: - return "OPTIMIZER_TOP_N"; - case MetricsType::OPTIMIZER_COMPRESSED_MATERIALIZATION: - return "OPTIMIZER_COMPRESSED_MATERIALIZATION"; - case MetricsType::OPTIMIZER_DUPLICATE_GROUPS: - return "OPTIMIZER_DUPLICATE_GROUPS"; - case MetricsType::OPTIMIZER_REORDER_FILTER: - return "OPTIMIZER_REORDER_FILTER"; - case MetricsType::OPTIMIZER_JOIN_FILTER_PUSHDOWN: - return "OPTIMIZER_JOIN_FILTER_PUSHDOWN"; - case MetricsType::OPTIMIZER_EXTENSION: - return "OPTIMIZER_EXTENSION"; - case MetricsType::OPTIMIZER_MATERIALIZED_CTE: - return "OPTIMIZER_MATERIALIZED_CTE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetMetricsTypeValues(), 46, "MetricsType", static_cast(value)); } template<> MetricsType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "QUERY_NAME")) { - return MetricsType::QUERY_NAME; - } - if (StringUtil::Equals(value, "BLOCKED_THREAD_TIME")) { - return MetricsType::BLOCKED_THREAD_TIME; - } - if (StringUtil::Equals(value, "CPU_TIME")) { - return MetricsType::CPU_TIME; - } - if (StringUtil::Equals(value, "EXTRA_INFO")) { - return MetricsType::EXTRA_INFO; - } - if (StringUtil::Equals(value, "CUMULATIVE_CARDINALITY")) { - return MetricsType::CUMULATIVE_CARDINALITY; - } - if (StringUtil::Equals(value, "OPERATOR_TYPE")) { - return MetricsType::OPERATOR_TYPE; - } - if (StringUtil::Equals(value, "OPERATOR_CARDINALITY")) { - return MetricsType::OPERATOR_CARDINALITY; - } - if (StringUtil::Equals(value, "CUMULATIVE_ROWS_SCANNED")) { - return MetricsType::CUMULATIVE_ROWS_SCANNED; - } - if (StringUtil::Equals(value, "OPERATOR_ROWS_SCANNED")) { - return MetricsType::OPERATOR_ROWS_SCANNED; - } - if (StringUtil::Equals(value, "OPERATOR_TIMING")) { - return MetricsType::OPERATOR_TIMING; - } - if (StringUtil::Equals(value, "LATENCY")) { - return MetricsType::LATENCY; - } - if (StringUtil::Equals(value, "ROWS_RETURNED")) { - return MetricsType::ROWS_RETURNED; - } - if (StringUtil::Equals(value, "RESULT_SET_SIZE")) { - return MetricsType::RESULT_SET_SIZE; - } - if (StringUtil::Equals(value, "ALL_OPTIMIZERS")) { - return MetricsType::ALL_OPTIMIZERS; - } - if (StringUtil::Equals(value, "CUMULATIVE_OPTIMIZER_TIMING")) { - return MetricsType::CUMULATIVE_OPTIMIZER_TIMING; - } - if (StringUtil::Equals(value, "PLANNER")) { - return MetricsType::PLANNER; - } - if (StringUtil::Equals(value, "PLANNER_BINDING")) { - return MetricsType::PLANNER_BINDING; - } - if (StringUtil::Equals(value, "PHYSICAL_PLANNER")) { - return MetricsType::PHYSICAL_PLANNER; - } - if (StringUtil::Equals(value, "PHYSICAL_PLANNER_COLUMN_BINDING")) { - return MetricsType::PHYSICAL_PLANNER_COLUMN_BINDING; - } - if (StringUtil::Equals(value, "PHYSICAL_PLANNER_RESOLVE_TYPES")) { - return MetricsType::PHYSICAL_PLANNER_RESOLVE_TYPES; - } - if (StringUtil::Equals(value, "PHYSICAL_PLANNER_CREATE_PLAN")) { - return MetricsType::PHYSICAL_PLANNER_CREATE_PLAN; - } - if (StringUtil::Equals(value, "OPTIMIZER_EXPRESSION_REWRITER")) { - return MetricsType::OPTIMIZER_EXPRESSION_REWRITER; - } - if (StringUtil::Equals(value, "OPTIMIZER_FILTER_PULLUP")) { - return MetricsType::OPTIMIZER_FILTER_PULLUP; - } - if (StringUtil::Equals(value, "OPTIMIZER_FILTER_PUSHDOWN")) { - return MetricsType::OPTIMIZER_FILTER_PUSHDOWN; - } - if (StringUtil::Equals(value, "OPTIMIZER_CTE_FILTER_PUSHER")) { - return MetricsType::OPTIMIZER_CTE_FILTER_PUSHER; - } - if (StringUtil::Equals(value, "OPTIMIZER_REGEX_RANGE")) { - return MetricsType::OPTIMIZER_REGEX_RANGE; - } - if (StringUtil::Equals(value, "OPTIMIZER_IN_CLAUSE")) { - return MetricsType::OPTIMIZER_IN_CLAUSE; - } - if (StringUtil::Equals(value, "OPTIMIZER_JOIN_ORDER")) { - return MetricsType::OPTIMIZER_JOIN_ORDER; - } - if (StringUtil::Equals(value, "OPTIMIZER_DELIMINATOR")) { - return MetricsType::OPTIMIZER_DELIMINATOR; - } - if (StringUtil::Equals(value, "OPTIMIZER_UNNEST_REWRITER")) { - return MetricsType::OPTIMIZER_UNNEST_REWRITER; - } - if (StringUtil::Equals(value, "OPTIMIZER_UNUSED_COLUMNS")) { - return MetricsType::OPTIMIZER_UNUSED_COLUMNS; - } - if (StringUtil::Equals(value, "OPTIMIZER_STATISTICS_PROPAGATION")) { - return MetricsType::OPTIMIZER_STATISTICS_PROPAGATION; - } - if (StringUtil::Equals(value, "OPTIMIZER_COMMON_SUBEXPRESSIONS")) { - return MetricsType::OPTIMIZER_COMMON_SUBEXPRESSIONS; - } - if (StringUtil::Equals(value, "OPTIMIZER_COMMON_AGGREGATE")) { - return MetricsType::OPTIMIZER_COMMON_AGGREGATE; - } - if (StringUtil::Equals(value, "OPTIMIZER_COLUMN_LIFETIME")) { - return MetricsType::OPTIMIZER_COLUMN_LIFETIME; - } - if (StringUtil::Equals(value, "OPTIMIZER_BUILD_SIDE_PROBE_SIDE")) { - return MetricsType::OPTIMIZER_BUILD_SIDE_PROBE_SIDE; - } - if (StringUtil::Equals(value, "OPTIMIZER_LIMIT_PUSHDOWN")) { - return MetricsType::OPTIMIZER_LIMIT_PUSHDOWN; - } - if (StringUtil::Equals(value, "OPTIMIZER_TOP_N")) { - return MetricsType::OPTIMIZER_TOP_N; - } - if (StringUtil::Equals(value, "OPTIMIZER_COMPRESSED_MATERIALIZATION")) { - return MetricsType::OPTIMIZER_COMPRESSED_MATERIALIZATION; - } - if (StringUtil::Equals(value, "OPTIMIZER_DUPLICATE_GROUPS")) { - return MetricsType::OPTIMIZER_DUPLICATE_GROUPS; - } - if (StringUtil::Equals(value, "OPTIMIZER_REORDER_FILTER")) { - return MetricsType::OPTIMIZER_REORDER_FILTER; - } - if (StringUtil::Equals(value, "OPTIMIZER_JOIN_FILTER_PUSHDOWN")) { - return MetricsType::OPTIMIZER_JOIN_FILTER_PUSHDOWN; - } - if (StringUtil::Equals(value, "OPTIMIZER_EXTENSION")) { - return MetricsType::OPTIMIZER_EXTENSION; - } - if (StringUtil::Equals(value, "OPTIMIZER_MATERIALIZED_CTE")) { - return MetricsType::OPTIMIZER_MATERIALIZED_CTE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetMetricsTypeValues(), 46, "MetricsType", value)); +} + +const StringUtil::EnumStringLiteral *GetNTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(NType::PREFIX), "PREFIX" }, + { static_cast(NType::LEAF), "LEAF" }, + { static_cast(NType::NODE_4), "NODE_4" }, + { static_cast(NType::NODE_16), "NODE_16" }, + { static_cast(NType::NODE_48), "NODE_48" }, + { static_cast(NType::NODE_256), "NODE_256" }, + { static_cast(NType::LEAF_INLINED), "LEAF_INLINED" }, + { static_cast(NType::NODE_7_LEAF), "NODE_7_LEAF" }, + { static_cast(NType::NODE_15_LEAF), "NODE_15_LEAF" }, + { static_cast(NType::NODE_256_LEAF), "NODE_256_LEAF" } + }; + return values; } template<> const char* EnumUtil::ToChars(NType value) { - switch(value) { - case NType::PREFIX: - return "PREFIX"; - case NType::LEAF: - return "LEAF"; - case NType::NODE_4: - return "NODE_4"; - case NType::NODE_16: - return "NODE_16"; - case NType::NODE_48: - return "NODE_48"; - case NType::NODE_256: - return "NODE_256"; - case NType::LEAF_INLINED: - return "LEAF_INLINED"; - case NType::NODE_7_LEAF: - return "NODE_7_LEAF"; - case NType::NODE_15_LEAF: - return "NODE_15_LEAF"; - case NType::NODE_256_LEAF: - return "NODE_256_LEAF"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetNTypeValues(), 10, "NType", static_cast(value)); } template<> NType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "PREFIX")) { - return NType::PREFIX; - } - if (StringUtil::Equals(value, "LEAF")) { - return NType::LEAF; - } - if (StringUtil::Equals(value, "NODE_4")) { - return NType::NODE_4; - } - if (StringUtil::Equals(value, "NODE_16")) { - return NType::NODE_16; - } - if (StringUtil::Equals(value, "NODE_48")) { - return NType::NODE_48; - } - if (StringUtil::Equals(value, "NODE_256")) { - return NType::NODE_256; - } - if (StringUtil::Equals(value, "LEAF_INLINED")) { - return NType::LEAF_INLINED; - } - if (StringUtil::Equals(value, "NODE_7_LEAF")) { - return NType::NODE_7_LEAF; - } - if (StringUtil::Equals(value, "NODE_15_LEAF")) { - return NType::NODE_15_LEAF; - } - if (StringUtil::Equals(value, "NODE_256_LEAF")) { - return NType::NODE_256_LEAF; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetNTypeValues(), 10, "NType", value)); +} + +const StringUtil::EnumStringLiteral *GetNewLineIdentifierValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(NewLineIdentifier::SINGLE_N), "SINGLE_N" }, + { static_cast(NewLineIdentifier::CARRY_ON), "CARRY_ON" }, + { static_cast(NewLineIdentifier::NOT_SET), "NOT_SET" }, + { static_cast(NewLineIdentifier::SINGLE_R), "SINGLE_R" } + }; + return values; } template<> const char* EnumUtil::ToChars(NewLineIdentifier value) { - switch(value) { - case NewLineIdentifier::SINGLE_N: - return "SINGLE_N"; - case NewLineIdentifier::CARRY_ON: - return "CARRY_ON"; - case NewLineIdentifier::NOT_SET: - return "NOT_SET"; - case NewLineIdentifier::SINGLE_R: - return "SINGLE_R"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetNewLineIdentifierValues(), 4, "NewLineIdentifier", static_cast(value)); } template<> NewLineIdentifier EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "SINGLE_N")) { - return NewLineIdentifier::SINGLE_N; - } - if (StringUtil::Equals(value, "CARRY_ON")) { - return NewLineIdentifier::CARRY_ON; - } - if (StringUtil::Equals(value, "NOT_SET")) { - return NewLineIdentifier::NOT_SET; - } - if (StringUtil::Equals(value, "SINGLE_R")) { - return NewLineIdentifier::SINGLE_R; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetNewLineIdentifierValues(), 4, "NewLineIdentifier", value)); +} + +const StringUtil::EnumStringLiteral *GetOnConflictActionValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(OnConflictAction::THROW), "THROW" }, + { static_cast(OnConflictAction::NOTHING), "NOTHING" }, + { static_cast(OnConflictAction::UPDATE), "UPDATE" }, + { static_cast(OnConflictAction::REPLACE), "REPLACE" } + }; + return values; } template<> const char* EnumUtil::ToChars(OnConflictAction value) { - switch(value) { - case OnConflictAction::THROW: - return "THROW"; - case OnConflictAction::NOTHING: - return "NOTHING"; - case OnConflictAction::UPDATE: - return "UPDATE"; - case OnConflictAction::REPLACE: - return "REPLACE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetOnConflictActionValues(), 4, "OnConflictAction", static_cast(value)); } template<> OnConflictAction EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "THROW")) { - return OnConflictAction::THROW; - } - if (StringUtil::Equals(value, "NOTHING")) { - return OnConflictAction::NOTHING; - } - if (StringUtil::Equals(value, "UPDATE")) { - return OnConflictAction::UPDATE; - } - if (StringUtil::Equals(value, "REPLACE")) { - return OnConflictAction::REPLACE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetOnConflictActionValues(), 4, "OnConflictAction", value)); +} + +const StringUtil::EnumStringLiteral *GetOnCreateConflictValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(OnCreateConflict::ERROR_ON_CONFLICT), "ERROR_ON_CONFLICT" }, + { static_cast(OnCreateConflict::IGNORE_ON_CONFLICT), "IGNORE_ON_CONFLICT" }, + { static_cast(OnCreateConflict::REPLACE_ON_CONFLICT), "REPLACE_ON_CONFLICT" }, + { static_cast(OnCreateConflict::ALTER_ON_CONFLICT), "ALTER_ON_CONFLICT" } + }; + return values; } template<> const char* EnumUtil::ToChars(OnCreateConflict value) { - switch(value) { - case OnCreateConflict::ERROR_ON_CONFLICT: - return "ERROR_ON_CONFLICT"; - case OnCreateConflict::IGNORE_ON_CONFLICT: - return "IGNORE_ON_CONFLICT"; - case OnCreateConflict::REPLACE_ON_CONFLICT: - return "REPLACE_ON_CONFLICT"; - case OnCreateConflict::ALTER_ON_CONFLICT: - return "ALTER_ON_CONFLICT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetOnCreateConflictValues(), 4, "OnCreateConflict", static_cast(value)); } template<> OnCreateConflict EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "ERROR_ON_CONFLICT")) { - return OnCreateConflict::ERROR_ON_CONFLICT; - } - if (StringUtil::Equals(value, "IGNORE_ON_CONFLICT")) { - return OnCreateConflict::IGNORE_ON_CONFLICT; - } - if (StringUtil::Equals(value, "REPLACE_ON_CONFLICT")) { - return OnCreateConflict::REPLACE_ON_CONFLICT; - } - if (StringUtil::Equals(value, "ALTER_ON_CONFLICT")) { - return OnCreateConflict::ALTER_ON_CONFLICT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetOnCreateConflictValues(), 4, "OnCreateConflict", value)); +} + +const StringUtil::EnumStringLiteral *GetOnEntryNotFoundValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(OnEntryNotFound::THROW_EXCEPTION), "THROW_EXCEPTION" }, + { static_cast(OnEntryNotFound::RETURN_NULL), "RETURN_NULL" } + }; + return values; } template<> const char* EnumUtil::ToChars(OnEntryNotFound value) { - switch(value) { - case OnEntryNotFound::THROW_EXCEPTION: - return "THROW_EXCEPTION"; - case OnEntryNotFound::RETURN_NULL: - return "RETURN_NULL"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetOnEntryNotFoundValues(), 2, "OnEntryNotFound", static_cast(value)); } template<> OnEntryNotFound EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "THROW_EXCEPTION")) { - return OnEntryNotFound::THROW_EXCEPTION; - } - if (StringUtil::Equals(value, "RETURN_NULL")) { - return OnEntryNotFound::RETURN_NULL; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetOnEntryNotFoundValues(), 2, "OnEntryNotFound", value)); +} + +const StringUtil::EnumStringLiteral *GetOperatorFinalizeResultTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(OperatorFinalizeResultType::HAVE_MORE_OUTPUT), "HAVE_MORE_OUTPUT" }, + { static_cast(OperatorFinalizeResultType::FINISHED), "FINISHED" } + }; + return values; } template<> const char* EnumUtil::ToChars(OperatorFinalizeResultType value) { - switch(value) { - case OperatorFinalizeResultType::HAVE_MORE_OUTPUT: - return "HAVE_MORE_OUTPUT"; - case OperatorFinalizeResultType::FINISHED: - return "FINISHED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetOperatorFinalizeResultTypeValues(), 2, "OperatorFinalizeResultType", static_cast(value)); } template<> OperatorFinalizeResultType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "HAVE_MORE_OUTPUT")) { - return OperatorFinalizeResultType::HAVE_MORE_OUTPUT; - } - if (StringUtil::Equals(value, "FINISHED")) { - return OperatorFinalizeResultType::FINISHED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetOperatorFinalizeResultTypeValues(), 2, "OperatorFinalizeResultType", value)); +} + +const StringUtil::EnumStringLiteral *GetOperatorResultTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(OperatorResultType::NEED_MORE_INPUT), "NEED_MORE_INPUT" }, + { static_cast(OperatorResultType::HAVE_MORE_OUTPUT), "HAVE_MORE_OUTPUT" }, + { static_cast(OperatorResultType::FINISHED), "FINISHED" }, + { static_cast(OperatorResultType::BLOCKED), "BLOCKED" } + }; + return values; } template<> const char* EnumUtil::ToChars(OperatorResultType value) { - switch(value) { - case OperatorResultType::NEED_MORE_INPUT: - return "NEED_MORE_INPUT"; - case OperatorResultType::HAVE_MORE_OUTPUT: - return "HAVE_MORE_OUTPUT"; - case OperatorResultType::FINISHED: - return "FINISHED"; - case OperatorResultType::BLOCKED: - return "BLOCKED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetOperatorResultTypeValues(), 4, "OperatorResultType", static_cast(value)); } template<> OperatorResultType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NEED_MORE_INPUT")) { - return OperatorResultType::NEED_MORE_INPUT; - } - if (StringUtil::Equals(value, "HAVE_MORE_OUTPUT")) { - return OperatorResultType::HAVE_MORE_OUTPUT; - } - if (StringUtil::Equals(value, "FINISHED")) { - return OperatorResultType::FINISHED; - } - if (StringUtil::Equals(value, "BLOCKED")) { - return OperatorResultType::BLOCKED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetOperatorResultTypeValues(), 4, "OperatorResultType", value)); +} + +const StringUtil::EnumStringLiteral *GetOptimizerTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(OptimizerType::INVALID), "INVALID" }, + { static_cast(OptimizerType::EXPRESSION_REWRITER), "EXPRESSION_REWRITER" }, + { static_cast(OptimizerType::FILTER_PULLUP), "FILTER_PULLUP" }, + { static_cast(OptimizerType::FILTER_PUSHDOWN), "FILTER_PUSHDOWN" }, + { static_cast(OptimizerType::EMPTY_RESULT_PULLUP), "EMPTY_RESULT_PULLUP" }, + { static_cast(OptimizerType::CTE_FILTER_PUSHER), "CTE_FILTER_PUSHER" }, + { static_cast(OptimizerType::REGEX_RANGE), "REGEX_RANGE" }, + { static_cast(OptimizerType::IN_CLAUSE), "IN_CLAUSE" }, + { static_cast(OptimizerType::JOIN_ORDER), "JOIN_ORDER" }, + { static_cast(OptimizerType::DELIMINATOR), "DELIMINATOR" }, + { static_cast(OptimizerType::UNNEST_REWRITER), "UNNEST_REWRITER" }, + { static_cast(OptimizerType::UNUSED_COLUMNS), "UNUSED_COLUMNS" }, + { static_cast(OptimizerType::STATISTICS_PROPAGATION), "STATISTICS_PROPAGATION" }, + { static_cast(OptimizerType::COMMON_SUBEXPRESSIONS), "COMMON_SUBEXPRESSIONS" }, + { static_cast(OptimizerType::COMMON_AGGREGATE), "COMMON_AGGREGATE" }, + { 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::TOP_N), "TOP_N" }, + { static_cast(OptimizerType::COMPRESSED_MATERIALIZATION), "COMPRESSED_MATERIALIZATION" }, + { static_cast(OptimizerType::DUPLICATE_GROUPS), "DUPLICATE_GROUPS" }, + { static_cast(OptimizerType::REORDER_FILTER), "REORDER_FILTER" }, + { static_cast(OptimizerType::SAMPLING_PUSHDOWN), "SAMPLING_PUSHDOWN" }, + { static_cast(OptimizerType::JOIN_FILTER_PUSHDOWN), "JOIN_FILTER_PUSHDOWN" }, + { static_cast(OptimizerType::EXTENSION), "EXTENSION" }, + { static_cast(OptimizerType::MATERIALIZED_CTE), "MATERIALIZED_CTE" } + }; + return values; } template<> const char* EnumUtil::ToChars(OptimizerType value) { - switch(value) { - case OptimizerType::INVALID: - return "INVALID"; - case OptimizerType::EXPRESSION_REWRITER: - return "EXPRESSION_REWRITER"; - case OptimizerType::FILTER_PULLUP: - return "FILTER_PULLUP"; - case OptimizerType::FILTER_PUSHDOWN: - return "FILTER_PUSHDOWN"; - case OptimizerType::CTE_FILTER_PUSHER: - return "CTE_FILTER_PUSHER"; - case OptimizerType::REGEX_RANGE: - return "REGEX_RANGE"; - case OptimizerType::IN_CLAUSE: - return "IN_CLAUSE"; - case OptimizerType::JOIN_ORDER: - return "JOIN_ORDER"; - case OptimizerType::DELIMINATOR: - return "DELIMINATOR"; - case OptimizerType::UNNEST_REWRITER: - return "UNNEST_REWRITER"; - case OptimizerType::UNUSED_COLUMNS: - return "UNUSED_COLUMNS"; - case OptimizerType::STATISTICS_PROPAGATION: - return "STATISTICS_PROPAGATION"; - case OptimizerType::COMMON_SUBEXPRESSIONS: - return "COMMON_SUBEXPRESSIONS"; - case OptimizerType::COMMON_AGGREGATE: - return "COMMON_AGGREGATE"; - case OptimizerType::COLUMN_LIFETIME: - return "COLUMN_LIFETIME"; - case OptimizerType::BUILD_SIDE_PROBE_SIDE: - return "BUILD_SIDE_PROBE_SIDE"; - case OptimizerType::LIMIT_PUSHDOWN: - return "LIMIT_PUSHDOWN"; - case OptimizerType::TOP_N: - return "TOP_N"; - case OptimizerType::COMPRESSED_MATERIALIZATION: - return "COMPRESSED_MATERIALIZATION"; - case OptimizerType::DUPLICATE_GROUPS: - return "DUPLICATE_GROUPS"; - case OptimizerType::REORDER_FILTER: - return "REORDER_FILTER"; - case OptimizerType::JOIN_FILTER_PUSHDOWN: - return "JOIN_FILTER_PUSHDOWN"; - case OptimizerType::EXTENSION: - return "EXTENSION"; - case OptimizerType::MATERIALIZED_CTE: - return "MATERIALIZED_CTE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetOptimizerTypeValues(), 26, "OptimizerType", static_cast(value)); } template<> OptimizerType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return OptimizerType::INVALID; - } - if (StringUtil::Equals(value, "EXPRESSION_REWRITER")) { - return OptimizerType::EXPRESSION_REWRITER; - } - if (StringUtil::Equals(value, "FILTER_PULLUP")) { - return OptimizerType::FILTER_PULLUP; - } - if (StringUtil::Equals(value, "FILTER_PUSHDOWN")) { - return OptimizerType::FILTER_PUSHDOWN; - } - if (StringUtil::Equals(value, "CTE_FILTER_PUSHER")) { - return OptimizerType::CTE_FILTER_PUSHER; - } - if (StringUtil::Equals(value, "REGEX_RANGE")) { - return OptimizerType::REGEX_RANGE; - } - if (StringUtil::Equals(value, "IN_CLAUSE")) { - return OptimizerType::IN_CLAUSE; - } - if (StringUtil::Equals(value, "JOIN_ORDER")) { - return OptimizerType::JOIN_ORDER; - } - if (StringUtil::Equals(value, "DELIMINATOR")) { - return OptimizerType::DELIMINATOR; - } - if (StringUtil::Equals(value, "UNNEST_REWRITER")) { - return OptimizerType::UNNEST_REWRITER; - } - if (StringUtil::Equals(value, "UNUSED_COLUMNS")) { - return OptimizerType::UNUSED_COLUMNS; - } - if (StringUtil::Equals(value, "STATISTICS_PROPAGATION")) { - return OptimizerType::STATISTICS_PROPAGATION; - } - if (StringUtil::Equals(value, "COMMON_SUBEXPRESSIONS")) { - return OptimizerType::COMMON_SUBEXPRESSIONS; - } - if (StringUtil::Equals(value, "COMMON_AGGREGATE")) { - return OptimizerType::COMMON_AGGREGATE; - } - if (StringUtil::Equals(value, "COLUMN_LIFETIME")) { - return OptimizerType::COLUMN_LIFETIME; - } - if (StringUtil::Equals(value, "BUILD_SIDE_PROBE_SIDE")) { - return OptimizerType::BUILD_SIDE_PROBE_SIDE; - } - if (StringUtil::Equals(value, "LIMIT_PUSHDOWN")) { - return OptimizerType::LIMIT_PUSHDOWN; - } - if (StringUtil::Equals(value, "TOP_N")) { - return OptimizerType::TOP_N; - } - if (StringUtil::Equals(value, "COMPRESSED_MATERIALIZATION")) { - return OptimizerType::COMPRESSED_MATERIALIZATION; - } - if (StringUtil::Equals(value, "DUPLICATE_GROUPS")) { - return OptimizerType::DUPLICATE_GROUPS; - } - if (StringUtil::Equals(value, "REORDER_FILTER")) { - return OptimizerType::REORDER_FILTER; - } - if (StringUtil::Equals(value, "JOIN_FILTER_PUSHDOWN")) { - return OptimizerType::JOIN_FILTER_PUSHDOWN; - } - if (StringUtil::Equals(value, "EXTENSION")) { - return OptimizerType::EXTENSION; - } - if (StringUtil::Equals(value, "MATERIALIZED_CTE")) { - return OptimizerType::MATERIALIZED_CTE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetOptimizerTypeValues(), 26, "OptimizerType", value)); +} + +const StringUtil::EnumStringLiteral *GetOrderByNullTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(OrderByNullType::INVALID), "INVALID" }, + { static_cast(OrderByNullType::ORDER_DEFAULT), "ORDER_DEFAULT" }, + { static_cast(OrderByNullType::ORDER_DEFAULT), "DEFAULT" }, + { static_cast(OrderByNullType::NULLS_FIRST), "NULLS_FIRST" }, + { static_cast(OrderByNullType::NULLS_FIRST), "NULLS FIRST" }, + { static_cast(OrderByNullType::NULLS_LAST), "NULLS_LAST" }, + { static_cast(OrderByNullType::NULLS_LAST), "NULLS LAST" } + }; + return values; } template<> const char* EnumUtil::ToChars(OrderByNullType value) { - switch(value) { - case OrderByNullType::INVALID: - return "INVALID"; - case OrderByNullType::ORDER_DEFAULT: - return "ORDER_DEFAULT"; - case OrderByNullType::NULLS_FIRST: - return "NULLS_FIRST"; - case OrderByNullType::NULLS_LAST: - return "NULLS_LAST"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetOrderByNullTypeValues(), 7, "OrderByNullType", static_cast(value)); } template<> OrderByNullType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return OrderByNullType::INVALID; - } - if (StringUtil::Equals(value, "ORDER_DEFAULT") || StringUtil::Equals(value, "DEFAULT")) { - return OrderByNullType::ORDER_DEFAULT; - } - if (StringUtil::Equals(value, "NULLS_FIRST") || StringUtil::Equals(value, "NULLS FIRST")) { - return OrderByNullType::NULLS_FIRST; - } - if (StringUtil::Equals(value, "NULLS_LAST") || StringUtil::Equals(value, "NULLS LAST")) { - return OrderByNullType::NULLS_LAST; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetOrderByNullTypeValues(), 7, "OrderByNullType", value)); +} + +const StringUtil::EnumStringLiteral *GetOrderPreservationTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(OrderPreservationType::NO_ORDER), "NO_ORDER" }, + { static_cast(OrderPreservationType::INSERTION_ORDER), "INSERTION_ORDER" }, + { static_cast(OrderPreservationType::FIXED_ORDER), "FIXED_ORDER" } + }; + return values; } template<> const char* EnumUtil::ToChars(OrderPreservationType value) { - switch(value) { - case OrderPreservationType::NO_ORDER: - return "NO_ORDER"; - case OrderPreservationType::INSERTION_ORDER: - return "INSERTION_ORDER"; - case OrderPreservationType::FIXED_ORDER: - return "FIXED_ORDER"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetOrderPreservationTypeValues(), 3, "OrderPreservationType", static_cast(value)); } template<> OrderPreservationType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NO_ORDER")) { - return OrderPreservationType::NO_ORDER; - } - if (StringUtil::Equals(value, "INSERTION_ORDER")) { - return OrderPreservationType::INSERTION_ORDER; - } - if (StringUtil::Equals(value, "FIXED_ORDER")) { - return OrderPreservationType::FIXED_ORDER; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetOrderPreservationTypeValues(), 3, "OrderPreservationType", value)); +} + +const StringUtil::EnumStringLiteral *GetOrderTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(OrderType::INVALID), "INVALID" }, + { static_cast(OrderType::ORDER_DEFAULT), "ORDER_DEFAULT" }, + { static_cast(OrderType::ORDER_DEFAULT), "DEFAULT" }, + { static_cast(OrderType::ASCENDING), "ASCENDING" }, + { static_cast(OrderType::ASCENDING), "ASC" }, + { static_cast(OrderType::DESCENDING), "DESCENDING" }, + { static_cast(OrderType::DESCENDING), "DESC" } + }; + return values; } template<> const char* EnumUtil::ToChars(OrderType value) { - switch(value) { - case OrderType::INVALID: - return "INVALID"; - case OrderType::ORDER_DEFAULT: - return "ORDER_DEFAULT"; - case OrderType::ASCENDING: - return "ASCENDING"; - case OrderType::DESCENDING: - return "DESCENDING"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetOrderTypeValues(), 7, "OrderType", static_cast(value)); } template<> OrderType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return OrderType::INVALID; - } - if (StringUtil::Equals(value, "ORDER_DEFAULT") || StringUtil::Equals(value, "DEFAULT")) { - return OrderType::ORDER_DEFAULT; - } - if (StringUtil::Equals(value, "ASCENDING") || StringUtil::Equals(value, "ASC")) { - return OrderType::ASCENDING; - } - if (StringUtil::Equals(value, "DESCENDING") || StringUtil::Equals(value, "DESC")) { - return OrderType::DESCENDING; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetOrderTypeValues(), 7, "OrderType", value)); +} + +const StringUtil::EnumStringLiteral *GetOutputStreamValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(OutputStream::STREAM_STDOUT), "STREAM_STDOUT" }, + { static_cast(OutputStream::STREAM_STDERR), "STREAM_STDERR" } + }; + return values; } template<> const char* EnumUtil::ToChars(OutputStream value) { - switch(value) { - case OutputStream::STREAM_STDOUT: - return "STREAM_STDOUT"; - case OutputStream::STREAM_STDERR: - return "STREAM_STDERR"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetOutputStreamValues(), 2, "OutputStream", static_cast(value)); } template<> OutputStream EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "STREAM_STDOUT")) { - return OutputStream::STREAM_STDOUT; - } - if (StringUtil::Equals(value, "STREAM_STDERR")) { - return OutputStream::STREAM_STDERR; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetOutputStreamValues(), 2, "OutputStream", value)); +} + +const StringUtil::EnumStringLiteral *GetParseInfoTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ParseInfoType::ALTER_INFO), "ALTER_INFO" }, + { static_cast(ParseInfoType::ATTACH_INFO), "ATTACH_INFO" }, + { static_cast(ParseInfoType::COPY_INFO), "COPY_INFO" }, + { static_cast(ParseInfoType::CREATE_INFO), "CREATE_INFO" }, + { static_cast(ParseInfoType::CREATE_SECRET_INFO), "CREATE_SECRET_INFO" }, + { static_cast(ParseInfoType::DETACH_INFO), "DETACH_INFO" }, + { static_cast(ParseInfoType::DROP_INFO), "DROP_INFO" }, + { static_cast(ParseInfoType::BOUND_EXPORT_DATA), "BOUND_EXPORT_DATA" }, + { static_cast(ParseInfoType::LOAD_INFO), "LOAD_INFO" }, + { static_cast(ParseInfoType::PRAGMA_INFO), "PRAGMA_INFO" }, + { static_cast(ParseInfoType::SHOW_SELECT_INFO), "SHOW_SELECT_INFO" }, + { static_cast(ParseInfoType::TRANSACTION_INFO), "TRANSACTION_INFO" }, + { static_cast(ParseInfoType::VACUUM_INFO), "VACUUM_INFO" }, + { static_cast(ParseInfoType::COMMENT_ON_INFO), "COMMENT_ON_INFO" }, + { static_cast(ParseInfoType::COMMENT_ON_COLUMN_INFO), "COMMENT_ON_COLUMN_INFO" }, + { static_cast(ParseInfoType::COPY_DATABASE_INFO), "COPY_DATABASE_INFO" }, + { static_cast(ParseInfoType::UPDATE_EXTENSIONS_INFO), "UPDATE_EXTENSIONS_INFO" } + }; + return values; } template<> const char* EnumUtil::ToChars(ParseInfoType value) { - switch(value) { - case ParseInfoType::ALTER_INFO: - return "ALTER_INFO"; - case ParseInfoType::ATTACH_INFO: - return "ATTACH_INFO"; - case ParseInfoType::COPY_INFO: - return "COPY_INFO"; - case ParseInfoType::CREATE_INFO: - return "CREATE_INFO"; - case ParseInfoType::CREATE_SECRET_INFO: - return "CREATE_SECRET_INFO"; - case ParseInfoType::DETACH_INFO: - return "DETACH_INFO"; - case ParseInfoType::DROP_INFO: - return "DROP_INFO"; - case ParseInfoType::BOUND_EXPORT_DATA: - return "BOUND_EXPORT_DATA"; - case ParseInfoType::LOAD_INFO: - return "LOAD_INFO"; - case ParseInfoType::PRAGMA_INFO: - return "PRAGMA_INFO"; - case ParseInfoType::SHOW_SELECT_INFO: - return "SHOW_SELECT_INFO"; - case ParseInfoType::TRANSACTION_INFO: - return "TRANSACTION_INFO"; - case ParseInfoType::VACUUM_INFO: - return "VACUUM_INFO"; - case ParseInfoType::COMMENT_ON_INFO: - return "COMMENT_ON_INFO"; - case ParseInfoType::COMMENT_ON_COLUMN_INFO: - return "COMMENT_ON_COLUMN_INFO"; - case ParseInfoType::COPY_DATABASE_INFO: - return "COPY_DATABASE_INFO"; - case ParseInfoType::UPDATE_EXTENSIONS_INFO: - return "UPDATE_EXTENSIONS_INFO"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetParseInfoTypeValues(), 17, "ParseInfoType", static_cast(value)); } template<> ParseInfoType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "ALTER_INFO")) { - return ParseInfoType::ALTER_INFO; - } - if (StringUtil::Equals(value, "ATTACH_INFO")) { - return ParseInfoType::ATTACH_INFO; - } - if (StringUtil::Equals(value, "COPY_INFO")) { - return ParseInfoType::COPY_INFO; - } - if (StringUtil::Equals(value, "CREATE_INFO")) { - return ParseInfoType::CREATE_INFO; - } - if (StringUtil::Equals(value, "CREATE_SECRET_INFO")) { - return ParseInfoType::CREATE_SECRET_INFO; - } - if (StringUtil::Equals(value, "DETACH_INFO")) { - return ParseInfoType::DETACH_INFO; - } - if (StringUtil::Equals(value, "DROP_INFO")) { - return ParseInfoType::DROP_INFO; - } - if (StringUtil::Equals(value, "BOUND_EXPORT_DATA")) { - return ParseInfoType::BOUND_EXPORT_DATA; - } - if (StringUtil::Equals(value, "LOAD_INFO")) { - return ParseInfoType::LOAD_INFO; - } - if (StringUtil::Equals(value, "PRAGMA_INFO")) { - return ParseInfoType::PRAGMA_INFO; - } - if (StringUtil::Equals(value, "SHOW_SELECT_INFO")) { - return ParseInfoType::SHOW_SELECT_INFO; - } - if (StringUtil::Equals(value, "TRANSACTION_INFO")) { - return ParseInfoType::TRANSACTION_INFO; - } - if (StringUtil::Equals(value, "VACUUM_INFO")) { - return ParseInfoType::VACUUM_INFO; - } - if (StringUtil::Equals(value, "COMMENT_ON_INFO")) { - return ParseInfoType::COMMENT_ON_INFO; - } - if (StringUtil::Equals(value, "COMMENT_ON_COLUMN_INFO")) { - return ParseInfoType::COMMENT_ON_COLUMN_INFO; - } - if (StringUtil::Equals(value, "COPY_DATABASE_INFO")) { - return ParseInfoType::COPY_DATABASE_INFO; - } - if (StringUtil::Equals(value, "UPDATE_EXTENSIONS_INFO")) { - return ParseInfoType::UPDATE_EXTENSIONS_INFO; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetParseInfoTypeValues(), 17, "ParseInfoType", value)); +} + +const StringUtil::EnumStringLiteral *GetParserExtensionResultTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ParserExtensionResultType::PARSE_SUCCESSFUL), "PARSE_SUCCESSFUL" }, + { static_cast(ParserExtensionResultType::DISPLAY_ORIGINAL_ERROR), "DISPLAY_ORIGINAL_ERROR" }, + { static_cast(ParserExtensionResultType::DISPLAY_EXTENSION_ERROR), "DISPLAY_EXTENSION_ERROR" } + }; + return values; } template<> const char* EnumUtil::ToChars(ParserExtensionResultType value) { - switch(value) { - case ParserExtensionResultType::PARSE_SUCCESSFUL: - return "PARSE_SUCCESSFUL"; - case ParserExtensionResultType::DISPLAY_ORIGINAL_ERROR: - return "DISPLAY_ORIGINAL_ERROR"; - case ParserExtensionResultType::DISPLAY_EXTENSION_ERROR: - return "DISPLAY_EXTENSION_ERROR"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetParserExtensionResultTypeValues(), 3, "ParserExtensionResultType", static_cast(value)); } template<> ParserExtensionResultType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "PARSE_SUCCESSFUL")) { - return ParserExtensionResultType::PARSE_SUCCESSFUL; - } - if (StringUtil::Equals(value, "DISPLAY_ORIGINAL_ERROR")) { - return ParserExtensionResultType::DISPLAY_ORIGINAL_ERROR; - } - if (StringUtil::Equals(value, "DISPLAY_EXTENSION_ERROR")) { - return ParserExtensionResultType::DISPLAY_EXTENSION_ERROR; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetParserExtensionResultTypeValues(), 3, "ParserExtensionResultType", value)); +} + +const StringUtil::EnumStringLiteral *GetPartitionSortStageValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(PartitionSortStage::INIT), "INIT" }, + { static_cast(PartitionSortStage::SCAN), "SCAN" }, + { static_cast(PartitionSortStage::PREPARE), "PREPARE" }, + { static_cast(PartitionSortStage::MERGE), "MERGE" }, + { static_cast(PartitionSortStage::SORTED), "SORTED" }, + { static_cast(PartitionSortStage::FINISHED), "FINISHED" } + }; + return values; } template<> const char* EnumUtil::ToChars(PartitionSortStage value) { - switch(value) { - case PartitionSortStage::INIT: - return "INIT"; - case PartitionSortStage::SCAN: - return "SCAN"; - case PartitionSortStage::PREPARE: - return "PREPARE"; - case PartitionSortStage::MERGE: - return "MERGE"; - case PartitionSortStage::SORTED: - return "SORTED"; - case PartitionSortStage::FINISHED: - return "FINISHED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetPartitionSortStageValues(), 6, "PartitionSortStage", static_cast(value)); } template<> PartitionSortStage EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INIT")) { - return PartitionSortStage::INIT; - } - if (StringUtil::Equals(value, "SCAN")) { - return PartitionSortStage::SCAN; - } - if (StringUtil::Equals(value, "PREPARE")) { - return PartitionSortStage::PREPARE; - } - if (StringUtil::Equals(value, "MERGE")) { - return PartitionSortStage::MERGE; - } - if (StringUtil::Equals(value, "SORTED")) { - return PartitionSortStage::SORTED; - } - if (StringUtil::Equals(value, "FINISHED")) { - return PartitionSortStage::FINISHED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetPartitionSortStageValues(), 6, "PartitionSortStage", value)); +} + +const StringUtil::EnumStringLiteral *GetPartitionedColumnDataTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(PartitionedColumnDataType::INVALID), "INVALID" }, + { static_cast(PartitionedColumnDataType::RADIX), "RADIX" }, + { static_cast(PartitionedColumnDataType::HIVE), "HIVE" } + }; + return values; } template<> const char* EnumUtil::ToChars(PartitionedColumnDataType value) { - switch(value) { - case PartitionedColumnDataType::INVALID: - return "INVALID"; - case PartitionedColumnDataType::RADIX: - return "RADIX"; - case PartitionedColumnDataType::HIVE: - return "HIVE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetPartitionedColumnDataTypeValues(), 3, "PartitionedColumnDataType", static_cast(value)); } template<> PartitionedColumnDataType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return PartitionedColumnDataType::INVALID; - } - if (StringUtil::Equals(value, "RADIX")) { - return PartitionedColumnDataType::RADIX; - } - if (StringUtil::Equals(value, "HIVE")) { - return PartitionedColumnDataType::HIVE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetPartitionedColumnDataTypeValues(), 3, "PartitionedColumnDataType", value)); +} + +const StringUtil::EnumStringLiteral *GetPartitionedTupleDataTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(PartitionedTupleDataType::INVALID), "INVALID" }, + { static_cast(PartitionedTupleDataType::RADIX), "RADIX" } + }; + return values; } template<> const char* EnumUtil::ToChars(PartitionedTupleDataType value) { - switch(value) { - case PartitionedTupleDataType::INVALID: - return "INVALID"; - case PartitionedTupleDataType::RADIX: - return "RADIX"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetPartitionedTupleDataTypeValues(), 2, "PartitionedTupleDataType", static_cast(value)); } template<> PartitionedTupleDataType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return PartitionedTupleDataType::INVALID; - } - if (StringUtil::Equals(value, "RADIX")) { - return PartitionedTupleDataType::RADIX; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetPartitionedTupleDataTypeValues(), 2, "PartitionedTupleDataType", value)); +} + +const StringUtil::EnumStringLiteral *GetPendingExecutionResultValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(PendingExecutionResult::RESULT_READY), "RESULT_READY" }, + { static_cast(PendingExecutionResult::RESULT_NOT_READY), "RESULT_NOT_READY" }, + { static_cast(PendingExecutionResult::EXECUTION_ERROR), "EXECUTION_ERROR" }, + { static_cast(PendingExecutionResult::BLOCKED), "BLOCKED" }, + { static_cast(PendingExecutionResult::NO_TASKS_AVAILABLE), "NO_TASKS_AVAILABLE" }, + { static_cast(PendingExecutionResult::EXECUTION_FINISHED), "EXECUTION_FINISHED" } + }; + return values; } template<> const char* EnumUtil::ToChars(PendingExecutionResult value) { - switch(value) { - case PendingExecutionResult::RESULT_READY: - return "RESULT_READY"; - case PendingExecutionResult::RESULT_NOT_READY: - return "RESULT_NOT_READY"; - case PendingExecutionResult::EXECUTION_ERROR: - return "EXECUTION_ERROR"; - case PendingExecutionResult::BLOCKED: - return "BLOCKED"; - case PendingExecutionResult::NO_TASKS_AVAILABLE: - return "NO_TASKS_AVAILABLE"; - case PendingExecutionResult::EXECUTION_FINISHED: - return "EXECUTION_FINISHED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetPendingExecutionResultValues(), 6, "PendingExecutionResult", static_cast(value)); } template<> PendingExecutionResult EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "RESULT_READY")) { - return PendingExecutionResult::RESULT_READY; - } - if (StringUtil::Equals(value, "RESULT_NOT_READY")) { - return PendingExecutionResult::RESULT_NOT_READY; - } - if (StringUtil::Equals(value, "EXECUTION_ERROR")) { - return PendingExecutionResult::EXECUTION_ERROR; - } - if (StringUtil::Equals(value, "BLOCKED")) { - return PendingExecutionResult::BLOCKED; - } - if (StringUtil::Equals(value, "NO_TASKS_AVAILABLE")) { - return PendingExecutionResult::NO_TASKS_AVAILABLE; - } - if (StringUtil::Equals(value, "EXECUTION_FINISHED")) { - return PendingExecutionResult::EXECUTION_FINISHED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetPendingExecutionResultValues(), 6, "PendingExecutionResult", value)); +} + +const StringUtil::EnumStringLiteral *GetPhysicalOperatorTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(PhysicalOperatorType::INVALID), "INVALID" }, + { static_cast(PhysicalOperatorType::ORDER_BY), "ORDER_BY" }, + { static_cast(PhysicalOperatorType::LIMIT), "LIMIT" }, + { static_cast(PhysicalOperatorType::STREAMING_LIMIT), "STREAMING_LIMIT" }, + { static_cast(PhysicalOperatorType::LIMIT_PERCENT), "LIMIT_PERCENT" }, + { static_cast(PhysicalOperatorType::TOP_N), "TOP_N" }, + { static_cast(PhysicalOperatorType::WINDOW), "WINDOW" }, + { static_cast(PhysicalOperatorType::UNNEST), "UNNEST" }, + { static_cast(PhysicalOperatorType::UNGROUPED_AGGREGATE), "UNGROUPED_AGGREGATE" }, + { static_cast(PhysicalOperatorType::HASH_GROUP_BY), "HASH_GROUP_BY" }, + { static_cast(PhysicalOperatorType::PERFECT_HASH_GROUP_BY), "PERFECT_HASH_GROUP_BY" }, + { static_cast(PhysicalOperatorType::PARTITIONED_AGGREGATE), "PARTITIONED_AGGREGATE" }, + { static_cast(PhysicalOperatorType::FILTER), "FILTER" }, + { static_cast(PhysicalOperatorType::PROJECTION), "PROJECTION" }, + { static_cast(PhysicalOperatorType::COPY_TO_FILE), "COPY_TO_FILE" }, + { static_cast(PhysicalOperatorType::BATCH_COPY_TO_FILE), "BATCH_COPY_TO_FILE" }, + { static_cast(PhysicalOperatorType::RESERVOIR_SAMPLE), "RESERVOIR_SAMPLE" }, + { static_cast(PhysicalOperatorType::STREAMING_SAMPLE), "STREAMING_SAMPLE" }, + { static_cast(PhysicalOperatorType::STREAMING_WINDOW), "STREAMING_WINDOW" }, + { static_cast(PhysicalOperatorType::PIVOT), "PIVOT" }, + { static_cast(PhysicalOperatorType::COPY_DATABASE), "COPY_DATABASE" }, + { static_cast(PhysicalOperatorType::TABLE_SCAN), "TABLE_SCAN" }, + { static_cast(PhysicalOperatorType::DUMMY_SCAN), "DUMMY_SCAN" }, + { static_cast(PhysicalOperatorType::COLUMN_DATA_SCAN), "COLUMN_DATA_SCAN" }, + { static_cast(PhysicalOperatorType::CHUNK_SCAN), "CHUNK_SCAN" }, + { static_cast(PhysicalOperatorType::RECURSIVE_CTE_SCAN), "RECURSIVE_CTE_SCAN" }, + { static_cast(PhysicalOperatorType::CTE_SCAN), "CTE_SCAN" }, + { static_cast(PhysicalOperatorType::DELIM_SCAN), "DELIM_SCAN" }, + { static_cast(PhysicalOperatorType::EXPRESSION_SCAN), "EXPRESSION_SCAN" }, + { static_cast(PhysicalOperatorType::POSITIONAL_SCAN), "POSITIONAL_SCAN" }, + { static_cast(PhysicalOperatorType::BLOCKWISE_NL_JOIN), "BLOCKWISE_NL_JOIN" }, + { static_cast(PhysicalOperatorType::NESTED_LOOP_JOIN), "NESTED_LOOP_JOIN" }, + { static_cast(PhysicalOperatorType::HASH_JOIN), "HASH_JOIN" }, + { static_cast(PhysicalOperatorType::CROSS_PRODUCT), "CROSS_PRODUCT" }, + { static_cast(PhysicalOperatorType::PIECEWISE_MERGE_JOIN), "PIECEWISE_MERGE_JOIN" }, + { static_cast(PhysicalOperatorType::IE_JOIN), "IE_JOIN" }, + { static_cast(PhysicalOperatorType::LEFT_DELIM_JOIN), "LEFT_DELIM_JOIN" }, + { static_cast(PhysicalOperatorType::RIGHT_DELIM_JOIN), "RIGHT_DELIM_JOIN" }, + { static_cast(PhysicalOperatorType::POSITIONAL_JOIN), "POSITIONAL_JOIN" }, + { static_cast(PhysicalOperatorType::ASOF_JOIN), "ASOF_JOIN" }, + { static_cast(PhysicalOperatorType::UNION), "UNION" }, + { static_cast(PhysicalOperatorType::RECURSIVE_CTE), "RECURSIVE_CTE" }, + { static_cast(PhysicalOperatorType::CTE), "CTE" }, + { static_cast(PhysicalOperatorType::INSERT), "INSERT" }, + { static_cast(PhysicalOperatorType::BATCH_INSERT), "BATCH_INSERT" }, + { static_cast(PhysicalOperatorType::DELETE_OPERATOR), "DELETE_OPERATOR" }, + { static_cast(PhysicalOperatorType::UPDATE), "UPDATE" }, + { static_cast(PhysicalOperatorType::CREATE_TABLE), "CREATE_TABLE" }, + { static_cast(PhysicalOperatorType::CREATE_TABLE_AS), "CREATE_TABLE_AS" }, + { static_cast(PhysicalOperatorType::BATCH_CREATE_TABLE_AS), "BATCH_CREATE_TABLE_AS" }, + { static_cast(PhysicalOperatorType::CREATE_INDEX), "CREATE_INDEX" }, + { static_cast(PhysicalOperatorType::ALTER), "ALTER" }, + { static_cast(PhysicalOperatorType::CREATE_SEQUENCE), "CREATE_SEQUENCE" }, + { static_cast(PhysicalOperatorType::CREATE_VIEW), "CREATE_VIEW" }, + { static_cast(PhysicalOperatorType::CREATE_SCHEMA), "CREATE_SCHEMA" }, + { static_cast(PhysicalOperatorType::CREATE_MACRO), "CREATE_MACRO" }, + { static_cast(PhysicalOperatorType::DROP), "DROP" }, + { static_cast(PhysicalOperatorType::PRAGMA), "PRAGMA" }, + { static_cast(PhysicalOperatorType::TRANSACTION), "TRANSACTION" }, + { static_cast(PhysicalOperatorType::CREATE_TYPE), "CREATE_TYPE" }, + { static_cast(PhysicalOperatorType::ATTACH), "ATTACH" }, + { static_cast(PhysicalOperatorType::DETACH), "DETACH" }, + { static_cast(PhysicalOperatorType::EXPLAIN), "EXPLAIN" }, + { static_cast(PhysicalOperatorType::EXPLAIN_ANALYZE), "EXPLAIN_ANALYZE" }, + { static_cast(PhysicalOperatorType::EMPTY_RESULT), "EMPTY_RESULT" }, + { static_cast(PhysicalOperatorType::EXECUTE), "EXECUTE" }, + { static_cast(PhysicalOperatorType::PREPARE), "PREPARE" }, + { static_cast(PhysicalOperatorType::VACUUM), "VACUUM" }, + { static_cast(PhysicalOperatorType::EXPORT), "EXPORT" }, + { static_cast(PhysicalOperatorType::SET), "SET" }, + { static_cast(PhysicalOperatorType::SET_VARIABLE), "SET_VARIABLE" }, + { static_cast(PhysicalOperatorType::LOAD), "LOAD" }, + { static_cast(PhysicalOperatorType::INOUT_FUNCTION), "INOUT_FUNCTION" }, + { static_cast(PhysicalOperatorType::RESULT_COLLECTOR), "RESULT_COLLECTOR" }, + { static_cast(PhysicalOperatorType::RESET), "RESET" }, + { static_cast(PhysicalOperatorType::EXTENSION), "EXTENSION" }, + { static_cast(PhysicalOperatorType::VERIFY_VECTOR), "VERIFY_VECTOR" }, + { static_cast(PhysicalOperatorType::UPDATE_EXTENSIONS), "UPDATE_EXTENSIONS" }, + { static_cast(PhysicalOperatorType::CREATE_SECRET), "CREATE_SECRET" } + }; + return values; } template<> const char* EnumUtil::ToChars(PhysicalOperatorType value) { - switch(value) { - case PhysicalOperatorType::INVALID: - return "INVALID"; - case PhysicalOperatorType::ORDER_BY: - return "ORDER_BY"; - case PhysicalOperatorType::LIMIT: - return "LIMIT"; - case PhysicalOperatorType::STREAMING_LIMIT: - return "STREAMING_LIMIT"; - case PhysicalOperatorType::LIMIT_PERCENT: - return "LIMIT_PERCENT"; - case PhysicalOperatorType::TOP_N: - return "TOP_N"; - case PhysicalOperatorType::WINDOW: - return "WINDOW"; - case PhysicalOperatorType::UNNEST: - return "UNNEST"; - case PhysicalOperatorType::UNGROUPED_AGGREGATE: - return "UNGROUPED_AGGREGATE"; - case PhysicalOperatorType::HASH_GROUP_BY: - return "HASH_GROUP_BY"; - case PhysicalOperatorType::PERFECT_HASH_GROUP_BY: - return "PERFECT_HASH_GROUP_BY"; - case PhysicalOperatorType::FILTER: - return "FILTER"; - case PhysicalOperatorType::PROJECTION: - return "PROJECTION"; - case PhysicalOperatorType::COPY_TO_FILE: - return "COPY_TO_FILE"; - case PhysicalOperatorType::BATCH_COPY_TO_FILE: - return "BATCH_COPY_TO_FILE"; - case PhysicalOperatorType::RESERVOIR_SAMPLE: - return "RESERVOIR_SAMPLE"; - case PhysicalOperatorType::STREAMING_SAMPLE: - return "STREAMING_SAMPLE"; - case PhysicalOperatorType::STREAMING_WINDOW: - return "STREAMING_WINDOW"; - case PhysicalOperatorType::PIVOT: - return "PIVOT"; - case PhysicalOperatorType::COPY_DATABASE: - return "COPY_DATABASE"; - case PhysicalOperatorType::TABLE_SCAN: - return "TABLE_SCAN"; - case PhysicalOperatorType::DUMMY_SCAN: - return "DUMMY_SCAN"; - case PhysicalOperatorType::COLUMN_DATA_SCAN: - return "COLUMN_DATA_SCAN"; - case PhysicalOperatorType::CHUNK_SCAN: - return "CHUNK_SCAN"; - case PhysicalOperatorType::RECURSIVE_CTE_SCAN: - return "RECURSIVE_CTE_SCAN"; - case PhysicalOperatorType::CTE_SCAN: - return "CTE_SCAN"; - case PhysicalOperatorType::DELIM_SCAN: - return "DELIM_SCAN"; - case PhysicalOperatorType::EXPRESSION_SCAN: - return "EXPRESSION_SCAN"; - case PhysicalOperatorType::POSITIONAL_SCAN: - return "POSITIONAL_SCAN"; - case PhysicalOperatorType::BLOCKWISE_NL_JOIN: - return "BLOCKWISE_NL_JOIN"; - case PhysicalOperatorType::NESTED_LOOP_JOIN: - return "NESTED_LOOP_JOIN"; - case PhysicalOperatorType::HASH_JOIN: - return "HASH_JOIN"; - case PhysicalOperatorType::CROSS_PRODUCT: - return "CROSS_PRODUCT"; - case PhysicalOperatorType::PIECEWISE_MERGE_JOIN: - return "PIECEWISE_MERGE_JOIN"; - case PhysicalOperatorType::IE_JOIN: - return "IE_JOIN"; - case PhysicalOperatorType::LEFT_DELIM_JOIN: - return "LEFT_DELIM_JOIN"; - case PhysicalOperatorType::RIGHT_DELIM_JOIN: - return "RIGHT_DELIM_JOIN"; - case PhysicalOperatorType::POSITIONAL_JOIN: - return "POSITIONAL_JOIN"; - case PhysicalOperatorType::ASOF_JOIN: - return "ASOF_JOIN"; - case PhysicalOperatorType::UNION: - return "UNION"; - case PhysicalOperatorType::RECURSIVE_CTE: - return "RECURSIVE_CTE"; - case PhysicalOperatorType::CTE: - return "CTE"; - case PhysicalOperatorType::INSERT: - return "INSERT"; - case PhysicalOperatorType::BATCH_INSERT: - return "BATCH_INSERT"; - case PhysicalOperatorType::DELETE_OPERATOR: - return "DELETE_OPERATOR"; - case PhysicalOperatorType::UPDATE: - return "UPDATE"; - case PhysicalOperatorType::CREATE_TABLE: - return "CREATE_TABLE"; - case PhysicalOperatorType::CREATE_TABLE_AS: - return "CREATE_TABLE_AS"; - case PhysicalOperatorType::BATCH_CREATE_TABLE_AS: - return "BATCH_CREATE_TABLE_AS"; - case PhysicalOperatorType::CREATE_INDEX: - return "CREATE_INDEX"; - case PhysicalOperatorType::ALTER: - return "ALTER"; - case PhysicalOperatorType::CREATE_SEQUENCE: - return "CREATE_SEQUENCE"; - case PhysicalOperatorType::CREATE_VIEW: - return "CREATE_VIEW"; - case PhysicalOperatorType::CREATE_SCHEMA: - return "CREATE_SCHEMA"; - case PhysicalOperatorType::CREATE_MACRO: - return "CREATE_MACRO"; - case PhysicalOperatorType::DROP: - return "DROP"; - case PhysicalOperatorType::PRAGMA: - return "PRAGMA"; - case PhysicalOperatorType::TRANSACTION: - return "TRANSACTION"; - case PhysicalOperatorType::CREATE_TYPE: - return "CREATE_TYPE"; - case PhysicalOperatorType::ATTACH: - return "ATTACH"; - case PhysicalOperatorType::DETACH: - return "DETACH"; - case PhysicalOperatorType::EXPLAIN: - return "EXPLAIN"; - case PhysicalOperatorType::EXPLAIN_ANALYZE: - return "EXPLAIN_ANALYZE"; - case PhysicalOperatorType::EMPTY_RESULT: - return "EMPTY_RESULT"; - case PhysicalOperatorType::EXECUTE: - return "EXECUTE"; - case PhysicalOperatorType::PREPARE: - return "PREPARE"; - case PhysicalOperatorType::VACUUM: - return "VACUUM"; - case PhysicalOperatorType::EXPORT: - return "EXPORT"; - case PhysicalOperatorType::SET: - return "SET"; - case PhysicalOperatorType::SET_VARIABLE: - return "SET_VARIABLE"; - case PhysicalOperatorType::LOAD: - return "LOAD"; - case PhysicalOperatorType::INOUT_FUNCTION: - return "INOUT_FUNCTION"; - case PhysicalOperatorType::RESULT_COLLECTOR: - return "RESULT_COLLECTOR"; - case PhysicalOperatorType::RESET: - return "RESET"; - case PhysicalOperatorType::EXTENSION: - return "EXTENSION"; - case PhysicalOperatorType::VERIFY_VECTOR: - return "VERIFY_VECTOR"; - case PhysicalOperatorType::UPDATE_EXTENSIONS: - return "UPDATE_EXTENSIONS"; - case PhysicalOperatorType::CREATE_SECRET: - return "CREATE_SECRET"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetPhysicalOperatorTypeValues(), 79, "PhysicalOperatorType", static_cast(value)); } template<> PhysicalOperatorType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return PhysicalOperatorType::INVALID; - } - if (StringUtil::Equals(value, "ORDER_BY")) { - return PhysicalOperatorType::ORDER_BY; - } - if (StringUtil::Equals(value, "LIMIT")) { - return PhysicalOperatorType::LIMIT; - } - if (StringUtil::Equals(value, "STREAMING_LIMIT")) { - return PhysicalOperatorType::STREAMING_LIMIT; - } - if (StringUtil::Equals(value, "LIMIT_PERCENT")) { - return PhysicalOperatorType::LIMIT_PERCENT; - } - if (StringUtil::Equals(value, "TOP_N")) { - return PhysicalOperatorType::TOP_N; - } - if (StringUtil::Equals(value, "WINDOW")) { - return PhysicalOperatorType::WINDOW; - } - if (StringUtil::Equals(value, "UNNEST")) { - return PhysicalOperatorType::UNNEST; - } - if (StringUtil::Equals(value, "UNGROUPED_AGGREGATE")) { - return PhysicalOperatorType::UNGROUPED_AGGREGATE; - } - if (StringUtil::Equals(value, "HASH_GROUP_BY")) { - return PhysicalOperatorType::HASH_GROUP_BY; - } - if (StringUtil::Equals(value, "PERFECT_HASH_GROUP_BY")) { - return PhysicalOperatorType::PERFECT_HASH_GROUP_BY; - } - if (StringUtil::Equals(value, "FILTER")) { - return PhysicalOperatorType::FILTER; - } - if (StringUtil::Equals(value, "PROJECTION")) { - return PhysicalOperatorType::PROJECTION; - } - if (StringUtil::Equals(value, "COPY_TO_FILE")) { - return PhysicalOperatorType::COPY_TO_FILE; - } - if (StringUtil::Equals(value, "BATCH_COPY_TO_FILE")) { - return PhysicalOperatorType::BATCH_COPY_TO_FILE; - } - if (StringUtil::Equals(value, "RESERVOIR_SAMPLE")) { - return PhysicalOperatorType::RESERVOIR_SAMPLE; - } - if (StringUtil::Equals(value, "STREAMING_SAMPLE")) { - return PhysicalOperatorType::STREAMING_SAMPLE; - } - if (StringUtil::Equals(value, "STREAMING_WINDOW")) { - return PhysicalOperatorType::STREAMING_WINDOW; - } - if (StringUtil::Equals(value, "PIVOT")) { - return PhysicalOperatorType::PIVOT; - } - if (StringUtil::Equals(value, "COPY_DATABASE")) { - return PhysicalOperatorType::COPY_DATABASE; - } - if (StringUtil::Equals(value, "TABLE_SCAN")) { - return PhysicalOperatorType::TABLE_SCAN; - } - if (StringUtil::Equals(value, "DUMMY_SCAN")) { - return PhysicalOperatorType::DUMMY_SCAN; - } - if (StringUtil::Equals(value, "COLUMN_DATA_SCAN")) { - return PhysicalOperatorType::COLUMN_DATA_SCAN; - } - if (StringUtil::Equals(value, "CHUNK_SCAN")) { - return PhysicalOperatorType::CHUNK_SCAN; - } - if (StringUtil::Equals(value, "RECURSIVE_CTE_SCAN")) { - return PhysicalOperatorType::RECURSIVE_CTE_SCAN; - } - if (StringUtil::Equals(value, "CTE_SCAN")) { - return PhysicalOperatorType::CTE_SCAN; - } - if (StringUtil::Equals(value, "DELIM_SCAN")) { - return PhysicalOperatorType::DELIM_SCAN; - } - if (StringUtil::Equals(value, "EXPRESSION_SCAN")) { - return PhysicalOperatorType::EXPRESSION_SCAN; - } - if (StringUtil::Equals(value, "POSITIONAL_SCAN")) { - return PhysicalOperatorType::POSITIONAL_SCAN; - } - if (StringUtil::Equals(value, "BLOCKWISE_NL_JOIN")) { - return PhysicalOperatorType::BLOCKWISE_NL_JOIN; - } - if (StringUtil::Equals(value, "NESTED_LOOP_JOIN")) { - return PhysicalOperatorType::NESTED_LOOP_JOIN; - } - if (StringUtil::Equals(value, "HASH_JOIN")) { - return PhysicalOperatorType::HASH_JOIN; - } - if (StringUtil::Equals(value, "CROSS_PRODUCT")) { - return PhysicalOperatorType::CROSS_PRODUCT; - } - if (StringUtil::Equals(value, "PIECEWISE_MERGE_JOIN")) { - return PhysicalOperatorType::PIECEWISE_MERGE_JOIN; - } - if (StringUtil::Equals(value, "IE_JOIN")) { - return PhysicalOperatorType::IE_JOIN; - } - if (StringUtil::Equals(value, "LEFT_DELIM_JOIN")) { - return PhysicalOperatorType::LEFT_DELIM_JOIN; - } - if (StringUtil::Equals(value, "RIGHT_DELIM_JOIN")) { - return PhysicalOperatorType::RIGHT_DELIM_JOIN; - } - if (StringUtil::Equals(value, "POSITIONAL_JOIN")) { - return PhysicalOperatorType::POSITIONAL_JOIN; - } - if (StringUtil::Equals(value, "ASOF_JOIN")) { - return PhysicalOperatorType::ASOF_JOIN; - } - if (StringUtil::Equals(value, "UNION")) { - return PhysicalOperatorType::UNION; - } - if (StringUtil::Equals(value, "RECURSIVE_CTE")) { - return PhysicalOperatorType::RECURSIVE_CTE; - } - if (StringUtil::Equals(value, "CTE")) { - return PhysicalOperatorType::CTE; - } - if (StringUtil::Equals(value, "INSERT")) { - return PhysicalOperatorType::INSERT; - } - if (StringUtil::Equals(value, "BATCH_INSERT")) { - return PhysicalOperatorType::BATCH_INSERT; - } - if (StringUtil::Equals(value, "DELETE_OPERATOR")) { - return PhysicalOperatorType::DELETE_OPERATOR; - } - if (StringUtil::Equals(value, "UPDATE")) { - return PhysicalOperatorType::UPDATE; - } - if (StringUtil::Equals(value, "CREATE_TABLE")) { - return PhysicalOperatorType::CREATE_TABLE; - } - if (StringUtil::Equals(value, "CREATE_TABLE_AS")) { - return PhysicalOperatorType::CREATE_TABLE_AS; - } - if (StringUtil::Equals(value, "BATCH_CREATE_TABLE_AS")) { - return PhysicalOperatorType::BATCH_CREATE_TABLE_AS; - } - if (StringUtil::Equals(value, "CREATE_INDEX")) { - return PhysicalOperatorType::CREATE_INDEX; - } - if (StringUtil::Equals(value, "ALTER")) { - return PhysicalOperatorType::ALTER; - } - if (StringUtil::Equals(value, "CREATE_SEQUENCE")) { - return PhysicalOperatorType::CREATE_SEQUENCE; - } - if (StringUtil::Equals(value, "CREATE_VIEW")) { - return PhysicalOperatorType::CREATE_VIEW; - } - if (StringUtil::Equals(value, "CREATE_SCHEMA")) { - return PhysicalOperatorType::CREATE_SCHEMA; - } - if (StringUtil::Equals(value, "CREATE_MACRO")) { - return PhysicalOperatorType::CREATE_MACRO; - } - if (StringUtil::Equals(value, "DROP")) { - return PhysicalOperatorType::DROP; - } - if (StringUtil::Equals(value, "PRAGMA")) { - return PhysicalOperatorType::PRAGMA; - } - if (StringUtil::Equals(value, "TRANSACTION")) { - return PhysicalOperatorType::TRANSACTION; - } - if (StringUtil::Equals(value, "CREATE_TYPE")) { - return PhysicalOperatorType::CREATE_TYPE; - } - if (StringUtil::Equals(value, "ATTACH")) { - return PhysicalOperatorType::ATTACH; - } - if (StringUtil::Equals(value, "DETACH")) { - return PhysicalOperatorType::DETACH; - } - if (StringUtil::Equals(value, "EXPLAIN")) { - return PhysicalOperatorType::EXPLAIN; - } - if (StringUtil::Equals(value, "EXPLAIN_ANALYZE")) { - return PhysicalOperatorType::EXPLAIN_ANALYZE; - } - if (StringUtil::Equals(value, "EMPTY_RESULT")) { - return PhysicalOperatorType::EMPTY_RESULT; - } - if (StringUtil::Equals(value, "EXECUTE")) { - return PhysicalOperatorType::EXECUTE; - } - if (StringUtil::Equals(value, "PREPARE")) { - return PhysicalOperatorType::PREPARE; - } - if (StringUtil::Equals(value, "VACUUM")) { - return PhysicalOperatorType::VACUUM; - } - if (StringUtil::Equals(value, "EXPORT")) { - return PhysicalOperatorType::EXPORT; - } - if (StringUtil::Equals(value, "SET")) { - return PhysicalOperatorType::SET; - } - if (StringUtil::Equals(value, "SET_VARIABLE")) { - return PhysicalOperatorType::SET_VARIABLE; - } - if (StringUtil::Equals(value, "LOAD")) { - return PhysicalOperatorType::LOAD; - } - if (StringUtil::Equals(value, "INOUT_FUNCTION")) { - return PhysicalOperatorType::INOUT_FUNCTION; - } - if (StringUtil::Equals(value, "RESULT_COLLECTOR")) { - return PhysicalOperatorType::RESULT_COLLECTOR; - } - if (StringUtil::Equals(value, "RESET")) { - return PhysicalOperatorType::RESET; - } - if (StringUtil::Equals(value, "EXTENSION")) { - return PhysicalOperatorType::EXTENSION; - } - if (StringUtil::Equals(value, "VERIFY_VECTOR")) { - return PhysicalOperatorType::VERIFY_VECTOR; - } - if (StringUtil::Equals(value, "UPDATE_EXTENSIONS")) { - return PhysicalOperatorType::UPDATE_EXTENSIONS; - } - if (StringUtil::Equals(value, "CREATE_SECRET")) { - return PhysicalOperatorType::CREATE_SECRET; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetPhysicalOperatorTypeValues(), 79, "PhysicalOperatorType", value)); +} + +const StringUtil::EnumStringLiteral *GetPhysicalTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(PhysicalType::BOOL), "BOOL" }, + { static_cast(PhysicalType::UINT8), "UINT8" }, + { static_cast(PhysicalType::INT8), "INT8" }, + { static_cast(PhysicalType::UINT16), "UINT16" }, + { static_cast(PhysicalType::INT16), "INT16" }, + { static_cast(PhysicalType::UINT32), "UINT32" }, + { static_cast(PhysicalType::INT32), "INT32" }, + { static_cast(PhysicalType::UINT64), "UINT64" }, + { static_cast(PhysicalType::INT64), "INT64" }, + { static_cast(PhysicalType::FLOAT), "FLOAT" }, + { static_cast(PhysicalType::DOUBLE), "DOUBLE" }, + { static_cast(PhysicalType::INTERVAL), "INTERVAL" }, + { static_cast(PhysicalType::LIST), "LIST" }, + { static_cast(PhysicalType::STRUCT), "STRUCT" }, + { static_cast(PhysicalType::ARRAY), "ARRAY" }, + { static_cast(PhysicalType::VARCHAR), "VARCHAR" }, + { static_cast(PhysicalType::UINT128), "UINT128" }, + { static_cast(PhysicalType::INT128), "INT128" }, + { static_cast(PhysicalType::UNKNOWN), "UNKNOWN" }, + { static_cast(PhysicalType::BIT), "BIT" }, + { static_cast(PhysicalType::INVALID), "INVALID" } + }; + return values; } template<> const char* EnumUtil::ToChars(PhysicalType value) { - switch(value) { - case PhysicalType::BOOL: - return "BOOL"; - case PhysicalType::UINT8: - return "UINT8"; - case PhysicalType::INT8: - return "INT8"; - case PhysicalType::UINT16: - return "UINT16"; - case PhysicalType::INT16: - return "INT16"; - case PhysicalType::UINT32: - return "UINT32"; - case PhysicalType::INT32: - return "INT32"; - case PhysicalType::UINT64: - return "UINT64"; - case PhysicalType::INT64: - return "INT64"; - case PhysicalType::FLOAT: - return "FLOAT"; - case PhysicalType::DOUBLE: - return "DOUBLE"; - case PhysicalType::INTERVAL: - return "INTERVAL"; - case PhysicalType::LIST: - return "LIST"; - case PhysicalType::STRUCT: - return "STRUCT"; - case PhysicalType::ARRAY: - return "ARRAY"; - case PhysicalType::VARCHAR: - return "VARCHAR"; - case PhysicalType::UINT128: - return "UINT128"; - case PhysicalType::INT128: - return "INT128"; - case PhysicalType::UNKNOWN: - return "UNKNOWN"; - case PhysicalType::BIT: - return "BIT"; - case PhysicalType::INVALID: - return "INVALID"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetPhysicalTypeValues(), 21, "PhysicalType", static_cast(value)); } template<> PhysicalType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "BOOL")) { - return PhysicalType::BOOL; - } - if (StringUtil::Equals(value, "UINT8")) { - return PhysicalType::UINT8; - } - if (StringUtil::Equals(value, "INT8")) { - return PhysicalType::INT8; - } - if (StringUtil::Equals(value, "UINT16")) { - return PhysicalType::UINT16; - } - if (StringUtil::Equals(value, "INT16")) { - return PhysicalType::INT16; - } - if (StringUtil::Equals(value, "UINT32")) { - return PhysicalType::UINT32; - } - if (StringUtil::Equals(value, "INT32")) { - return PhysicalType::INT32; - } - if (StringUtil::Equals(value, "UINT64")) { - return PhysicalType::UINT64; - } - if (StringUtil::Equals(value, "INT64")) { - return PhysicalType::INT64; - } - if (StringUtil::Equals(value, "FLOAT")) { - return PhysicalType::FLOAT; - } - if (StringUtil::Equals(value, "DOUBLE")) { - return PhysicalType::DOUBLE; - } - if (StringUtil::Equals(value, "INTERVAL")) { - return PhysicalType::INTERVAL; - } - if (StringUtil::Equals(value, "LIST")) { - return PhysicalType::LIST; - } - if (StringUtil::Equals(value, "STRUCT")) { - return PhysicalType::STRUCT; - } - if (StringUtil::Equals(value, "ARRAY")) { - return PhysicalType::ARRAY; - } - if (StringUtil::Equals(value, "VARCHAR")) { - return PhysicalType::VARCHAR; - } - if (StringUtil::Equals(value, "UINT128")) { - return PhysicalType::UINT128; - } - if (StringUtil::Equals(value, "INT128")) { - return PhysicalType::INT128; - } - if (StringUtil::Equals(value, "UNKNOWN")) { - return PhysicalType::UNKNOWN; - } - if (StringUtil::Equals(value, "BIT")) { - return PhysicalType::BIT; - } - if (StringUtil::Equals(value, "INVALID")) { - return PhysicalType::INVALID; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetPhysicalTypeValues(), 21, "PhysicalType", value)); +} + +const StringUtil::EnumStringLiteral *GetPragmaTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(PragmaType::PRAGMA_STATEMENT), "PRAGMA_STATEMENT" }, + { static_cast(PragmaType::PRAGMA_CALL), "PRAGMA_CALL" } + }; + return values; } template<> const char* EnumUtil::ToChars(PragmaType value) { - switch(value) { - case PragmaType::PRAGMA_STATEMENT: - return "PRAGMA_STATEMENT"; - case PragmaType::PRAGMA_CALL: - return "PRAGMA_CALL"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetPragmaTypeValues(), 2, "PragmaType", static_cast(value)); } template<> PragmaType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "PRAGMA_STATEMENT")) { - return PragmaType::PRAGMA_STATEMENT; - } - if (StringUtil::Equals(value, "PRAGMA_CALL")) { - return PragmaType::PRAGMA_CALL; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetPragmaTypeValues(), 2, "PragmaType", value)); +} + +const StringUtil::EnumStringLiteral *GetPreparedParamTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(PreparedParamType::AUTO_INCREMENT), "AUTO_INCREMENT" }, + { static_cast(PreparedParamType::POSITIONAL), "POSITIONAL" }, + { static_cast(PreparedParamType::NAMED), "NAMED" }, + { static_cast(PreparedParamType::INVALID), "INVALID" } + }; + return values; } template<> const char* EnumUtil::ToChars(PreparedParamType value) { - switch(value) { - case PreparedParamType::AUTO_INCREMENT: - return "AUTO_INCREMENT"; - case PreparedParamType::POSITIONAL: - return "POSITIONAL"; - case PreparedParamType::NAMED: - return "NAMED"; - case PreparedParamType::INVALID: - return "INVALID"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetPreparedParamTypeValues(), 4, "PreparedParamType", static_cast(value)); } template<> PreparedParamType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "AUTO_INCREMENT")) { - return PreparedParamType::AUTO_INCREMENT; - } - if (StringUtil::Equals(value, "POSITIONAL")) { - return PreparedParamType::POSITIONAL; - } - if (StringUtil::Equals(value, "NAMED")) { - return PreparedParamType::NAMED; - } - if (StringUtil::Equals(value, "INVALID")) { - return PreparedParamType::INVALID; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetPreparedParamTypeValues(), 4, "PreparedParamType", value)); +} + +const StringUtil::EnumStringLiteral *GetPreparedStatementModeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(PreparedStatementMode::PREPARE_ONLY), "PREPARE_ONLY" }, + { static_cast(PreparedStatementMode::PREPARE_AND_EXECUTE), "PREPARE_AND_EXECUTE" } + }; + return values; } template<> const char* EnumUtil::ToChars(PreparedStatementMode value) { - switch(value) { - case PreparedStatementMode::PREPARE_ONLY: - return "PREPARE_ONLY"; - case PreparedStatementMode::PREPARE_AND_EXECUTE: - return "PREPARE_AND_EXECUTE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetPreparedStatementModeValues(), 2, "PreparedStatementMode", static_cast(value)); } template<> PreparedStatementMode EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "PREPARE_ONLY")) { - return PreparedStatementMode::PREPARE_ONLY; - } - if (StringUtil::Equals(value, "PREPARE_AND_EXECUTE")) { - return PreparedStatementMode::PREPARE_AND_EXECUTE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetPreparedStatementModeValues(), 2, "PreparedStatementMode", value)); +} + +const StringUtil::EnumStringLiteral *GetProfilerPrintFormatValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ProfilerPrintFormat::QUERY_TREE), "QUERY_TREE" }, + { static_cast(ProfilerPrintFormat::JSON), "JSON" }, + { static_cast(ProfilerPrintFormat::QUERY_TREE_OPTIMIZER), "QUERY_TREE_OPTIMIZER" }, + { static_cast(ProfilerPrintFormat::NO_OUTPUT), "NO_OUTPUT" }, + { static_cast(ProfilerPrintFormat::HTML), "HTML" }, + { static_cast(ProfilerPrintFormat::GRAPHVIZ), "GRAPHVIZ" } + }; + return values; } template<> const char* EnumUtil::ToChars(ProfilerPrintFormat value) { - switch(value) { - case ProfilerPrintFormat::QUERY_TREE: - return "QUERY_TREE"; - case ProfilerPrintFormat::JSON: - return "JSON"; - case ProfilerPrintFormat::QUERY_TREE_OPTIMIZER: - return "QUERY_TREE_OPTIMIZER"; - case ProfilerPrintFormat::NO_OUTPUT: - return "NO_OUTPUT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetProfilerPrintFormatValues(), 6, "ProfilerPrintFormat", static_cast(value)); } template<> ProfilerPrintFormat EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "QUERY_TREE")) { - return ProfilerPrintFormat::QUERY_TREE; - } - if (StringUtil::Equals(value, "JSON")) { - return ProfilerPrintFormat::JSON; - } - if (StringUtil::Equals(value, "QUERY_TREE_OPTIMIZER")) { - return ProfilerPrintFormat::QUERY_TREE_OPTIMIZER; - } - if (StringUtil::Equals(value, "NO_OUTPUT")) { - return ProfilerPrintFormat::NO_OUTPUT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetProfilerPrintFormatValues(), 6, "ProfilerPrintFormat", value)); +} + +const StringUtil::EnumStringLiteral *GetQuantileSerializationTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(QuantileSerializationType::NON_DECIMAL), "NON_DECIMAL" }, + { static_cast(QuantileSerializationType::DECIMAL_DISCRETE), "DECIMAL_DISCRETE" }, + { static_cast(QuantileSerializationType::DECIMAL_DISCRETE_LIST), "DECIMAL_DISCRETE_LIST" }, + { static_cast(QuantileSerializationType::DECIMAL_CONTINUOUS), "DECIMAL_CONTINUOUS" }, + { static_cast(QuantileSerializationType::DECIMAL_CONTINUOUS_LIST), "DECIMAL_CONTINUOUS_LIST" } + }; + return values; } template<> const char* EnumUtil::ToChars(QuantileSerializationType value) { - switch(value) { - case QuantileSerializationType::NON_DECIMAL: - return "NON_DECIMAL"; - case QuantileSerializationType::DECIMAL_DISCRETE: - return "DECIMAL_DISCRETE"; - case QuantileSerializationType::DECIMAL_DISCRETE_LIST: - return "DECIMAL_DISCRETE_LIST"; - case QuantileSerializationType::DECIMAL_CONTINUOUS: - return "DECIMAL_CONTINUOUS"; - case QuantileSerializationType::DECIMAL_CONTINUOUS_LIST: - return "DECIMAL_CONTINUOUS_LIST"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetQuantileSerializationTypeValues(), 5, "QuantileSerializationType", static_cast(value)); } template<> QuantileSerializationType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NON_DECIMAL")) { - return QuantileSerializationType::NON_DECIMAL; - } - if (StringUtil::Equals(value, "DECIMAL_DISCRETE")) { - return QuantileSerializationType::DECIMAL_DISCRETE; - } - if (StringUtil::Equals(value, "DECIMAL_DISCRETE_LIST")) { - return QuantileSerializationType::DECIMAL_DISCRETE_LIST; - } - if (StringUtil::Equals(value, "DECIMAL_CONTINUOUS")) { - return QuantileSerializationType::DECIMAL_CONTINUOUS; - } - if (StringUtil::Equals(value, "DECIMAL_CONTINUOUS_LIST")) { - return QuantileSerializationType::DECIMAL_CONTINUOUS_LIST; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetQuantileSerializationTypeValues(), 5, "QuantileSerializationType", value)); +} + +const StringUtil::EnumStringLiteral *GetQueryNodeTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(QueryNodeType::SELECT_NODE), "SELECT_NODE" }, + { static_cast(QueryNodeType::SET_OPERATION_NODE), "SET_OPERATION_NODE" }, + { static_cast(QueryNodeType::BOUND_SUBQUERY_NODE), "BOUND_SUBQUERY_NODE" }, + { static_cast(QueryNodeType::RECURSIVE_CTE_NODE), "RECURSIVE_CTE_NODE" }, + { static_cast(QueryNodeType::CTE_NODE), "CTE_NODE" } + }; + return values; } template<> const char* EnumUtil::ToChars(QueryNodeType value) { - switch(value) { - case QueryNodeType::SELECT_NODE: - return "SELECT_NODE"; - case QueryNodeType::SET_OPERATION_NODE: - return "SET_OPERATION_NODE"; - case QueryNodeType::BOUND_SUBQUERY_NODE: - return "BOUND_SUBQUERY_NODE"; - case QueryNodeType::RECURSIVE_CTE_NODE: - return "RECURSIVE_CTE_NODE"; - case QueryNodeType::CTE_NODE: - return "CTE_NODE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetQueryNodeTypeValues(), 5, "QueryNodeType", static_cast(value)); } template<> QueryNodeType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "SELECT_NODE")) { - return QueryNodeType::SELECT_NODE; - } - if (StringUtil::Equals(value, "SET_OPERATION_NODE")) { - return QueryNodeType::SET_OPERATION_NODE; - } - if (StringUtil::Equals(value, "BOUND_SUBQUERY_NODE")) { - return QueryNodeType::BOUND_SUBQUERY_NODE; - } - if (StringUtil::Equals(value, "RECURSIVE_CTE_NODE")) { - return QueryNodeType::RECURSIVE_CTE_NODE; - } - if (StringUtil::Equals(value, "CTE_NODE")) { - return QueryNodeType::CTE_NODE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetQueryNodeTypeValues(), 5, "QueryNodeType", value)); +} + +const StringUtil::EnumStringLiteral *GetQueryResultTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(QueryResultType::MATERIALIZED_RESULT), "MATERIALIZED_RESULT" }, + { static_cast(QueryResultType::STREAM_RESULT), "STREAM_RESULT" }, + { static_cast(QueryResultType::PENDING_RESULT), "PENDING_RESULT" }, + { static_cast(QueryResultType::ARROW_RESULT), "ARROW_RESULT" } + }; + return values; } template<> const char* EnumUtil::ToChars(QueryResultType value) { - switch(value) { - case QueryResultType::MATERIALIZED_RESULT: - return "MATERIALIZED_RESULT"; - case QueryResultType::STREAM_RESULT: - return "STREAM_RESULT"; - case QueryResultType::PENDING_RESULT: - return "PENDING_RESULT"; - case QueryResultType::ARROW_RESULT: - return "ARROW_RESULT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetQueryResultTypeValues(), 4, "QueryResultType", static_cast(value)); } template<> QueryResultType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "MATERIALIZED_RESULT")) { - return QueryResultType::MATERIALIZED_RESULT; - } - if (StringUtil::Equals(value, "STREAM_RESULT")) { - return QueryResultType::STREAM_RESULT; - } - if (StringUtil::Equals(value, "PENDING_RESULT")) { - return QueryResultType::PENDING_RESULT; - } - if (StringUtil::Equals(value, "ARROW_RESULT")) { - return QueryResultType::ARROW_RESULT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetQueryResultTypeValues(), 4, "QueryResultType", value)); +} + +const StringUtil::EnumStringLiteral *GetQuoteRuleValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(QuoteRule::QUOTES_RFC), "QUOTES_RFC" }, + { static_cast(QuoteRule::QUOTES_OTHER), "QUOTES_OTHER" }, + { static_cast(QuoteRule::NO_QUOTES), "NO_QUOTES" } + }; + return values; } template<> const char* EnumUtil::ToChars(QuoteRule value) { - switch(value) { - case QuoteRule::QUOTES_RFC: - return "QUOTES_RFC"; - case QuoteRule::QUOTES_OTHER: - return "QUOTES_OTHER"; - case QuoteRule::NO_QUOTES: - return "NO_QUOTES"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetQuoteRuleValues(), 3, "QuoteRule", static_cast(value)); } template<> QuoteRule EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "QUOTES_RFC")) { - return QuoteRule::QUOTES_RFC; - } - if (StringUtil::Equals(value, "QUOTES_OTHER")) { - return QuoteRule::QUOTES_OTHER; - } - if (StringUtil::Equals(value, "NO_QUOTES")) { - return QuoteRule::NO_QUOTES; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetQuoteRuleValues(), 3, "QuoteRule", value)); +} + +const StringUtil::EnumStringLiteral *GetRelationTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(RelationType::INVALID_RELATION), "INVALID_RELATION" }, + { static_cast(RelationType::TABLE_RELATION), "TABLE_RELATION" }, + { static_cast(RelationType::PROJECTION_RELATION), "PROJECTION_RELATION" }, + { static_cast(RelationType::FILTER_RELATION), "FILTER_RELATION" }, + { static_cast(RelationType::EXPLAIN_RELATION), "EXPLAIN_RELATION" }, + { static_cast(RelationType::CROSS_PRODUCT_RELATION), "CROSS_PRODUCT_RELATION" }, + { static_cast(RelationType::JOIN_RELATION), "JOIN_RELATION" }, + { static_cast(RelationType::AGGREGATE_RELATION), "AGGREGATE_RELATION" }, + { static_cast(RelationType::SET_OPERATION_RELATION), "SET_OPERATION_RELATION" }, + { static_cast(RelationType::DISTINCT_RELATION), "DISTINCT_RELATION" }, + { static_cast(RelationType::LIMIT_RELATION), "LIMIT_RELATION" }, + { static_cast(RelationType::ORDER_RELATION), "ORDER_RELATION" }, + { static_cast(RelationType::CREATE_VIEW_RELATION), "CREATE_VIEW_RELATION" }, + { static_cast(RelationType::CREATE_TABLE_RELATION), "CREATE_TABLE_RELATION" }, + { static_cast(RelationType::INSERT_RELATION), "INSERT_RELATION" }, + { static_cast(RelationType::VALUE_LIST_RELATION), "VALUE_LIST_RELATION" }, + { static_cast(RelationType::MATERIALIZED_RELATION), "MATERIALIZED_RELATION" }, + { static_cast(RelationType::DELETE_RELATION), "DELETE_RELATION" }, + { static_cast(RelationType::UPDATE_RELATION), "UPDATE_RELATION" }, + { static_cast(RelationType::WRITE_CSV_RELATION), "WRITE_CSV_RELATION" }, + { static_cast(RelationType::WRITE_PARQUET_RELATION), "WRITE_PARQUET_RELATION" }, + { static_cast(RelationType::READ_CSV_RELATION), "READ_CSV_RELATION" }, + { static_cast(RelationType::SUBQUERY_RELATION), "SUBQUERY_RELATION" }, + { static_cast(RelationType::TABLE_FUNCTION_RELATION), "TABLE_FUNCTION_RELATION" }, + { static_cast(RelationType::VIEW_RELATION), "VIEW_RELATION" }, + { static_cast(RelationType::QUERY_RELATION), "QUERY_RELATION" }, + { static_cast(RelationType::DELIM_JOIN_RELATION), "DELIM_JOIN_RELATION" }, + { static_cast(RelationType::DELIM_GET_RELATION), "DELIM_GET_RELATION" } + }; + return values; } template<> const char* EnumUtil::ToChars(RelationType value) { - switch(value) { - case RelationType::INVALID_RELATION: - return "INVALID_RELATION"; - case RelationType::TABLE_RELATION: - return "TABLE_RELATION"; - case RelationType::PROJECTION_RELATION: - return "PROJECTION_RELATION"; - case RelationType::FILTER_RELATION: - return "FILTER_RELATION"; - case RelationType::EXPLAIN_RELATION: - return "EXPLAIN_RELATION"; - case RelationType::CROSS_PRODUCT_RELATION: - return "CROSS_PRODUCT_RELATION"; - case RelationType::JOIN_RELATION: - return "JOIN_RELATION"; - case RelationType::AGGREGATE_RELATION: - return "AGGREGATE_RELATION"; - case RelationType::SET_OPERATION_RELATION: - return "SET_OPERATION_RELATION"; - case RelationType::DISTINCT_RELATION: - return "DISTINCT_RELATION"; - case RelationType::LIMIT_RELATION: - return "LIMIT_RELATION"; - case RelationType::ORDER_RELATION: - return "ORDER_RELATION"; - case RelationType::CREATE_VIEW_RELATION: - return "CREATE_VIEW_RELATION"; - case RelationType::CREATE_TABLE_RELATION: - return "CREATE_TABLE_RELATION"; - case RelationType::INSERT_RELATION: - return "INSERT_RELATION"; - case RelationType::VALUE_LIST_RELATION: - return "VALUE_LIST_RELATION"; - case RelationType::MATERIALIZED_RELATION: - return "MATERIALIZED_RELATION"; - case RelationType::DELETE_RELATION: - return "DELETE_RELATION"; - case RelationType::UPDATE_RELATION: - return "UPDATE_RELATION"; - case RelationType::WRITE_CSV_RELATION: - return "WRITE_CSV_RELATION"; - case RelationType::WRITE_PARQUET_RELATION: - return "WRITE_PARQUET_RELATION"; - case RelationType::READ_CSV_RELATION: - return "READ_CSV_RELATION"; - case RelationType::SUBQUERY_RELATION: - return "SUBQUERY_RELATION"; - case RelationType::TABLE_FUNCTION_RELATION: - return "TABLE_FUNCTION_RELATION"; - case RelationType::VIEW_RELATION: - return "VIEW_RELATION"; - case RelationType::QUERY_RELATION: - return "QUERY_RELATION"; - case RelationType::DELIM_JOIN_RELATION: - return "DELIM_JOIN_RELATION"; - case RelationType::DELIM_GET_RELATION: - return "DELIM_GET_RELATION"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetRelationTypeValues(), 28, "RelationType", static_cast(value)); } template<> RelationType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID_RELATION")) { - return RelationType::INVALID_RELATION; - } - if (StringUtil::Equals(value, "TABLE_RELATION")) { - return RelationType::TABLE_RELATION; - } - if (StringUtil::Equals(value, "PROJECTION_RELATION")) { - return RelationType::PROJECTION_RELATION; - } - if (StringUtil::Equals(value, "FILTER_RELATION")) { - return RelationType::FILTER_RELATION; - } - if (StringUtil::Equals(value, "EXPLAIN_RELATION")) { - return RelationType::EXPLAIN_RELATION; - } - if (StringUtil::Equals(value, "CROSS_PRODUCT_RELATION")) { - return RelationType::CROSS_PRODUCT_RELATION; - } - if (StringUtil::Equals(value, "JOIN_RELATION")) { - return RelationType::JOIN_RELATION; - } - if (StringUtil::Equals(value, "AGGREGATE_RELATION")) { - return RelationType::AGGREGATE_RELATION; - } - if (StringUtil::Equals(value, "SET_OPERATION_RELATION")) { - return RelationType::SET_OPERATION_RELATION; - } - if (StringUtil::Equals(value, "DISTINCT_RELATION")) { - return RelationType::DISTINCT_RELATION; - } - if (StringUtil::Equals(value, "LIMIT_RELATION")) { - return RelationType::LIMIT_RELATION; - } - if (StringUtil::Equals(value, "ORDER_RELATION")) { - return RelationType::ORDER_RELATION; - } - if (StringUtil::Equals(value, "CREATE_VIEW_RELATION")) { - return RelationType::CREATE_VIEW_RELATION; - } - if (StringUtil::Equals(value, "CREATE_TABLE_RELATION")) { - return RelationType::CREATE_TABLE_RELATION; - } - if (StringUtil::Equals(value, "INSERT_RELATION")) { - return RelationType::INSERT_RELATION; - } - if (StringUtil::Equals(value, "VALUE_LIST_RELATION")) { - return RelationType::VALUE_LIST_RELATION; - } - if (StringUtil::Equals(value, "MATERIALIZED_RELATION")) { - return RelationType::MATERIALIZED_RELATION; - } - if (StringUtil::Equals(value, "DELETE_RELATION")) { - return RelationType::DELETE_RELATION; - } - if (StringUtil::Equals(value, "UPDATE_RELATION")) { - return RelationType::UPDATE_RELATION; - } - if (StringUtil::Equals(value, "WRITE_CSV_RELATION")) { - return RelationType::WRITE_CSV_RELATION; - } - if (StringUtil::Equals(value, "WRITE_PARQUET_RELATION")) { - return RelationType::WRITE_PARQUET_RELATION; - } - if (StringUtil::Equals(value, "READ_CSV_RELATION")) { - return RelationType::READ_CSV_RELATION; - } - if (StringUtil::Equals(value, "SUBQUERY_RELATION")) { - return RelationType::SUBQUERY_RELATION; - } - if (StringUtil::Equals(value, "TABLE_FUNCTION_RELATION")) { - return RelationType::TABLE_FUNCTION_RELATION; - } - if (StringUtil::Equals(value, "VIEW_RELATION")) { - return RelationType::VIEW_RELATION; - } - if (StringUtil::Equals(value, "QUERY_RELATION")) { - return RelationType::QUERY_RELATION; - } - if (StringUtil::Equals(value, "DELIM_JOIN_RELATION")) { - return RelationType::DELIM_JOIN_RELATION; - } - if (StringUtil::Equals(value, "DELIM_GET_RELATION")) { - return RelationType::DELIM_GET_RELATION; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetRelationTypeValues(), 28, "RelationType", value)); +} + +const StringUtil::EnumStringLiteral *GetRenderModeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(RenderMode::ROWS), "ROWS" }, + { static_cast(RenderMode::COLUMNS), "COLUMNS" } + }; + return values; } template<> const char* EnumUtil::ToChars(RenderMode value) { - switch(value) { - case RenderMode::ROWS: - return "ROWS"; - case RenderMode::COLUMNS: - return "COLUMNS"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetRenderModeValues(), 2, "RenderMode", static_cast(value)); } template<> RenderMode EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "ROWS")) { - return RenderMode::ROWS; - } - if (StringUtil::Equals(value, "COLUMNS")) { - return RenderMode::COLUMNS; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetRenderModeValues(), 2, "RenderMode", value)); +} + +const StringUtil::EnumStringLiteral *GetResultModifierTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ResultModifierType::LIMIT_MODIFIER), "LIMIT_MODIFIER" }, + { static_cast(ResultModifierType::ORDER_MODIFIER), "ORDER_MODIFIER" }, + { static_cast(ResultModifierType::DISTINCT_MODIFIER), "DISTINCT_MODIFIER" }, + { static_cast(ResultModifierType::LIMIT_PERCENT_MODIFIER), "LIMIT_PERCENT_MODIFIER" } + }; + return values; } template<> const char* EnumUtil::ToChars(ResultModifierType value) { - switch(value) { - case ResultModifierType::LIMIT_MODIFIER: - return "LIMIT_MODIFIER"; - case ResultModifierType::ORDER_MODIFIER: - return "ORDER_MODIFIER"; - case ResultModifierType::DISTINCT_MODIFIER: - return "DISTINCT_MODIFIER"; - case ResultModifierType::LIMIT_PERCENT_MODIFIER: - return "LIMIT_PERCENT_MODIFIER"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetResultModifierTypeValues(), 4, "ResultModifierType", static_cast(value)); } template<> ResultModifierType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "LIMIT_MODIFIER")) { - return ResultModifierType::LIMIT_MODIFIER; - } - if (StringUtil::Equals(value, "ORDER_MODIFIER")) { - return ResultModifierType::ORDER_MODIFIER; - } - if (StringUtil::Equals(value, "DISTINCT_MODIFIER")) { - return ResultModifierType::DISTINCT_MODIFIER; - } - if (StringUtil::Equals(value, "LIMIT_PERCENT_MODIFIER")) { - return ResultModifierType::LIMIT_PERCENT_MODIFIER; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetResultModifierTypeValues(), 4, "ResultModifierType", value)); +} + +const StringUtil::EnumStringLiteral *GetSampleMethodValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SampleMethod::SYSTEM_SAMPLE), "System" }, + { static_cast(SampleMethod::BERNOULLI_SAMPLE), "Bernoulli" }, + { static_cast(SampleMethod::RESERVOIR_SAMPLE), "Reservoir" }, + { static_cast(SampleMethod::INVALID), "INVALID" } + }; + return values; } template<> const char* EnumUtil::ToChars(SampleMethod value) { - switch(value) { - case SampleMethod::SYSTEM_SAMPLE: - return "System"; - case SampleMethod::BERNOULLI_SAMPLE: - return "Bernoulli"; - case SampleMethod::RESERVOIR_SAMPLE: - return "Reservoir"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSampleMethodValues(), 4, "SampleMethod", static_cast(value)); } template<> SampleMethod EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "System")) { - return SampleMethod::SYSTEM_SAMPLE; - } - if (StringUtil::Equals(value, "Bernoulli")) { - return SampleMethod::BERNOULLI_SAMPLE; - } - if (StringUtil::Equals(value, "Reservoir")) { - return SampleMethod::RESERVOIR_SAMPLE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSampleMethodValues(), 4, "SampleMethod", value)); +} + +const StringUtil::EnumStringLiteral *GetSampleTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SampleType::BLOCKING_SAMPLE), "BLOCKING_SAMPLE" }, + { static_cast(SampleType::RESERVOIR_SAMPLE), "RESERVOIR_SAMPLE" }, + { static_cast(SampleType::RESERVOIR_PERCENTAGE_SAMPLE), "RESERVOIR_PERCENTAGE_SAMPLE" } + }; + return values; } template<> const char* EnumUtil::ToChars(SampleType value) { - switch(value) { - case SampleType::BLOCKING_SAMPLE: - return "BLOCKING_SAMPLE"; - case SampleType::RESERVOIR_SAMPLE: - return "RESERVOIR_SAMPLE"; - case SampleType::RESERVOIR_PERCENTAGE_SAMPLE: - return "RESERVOIR_PERCENTAGE_SAMPLE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSampleTypeValues(), 3, "SampleType", static_cast(value)); } template<> SampleType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "BLOCKING_SAMPLE")) { - return SampleType::BLOCKING_SAMPLE; - } - if (StringUtil::Equals(value, "RESERVOIR_SAMPLE")) { - return SampleType::RESERVOIR_SAMPLE; - } - if (StringUtil::Equals(value, "RESERVOIR_PERCENTAGE_SAMPLE")) { - return SampleType::RESERVOIR_PERCENTAGE_SAMPLE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSampleTypeValues(), 3, "SampleType", value)); +} + +const StringUtil::EnumStringLiteral *GetScanTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ScanType::TABLE), "TABLE" }, + { static_cast(ScanType::PARQUET), "PARQUET" }, + { static_cast(ScanType::EXTERNAL), "EXTERNAL" } + }; + return values; } template<> const char* EnumUtil::ToChars(ScanType value) { - switch(value) { - case ScanType::TABLE: - return "TABLE"; - case ScanType::PARQUET: - return "PARQUET"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetScanTypeValues(), 3, "ScanType", static_cast(value)); } template<> ScanType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "TABLE")) { - return ScanType::TABLE; - } - if (StringUtil::Equals(value, "PARQUET")) { - return ScanType::PARQUET; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetScanTypeValues(), 3, "ScanType", value)); +} + +const StringUtil::EnumStringLiteral *GetSecretDisplayTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SecretDisplayType::REDACTED), "REDACTED" }, + { static_cast(SecretDisplayType::UNREDACTED), "UNREDACTED" } + }; + return values; } template<> const char* EnumUtil::ToChars(SecretDisplayType value) { - switch(value) { - case SecretDisplayType::REDACTED: - return "REDACTED"; - case SecretDisplayType::UNREDACTED: - return "UNREDACTED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSecretDisplayTypeValues(), 2, "SecretDisplayType", static_cast(value)); } template<> SecretDisplayType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "REDACTED")) { - return SecretDisplayType::REDACTED; - } - if (StringUtil::Equals(value, "UNREDACTED")) { - return SecretDisplayType::UNREDACTED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSecretDisplayTypeValues(), 2, "SecretDisplayType", value)); +} + +const StringUtil::EnumStringLiteral *GetSecretPersistTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SecretPersistType::DEFAULT), "DEFAULT" }, + { static_cast(SecretPersistType::TEMPORARY), "TEMPORARY" }, + { static_cast(SecretPersistType::PERSISTENT), "PERSISTENT" } + }; + return values; } template<> const char* EnumUtil::ToChars(SecretPersistType value) { - switch(value) { - case SecretPersistType::DEFAULT: - return "DEFAULT"; - case SecretPersistType::TEMPORARY: - return "TEMPORARY"; - case SecretPersistType::PERSISTENT: - return "PERSISTENT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSecretPersistTypeValues(), 3, "SecretPersistType", static_cast(value)); } template<> SecretPersistType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "DEFAULT")) { - return SecretPersistType::DEFAULT; - } - if (StringUtil::Equals(value, "TEMPORARY")) { - return SecretPersistType::TEMPORARY; - } - if (StringUtil::Equals(value, "PERSISTENT")) { - return SecretPersistType::PERSISTENT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSecretPersistTypeValues(), 3, "SecretPersistType", value)); +} + +const StringUtil::EnumStringLiteral *GetSecretSerializationTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SecretSerializationType::CUSTOM), "CUSTOM" }, + { static_cast(SecretSerializationType::KEY_VALUE_SECRET), "KEY_VALUE_SECRET" } + }; + return values; } template<> const char* EnumUtil::ToChars(SecretSerializationType value) { - switch(value) { - case SecretSerializationType::CUSTOM: - return "CUSTOM"; - case SecretSerializationType::KEY_VALUE_SECRET: - return "KEY_VALUE_SECRET"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSecretSerializationTypeValues(), 2, "SecretSerializationType", static_cast(value)); } template<> SecretSerializationType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "CUSTOM")) { - return SecretSerializationType::CUSTOM; - } - if (StringUtil::Equals(value, "KEY_VALUE_SECRET")) { - return SecretSerializationType::KEY_VALUE_SECRET; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSecretSerializationTypeValues(), 2, "SecretSerializationType", value)); +} + +const StringUtil::EnumStringLiteral *GetSequenceInfoValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SequenceInfo::SEQ_START), "SEQ_START" }, + { static_cast(SequenceInfo::SEQ_INC), "SEQ_INC" }, + { static_cast(SequenceInfo::SEQ_MIN), "SEQ_MIN" }, + { static_cast(SequenceInfo::SEQ_MAX), "SEQ_MAX" }, + { static_cast(SequenceInfo::SEQ_CYCLE), "SEQ_CYCLE" }, + { static_cast(SequenceInfo::SEQ_OWN), "SEQ_OWN" } + }; + return values; } template<> const char* EnumUtil::ToChars(SequenceInfo value) { - switch(value) { - case SequenceInfo::SEQ_START: - return "SEQ_START"; - case SequenceInfo::SEQ_INC: - return "SEQ_INC"; - case SequenceInfo::SEQ_MIN: - return "SEQ_MIN"; - case SequenceInfo::SEQ_MAX: - return "SEQ_MAX"; - case SequenceInfo::SEQ_CYCLE: - return "SEQ_CYCLE"; - case SequenceInfo::SEQ_OWN: - return "SEQ_OWN"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSequenceInfoValues(), 6, "SequenceInfo", static_cast(value)); } template<> SequenceInfo EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "SEQ_START")) { - return SequenceInfo::SEQ_START; - } - if (StringUtil::Equals(value, "SEQ_INC")) { - return SequenceInfo::SEQ_INC; - } - if (StringUtil::Equals(value, "SEQ_MIN")) { - return SequenceInfo::SEQ_MIN; - } - if (StringUtil::Equals(value, "SEQ_MAX")) { - return SequenceInfo::SEQ_MAX; - } - if (StringUtil::Equals(value, "SEQ_CYCLE")) { - return SequenceInfo::SEQ_CYCLE; - } - if (StringUtil::Equals(value, "SEQ_OWN")) { - return SequenceInfo::SEQ_OWN; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSequenceInfoValues(), 6, "SequenceInfo", value)); +} + +const StringUtil::EnumStringLiteral *GetSetOperationTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SetOperationType::NONE), "NONE" }, + { static_cast(SetOperationType::UNION), "UNION" }, + { static_cast(SetOperationType::EXCEPT), "EXCEPT" }, + { static_cast(SetOperationType::INTERSECT), "INTERSECT" }, + { static_cast(SetOperationType::UNION_BY_NAME), "UNION_BY_NAME" } + }; + return values; } template<> const char* EnumUtil::ToChars(SetOperationType value) { - switch(value) { - case SetOperationType::NONE: - return "NONE"; - case SetOperationType::UNION: - return "UNION"; - case SetOperationType::EXCEPT: - return "EXCEPT"; - case SetOperationType::INTERSECT: - return "INTERSECT"; - case SetOperationType::UNION_BY_NAME: - return "UNION_BY_NAME"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSetOperationTypeValues(), 5, "SetOperationType", static_cast(value)); } template<> SetOperationType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NONE")) { - return SetOperationType::NONE; - } - if (StringUtil::Equals(value, "UNION")) { - return SetOperationType::UNION; - } - if (StringUtil::Equals(value, "EXCEPT")) { - return SetOperationType::EXCEPT; - } - if (StringUtil::Equals(value, "INTERSECT")) { - return SetOperationType::INTERSECT; - } - if (StringUtil::Equals(value, "UNION_BY_NAME")) { - return SetOperationType::UNION_BY_NAME; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSetOperationTypeValues(), 5, "SetOperationType", value)); +} + +const StringUtil::EnumStringLiteral *GetSetScopeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SetScope::AUTOMATIC), "AUTOMATIC" }, + { static_cast(SetScope::LOCAL), "LOCAL" }, + { static_cast(SetScope::SESSION), "SESSION" }, + { static_cast(SetScope::GLOBAL), "GLOBAL" }, + { static_cast(SetScope::VARIABLE), "VARIABLE" } + }; + return values; } template<> const char* EnumUtil::ToChars(SetScope value) { - switch(value) { - case SetScope::AUTOMATIC: - return "AUTOMATIC"; - case SetScope::LOCAL: - return "LOCAL"; - case SetScope::SESSION: - return "SESSION"; - case SetScope::GLOBAL: - return "GLOBAL"; - case SetScope::VARIABLE: - return "VARIABLE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSetScopeValues(), 5, "SetScope", static_cast(value)); } template<> SetScope EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "AUTOMATIC")) { - return SetScope::AUTOMATIC; - } - if (StringUtil::Equals(value, "LOCAL")) { - return SetScope::LOCAL; - } - if (StringUtil::Equals(value, "SESSION")) { - return SetScope::SESSION; - } - if (StringUtil::Equals(value, "GLOBAL")) { - return SetScope::GLOBAL; - } - if (StringUtil::Equals(value, "VARIABLE")) { - return SetScope::VARIABLE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSetScopeValues(), 5, "SetScope", value)); +} + +const StringUtil::EnumStringLiteral *GetSetTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SetType::SET), "SET" }, + { static_cast(SetType::RESET), "RESET" } + }; + return values; } template<> const char* EnumUtil::ToChars(SetType value) { - switch(value) { - case SetType::SET: - return "SET"; - case SetType::RESET: - return "RESET"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSetTypeValues(), 2, "SetType", static_cast(value)); } template<> SetType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "SET")) { - return SetType::SET; - } - if (StringUtil::Equals(value, "RESET")) { - return SetType::RESET; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSetTypeValues(), 2, "SetType", value)); +} + +const StringUtil::EnumStringLiteral *GetSettingScopeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SettingScope::GLOBAL), "GLOBAL" }, + { static_cast(SettingScope::LOCAL), "LOCAL" }, + { static_cast(SettingScope::SECRET), "SECRET" }, + { static_cast(SettingScope::INVALID), "INVALID" } + }; + return values; } template<> const char* EnumUtil::ToChars(SettingScope value) { - switch(value) { - case SettingScope::GLOBAL: - return "GLOBAL"; - case SettingScope::LOCAL: - return "LOCAL"; - case SettingScope::SECRET: - return "SECRET"; - case SettingScope::INVALID: - return "INVALID"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSettingScopeValues(), 4, "SettingScope", static_cast(value)); } template<> SettingScope EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "GLOBAL")) { - return SettingScope::GLOBAL; - } - if (StringUtil::Equals(value, "LOCAL")) { - return SettingScope::LOCAL; - } - if (StringUtil::Equals(value, "SECRET")) { - return SettingScope::SECRET; - } - if (StringUtil::Equals(value, "INVALID")) { - return SettingScope::INVALID; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSettingScopeValues(), 4, "SettingScope", value)); +} + +const StringUtil::EnumStringLiteral *GetShowTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(ShowType::SUMMARY), "SUMMARY" }, + { static_cast(ShowType::DESCRIBE), "DESCRIBE" } + }; + return values; } template<> const char* EnumUtil::ToChars(ShowType value) { - switch(value) { - case ShowType::SUMMARY: - return "SUMMARY"; - case ShowType::DESCRIBE: - return "DESCRIBE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetShowTypeValues(), 2, "ShowType", static_cast(value)); } template<> ShowType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "SUMMARY")) { - return ShowType::SUMMARY; - } - if (StringUtil::Equals(value, "DESCRIBE")) { - return ShowType::DESCRIBE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetShowTypeValues(), 2, "ShowType", value)); +} + +const StringUtil::EnumStringLiteral *GetSimplifiedTokenTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SimplifiedTokenType::SIMPLIFIED_TOKEN_IDENTIFIER), "SIMPLIFIED_TOKEN_IDENTIFIER" }, + { static_cast(SimplifiedTokenType::SIMPLIFIED_TOKEN_NUMERIC_CONSTANT), "SIMPLIFIED_TOKEN_NUMERIC_CONSTANT" }, + { static_cast(SimplifiedTokenType::SIMPLIFIED_TOKEN_STRING_CONSTANT), "SIMPLIFIED_TOKEN_STRING_CONSTANT" }, + { static_cast(SimplifiedTokenType::SIMPLIFIED_TOKEN_OPERATOR), "SIMPLIFIED_TOKEN_OPERATOR" }, + { static_cast(SimplifiedTokenType::SIMPLIFIED_TOKEN_KEYWORD), "SIMPLIFIED_TOKEN_KEYWORD" }, + { static_cast(SimplifiedTokenType::SIMPLIFIED_TOKEN_COMMENT), "SIMPLIFIED_TOKEN_COMMENT" } + }; + return values; } template<> const char* EnumUtil::ToChars(SimplifiedTokenType value) { - switch(value) { - case SimplifiedTokenType::SIMPLIFIED_TOKEN_IDENTIFIER: - return "SIMPLIFIED_TOKEN_IDENTIFIER"; - case SimplifiedTokenType::SIMPLIFIED_TOKEN_NUMERIC_CONSTANT: - return "SIMPLIFIED_TOKEN_NUMERIC_CONSTANT"; - case SimplifiedTokenType::SIMPLIFIED_TOKEN_STRING_CONSTANT: - return "SIMPLIFIED_TOKEN_STRING_CONSTANT"; - case SimplifiedTokenType::SIMPLIFIED_TOKEN_OPERATOR: - return "SIMPLIFIED_TOKEN_OPERATOR"; - case SimplifiedTokenType::SIMPLIFIED_TOKEN_KEYWORD: - return "SIMPLIFIED_TOKEN_KEYWORD"; - case SimplifiedTokenType::SIMPLIFIED_TOKEN_COMMENT: - return "SIMPLIFIED_TOKEN_COMMENT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSimplifiedTokenTypeValues(), 6, "SimplifiedTokenType", static_cast(value)); } template<> SimplifiedTokenType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "SIMPLIFIED_TOKEN_IDENTIFIER")) { - return SimplifiedTokenType::SIMPLIFIED_TOKEN_IDENTIFIER; - } - if (StringUtil::Equals(value, "SIMPLIFIED_TOKEN_NUMERIC_CONSTANT")) { - return SimplifiedTokenType::SIMPLIFIED_TOKEN_NUMERIC_CONSTANT; - } - if (StringUtil::Equals(value, "SIMPLIFIED_TOKEN_STRING_CONSTANT")) { - return SimplifiedTokenType::SIMPLIFIED_TOKEN_STRING_CONSTANT; - } - if (StringUtil::Equals(value, "SIMPLIFIED_TOKEN_OPERATOR")) { - return SimplifiedTokenType::SIMPLIFIED_TOKEN_OPERATOR; - } - if (StringUtil::Equals(value, "SIMPLIFIED_TOKEN_KEYWORD")) { - return SimplifiedTokenType::SIMPLIFIED_TOKEN_KEYWORD; - } - if (StringUtil::Equals(value, "SIMPLIFIED_TOKEN_COMMENT")) { - return SimplifiedTokenType::SIMPLIFIED_TOKEN_COMMENT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSimplifiedTokenTypeValues(), 6, "SimplifiedTokenType", value)); +} + +const StringUtil::EnumStringLiteral *GetSinkCombineResultTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SinkCombineResultType::FINISHED), "FINISHED" }, + { static_cast(SinkCombineResultType::BLOCKED), "BLOCKED" } + }; + return values; } template<> const char* EnumUtil::ToChars(SinkCombineResultType value) { - switch(value) { - case SinkCombineResultType::FINISHED: - return "FINISHED"; - case SinkCombineResultType::BLOCKED: - return "BLOCKED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSinkCombineResultTypeValues(), 2, "SinkCombineResultType", static_cast(value)); } template<> SinkCombineResultType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "FINISHED")) { - return SinkCombineResultType::FINISHED; - } - if (StringUtil::Equals(value, "BLOCKED")) { - return SinkCombineResultType::BLOCKED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSinkCombineResultTypeValues(), 2, "SinkCombineResultType", value)); +} + +const StringUtil::EnumStringLiteral *GetSinkFinalizeTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SinkFinalizeType::READY), "READY" }, + { static_cast(SinkFinalizeType::NO_OUTPUT_POSSIBLE), "NO_OUTPUT_POSSIBLE" }, + { static_cast(SinkFinalizeType::BLOCKED), "BLOCKED" } + }; + return values; } template<> const char* EnumUtil::ToChars(SinkFinalizeType value) { - switch(value) { - case SinkFinalizeType::READY: - return "READY"; - case SinkFinalizeType::NO_OUTPUT_POSSIBLE: - return "NO_OUTPUT_POSSIBLE"; - case SinkFinalizeType::BLOCKED: - return "BLOCKED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSinkFinalizeTypeValues(), 3, "SinkFinalizeType", static_cast(value)); } template<> SinkFinalizeType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "READY")) { - return SinkFinalizeType::READY; - } - if (StringUtil::Equals(value, "NO_OUTPUT_POSSIBLE")) { - return SinkFinalizeType::NO_OUTPUT_POSSIBLE; - } - if (StringUtil::Equals(value, "BLOCKED")) { - return SinkFinalizeType::BLOCKED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSinkFinalizeTypeValues(), 3, "SinkFinalizeType", value)); +} + +const StringUtil::EnumStringLiteral *GetSinkNextBatchTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SinkNextBatchType::READY), "READY" }, + { static_cast(SinkNextBatchType::BLOCKED), "BLOCKED" } + }; + return values; } template<> const char* EnumUtil::ToChars(SinkNextBatchType value) { - switch(value) { - case SinkNextBatchType::READY: - return "READY"; - case SinkNextBatchType::BLOCKED: - return "BLOCKED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSinkNextBatchTypeValues(), 2, "SinkNextBatchType", static_cast(value)); } template<> SinkNextBatchType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "READY")) { - return SinkNextBatchType::READY; - } - if (StringUtil::Equals(value, "BLOCKED")) { - return SinkNextBatchType::BLOCKED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSinkNextBatchTypeValues(), 2, "SinkNextBatchType", value)); +} + +const StringUtil::EnumStringLiteral *GetSinkResultTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SinkResultType::NEED_MORE_INPUT), "NEED_MORE_INPUT" }, + { static_cast(SinkResultType::FINISHED), "FINISHED" }, + { static_cast(SinkResultType::BLOCKED), "BLOCKED" } + }; + return values; } template<> const char* EnumUtil::ToChars(SinkResultType value) { - switch(value) { - case SinkResultType::NEED_MORE_INPUT: - return "NEED_MORE_INPUT"; - case SinkResultType::FINISHED: - return "FINISHED"; - case SinkResultType::BLOCKED: - return "BLOCKED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSinkResultTypeValues(), 3, "SinkResultType", static_cast(value)); } template<> SinkResultType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NEED_MORE_INPUT")) { - return SinkResultType::NEED_MORE_INPUT; - } - if (StringUtil::Equals(value, "FINISHED")) { - return SinkResultType::FINISHED; - } - if (StringUtil::Equals(value, "BLOCKED")) { - return SinkResultType::BLOCKED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSinkResultTypeValues(), 3, "SinkResultType", value)); +} + +const StringUtil::EnumStringLiteral *GetSourceResultTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SourceResultType::HAVE_MORE_OUTPUT), "HAVE_MORE_OUTPUT" }, + { static_cast(SourceResultType::FINISHED), "FINISHED" }, + { static_cast(SourceResultType::BLOCKED), "BLOCKED" } + }; + return values; } template<> const char* EnumUtil::ToChars(SourceResultType value) { - switch(value) { - case SourceResultType::HAVE_MORE_OUTPUT: - return "HAVE_MORE_OUTPUT"; - case SourceResultType::FINISHED: - return "FINISHED"; - case SourceResultType::BLOCKED: - return "BLOCKED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSourceResultTypeValues(), 3, "SourceResultType", static_cast(value)); } template<> SourceResultType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "HAVE_MORE_OUTPUT")) { - return SourceResultType::HAVE_MORE_OUTPUT; - } - if (StringUtil::Equals(value, "FINISHED")) { - return SourceResultType::FINISHED; - } - if (StringUtil::Equals(value, "BLOCKED")) { - return SourceResultType::BLOCKED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSourceResultTypeValues(), 3, "SourceResultType", value)); +} + +const StringUtil::EnumStringLiteral *GetStatementReturnTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(StatementReturnType::QUERY_RESULT), "QUERY_RESULT" }, + { static_cast(StatementReturnType::CHANGED_ROWS), "CHANGED_ROWS" }, + { static_cast(StatementReturnType::NOTHING), "NOTHING" } + }; + return values; } template<> const char* EnumUtil::ToChars(StatementReturnType value) { - switch(value) { - case StatementReturnType::QUERY_RESULT: - return "QUERY_RESULT"; - case StatementReturnType::CHANGED_ROWS: - return "CHANGED_ROWS"; - case StatementReturnType::NOTHING: - return "NOTHING"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetStatementReturnTypeValues(), 3, "StatementReturnType", static_cast(value)); } template<> StatementReturnType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "QUERY_RESULT")) { - return StatementReturnType::QUERY_RESULT; - } - if (StringUtil::Equals(value, "CHANGED_ROWS")) { - return StatementReturnType::CHANGED_ROWS; - } - if (StringUtil::Equals(value, "NOTHING")) { - return StatementReturnType::NOTHING; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetStatementReturnTypeValues(), 3, "StatementReturnType", value)); +} + +const StringUtil::EnumStringLiteral *GetStatementTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(StatementType::INVALID_STATEMENT), "INVALID_STATEMENT" }, + { static_cast(StatementType::SELECT_STATEMENT), "SELECT_STATEMENT" }, + { static_cast(StatementType::INSERT_STATEMENT), "INSERT_STATEMENT" }, + { static_cast(StatementType::UPDATE_STATEMENT), "UPDATE_STATEMENT" }, + { static_cast(StatementType::CREATE_STATEMENT), "CREATE_STATEMENT" }, + { static_cast(StatementType::DELETE_STATEMENT), "DELETE_STATEMENT" }, + { static_cast(StatementType::PREPARE_STATEMENT), "PREPARE_STATEMENT" }, + { static_cast(StatementType::EXECUTE_STATEMENT), "EXECUTE_STATEMENT" }, + { static_cast(StatementType::ALTER_STATEMENT), "ALTER_STATEMENT" }, + { static_cast(StatementType::TRANSACTION_STATEMENT), "TRANSACTION_STATEMENT" }, + { static_cast(StatementType::COPY_STATEMENT), "COPY_STATEMENT" }, + { static_cast(StatementType::ANALYZE_STATEMENT), "ANALYZE_STATEMENT" }, + { static_cast(StatementType::VARIABLE_SET_STATEMENT), "VARIABLE_SET_STATEMENT" }, + { static_cast(StatementType::CREATE_FUNC_STATEMENT), "CREATE_FUNC_STATEMENT" }, + { static_cast(StatementType::EXPLAIN_STATEMENT), "EXPLAIN_STATEMENT" }, + { static_cast(StatementType::DROP_STATEMENT), "DROP_STATEMENT" }, + { static_cast(StatementType::EXPORT_STATEMENT), "EXPORT_STATEMENT" }, + { static_cast(StatementType::PRAGMA_STATEMENT), "PRAGMA_STATEMENT" }, + { static_cast(StatementType::VACUUM_STATEMENT), "VACUUM_STATEMENT" }, + { static_cast(StatementType::CALL_STATEMENT), "CALL_STATEMENT" }, + { static_cast(StatementType::SET_STATEMENT), "SET_STATEMENT" }, + { static_cast(StatementType::LOAD_STATEMENT), "LOAD_STATEMENT" }, + { static_cast(StatementType::RELATION_STATEMENT), "RELATION_STATEMENT" }, + { static_cast(StatementType::EXTENSION_STATEMENT), "EXTENSION_STATEMENT" }, + { static_cast(StatementType::LOGICAL_PLAN_STATEMENT), "LOGICAL_PLAN_STATEMENT" }, + { static_cast(StatementType::ATTACH_STATEMENT), "ATTACH_STATEMENT" }, + { static_cast(StatementType::DETACH_STATEMENT), "DETACH_STATEMENT" }, + { static_cast(StatementType::MULTI_STATEMENT), "MULTI_STATEMENT" }, + { static_cast(StatementType::COPY_DATABASE_STATEMENT), "COPY_DATABASE_STATEMENT" }, + { static_cast(StatementType::UPDATE_EXTENSIONS_STATEMENT), "UPDATE_EXTENSIONS_STATEMENT" } + }; + return values; } template<> const char* EnumUtil::ToChars(StatementType value) { - switch(value) { - case StatementType::INVALID_STATEMENT: - return "INVALID_STATEMENT"; - case StatementType::SELECT_STATEMENT: - return "SELECT_STATEMENT"; - case StatementType::INSERT_STATEMENT: - return "INSERT_STATEMENT"; - case StatementType::UPDATE_STATEMENT: - return "UPDATE_STATEMENT"; - case StatementType::CREATE_STATEMENT: - return "CREATE_STATEMENT"; - case StatementType::DELETE_STATEMENT: - return "DELETE_STATEMENT"; - case StatementType::PREPARE_STATEMENT: - return "PREPARE_STATEMENT"; - case StatementType::EXECUTE_STATEMENT: - return "EXECUTE_STATEMENT"; - case StatementType::ALTER_STATEMENT: - return "ALTER_STATEMENT"; - case StatementType::TRANSACTION_STATEMENT: - return "TRANSACTION_STATEMENT"; - case StatementType::COPY_STATEMENT: - return "COPY_STATEMENT"; - case StatementType::ANALYZE_STATEMENT: - return "ANALYZE_STATEMENT"; - case StatementType::VARIABLE_SET_STATEMENT: - return "VARIABLE_SET_STATEMENT"; - case StatementType::CREATE_FUNC_STATEMENT: - return "CREATE_FUNC_STATEMENT"; - case StatementType::EXPLAIN_STATEMENT: - return "EXPLAIN_STATEMENT"; - case StatementType::DROP_STATEMENT: - return "DROP_STATEMENT"; - case StatementType::EXPORT_STATEMENT: - return "EXPORT_STATEMENT"; - case StatementType::PRAGMA_STATEMENT: - return "PRAGMA_STATEMENT"; - case StatementType::VACUUM_STATEMENT: - return "VACUUM_STATEMENT"; - case StatementType::CALL_STATEMENT: - return "CALL_STATEMENT"; - case StatementType::SET_STATEMENT: - return "SET_STATEMENT"; - case StatementType::LOAD_STATEMENT: - return "LOAD_STATEMENT"; - case StatementType::RELATION_STATEMENT: - return "RELATION_STATEMENT"; - case StatementType::EXTENSION_STATEMENT: - return "EXTENSION_STATEMENT"; - case StatementType::LOGICAL_PLAN_STATEMENT: - return "LOGICAL_PLAN_STATEMENT"; - case StatementType::ATTACH_STATEMENT: - return "ATTACH_STATEMENT"; - case StatementType::DETACH_STATEMENT: - return "DETACH_STATEMENT"; - case StatementType::MULTI_STATEMENT: - return "MULTI_STATEMENT"; - case StatementType::COPY_DATABASE_STATEMENT: - return "COPY_DATABASE_STATEMENT"; - case StatementType::UPDATE_EXTENSIONS_STATEMENT: - return "UPDATE_EXTENSIONS_STATEMENT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetStatementTypeValues(), 30, "StatementType", static_cast(value)); } template<> StatementType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID_STATEMENT")) { - return StatementType::INVALID_STATEMENT; - } - if (StringUtil::Equals(value, "SELECT_STATEMENT")) { - return StatementType::SELECT_STATEMENT; - } - if (StringUtil::Equals(value, "INSERT_STATEMENT")) { - return StatementType::INSERT_STATEMENT; - } - if (StringUtil::Equals(value, "UPDATE_STATEMENT")) { - return StatementType::UPDATE_STATEMENT; - } - if (StringUtil::Equals(value, "CREATE_STATEMENT")) { - return StatementType::CREATE_STATEMENT; - } - if (StringUtil::Equals(value, "DELETE_STATEMENT")) { - return StatementType::DELETE_STATEMENT; - } - if (StringUtil::Equals(value, "PREPARE_STATEMENT")) { - return StatementType::PREPARE_STATEMENT; - } - if (StringUtil::Equals(value, "EXECUTE_STATEMENT")) { - return StatementType::EXECUTE_STATEMENT; - } - if (StringUtil::Equals(value, "ALTER_STATEMENT")) { - return StatementType::ALTER_STATEMENT; - } - if (StringUtil::Equals(value, "TRANSACTION_STATEMENT")) { - return StatementType::TRANSACTION_STATEMENT; - } - if (StringUtil::Equals(value, "COPY_STATEMENT")) { - return StatementType::COPY_STATEMENT; - } - if (StringUtil::Equals(value, "ANALYZE_STATEMENT")) { - return StatementType::ANALYZE_STATEMENT; - } - if (StringUtil::Equals(value, "VARIABLE_SET_STATEMENT")) { - return StatementType::VARIABLE_SET_STATEMENT; - } - if (StringUtil::Equals(value, "CREATE_FUNC_STATEMENT")) { - return StatementType::CREATE_FUNC_STATEMENT; - } - if (StringUtil::Equals(value, "EXPLAIN_STATEMENT")) { - return StatementType::EXPLAIN_STATEMENT; - } - if (StringUtil::Equals(value, "DROP_STATEMENT")) { - return StatementType::DROP_STATEMENT; - } - if (StringUtil::Equals(value, "EXPORT_STATEMENT")) { - return StatementType::EXPORT_STATEMENT; - } - if (StringUtil::Equals(value, "PRAGMA_STATEMENT")) { - return StatementType::PRAGMA_STATEMENT; - } - if (StringUtil::Equals(value, "VACUUM_STATEMENT")) { - return StatementType::VACUUM_STATEMENT; - } - if (StringUtil::Equals(value, "CALL_STATEMENT")) { - return StatementType::CALL_STATEMENT; - } - if (StringUtil::Equals(value, "SET_STATEMENT")) { - return StatementType::SET_STATEMENT; - } - if (StringUtil::Equals(value, "LOAD_STATEMENT")) { - return StatementType::LOAD_STATEMENT; - } - if (StringUtil::Equals(value, "RELATION_STATEMENT")) { - return StatementType::RELATION_STATEMENT; - } - if (StringUtil::Equals(value, "EXTENSION_STATEMENT")) { - return StatementType::EXTENSION_STATEMENT; - } - if (StringUtil::Equals(value, "LOGICAL_PLAN_STATEMENT")) { - return StatementType::LOGICAL_PLAN_STATEMENT; - } - if (StringUtil::Equals(value, "ATTACH_STATEMENT")) { - return StatementType::ATTACH_STATEMENT; - } - if (StringUtil::Equals(value, "DETACH_STATEMENT")) { - return StatementType::DETACH_STATEMENT; - } - if (StringUtil::Equals(value, "MULTI_STATEMENT")) { - return StatementType::MULTI_STATEMENT; - } - if (StringUtil::Equals(value, "COPY_DATABASE_STATEMENT")) { - return StatementType::COPY_DATABASE_STATEMENT; - } - if (StringUtil::Equals(value, "UPDATE_EXTENSIONS_STATEMENT")) { - return StatementType::UPDATE_EXTENSIONS_STATEMENT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetStatementTypeValues(), 30, "StatementType", value)); +} + +const StringUtil::EnumStringLiteral *GetStatisticsTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(StatisticsType::NUMERIC_STATS), "NUMERIC_STATS" }, + { static_cast(StatisticsType::STRING_STATS), "STRING_STATS" }, + { static_cast(StatisticsType::LIST_STATS), "LIST_STATS" }, + { static_cast(StatisticsType::STRUCT_STATS), "STRUCT_STATS" }, + { static_cast(StatisticsType::BASE_STATS), "BASE_STATS" }, + { static_cast(StatisticsType::ARRAY_STATS), "ARRAY_STATS" } + }; + return values; } template<> const char* EnumUtil::ToChars(StatisticsType value) { - switch(value) { - case StatisticsType::NUMERIC_STATS: - return "NUMERIC_STATS"; - case StatisticsType::STRING_STATS: - return "STRING_STATS"; - case StatisticsType::LIST_STATS: - return "LIST_STATS"; - case StatisticsType::STRUCT_STATS: - return "STRUCT_STATS"; - case StatisticsType::BASE_STATS: - return "BASE_STATS"; - case StatisticsType::ARRAY_STATS: - return "ARRAY_STATS"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetStatisticsTypeValues(), 6, "StatisticsType", static_cast(value)); } template<> StatisticsType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NUMERIC_STATS")) { - return StatisticsType::NUMERIC_STATS; - } - if (StringUtil::Equals(value, "STRING_STATS")) { - return StatisticsType::STRING_STATS; - } - if (StringUtil::Equals(value, "LIST_STATS")) { - return StatisticsType::LIST_STATS; - } - if (StringUtil::Equals(value, "STRUCT_STATS")) { - return StatisticsType::STRUCT_STATS; - } - if (StringUtil::Equals(value, "BASE_STATS")) { - return StatisticsType::BASE_STATS; - } - if (StringUtil::Equals(value, "ARRAY_STATS")) { - return StatisticsType::ARRAY_STATS; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetStatisticsTypeValues(), 6, "StatisticsType", value)); +} + +const StringUtil::EnumStringLiteral *GetStatsInfoValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(StatsInfo::CAN_HAVE_NULL_VALUES), "CAN_HAVE_NULL_VALUES" }, + { static_cast(StatsInfo::CANNOT_HAVE_NULL_VALUES), "CANNOT_HAVE_NULL_VALUES" }, + { static_cast(StatsInfo::CAN_HAVE_VALID_VALUES), "CAN_HAVE_VALID_VALUES" }, + { static_cast(StatsInfo::CANNOT_HAVE_VALID_VALUES), "CANNOT_HAVE_VALID_VALUES" }, + { static_cast(StatsInfo::CAN_HAVE_NULL_AND_VALID_VALUES), "CAN_HAVE_NULL_AND_VALID_VALUES" } + }; + return values; } template<> const char* EnumUtil::ToChars(StatsInfo value) { - switch(value) { - case StatsInfo::CAN_HAVE_NULL_VALUES: - return "CAN_HAVE_NULL_VALUES"; - case StatsInfo::CANNOT_HAVE_NULL_VALUES: - return "CANNOT_HAVE_NULL_VALUES"; - case StatsInfo::CAN_HAVE_VALID_VALUES: - return "CAN_HAVE_VALID_VALUES"; - case StatsInfo::CANNOT_HAVE_VALID_VALUES: - return "CANNOT_HAVE_VALID_VALUES"; - case StatsInfo::CAN_HAVE_NULL_AND_VALID_VALUES: - return "CAN_HAVE_NULL_AND_VALID_VALUES"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetStatsInfoValues(), 5, "StatsInfo", static_cast(value)); } template<> StatsInfo EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "CAN_HAVE_NULL_VALUES")) { - return StatsInfo::CAN_HAVE_NULL_VALUES; - } - if (StringUtil::Equals(value, "CANNOT_HAVE_NULL_VALUES")) { - return StatsInfo::CANNOT_HAVE_NULL_VALUES; - } - if (StringUtil::Equals(value, "CAN_HAVE_VALID_VALUES")) { - return StatsInfo::CAN_HAVE_VALID_VALUES; - } - if (StringUtil::Equals(value, "CANNOT_HAVE_VALID_VALUES")) { - return StatsInfo::CANNOT_HAVE_VALID_VALUES; - } - if (StringUtil::Equals(value, "CAN_HAVE_NULL_AND_VALID_VALUES")) { - return StatsInfo::CAN_HAVE_NULL_AND_VALID_VALUES; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetStatsInfoValues(), 5, "StatsInfo", value)); +} + +const StringUtil::EnumStringLiteral *GetStrTimeSpecifierValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(StrTimeSpecifier::ABBREVIATED_WEEKDAY_NAME), "ABBREVIATED_WEEKDAY_NAME" }, + { static_cast(StrTimeSpecifier::FULL_WEEKDAY_NAME), "FULL_WEEKDAY_NAME" }, + { static_cast(StrTimeSpecifier::WEEKDAY_DECIMAL), "WEEKDAY_DECIMAL" }, + { static_cast(StrTimeSpecifier::DAY_OF_MONTH_PADDED), "DAY_OF_MONTH_PADDED" }, + { static_cast(StrTimeSpecifier::DAY_OF_MONTH), "DAY_OF_MONTH" }, + { static_cast(StrTimeSpecifier::ABBREVIATED_MONTH_NAME), "ABBREVIATED_MONTH_NAME" }, + { static_cast(StrTimeSpecifier::FULL_MONTH_NAME), "FULL_MONTH_NAME" }, + { static_cast(StrTimeSpecifier::MONTH_DECIMAL_PADDED), "MONTH_DECIMAL_PADDED" }, + { static_cast(StrTimeSpecifier::MONTH_DECIMAL), "MONTH_DECIMAL" }, + { static_cast(StrTimeSpecifier::YEAR_WITHOUT_CENTURY_PADDED), "YEAR_WITHOUT_CENTURY_PADDED" }, + { static_cast(StrTimeSpecifier::YEAR_WITHOUT_CENTURY), "YEAR_WITHOUT_CENTURY" }, + { static_cast(StrTimeSpecifier::YEAR_DECIMAL), "YEAR_DECIMAL" }, + { static_cast(StrTimeSpecifier::HOUR_24_PADDED), "HOUR_24_PADDED" }, + { static_cast(StrTimeSpecifier::HOUR_24_DECIMAL), "HOUR_24_DECIMAL" }, + { static_cast(StrTimeSpecifier::HOUR_12_PADDED), "HOUR_12_PADDED" }, + { static_cast(StrTimeSpecifier::HOUR_12_DECIMAL), "HOUR_12_DECIMAL" }, + { static_cast(StrTimeSpecifier::AM_PM), "AM_PM" }, + { static_cast(StrTimeSpecifier::MINUTE_PADDED), "MINUTE_PADDED" }, + { static_cast(StrTimeSpecifier::MINUTE_DECIMAL), "MINUTE_DECIMAL" }, + { static_cast(StrTimeSpecifier::SECOND_PADDED), "SECOND_PADDED" }, + { static_cast(StrTimeSpecifier::SECOND_DECIMAL), "SECOND_DECIMAL" }, + { static_cast(StrTimeSpecifier::MICROSECOND_PADDED), "MICROSECOND_PADDED" }, + { static_cast(StrTimeSpecifier::MILLISECOND_PADDED), "MILLISECOND_PADDED" }, + { static_cast(StrTimeSpecifier::UTC_OFFSET), "UTC_OFFSET" }, + { static_cast(StrTimeSpecifier::TZ_NAME), "TZ_NAME" }, + { static_cast(StrTimeSpecifier::DAY_OF_YEAR_PADDED), "DAY_OF_YEAR_PADDED" }, + { static_cast(StrTimeSpecifier::DAY_OF_YEAR_DECIMAL), "DAY_OF_YEAR_DECIMAL" }, + { static_cast(StrTimeSpecifier::WEEK_NUMBER_PADDED_SUN_FIRST), "WEEK_NUMBER_PADDED_SUN_FIRST" }, + { static_cast(StrTimeSpecifier::WEEK_NUMBER_PADDED_MON_FIRST), "WEEK_NUMBER_PADDED_MON_FIRST" }, + { static_cast(StrTimeSpecifier::LOCALE_APPROPRIATE_DATE_AND_TIME), "LOCALE_APPROPRIATE_DATE_AND_TIME" }, + { static_cast(StrTimeSpecifier::LOCALE_APPROPRIATE_DATE), "LOCALE_APPROPRIATE_DATE" }, + { static_cast(StrTimeSpecifier::LOCALE_APPROPRIATE_TIME), "LOCALE_APPROPRIATE_TIME" }, + { static_cast(StrTimeSpecifier::NANOSECOND_PADDED), "NANOSECOND_PADDED" }, + { static_cast(StrTimeSpecifier::YEAR_ISO), "YEAR_ISO" }, + { static_cast(StrTimeSpecifier::WEEKDAY_ISO), "WEEKDAY_ISO" }, + { static_cast(StrTimeSpecifier::WEEK_NUMBER_ISO), "WEEK_NUMBER_ISO" } + }; + return values; } template<> const char* EnumUtil::ToChars(StrTimeSpecifier value) { - switch(value) { - case StrTimeSpecifier::ABBREVIATED_WEEKDAY_NAME: - return "ABBREVIATED_WEEKDAY_NAME"; - case StrTimeSpecifier::FULL_WEEKDAY_NAME: - return "FULL_WEEKDAY_NAME"; - case StrTimeSpecifier::WEEKDAY_DECIMAL: - return "WEEKDAY_DECIMAL"; - case StrTimeSpecifier::DAY_OF_MONTH_PADDED: - return "DAY_OF_MONTH_PADDED"; - case StrTimeSpecifier::DAY_OF_MONTH: - return "DAY_OF_MONTH"; - case StrTimeSpecifier::ABBREVIATED_MONTH_NAME: - return "ABBREVIATED_MONTH_NAME"; - case StrTimeSpecifier::FULL_MONTH_NAME: - return "FULL_MONTH_NAME"; - case StrTimeSpecifier::MONTH_DECIMAL_PADDED: - return "MONTH_DECIMAL_PADDED"; - case StrTimeSpecifier::MONTH_DECIMAL: - return "MONTH_DECIMAL"; - case StrTimeSpecifier::YEAR_WITHOUT_CENTURY_PADDED: - return "YEAR_WITHOUT_CENTURY_PADDED"; - case StrTimeSpecifier::YEAR_WITHOUT_CENTURY: - return "YEAR_WITHOUT_CENTURY"; - case StrTimeSpecifier::YEAR_DECIMAL: - return "YEAR_DECIMAL"; - case StrTimeSpecifier::HOUR_24_PADDED: - return "HOUR_24_PADDED"; - case StrTimeSpecifier::HOUR_24_DECIMAL: - return "HOUR_24_DECIMAL"; - case StrTimeSpecifier::HOUR_12_PADDED: - return "HOUR_12_PADDED"; - case StrTimeSpecifier::HOUR_12_DECIMAL: - return "HOUR_12_DECIMAL"; - case StrTimeSpecifier::AM_PM: - return "AM_PM"; - case StrTimeSpecifier::MINUTE_PADDED: - return "MINUTE_PADDED"; - case StrTimeSpecifier::MINUTE_DECIMAL: - return "MINUTE_DECIMAL"; - case StrTimeSpecifier::SECOND_PADDED: - return "SECOND_PADDED"; - case StrTimeSpecifier::SECOND_DECIMAL: - return "SECOND_DECIMAL"; - case StrTimeSpecifier::MICROSECOND_PADDED: - return "MICROSECOND_PADDED"; - case StrTimeSpecifier::MILLISECOND_PADDED: - return "MILLISECOND_PADDED"; - case StrTimeSpecifier::UTC_OFFSET: - return "UTC_OFFSET"; - case StrTimeSpecifier::TZ_NAME: - return "TZ_NAME"; - case StrTimeSpecifier::DAY_OF_YEAR_PADDED: - return "DAY_OF_YEAR_PADDED"; - case StrTimeSpecifier::DAY_OF_YEAR_DECIMAL: - return "DAY_OF_YEAR_DECIMAL"; - case StrTimeSpecifier::WEEK_NUMBER_PADDED_SUN_FIRST: - return "WEEK_NUMBER_PADDED_SUN_FIRST"; - case StrTimeSpecifier::WEEK_NUMBER_PADDED_MON_FIRST: - return "WEEK_NUMBER_PADDED_MON_FIRST"; - case StrTimeSpecifier::LOCALE_APPROPRIATE_DATE_AND_TIME: - return "LOCALE_APPROPRIATE_DATE_AND_TIME"; - case StrTimeSpecifier::LOCALE_APPROPRIATE_DATE: - return "LOCALE_APPROPRIATE_DATE"; - case StrTimeSpecifier::LOCALE_APPROPRIATE_TIME: - return "LOCALE_APPROPRIATE_TIME"; - case StrTimeSpecifier::NANOSECOND_PADDED: - return "NANOSECOND_PADDED"; - case StrTimeSpecifier::YEAR_ISO: - return "YEAR_ISO"; - case StrTimeSpecifier::WEEKDAY_ISO: - return "WEEKDAY_ISO"; - case StrTimeSpecifier::WEEK_NUMBER_ISO: - return "WEEK_NUMBER_ISO"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetStrTimeSpecifierValues(), 36, "StrTimeSpecifier", static_cast(value)); } template<> StrTimeSpecifier EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "ABBREVIATED_WEEKDAY_NAME")) { - return StrTimeSpecifier::ABBREVIATED_WEEKDAY_NAME; - } - if (StringUtil::Equals(value, "FULL_WEEKDAY_NAME")) { - return StrTimeSpecifier::FULL_WEEKDAY_NAME; - } - if (StringUtil::Equals(value, "WEEKDAY_DECIMAL")) { - return StrTimeSpecifier::WEEKDAY_DECIMAL; - } - if (StringUtil::Equals(value, "DAY_OF_MONTH_PADDED")) { - return StrTimeSpecifier::DAY_OF_MONTH_PADDED; - } - if (StringUtil::Equals(value, "DAY_OF_MONTH")) { - return StrTimeSpecifier::DAY_OF_MONTH; - } - if (StringUtil::Equals(value, "ABBREVIATED_MONTH_NAME")) { - return StrTimeSpecifier::ABBREVIATED_MONTH_NAME; - } - if (StringUtil::Equals(value, "FULL_MONTH_NAME")) { - return StrTimeSpecifier::FULL_MONTH_NAME; - } - if (StringUtil::Equals(value, "MONTH_DECIMAL_PADDED")) { - return StrTimeSpecifier::MONTH_DECIMAL_PADDED; - } - if (StringUtil::Equals(value, "MONTH_DECIMAL")) { - return StrTimeSpecifier::MONTH_DECIMAL; - } - if (StringUtil::Equals(value, "YEAR_WITHOUT_CENTURY_PADDED")) { - return StrTimeSpecifier::YEAR_WITHOUT_CENTURY_PADDED; - } - if (StringUtil::Equals(value, "YEAR_WITHOUT_CENTURY")) { - return StrTimeSpecifier::YEAR_WITHOUT_CENTURY; - } - if (StringUtil::Equals(value, "YEAR_DECIMAL")) { - return StrTimeSpecifier::YEAR_DECIMAL; - } - if (StringUtil::Equals(value, "HOUR_24_PADDED")) { - return StrTimeSpecifier::HOUR_24_PADDED; - } - if (StringUtil::Equals(value, "HOUR_24_DECIMAL")) { - return StrTimeSpecifier::HOUR_24_DECIMAL; - } - if (StringUtil::Equals(value, "HOUR_12_PADDED")) { - return StrTimeSpecifier::HOUR_12_PADDED; - } - if (StringUtil::Equals(value, "HOUR_12_DECIMAL")) { - return StrTimeSpecifier::HOUR_12_DECIMAL; - } - if (StringUtil::Equals(value, "AM_PM")) { - return StrTimeSpecifier::AM_PM; - } - if (StringUtil::Equals(value, "MINUTE_PADDED")) { - return StrTimeSpecifier::MINUTE_PADDED; - } - if (StringUtil::Equals(value, "MINUTE_DECIMAL")) { - return StrTimeSpecifier::MINUTE_DECIMAL; - } - if (StringUtil::Equals(value, "SECOND_PADDED")) { - return StrTimeSpecifier::SECOND_PADDED; - } - if (StringUtil::Equals(value, "SECOND_DECIMAL")) { - return StrTimeSpecifier::SECOND_DECIMAL; - } - if (StringUtil::Equals(value, "MICROSECOND_PADDED")) { - return StrTimeSpecifier::MICROSECOND_PADDED; - } - if (StringUtil::Equals(value, "MILLISECOND_PADDED")) { - return StrTimeSpecifier::MILLISECOND_PADDED; - } - if (StringUtil::Equals(value, "UTC_OFFSET")) { - return StrTimeSpecifier::UTC_OFFSET; - } - if (StringUtil::Equals(value, "TZ_NAME")) { - return StrTimeSpecifier::TZ_NAME; - } - if (StringUtil::Equals(value, "DAY_OF_YEAR_PADDED")) { - return StrTimeSpecifier::DAY_OF_YEAR_PADDED; - } - if (StringUtil::Equals(value, "DAY_OF_YEAR_DECIMAL")) { - return StrTimeSpecifier::DAY_OF_YEAR_DECIMAL; - } - if (StringUtil::Equals(value, "WEEK_NUMBER_PADDED_SUN_FIRST")) { - return StrTimeSpecifier::WEEK_NUMBER_PADDED_SUN_FIRST; - } - if (StringUtil::Equals(value, "WEEK_NUMBER_PADDED_MON_FIRST")) { - return StrTimeSpecifier::WEEK_NUMBER_PADDED_MON_FIRST; - } - if (StringUtil::Equals(value, "LOCALE_APPROPRIATE_DATE_AND_TIME")) { - return StrTimeSpecifier::LOCALE_APPROPRIATE_DATE_AND_TIME; - } - if (StringUtil::Equals(value, "LOCALE_APPROPRIATE_DATE")) { - return StrTimeSpecifier::LOCALE_APPROPRIATE_DATE; - } - if (StringUtil::Equals(value, "LOCALE_APPROPRIATE_TIME")) { - return StrTimeSpecifier::LOCALE_APPROPRIATE_TIME; - } - if (StringUtil::Equals(value, "NANOSECOND_PADDED")) { - return StrTimeSpecifier::NANOSECOND_PADDED; - } - if (StringUtil::Equals(value, "YEAR_ISO")) { - return StrTimeSpecifier::YEAR_ISO; - } - if (StringUtil::Equals(value, "WEEKDAY_ISO")) { - return StrTimeSpecifier::WEEKDAY_ISO; - } - if (StringUtil::Equals(value, "WEEK_NUMBER_ISO")) { - return StrTimeSpecifier::WEEK_NUMBER_ISO; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetStrTimeSpecifierValues(), 36, "StrTimeSpecifier", value)); +} + +const StringUtil::EnumStringLiteral *GetStreamExecutionResultValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(StreamExecutionResult::CHUNK_READY), "CHUNK_READY" }, + { static_cast(StreamExecutionResult::CHUNK_NOT_READY), "CHUNK_NOT_READY" }, + { static_cast(StreamExecutionResult::EXECUTION_ERROR), "EXECUTION_ERROR" }, + { static_cast(StreamExecutionResult::EXECUTION_CANCELLED), "EXECUTION_CANCELLED" }, + { static_cast(StreamExecutionResult::BLOCKED), "BLOCKED" }, + { static_cast(StreamExecutionResult::NO_TASKS_AVAILABLE), "NO_TASKS_AVAILABLE" }, + { static_cast(StreamExecutionResult::EXECUTION_FINISHED), "EXECUTION_FINISHED" } + }; + return values; } template<> const char* EnumUtil::ToChars(StreamExecutionResult value) { - switch(value) { - case StreamExecutionResult::CHUNK_READY: - return "CHUNK_READY"; - case StreamExecutionResult::CHUNK_NOT_READY: - return "CHUNK_NOT_READY"; - case StreamExecutionResult::EXECUTION_ERROR: - return "EXECUTION_ERROR"; - case StreamExecutionResult::EXECUTION_CANCELLED: - return "EXECUTION_CANCELLED"; - case StreamExecutionResult::BLOCKED: - return "BLOCKED"; - case StreamExecutionResult::NO_TASKS_AVAILABLE: - return "NO_TASKS_AVAILABLE"; - case StreamExecutionResult::EXECUTION_FINISHED: - return "EXECUTION_FINISHED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetStreamExecutionResultValues(), 7, "StreamExecutionResult", static_cast(value)); } template<> StreamExecutionResult EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "CHUNK_READY")) { - return StreamExecutionResult::CHUNK_READY; - } - if (StringUtil::Equals(value, "CHUNK_NOT_READY")) { - return StreamExecutionResult::CHUNK_NOT_READY; - } - if (StringUtil::Equals(value, "EXECUTION_ERROR")) { - return StreamExecutionResult::EXECUTION_ERROR; - } - if (StringUtil::Equals(value, "EXECUTION_CANCELLED")) { - return StreamExecutionResult::EXECUTION_CANCELLED; - } - if (StringUtil::Equals(value, "BLOCKED")) { - return StreamExecutionResult::BLOCKED; - } - if (StringUtil::Equals(value, "NO_TASKS_AVAILABLE")) { - return StreamExecutionResult::NO_TASKS_AVAILABLE; - } - if (StringUtil::Equals(value, "EXECUTION_FINISHED")) { - return StreamExecutionResult::EXECUTION_FINISHED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetStreamExecutionResultValues(), 7, "StreamExecutionResult", value)); +} + +const StringUtil::EnumStringLiteral *GetSubqueryTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(SubqueryType::INVALID), "INVALID" }, + { static_cast(SubqueryType::SCALAR), "SCALAR" }, + { static_cast(SubqueryType::EXISTS), "EXISTS" }, + { static_cast(SubqueryType::NOT_EXISTS), "NOT_EXISTS" }, + { static_cast(SubqueryType::ANY), "ANY" } + }; + return values; } template<> const char* EnumUtil::ToChars(SubqueryType value) { - switch(value) { - case SubqueryType::INVALID: - return "INVALID"; - case SubqueryType::SCALAR: - return "SCALAR"; - case SubqueryType::EXISTS: - return "EXISTS"; - case SubqueryType::NOT_EXISTS: - return "NOT_EXISTS"; - case SubqueryType::ANY: - return "ANY"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetSubqueryTypeValues(), 5, "SubqueryType", static_cast(value)); } template<> SubqueryType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return SubqueryType::INVALID; - } - if (StringUtil::Equals(value, "SCALAR")) { - return SubqueryType::SCALAR; - } - if (StringUtil::Equals(value, "EXISTS")) { - return SubqueryType::EXISTS; - } - if (StringUtil::Equals(value, "NOT_EXISTS")) { - return SubqueryType::NOT_EXISTS; - } - if (StringUtil::Equals(value, "ANY")) { - return SubqueryType::ANY; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetSubqueryTypeValues(), 5, "SubqueryType", value)); +} + +const StringUtil::EnumStringLiteral *GetTableColumnTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(TableColumnType::STANDARD), "STANDARD" }, + { static_cast(TableColumnType::GENERATED), "GENERATED" } + }; + return values; } template<> const char* EnumUtil::ToChars(TableColumnType value) { - switch(value) { - case TableColumnType::STANDARD: - return "STANDARD"; - case TableColumnType::GENERATED: - return "GENERATED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetTableColumnTypeValues(), 2, "TableColumnType", static_cast(value)); } template<> TableColumnType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "STANDARD")) { - return TableColumnType::STANDARD; - } - if (StringUtil::Equals(value, "GENERATED")) { - return TableColumnType::GENERATED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetTableColumnTypeValues(), 2, "TableColumnType", value)); +} + +const StringUtil::EnumStringLiteral *GetTableFilterTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(TableFilterType::CONSTANT_COMPARISON), "CONSTANT_COMPARISON" }, + { static_cast(TableFilterType::IS_NULL), "IS_NULL" }, + { static_cast(TableFilterType::IS_NOT_NULL), "IS_NOT_NULL" }, + { static_cast(TableFilterType::CONJUNCTION_OR), "CONJUNCTION_OR" }, + { static_cast(TableFilterType::CONJUNCTION_AND), "CONJUNCTION_AND" }, + { static_cast(TableFilterType::STRUCT_EXTRACT), "STRUCT_EXTRACT" }, + { static_cast(TableFilterType::OPTIONAL_FILTER), "OPTIONAL_FILTER" } + }; + return values; } template<> const char* EnumUtil::ToChars(TableFilterType value) { - switch(value) { - case TableFilterType::CONSTANT_COMPARISON: - return "CONSTANT_COMPARISON"; - case TableFilterType::IS_NULL: - return "IS_NULL"; - case TableFilterType::IS_NOT_NULL: - return "IS_NOT_NULL"; - case TableFilterType::CONJUNCTION_OR: - return "CONJUNCTION_OR"; - case TableFilterType::CONJUNCTION_AND: - return "CONJUNCTION_AND"; - case TableFilterType::STRUCT_EXTRACT: - return "STRUCT_EXTRACT"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetTableFilterTypeValues(), 7, "TableFilterType", static_cast(value)); } template<> TableFilterType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "CONSTANT_COMPARISON")) { - return TableFilterType::CONSTANT_COMPARISON; - } - if (StringUtil::Equals(value, "IS_NULL")) { - return TableFilterType::IS_NULL; - } - if (StringUtil::Equals(value, "IS_NOT_NULL")) { - return TableFilterType::IS_NOT_NULL; - } - if (StringUtil::Equals(value, "CONJUNCTION_OR")) { - return TableFilterType::CONJUNCTION_OR; - } - if (StringUtil::Equals(value, "CONJUNCTION_AND")) { - return TableFilterType::CONJUNCTION_AND; - } - if (StringUtil::Equals(value, "STRUCT_EXTRACT")) { - return TableFilterType::STRUCT_EXTRACT; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetTableFilterTypeValues(), 7, "TableFilterType", value)); +} + +const StringUtil::EnumStringLiteral *GetTablePartitionInfoValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(TablePartitionInfo::NOT_PARTITIONED), "NOT_PARTITIONED" }, + { static_cast(TablePartitionInfo::SINGLE_VALUE_PARTITIONS), "SINGLE_VALUE_PARTITIONS" }, + { static_cast(TablePartitionInfo::OVERLAPPING_PARTITIONS), "OVERLAPPING_PARTITIONS" }, + { static_cast(TablePartitionInfo::DISJOINT_PARTITIONS), "DISJOINT_PARTITIONS" } + }; + return values; +} + +template<> +const char* EnumUtil::ToChars(TablePartitionInfo value) { + return StringUtil::EnumToString(GetTablePartitionInfoValues(), 4, "TablePartitionInfo", static_cast(value)); +} + +template<> +TablePartitionInfo EnumUtil::FromString(const char *value) { + return static_cast(StringUtil::StringToEnum(GetTablePartitionInfoValues(), 4, "TablePartitionInfo", value)); +} + +const StringUtil::EnumStringLiteral *GetTableReferenceTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(TableReferenceType::INVALID), "INVALID" }, + { static_cast(TableReferenceType::BASE_TABLE), "BASE_TABLE" }, + { static_cast(TableReferenceType::SUBQUERY), "SUBQUERY" }, + { static_cast(TableReferenceType::JOIN), "JOIN" }, + { static_cast(TableReferenceType::TABLE_FUNCTION), "TABLE_FUNCTION" }, + { static_cast(TableReferenceType::EXPRESSION_LIST), "EXPRESSION_LIST" }, + { static_cast(TableReferenceType::CTE), "CTE" }, + { static_cast(TableReferenceType::EMPTY_FROM), "EMPTY" }, + { static_cast(TableReferenceType::PIVOT), "PIVOT" }, + { static_cast(TableReferenceType::SHOW_REF), "SHOW_REF" }, + { static_cast(TableReferenceType::COLUMN_DATA), "COLUMN_DATA" }, + { static_cast(TableReferenceType::DELIM_GET), "DELIM_GET" } + }; + return values; } template<> const char* EnumUtil::ToChars(TableReferenceType value) { - switch(value) { - case TableReferenceType::INVALID: - return "INVALID"; - case TableReferenceType::BASE_TABLE: - return "BASE_TABLE"; - case TableReferenceType::SUBQUERY: - return "SUBQUERY"; - case TableReferenceType::JOIN: - return "JOIN"; - case TableReferenceType::TABLE_FUNCTION: - return "TABLE_FUNCTION"; - case TableReferenceType::EXPRESSION_LIST: - return "EXPRESSION_LIST"; - case TableReferenceType::CTE: - return "CTE"; - case TableReferenceType::EMPTY_FROM: - return "EMPTY"; - case TableReferenceType::PIVOT: - return "PIVOT"; - case TableReferenceType::SHOW_REF: - return "SHOW_REF"; - case TableReferenceType::COLUMN_DATA: - return "COLUMN_DATA"; - case TableReferenceType::DELIM_GET: - return "DELIM_GET"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetTableReferenceTypeValues(), 12, "TableReferenceType", static_cast(value)); } template<> TableReferenceType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return TableReferenceType::INVALID; - } - if (StringUtil::Equals(value, "BASE_TABLE")) { - return TableReferenceType::BASE_TABLE; - } - if (StringUtil::Equals(value, "SUBQUERY")) { - return TableReferenceType::SUBQUERY; - } - if (StringUtil::Equals(value, "JOIN")) { - return TableReferenceType::JOIN; - } - if (StringUtil::Equals(value, "TABLE_FUNCTION")) { - return TableReferenceType::TABLE_FUNCTION; - } - if (StringUtil::Equals(value, "EXPRESSION_LIST")) { - return TableReferenceType::EXPRESSION_LIST; - } - if (StringUtil::Equals(value, "CTE")) { - return TableReferenceType::CTE; - } - if (StringUtil::Equals(value, "EMPTY")) { - return TableReferenceType::EMPTY_FROM; - } - if (StringUtil::Equals(value, "PIVOT")) { - return TableReferenceType::PIVOT; - } - if (StringUtil::Equals(value, "SHOW_REF")) { - return TableReferenceType::SHOW_REF; - } - if (StringUtil::Equals(value, "COLUMN_DATA")) { - return TableReferenceType::COLUMN_DATA; - } - if (StringUtil::Equals(value, "DELIM_GET")) { - return TableReferenceType::DELIM_GET; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetTableReferenceTypeValues(), 12, "TableReferenceType", value)); +} + +const StringUtil::EnumStringLiteral *GetTableScanTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(TableScanType::TABLE_SCAN_REGULAR), "TABLE_SCAN_REGULAR" }, + { static_cast(TableScanType::TABLE_SCAN_COMMITTED_ROWS), "TABLE_SCAN_COMMITTED_ROWS" }, + { static_cast(TableScanType::TABLE_SCAN_COMMITTED_ROWS_DISALLOW_UPDATES), "TABLE_SCAN_COMMITTED_ROWS_DISALLOW_UPDATES" }, + { static_cast(TableScanType::TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED), "TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED" }, + { static_cast(TableScanType::TABLE_SCAN_LATEST_COMMITTED_ROWS), "TABLE_SCAN_LATEST_COMMITTED_ROWS" } + }; + return values; } template<> const char* EnumUtil::ToChars(TableScanType value) { - switch(value) { - case TableScanType::TABLE_SCAN_REGULAR: - return "TABLE_SCAN_REGULAR"; - case TableScanType::TABLE_SCAN_COMMITTED_ROWS: - return "TABLE_SCAN_COMMITTED_ROWS"; - case TableScanType::TABLE_SCAN_COMMITTED_ROWS_DISALLOW_UPDATES: - return "TABLE_SCAN_COMMITTED_ROWS_DISALLOW_UPDATES"; - case TableScanType::TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED: - return "TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED"; - case TableScanType::TABLE_SCAN_LATEST_COMMITTED_ROWS: - return "TABLE_SCAN_LATEST_COMMITTED_ROWS"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetTableScanTypeValues(), 5, "TableScanType", static_cast(value)); } template<> TableScanType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "TABLE_SCAN_REGULAR")) { - return TableScanType::TABLE_SCAN_REGULAR; - } - if (StringUtil::Equals(value, "TABLE_SCAN_COMMITTED_ROWS")) { - return TableScanType::TABLE_SCAN_COMMITTED_ROWS; - } - if (StringUtil::Equals(value, "TABLE_SCAN_COMMITTED_ROWS_DISALLOW_UPDATES")) { - return TableScanType::TABLE_SCAN_COMMITTED_ROWS_DISALLOW_UPDATES; - } - if (StringUtil::Equals(value, "TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED")) { - return TableScanType::TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED; - } - if (StringUtil::Equals(value, "TABLE_SCAN_LATEST_COMMITTED_ROWS")) { - return TableScanType::TABLE_SCAN_LATEST_COMMITTED_ROWS; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetTableScanTypeValues(), 5, "TableScanType", value)); +} + +const StringUtil::EnumStringLiteral *GetTaskExecutionModeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(TaskExecutionMode::PROCESS_ALL), "PROCESS_ALL" }, + { static_cast(TaskExecutionMode::PROCESS_PARTIAL), "PROCESS_PARTIAL" } + }; + return values; } template<> const char* EnumUtil::ToChars(TaskExecutionMode value) { - switch(value) { - case TaskExecutionMode::PROCESS_ALL: - return "PROCESS_ALL"; - case TaskExecutionMode::PROCESS_PARTIAL: - return "PROCESS_PARTIAL"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetTaskExecutionModeValues(), 2, "TaskExecutionMode", static_cast(value)); } template<> TaskExecutionMode EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "PROCESS_ALL")) { - return TaskExecutionMode::PROCESS_ALL; - } - if (StringUtil::Equals(value, "PROCESS_PARTIAL")) { - return TaskExecutionMode::PROCESS_PARTIAL; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetTaskExecutionModeValues(), 2, "TaskExecutionMode", value)); +} + +const StringUtil::EnumStringLiteral *GetTaskExecutionResultValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(TaskExecutionResult::TASK_FINISHED), "TASK_FINISHED" }, + { static_cast(TaskExecutionResult::TASK_NOT_FINISHED), "TASK_NOT_FINISHED" }, + { static_cast(TaskExecutionResult::TASK_ERROR), "TASK_ERROR" }, + { static_cast(TaskExecutionResult::TASK_BLOCKED), "TASK_BLOCKED" } + }; + return values; } template<> const char* EnumUtil::ToChars(TaskExecutionResult value) { - switch(value) { - case TaskExecutionResult::TASK_FINISHED: - return "TASK_FINISHED"; - case TaskExecutionResult::TASK_NOT_FINISHED: - return "TASK_NOT_FINISHED"; - case TaskExecutionResult::TASK_ERROR: - return "TASK_ERROR"; - case TaskExecutionResult::TASK_BLOCKED: - return "TASK_BLOCKED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetTaskExecutionResultValues(), 4, "TaskExecutionResult", static_cast(value)); } template<> TaskExecutionResult EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "TASK_FINISHED")) { - return TaskExecutionResult::TASK_FINISHED; - } - if (StringUtil::Equals(value, "TASK_NOT_FINISHED")) { - return TaskExecutionResult::TASK_NOT_FINISHED; - } - if (StringUtil::Equals(value, "TASK_ERROR")) { - return TaskExecutionResult::TASK_ERROR; - } - if (StringUtil::Equals(value, "TASK_BLOCKED")) { - return TaskExecutionResult::TASK_BLOCKED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetTaskExecutionResultValues(), 4, "TaskExecutionResult", value)); +} + +const StringUtil::EnumStringLiteral *GetTemporaryBufferSizeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(TemporaryBufferSize::INVALID), "INVALID" }, + { static_cast(TemporaryBufferSize::S32K), "S32K" }, + { static_cast(TemporaryBufferSize::S64K), "S64K" }, + { static_cast(TemporaryBufferSize::S96K), "S96K" }, + { static_cast(TemporaryBufferSize::S128K), "S128K" }, + { static_cast(TemporaryBufferSize::S160K), "S160K" }, + { static_cast(TemporaryBufferSize::S192K), "S192K" }, + { static_cast(TemporaryBufferSize::S224K), "S224K" }, + { static_cast(TemporaryBufferSize::DEFAULT), "DEFAULT" } + }; + return values; +} + +template<> +const char* EnumUtil::ToChars(TemporaryBufferSize value) { + return StringUtil::EnumToString(GetTemporaryBufferSizeValues(), 9, "TemporaryBufferSize", static_cast(value)); +} + +template<> +TemporaryBufferSize EnumUtil::FromString(const char *value) { + return static_cast(StringUtil::StringToEnum(GetTemporaryBufferSizeValues(), 9, "TemporaryBufferSize", value)); +} + +const StringUtil::EnumStringLiteral *GetTemporaryCompressionLevelValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(TemporaryCompressionLevel::ZSTD_MINUS_FIVE), "ZSTD_MINUS_FIVE" }, + { static_cast(TemporaryCompressionLevel::ZSTD_MINUS_THREE), "ZSTD_MINUS_THREE" }, + { static_cast(TemporaryCompressionLevel::ZSTD_MINUS_ONE), "ZSTD_MINUS_ONE" }, + { static_cast(TemporaryCompressionLevel::UNCOMPRESSED), "UNCOMPRESSED" }, + { static_cast(TemporaryCompressionLevel::ZSTD_ONE), "ZSTD_ONE" }, + { static_cast(TemporaryCompressionLevel::ZSTD_THREE), "ZSTD_THREE" }, + { static_cast(TemporaryCompressionLevel::ZSTD_FIVE), "ZSTD_FIVE" } + }; + return values; +} + +template<> +const char* EnumUtil::ToChars(TemporaryCompressionLevel value) { + return StringUtil::EnumToString(GetTemporaryCompressionLevelValues(), 7, "TemporaryCompressionLevel", static_cast(value)); +} + +template<> +TemporaryCompressionLevel EnumUtil::FromString(const char *value) { + return static_cast(StringUtil::StringToEnum(GetTemporaryCompressionLevelValues(), 7, "TemporaryCompressionLevel", value)); +} + +const StringUtil::EnumStringLiteral *GetTimestampCastResultValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(TimestampCastResult::SUCCESS), "SUCCESS" }, + { static_cast(TimestampCastResult::ERROR_INCORRECT_FORMAT), "ERROR_INCORRECT_FORMAT" }, + { static_cast(TimestampCastResult::ERROR_NON_UTC_TIMEZONE), "ERROR_NON_UTC_TIMEZONE" } + }; + return values; } template<> const char* EnumUtil::ToChars(TimestampCastResult value) { - switch(value) { - case TimestampCastResult::SUCCESS: - return "SUCCESS"; - case TimestampCastResult::ERROR_INCORRECT_FORMAT: - return "ERROR_INCORRECT_FORMAT"; - case TimestampCastResult::ERROR_NON_UTC_TIMEZONE: - return "ERROR_NON_UTC_TIMEZONE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetTimestampCastResultValues(), 3, "TimestampCastResult", static_cast(value)); } template<> TimestampCastResult EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "SUCCESS")) { - return TimestampCastResult::SUCCESS; - } - if (StringUtil::Equals(value, "ERROR_INCORRECT_FORMAT")) { - return TimestampCastResult::ERROR_INCORRECT_FORMAT; - } - if (StringUtil::Equals(value, "ERROR_NON_UTC_TIMEZONE")) { - return TimestampCastResult::ERROR_NON_UTC_TIMEZONE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetTimestampCastResultValues(), 3, "TimestampCastResult", value)); +} + +const StringUtil::EnumStringLiteral *GetTransactionModifierTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(TransactionModifierType::TRANSACTION_DEFAULT_MODIFIER), "TRANSACTION_DEFAULT_MODIFIER" }, + { static_cast(TransactionModifierType::TRANSACTION_READ_ONLY), "TRANSACTION_READ_ONLY" }, + { static_cast(TransactionModifierType::TRANSACTION_READ_WRITE), "TRANSACTION_READ_WRITE" } + }; + return values; } template<> const char* EnumUtil::ToChars(TransactionModifierType value) { - switch(value) { - case TransactionModifierType::TRANSACTION_DEFAULT_MODIFIER: - return "TRANSACTION_DEFAULT_MODIFIER"; - case TransactionModifierType::TRANSACTION_READ_ONLY: - return "TRANSACTION_READ_ONLY"; - case TransactionModifierType::TRANSACTION_READ_WRITE: - return "TRANSACTION_READ_WRITE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetTransactionModifierTypeValues(), 3, "TransactionModifierType", static_cast(value)); } template<> TransactionModifierType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "TRANSACTION_DEFAULT_MODIFIER")) { - return TransactionModifierType::TRANSACTION_DEFAULT_MODIFIER; - } - if (StringUtil::Equals(value, "TRANSACTION_READ_ONLY")) { - return TransactionModifierType::TRANSACTION_READ_ONLY; - } - if (StringUtil::Equals(value, "TRANSACTION_READ_WRITE")) { - return TransactionModifierType::TRANSACTION_READ_WRITE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetTransactionModifierTypeValues(), 3, "TransactionModifierType", value)); +} + +const StringUtil::EnumStringLiteral *GetTransactionTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(TransactionType::INVALID), "INVALID" }, + { static_cast(TransactionType::BEGIN_TRANSACTION), "BEGIN_TRANSACTION" }, + { static_cast(TransactionType::COMMIT), "COMMIT" }, + { static_cast(TransactionType::ROLLBACK), "ROLLBACK" } + }; + return values; } template<> const char* EnumUtil::ToChars(TransactionType value) { - switch(value) { - case TransactionType::INVALID: - return "INVALID"; - case TransactionType::BEGIN_TRANSACTION: - return "BEGIN_TRANSACTION"; - case TransactionType::COMMIT: - return "COMMIT"; - case TransactionType::ROLLBACK: - return "ROLLBACK"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetTransactionTypeValues(), 4, "TransactionType", static_cast(value)); } template<> TransactionType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return TransactionType::INVALID; - } - if (StringUtil::Equals(value, "BEGIN_TRANSACTION")) { - return TransactionType::BEGIN_TRANSACTION; - } - if (StringUtil::Equals(value, "COMMIT")) { - return TransactionType::COMMIT; - } - if (StringUtil::Equals(value, "ROLLBACK")) { - return TransactionType::ROLLBACK; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetTransactionTypeValues(), 4, "TransactionType", value)); +} + +const StringUtil::EnumStringLiteral *GetTupleDataPinPropertiesValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(TupleDataPinProperties::INVALID), "INVALID" }, + { static_cast(TupleDataPinProperties::KEEP_EVERYTHING_PINNED), "KEEP_EVERYTHING_PINNED" }, + { static_cast(TupleDataPinProperties::UNPIN_AFTER_DONE), "UNPIN_AFTER_DONE" }, + { static_cast(TupleDataPinProperties::DESTROY_AFTER_DONE), "DESTROY_AFTER_DONE" }, + { static_cast(TupleDataPinProperties::ALREADY_PINNED), "ALREADY_PINNED" } + }; + return values; } template<> const char* EnumUtil::ToChars(TupleDataPinProperties value) { - switch(value) { - case TupleDataPinProperties::INVALID: - return "INVALID"; - case TupleDataPinProperties::KEEP_EVERYTHING_PINNED: - return "KEEP_EVERYTHING_PINNED"; - case TupleDataPinProperties::UNPIN_AFTER_DONE: - return "UNPIN_AFTER_DONE"; - case TupleDataPinProperties::DESTROY_AFTER_DONE: - return "DESTROY_AFTER_DONE"; - case TupleDataPinProperties::ALREADY_PINNED: - return "ALREADY_PINNED"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetTupleDataPinPropertiesValues(), 5, "TupleDataPinProperties", static_cast(value)); } template<> TupleDataPinProperties EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return TupleDataPinProperties::INVALID; - } - if (StringUtil::Equals(value, "KEEP_EVERYTHING_PINNED")) { - return TupleDataPinProperties::KEEP_EVERYTHING_PINNED; - } - if (StringUtil::Equals(value, "UNPIN_AFTER_DONE")) { - return TupleDataPinProperties::UNPIN_AFTER_DONE; - } - if (StringUtil::Equals(value, "DESTROY_AFTER_DONE")) { - return TupleDataPinProperties::DESTROY_AFTER_DONE; - } - if (StringUtil::Equals(value, "ALREADY_PINNED")) { - return TupleDataPinProperties::ALREADY_PINNED; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetTupleDataPinPropertiesValues(), 5, "TupleDataPinProperties", value)); +} + +const StringUtil::EnumStringLiteral *GetUndoFlagsValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(UndoFlags::EMPTY_ENTRY), "EMPTY_ENTRY" }, + { static_cast(UndoFlags::CATALOG_ENTRY), "CATALOG_ENTRY" }, + { static_cast(UndoFlags::INSERT_TUPLE), "INSERT_TUPLE" }, + { static_cast(UndoFlags::DELETE_TUPLE), "DELETE_TUPLE" }, + { static_cast(UndoFlags::UPDATE_TUPLE), "UPDATE_TUPLE" }, + { static_cast(UndoFlags::SEQUENCE_VALUE), "SEQUENCE_VALUE" } + }; + return values; } template<> const char* EnumUtil::ToChars(UndoFlags value) { - switch(value) { - case UndoFlags::EMPTY_ENTRY: - return "EMPTY_ENTRY"; - case UndoFlags::CATALOG_ENTRY: - return "CATALOG_ENTRY"; - case UndoFlags::INSERT_TUPLE: - return "INSERT_TUPLE"; - case UndoFlags::DELETE_TUPLE: - return "DELETE_TUPLE"; - case UndoFlags::UPDATE_TUPLE: - return "UPDATE_TUPLE"; - case UndoFlags::SEQUENCE_VALUE: - return "SEQUENCE_VALUE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetUndoFlagsValues(), 6, "UndoFlags", static_cast(value)); } template<> UndoFlags EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "EMPTY_ENTRY")) { - return UndoFlags::EMPTY_ENTRY; - } - if (StringUtil::Equals(value, "CATALOG_ENTRY")) { - return UndoFlags::CATALOG_ENTRY; - } - if (StringUtil::Equals(value, "INSERT_TUPLE")) { - return UndoFlags::INSERT_TUPLE; - } - if (StringUtil::Equals(value, "DELETE_TUPLE")) { - return UndoFlags::DELETE_TUPLE; - } - if (StringUtil::Equals(value, "UPDATE_TUPLE")) { - return UndoFlags::UPDATE_TUPLE; - } - if (StringUtil::Equals(value, "SEQUENCE_VALUE")) { - return UndoFlags::SEQUENCE_VALUE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetUndoFlagsValues(), 6, "UndoFlags", value)); +} + +const StringUtil::EnumStringLiteral *GetUnionInvalidReasonValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(UnionInvalidReason::VALID), "VALID" }, + { static_cast(UnionInvalidReason::TAG_OUT_OF_RANGE), "TAG_OUT_OF_RANGE" }, + { static_cast(UnionInvalidReason::NO_MEMBERS), "NO_MEMBERS" }, + { static_cast(UnionInvalidReason::VALIDITY_OVERLAP), "VALIDITY_OVERLAP" }, + { static_cast(UnionInvalidReason::TAG_MISMATCH), "TAG_MISMATCH" }, + { static_cast(UnionInvalidReason::NULL_TAG), "NULL_TAG" } + }; + return values; } template<> const char* EnumUtil::ToChars(UnionInvalidReason value) { - switch(value) { - case UnionInvalidReason::VALID: - return "VALID"; - case UnionInvalidReason::TAG_OUT_OF_RANGE: - return "TAG_OUT_OF_RANGE"; - case UnionInvalidReason::NO_MEMBERS: - return "NO_MEMBERS"; - case UnionInvalidReason::VALIDITY_OVERLAP: - return "VALIDITY_OVERLAP"; - case UnionInvalidReason::TAG_MISMATCH: - return "TAG_MISMATCH"; - case UnionInvalidReason::NULL_TAG: - return "NULL_TAG"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetUnionInvalidReasonValues(), 6, "UnionInvalidReason", static_cast(value)); } template<> UnionInvalidReason EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "VALID")) { - return UnionInvalidReason::VALID; - } - if (StringUtil::Equals(value, "TAG_OUT_OF_RANGE")) { - return UnionInvalidReason::TAG_OUT_OF_RANGE; - } - if (StringUtil::Equals(value, "NO_MEMBERS")) { - return UnionInvalidReason::NO_MEMBERS; - } - if (StringUtil::Equals(value, "VALIDITY_OVERLAP")) { - return UnionInvalidReason::VALIDITY_OVERLAP; - } - if (StringUtil::Equals(value, "TAG_MISMATCH")) { - return UnionInvalidReason::TAG_MISMATCH; - } - if (StringUtil::Equals(value, "NULL_TAG")) { - return UnionInvalidReason::NULL_TAG; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetUnionInvalidReasonValues(), 6, "UnionInvalidReason", value)); +} + +const StringUtil::EnumStringLiteral *GetVectorAuxiliaryDataTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(VectorAuxiliaryDataType::ARROW_AUXILIARY), "ARROW_AUXILIARY" } + }; + return values; } template<> const char* EnumUtil::ToChars(VectorAuxiliaryDataType value) { - switch(value) { - case VectorAuxiliaryDataType::ARROW_AUXILIARY: - return "ARROW_AUXILIARY"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetVectorAuxiliaryDataTypeValues(), 1, "VectorAuxiliaryDataType", static_cast(value)); } template<> VectorAuxiliaryDataType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "ARROW_AUXILIARY")) { - return VectorAuxiliaryDataType::ARROW_AUXILIARY; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetVectorAuxiliaryDataTypeValues(), 1, "VectorAuxiliaryDataType", value)); +} + +const StringUtil::EnumStringLiteral *GetVectorBufferTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(VectorBufferType::STANDARD_BUFFER), "STANDARD_BUFFER" }, + { static_cast(VectorBufferType::DICTIONARY_BUFFER), "DICTIONARY_BUFFER" }, + { static_cast(VectorBufferType::VECTOR_CHILD_BUFFER), "VECTOR_CHILD_BUFFER" }, + { static_cast(VectorBufferType::STRING_BUFFER), "STRING_BUFFER" }, + { static_cast(VectorBufferType::FSST_BUFFER), "FSST_BUFFER" }, + { static_cast(VectorBufferType::STRUCT_BUFFER), "STRUCT_BUFFER" }, + { static_cast(VectorBufferType::LIST_BUFFER), "LIST_BUFFER" }, + { static_cast(VectorBufferType::MANAGED_BUFFER), "MANAGED_BUFFER" }, + { static_cast(VectorBufferType::OPAQUE_BUFFER), "OPAQUE_BUFFER" }, + { static_cast(VectorBufferType::ARRAY_BUFFER), "ARRAY_BUFFER" } + }; + return values; } template<> const char* EnumUtil::ToChars(VectorBufferType value) { - switch(value) { - case VectorBufferType::STANDARD_BUFFER: - return "STANDARD_BUFFER"; - case VectorBufferType::DICTIONARY_BUFFER: - return "DICTIONARY_BUFFER"; - case VectorBufferType::VECTOR_CHILD_BUFFER: - return "VECTOR_CHILD_BUFFER"; - case VectorBufferType::STRING_BUFFER: - return "STRING_BUFFER"; - case VectorBufferType::FSST_BUFFER: - return "FSST_BUFFER"; - case VectorBufferType::STRUCT_BUFFER: - return "STRUCT_BUFFER"; - case VectorBufferType::LIST_BUFFER: - return "LIST_BUFFER"; - case VectorBufferType::MANAGED_BUFFER: - return "MANAGED_BUFFER"; - case VectorBufferType::OPAQUE_BUFFER: - return "OPAQUE_BUFFER"; - case VectorBufferType::ARRAY_BUFFER: - return "ARRAY_BUFFER"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetVectorBufferTypeValues(), 10, "VectorBufferType", static_cast(value)); } template<> VectorBufferType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "STANDARD_BUFFER")) { - return VectorBufferType::STANDARD_BUFFER; - } - if (StringUtil::Equals(value, "DICTIONARY_BUFFER")) { - return VectorBufferType::DICTIONARY_BUFFER; - } - if (StringUtil::Equals(value, "VECTOR_CHILD_BUFFER")) { - return VectorBufferType::VECTOR_CHILD_BUFFER; - } - if (StringUtil::Equals(value, "STRING_BUFFER")) { - return VectorBufferType::STRING_BUFFER; - } - if (StringUtil::Equals(value, "FSST_BUFFER")) { - return VectorBufferType::FSST_BUFFER; - } - if (StringUtil::Equals(value, "STRUCT_BUFFER")) { - return VectorBufferType::STRUCT_BUFFER; - } - if (StringUtil::Equals(value, "LIST_BUFFER")) { - return VectorBufferType::LIST_BUFFER; - } - if (StringUtil::Equals(value, "MANAGED_BUFFER")) { - return VectorBufferType::MANAGED_BUFFER; - } - if (StringUtil::Equals(value, "OPAQUE_BUFFER")) { - return VectorBufferType::OPAQUE_BUFFER; - } - if (StringUtil::Equals(value, "ARRAY_BUFFER")) { - return VectorBufferType::ARRAY_BUFFER; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetVectorBufferTypeValues(), 10, "VectorBufferType", value)); +} + +const StringUtil::EnumStringLiteral *GetVectorTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(VectorType::FLAT_VECTOR), "FLAT_VECTOR" }, + { static_cast(VectorType::FSST_VECTOR), "FSST_VECTOR" }, + { static_cast(VectorType::CONSTANT_VECTOR), "CONSTANT_VECTOR" }, + { static_cast(VectorType::DICTIONARY_VECTOR), "DICTIONARY_VECTOR" }, + { static_cast(VectorType::SEQUENCE_VECTOR), "SEQUENCE_VECTOR" } + }; + return values; } template<> const char* EnumUtil::ToChars(VectorType value) { - switch(value) { - case VectorType::FLAT_VECTOR: - return "FLAT_VECTOR"; - case VectorType::FSST_VECTOR: - return "FSST_VECTOR"; - case VectorType::CONSTANT_VECTOR: - return "CONSTANT_VECTOR"; - case VectorType::DICTIONARY_VECTOR: - return "DICTIONARY_VECTOR"; - case VectorType::SEQUENCE_VECTOR: - return "SEQUENCE_VECTOR"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetVectorTypeValues(), 5, "VectorType", static_cast(value)); } template<> VectorType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "FLAT_VECTOR")) { - return VectorType::FLAT_VECTOR; - } - if (StringUtil::Equals(value, "FSST_VECTOR")) { - return VectorType::FSST_VECTOR; - } - if (StringUtil::Equals(value, "CONSTANT_VECTOR")) { - return VectorType::CONSTANT_VECTOR; - } - if (StringUtil::Equals(value, "DICTIONARY_VECTOR")) { - return VectorType::DICTIONARY_VECTOR; - } - if (StringUtil::Equals(value, "SEQUENCE_VECTOR")) { - return VectorType::SEQUENCE_VECTOR; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetVectorTypeValues(), 5, "VectorType", value)); +} + +const StringUtil::EnumStringLiteral *GetVerificationTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(VerificationType::ORIGINAL), "ORIGINAL" }, + { static_cast(VerificationType::COPIED), "COPIED" }, + { static_cast(VerificationType::DESERIALIZED), "DESERIALIZED" }, + { static_cast(VerificationType::PARSED), "PARSED" }, + { static_cast(VerificationType::UNOPTIMIZED), "UNOPTIMIZED" }, + { static_cast(VerificationType::NO_OPERATOR_CACHING), "NO_OPERATOR_CACHING" }, + { static_cast(VerificationType::PREPARED), "PREPARED" }, + { static_cast(VerificationType::EXTERNAL), "EXTERNAL" }, + { static_cast(VerificationType::FETCH_ROW_AS_SCAN), "FETCH_ROW_AS_SCAN" }, + { static_cast(VerificationType::INVALID), "INVALID" } + }; + return values; } template<> const char* EnumUtil::ToChars(VerificationType value) { - switch(value) { - case VerificationType::ORIGINAL: - return "ORIGINAL"; - case VerificationType::COPIED: - return "COPIED"; - case VerificationType::DESERIALIZED: - return "DESERIALIZED"; - case VerificationType::PARSED: - return "PARSED"; - case VerificationType::UNOPTIMIZED: - return "UNOPTIMIZED"; - case VerificationType::NO_OPERATOR_CACHING: - return "NO_OPERATOR_CACHING"; - case VerificationType::PREPARED: - return "PREPARED"; - case VerificationType::EXTERNAL: - return "EXTERNAL"; - case VerificationType::FETCH_ROW_AS_SCAN: - return "FETCH_ROW_AS_SCAN"; - case VerificationType::INVALID: - return "INVALID"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetVerificationTypeValues(), 10, "VerificationType", static_cast(value)); } template<> VerificationType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "ORIGINAL")) { - return VerificationType::ORIGINAL; - } - if (StringUtil::Equals(value, "COPIED")) { - return VerificationType::COPIED; - } - if (StringUtil::Equals(value, "DESERIALIZED")) { - return VerificationType::DESERIALIZED; - } - if (StringUtil::Equals(value, "PARSED")) { - return VerificationType::PARSED; - } - if (StringUtil::Equals(value, "UNOPTIMIZED")) { - return VerificationType::UNOPTIMIZED; - } - if (StringUtil::Equals(value, "NO_OPERATOR_CACHING")) { - return VerificationType::NO_OPERATOR_CACHING; - } - if (StringUtil::Equals(value, "PREPARED")) { - return VerificationType::PREPARED; - } - if (StringUtil::Equals(value, "EXTERNAL")) { - return VerificationType::EXTERNAL; - } - if (StringUtil::Equals(value, "FETCH_ROW_AS_SCAN")) { - return VerificationType::FETCH_ROW_AS_SCAN; - } - if (StringUtil::Equals(value, "INVALID")) { - return VerificationType::INVALID; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetVerificationTypeValues(), 10, "VerificationType", value)); +} + +const StringUtil::EnumStringLiteral *GetVerifyExistenceTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(VerifyExistenceType::APPEND), "APPEND" }, + { static_cast(VerifyExistenceType::APPEND_FK), "APPEND_FK" }, + { static_cast(VerifyExistenceType::DELETE_FK), "DELETE_FK" } + }; + return values; } template<> const char* EnumUtil::ToChars(VerifyExistenceType value) { - switch(value) { - case VerifyExistenceType::APPEND: - return "APPEND"; - case VerifyExistenceType::APPEND_FK: - return "APPEND_FK"; - case VerifyExistenceType::DELETE_FK: - return "DELETE_FK"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetVerifyExistenceTypeValues(), 3, "VerifyExistenceType", static_cast(value)); } template<> VerifyExistenceType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "APPEND")) { - return VerifyExistenceType::APPEND; - } - if (StringUtil::Equals(value, "APPEND_FK")) { - return VerifyExistenceType::APPEND_FK; - } - if (StringUtil::Equals(value, "DELETE_FK")) { - return VerifyExistenceType::DELETE_FK; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetVerifyExistenceTypeValues(), 3, "VerifyExistenceType", value)); +} + +const StringUtil::EnumStringLiteral *GetWALTypeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(WALType::INVALID), "INVALID" }, + { static_cast(WALType::CREATE_TABLE), "CREATE_TABLE" }, + { static_cast(WALType::DROP_TABLE), "DROP_TABLE" }, + { static_cast(WALType::CREATE_SCHEMA), "CREATE_SCHEMA" }, + { static_cast(WALType::DROP_SCHEMA), "DROP_SCHEMA" }, + { static_cast(WALType::CREATE_VIEW), "CREATE_VIEW" }, + { static_cast(WALType::DROP_VIEW), "DROP_VIEW" }, + { static_cast(WALType::CREATE_SEQUENCE), "CREATE_SEQUENCE" }, + { static_cast(WALType::DROP_SEQUENCE), "DROP_SEQUENCE" }, + { static_cast(WALType::SEQUENCE_VALUE), "SEQUENCE_VALUE" }, + { static_cast(WALType::CREATE_MACRO), "CREATE_MACRO" }, + { static_cast(WALType::DROP_MACRO), "DROP_MACRO" }, + { static_cast(WALType::CREATE_TYPE), "CREATE_TYPE" }, + { static_cast(WALType::DROP_TYPE), "DROP_TYPE" }, + { static_cast(WALType::ALTER_INFO), "ALTER_INFO" }, + { static_cast(WALType::CREATE_TABLE_MACRO), "CREATE_TABLE_MACRO" }, + { static_cast(WALType::DROP_TABLE_MACRO), "DROP_TABLE_MACRO" }, + { static_cast(WALType::CREATE_INDEX), "CREATE_INDEX" }, + { static_cast(WALType::DROP_INDEX), "DROP_INDEX" }, + { static_cast(WALType::USE_TABLE), "USE_TABLE" }, + { static_cast(WALType::INSERT_TUPLE), "INSERT_TUPLE" }, + { static_cast(WALType::DELETE_TUPLE), "DELETE_TUPLE" }, + { static_cast(WALType::UPDATE_TUPLE), "UPDATE_TUPLE" }, + { static_cast(WALType::ROW_GROUP_DATA), "ROW_GROUP_DATA" }, + { static_cast(WALType::WAL_VERSION), "WAL_VERSION" }, + { static_cast(WALType::CHECKPOINT), "CHECKPOINT" }, + { static_cast(WALType::WAL_FLUSH), "WAL_FLUSH" } + }; + return values; } template<> const char* EnumUtil::ToChars(WALType value) { - switch(value) { - case WALType::INVALID: - return "INVALID"; - case WALType::CREATE_TABLE: - return "CREATE_TABLE"; - case WALType::DROP_TABLE: - return "DROP_TABLE"; - case WALType::CREATE_SCHEMA: - return "CREATE_SCHEMA"; - case WALType::DROP_SCHEMA: - return "DROP_SCHEMA"; - case WALType::CREATE_VIEW: - return "CREATE_VIEW"; - case WALType::DROP_VIEW: - return "DROP_VIEW"; - case WALType::CREATE_SEQUENCE: - return "CREATE_SEQUENCE"; - case WALType::DROP_SEQUENCE: - return "DROP_SEQUENCE"; - case WALType::SEQUENCE_VALUE: - return "SEQUENCE_VALUE"; - case WALType::CREATE_MACRO: - return "CREATE_MACRO"; - case WALType::DROP_MACRO: - return "DROP_MACRO"; - case WALType::CREATE_TYPE: - return "CREATE_TYPE"; - case WALType::DROP_TYPE: - return "DROP_TYPE"; - case WALType::ALTER_INFO: - return "ALTER_INFO"; - case WALType::CREATE_TABLE_MACRO: - return "CREATE_TABLE_MACRO"; - case WALType::DROP_TABLE_MACRO: - return "DROP_TABLE_MACRO"; - case WALType::CREATE_INDEX: - return "CREATE_INDEX"; - case WALType::DROP_INDEX: - return "DROP_INDEX"; - case WALType::USE_TABLE: - return "USE_TABLE"; - case WALType::INSERT_TUPLE: - return "INSERT_TUPLE"; - case WALType::DELETE_TUPLE: - return "DELETE_TUPLE"; - case WALType::UPDATE_TUPLE: - return "UPDATE_TUPLE"; - case WALType::ROW_GROUP_DATA: - return "ROW_GROUP_DATA"; - case WALType::WAL_VERSION: - return "WAL_VERSION"; - case WALType::CHECKPOINT: - return "CHECKPOINT"; - case WALType::WAL_FLUSH: - return "WAL_FLUSH"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetWALTypeValues(), 27, "WALType", static_cast(value)); } template<> WALType EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return WALType::INVALID; - } - if (StringUtil::Equals(value, "CREATE_TABLE")) { - return WALType::CREATE_TABLE; - } - if (StringUtil::Equals(value, "DROP_TABLE")) { - return WALType::DROP_TABLE; - } - if (StringUtil::Equals(value, "CREATE_SCHEMA")) { - return WALType::CREATE_SCHEMA; - } - if (StringUtil::Equals(value, "DROP_SCHEMA")) { - return WALType::DROP_SCHEMA; - } - if (StringUtil::Equals(value, "CREATE_VIEW")) { - return WALType::CREATE_VIEW; - } - if (StringUtil::Equals(value, "DROP_VIEW")) { - return WALType::DROP_VIEW; - } - if (StringUtil::Equals(value, "CREATE_SEQUENCE")) { - return WALType::CREATE_SEQUENCE; - } - if (StringUtil::Equals(value, "DROP_SEQUENCE")) { - return WALType::DROP_SEQUENCE; - } - if (StringUtil::Equals(value, "SEQUENCE_VALUE")) { - return WALType::SEQUENCE_VALUE; - } - if (StringUtil::Equals(value, "CREATE_MACRO")) { - return WALType::CREATE_MACRO; - } - if (StringUtil::Equals(value, "DROP_MACRO")) { - return WALType::DROP_MACRO; - } - if (StringUtil::Equals(value, "CREATE_TYPE")) { - return WALType::CREATE_TYPE; - } - if (StringUtil::Equals(value, "DROP_TYPE")) { - return WALType::DROP_TYPE; - } - if (StringUtil::Equals(value, "ALTER_INFO")) { - return WALType::ALTER_INFO; - } - if (StringUtil::Equals(value, "CREATE_TABLE_MACRO")) { - return WALType::CREATE_TABLE_MACRO; - } - if (StringUtil::Equals(value, "DROP_TABLE_MACRO")) { - return WALType::DROP_TABLE_MACRO; - } - if (StringUtil::Equals(value, "CREATE_INDEX")) { - return WALType::CREATE_INDEX; - } - if (StringUtil::Equals(value, "DROP_INDEX")) { - return WALType::DROP_INDEX; - } - if (StringUtil::Equals(value, "USE_TABLE")) { - return WALType::USE_TABLE; - } - if (StringUtil::Equals(value, "INSERT_TUPLE")) { - return WALType::INSERT_TUPLE; - } - if (StringUtil::Equals(value, "DELETE_TUPLE")) { - return WALType::DELETE_TUPLE; - } - if (StringUtil::Equals(value, "UPDATE_TUPLE")) { - return WALType::UPDATE_TUPLE; - } - if (StringUtil::Equals(value, "ROW_GROUP_DATA")) { - return WALType::ROW_GROUP_DATA; - } - if (StringUtil::Equals(value, "WAL_VERSION")) { - return WALType::WAL_VERSION; - } - if (StringUtil::Equals(value, "CHECKPOINT")) { - return WALType::CHECKPOINT; - } - if (StringUtil::Equals(value, "WAL_FLUSH")) { - return WALType::WAL_FLUSH; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetWALTypeValues(), 27, "WALType", value)); +} + +const StringUtil::EnumStringLiteral *GetWindowAggregationModeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(WindowAggregationMode::WINDOW), "WINDOW" }, + { static_cast(WindowAggregationMode::COMBINE), "COMBINE" }, + { static_cast(WindowAggregationMode::SEPARATE), "SEPARATE" } + }; + return values; } template<> const char* EnumUtil::ToChars(WindowAggregationMode value) { - switch(value) { - case WindowAggregationMode::WINDOW: - return "WINDOW"; - case WindowAggregationMode::COMBINE: - return "COMBINE"; - case WindowAggregationMode::SEPARATE: - return "SEPARATE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetWindowAggregationModeValues(), 3, "WindowAggregationMode", static_cast(value)); } template<> WindowAggregationMode EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "WINDOW")) { - return WindowAggregationMode::WINDOW; - } - if (StringUtil::Equals(value, "COMBINE")) { - return WindowAggregationMode::COMBINE; - } - if (StringUtil::Equals(value, "SEPARATE")) { - return WindowAggregationMode::SEPARATE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetWindowAggregationModeValues(), 3, "WindowAggregationMode", value)); +} + +const StringUtil::EnumStringLiteral *GetWindowBoundaryValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(WindowBoundary::INVALID), "INVALID" }, + { static_cast(WindowBoundary::UNBOUNDED_PRECEDING), "UNBOUNDED_PRECEDING" }, + { static_cast(WindowBoundary::UNBOUNDED_FOLLOWING), "UNBOUNDED_FOLLOWING" }, + { static_cast(WindowBoundary::CURRENT_ROW_RANGE), "CURRENT_ROW_RANGE" }, + { static_cast(WindowBoundary::CURRENT_ROW_ROWS), "CURRENT_ROW_ROWS" }, + { static_cast(WindowBoundary::EXPR_PRECEDING_ROWS), "EXPR_PRECEDING_ROWS" }, + { static_cast(WindowBoundary::EXPR_FOLLOWING_ROWS), "EXPR_FOLLOWING_ROWS" }, + { static_cast(WindowBoundary::EXPR_PRECEDING_RANGE), "EXPR_PRECEDING_RANGE" }, + { static_cast(WindowBoundary::EXPR_FOLLOWING_RANGE), "EXPR_FOLLOWING_RANGE" } + }; + return values; } template<> const char* EnumUtil::ToChars(WindowBoundary value) { - switch(value) { - case WindowBoundary::INVALID: - return "INVALID"; - case WindowBoundary::UNBOUNDED_PRECEDING: - return "UNBOUNDED_PRECEDING"; - case WindowBoundary::UNBOUNDED_FOLLOWING: - return "UNBOUNDED_FOLLOWING"; - case WindowBoundary::CURRENT_ROW_RANGE: - return "CURRENT_ROW_RANGE"; - case WindowBoundary::CURRENT_ROW_ROWS: - return "CURRENT_ROW_ROWS"; - case WindowBoundary::EXPR_PRECEDING_ROWS: - return "EXPR_PRECEDING_ROWS"; - case WindowBoundary::EXPR_FOLLOWING_ROWS: - return "EXPR_FOLLOWING_ROWS"; - case WindowBoundary::EXPR_PRECEDING_RANGE: - return "EXPR_PRECEDING_RANGE"; - case WindowBoundary::EXPR_FOLLOWING_RANGE: - return "EXPR_FOLLOWING_RANGE"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetWindowBoundaryValues(), 9, "WindowBoundary", static_cast(value)); } template<> WindowBoundary EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "INVALID")) { - return WindowBoundary::INVALID; - } - if (StringUtil::Equals(value, "UNBOUNDED_PRECEDING")) { - return WindowBoundary::UNBOUNDED_PRECEDING; - } - if (StringUtil::Equals(value, "UNBOUNDED_FOLLOWING")) { - return WindowBoundary::UNBOUNDED_FOLLOWING; - } - if (StringUtil::Equals(value, "CURRENT_ROW_RANGE")) { - return WindowBoundary::CURRENT_ROW_RANGE; - } - if (StringUtil::Equals(value, "CURRENT_ROW_ROWS")) { - return WindowBoundary::CURRENT_ROW_ROWS; - } - if (StringUtil::Equals(value, "EXPR_PRECEDING_ROWS")) { - return WindowBoundary::EXPR_PRECEDING_ROWS; - } - if (StringUtil::Equals(value, "EXPR_FOLLOWING_ROWS")) { - return WindowBoundary::EXPR_FOLLOWING_ROWS; - } - if (StringUtil::Equals(value, "EXPR_PRECEDING_RANGE")) { - return WindowBoundary::EXPR_PRECEDING_RANGE; - } - if (StringUtil::Equals(value, "EXPR_FOLLOWING_RANGE")) { - return WindowBoundary::EXPR_FOLLOWING_RANGE; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetWindowBoundaryValues(), 9, "WindowBoundary", value)); +} + +const StringUtil::EnumStringLiteral *GetWindowExcludeModeValues() { + static constexpr StringUtil::EnumStringLiteral values[] { + { static_cast(WindowExcludeMode::NO_OTHER), "NO_OTHER" }, + { static_cast(WindowExcludeMode::CURRENT_ROW), "CURRENT_ROW" }, + { static_cast(WindowExcludeMode::GROUP), "GROUP" }, + { static_cast(WindowExcludeMode::TIES), "TIES" } + }; + return values; } template<> const char* EnumUtil::ToChars(WindowExcludeMode value) { - switch(value) { - case WindowExcludeMode::NO_OTHER: - return "NO_OTHER"; - case WindowExcludeMode::CURRENT_ROW: - return "CURRENT_ROW"; - case WindowExcludeMode::GROUP: - return "GROUP"; - case WindowExcludeMode::TIES: - return "TIES"; - default: - throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); - } + return StringUtil::EnumToString(GetWindowExcludeModeValues(), 4, "WindowExcludeMode", static_cast(value)); } template<> WindowExcludeMode EnumUtil::FromString(const char *value) { - if (StringUtil::Equals(value, "NO_OTHER")) { - return WindowExcludeMode::NO_OTHER; - } - if (StringUtil::Equals(value, "CURRENT_ROW")) { - return WindowExcludeMode::CURRENT_ROW; - } - if (StringUtil::Equals(value, "GROUP")) { - return WindowExcludeMode::GROUP; - } - if (StringUtil::Equals(value, "TIES")) { - return WindowExcludeMode::TIES; - } - throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); + return static_cast(StringUtil::StringToEnum(GetWindowExcludeModeValues(), 4, "WindowExcludeMode", value)); } } diff --git a/src/duckdb/src/common/enums/metric_type.cpp b/src/duckdb/src/common/enums/metric_type.cpp index a317f2d6a..cb684c956 100644 --- a/src/duckdb/src/common/enums/metric_type.cpp +++ b/src/duckdb/src/common/enums/metric_type.cpp @@ -86,6 +86,8 @@ MetricsType MetricsUtils::GetOptimizerMetricByType(OptimizerType type) { return MetricsType::OPTIMIZER_BUILD_SIDE_PROBE_SIDE; case OptimizerType::LIMIT_PUSHDOWN: return MetricsType::OPTIMIZER_LIMIT_PUSHDOWN; + case OptimizerType::SAMPLING_PUSHDOWN: + return MetricsType::OPTIMIZER_SAMPLING_PUSHDOWN; case OptimizerType::TOP_N: return MetricsType::OPTIMIZER_TOP_N; case OptimizerType::COMPRESSED_MATERIALIZATION: @@ -100,6 +102,8 @@ MetricsType MetricsUtils::GetOptimizerMetricByType(OptimizerType type) { return MetricsType::OPTIMIZER_EXTENSION; case OptimizerType::MATERIALIZED_CTE: return MetricsType::OPTIMIZER_MATERIALIZED_CTE; + case OptimizerType::EMPTY_RESULT_PULLUP: + return MetricsType::OPTIMIZER_EMPTY_RESULT_PULLUP; default: throw InternalException("OptimizerType %s cannot be converted to a MetricsType", EnumUtil::ToString(type)); }; @@ -153,6 +157,8 @@ OptimizerType MetricsUtils::GetOptimizerTypeByMetric(MetricsType type) { return OptimizerType::EXTENSION; case MetricsType::OPTIMIZER_MATERIALIZED_CTE: return OptimizerType::MATERIALIZED_CTE; + case MetricsType::OPTIMIZER_EMPTY_RESULT_PULLUP: + return OptimizerType::EMPTY_RESULT_PULLUP; default: return OptimizerType::INVALID; }; @@ -176,6 +182,7 @@ bool MetricsUtils::IsOptimizerMetric(MetricsType type) { case MetricsType::OPTIMIZER_COLUMN_LIFETIME: case MetricsType::OPTIMIZER_BUILD_SIDE_PROBE_SIDE: case MetricsType::OPTIMIZER_LIMIT_PUSHDOWN: + case MetricsType::OPTIMIZER_SAMPLING_PUSHDOWN: case MetricsType::OPTIMIZER_TOP_N: case MetricsType::OPTIMIZER_COMPRESSED_MATERIALIZATION: case MetricsType::OPTIMIZER_DUPLICATE_GROUPS: @@ -183,6 +190,7 @@ bool MetricsUtils::IsOptimizerMetric(MetricsType type) { case MetricsType::OPTIMIZER_JOIN_FILTER_PUSHDOWN: case MetricsType::OPTIMIZER_EXTENSION: case MetricsType::OPTIMIZER_MATERIALIZED_CTE: + case MetricsType::OPTIMIZER_EMPTY_RESULT_PULLUP: return true; default: return false; diff --git a/src/duckdb/src/common/enums/optimizer_type.cpp b/src/duckdb/src/common/enums/optimizer_type.cpp index 460bbb3a0..660b8ad50 100644 --- a/src/duckdb/src/common/enums/optimizer_type.cpp +++ b/src/duckdb/src/common/enums/optimizer_type.cpp @@ -15,6 +15,7 @@ static const DefaultOptimizerType internal_optimizer_types[] = { {"expression_rewriter", OptimizerType::EXPRESSION_REWRITER}, {"filter_pullup", OptimizerType::FILTER_PULLUP}, {"filter_pushdown", OptimizerType::FILTER_PUSHDOWN}, + {"empty_result_pullup", OptimizerType::EMPTY_RESULT_PULLUP}, {"cte_filter_pusher", OptimizerType::CTE_FILTER_PUSHER}, {"regex_range", OptimizerType::REGEX_RANGE}, {"in_clause", OptimizerType::IN_CLAUSE}, @@ -32,6 +33,7 @@ static const DefaultOptimizerType internal_optimizer_types[] = { {"compressed_materialization", OptimizerType::COMPRESSED_MATERIALIZATION}, {"duplicate_groups", OptimizerType::DUPLICATE_GROUPS}, {"reorder_filter", OptimizerType::REORDER_FILTER}, + {"sampling_pushdown", OptimizerType::SAMPLING_PUSHDOWN}, {"join_filter_pushdown", OptimizerType::JOIN_FILTER_PUSHDOWN}, {"extension", OptimizerType::EXTENSION}, {"materialized_cte", OptimizerType::MATERIALIZED_CTE}, diff --git a/src/duckdb/src/common/enums/physical_operator_type.cpp b/src/duckdb/src/common/enums/physical_operator_type.cpp index a48f44070..f520cb448 100644 --- a/src/duckdb/src/common/enums/physical_operator_type.cpp +++ b/src/duckdb/src/common/enums/physical_operator_type.cpp @@ -41,6 +41,8 @@ string PhysicalOperatorToString(PhysicalOperatorType type) { return "HASH_GROUP_BY"; case PhysicalOperatorType::PERFECT_HASH_GROUP_BY: return "PERFECT_HASH_GROUP_BY"; + case PhysicalOperatorType::PARTITIONED_AGGREGATE: + return "PARTITIONED_AGGREGATE"; case PhysicalOperatorType::FILTER: return "FILTER"; case PhysicalOperatorType::PROJECTION: diff --git a/src/duckdb/src/common/local_file_system.cpp b/src/duckdb/src/common/local_file_system.cpp index 70246d26a..4e47b9466 100644 --- a/src/duckdb/src/common/local_file_system.cpp +++ b/src/duckdb/src/common/local_file_system.cpp @@ -6,7 +6,7 @@ #include "duckdb/common/helper.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/common/windows.hpp" -#include "duckdb/function/scalar/string_functions.hpp" +#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/main/database.hpp" @@ -1194,7 +1194,7 @@ static void GlobFilesInternal(FileSystem &fs, const string &path, const string & if (is_directory != match_directory) { return; } - if (LikeFun::Glob(fname.c_str(), fname.size(), glob.c_str(), glob.size())) { + if (Glob(fname.c_str(), fname.size(), glob.c_str(), glob.size())) { if (join_path) { result.push_back(fs.JoinPath(path, fname)); } else { diff --git a/src/duckdb/src/common/multi_file_reader.cpp b/src/duckdb/src/common/multi_file_reader.cpp index b964a9357..1423bda89 100644 --- a/src/duckdb/src/common/multi_file_reader.cpp +++ b/src/duckdb/src/common/multi_file_reader.cpp @@ -23,7 +23,7 @@ MultiFileReader::~MultiFileReader() { unique_ptr MultiFileReader::Create(const TableFunction &table_function) { unique_ptr res; if (table_function.get_multi_file_reader) { - res = table_function.get_multi_file_reader(); + res = table_function.get_multi_file_reader(table_function); res->function_name = table_function.name; } else { res = make_uniq(); @@ -78,12 +78,8 @@ vector MultiFileReader::ParsePaths(const Value &input) { } } -unique_ptr MultiFileReader::CreateFileList(ClientContext &context, const vector &paths, +shared_ptr MultiFileReader::CreateFileList(ClientContext &context, const vector &paths, FileGlobOptions options) { - auto &config = DBConfig::GetConfig(context); - if (!config.options.enable_external_access) { - throw PermissionException("Scanning %s files is disabled through configuration", function_name); - } vector result_files; auto res = make_uniq(context, paths, options); @@ -93,7 +89,7 @@ unique_ptr MultiFileReader::CreateFileList(ClientContext &context return std::move(res); } -unique_ptr MultiFileReader::CreateFileList(ClientContext &context, const Value &input, +shared_ptr MultiFileReader::CreateFileList(ClientContext &context, const Value &input, FileGlobOptions options) { auto paths = ParsePaths(input); return CreateFileList(context, paths, options); @@ -410,6 +406,49 @@ void MultiFileReader::FinalizeChunk(ClientContext &context, const MultiFileReade chunk.Verify(); } +void MultiFileReader::GetPartitionData(ClientContext &context, const MultiFileReaderBindData &bind_data, + const MultiFileReaderData &reader_data, + optional_ptr global_state, + const OperatorPartitionInfo &partition_info, + OperatorPartitionData &partition_data) { + for (auto &col : partition_info.partition_columns) { + bool found_constant = false; + for (auto &constant : reader_data.constant_map) { + if (constant.column_id == col) { + found_constant = true; + partition_data.partition_data.emplace_back(constant.value); + break; + } + } + if (!found_constant) { + throw InternalException( + "MultiFileReader::GetPartitionData - did not find constant for the given partition"); + } + } +} + +TablePartitionInfo MultiFileReader::GetPartitionInfo(ClientContext &context, const MultiFileReaderBindData &bind_data, + TableFunctionPartitionInput &input) { + // check if all of the columns are in the hive partition set + for (auto &partition_col : input.partition_ids) { + // check if this column is in the hive partitioned set + bool found = false; + for (auto &partition : bind_data.hive_partitioning_indexes) { + if (partition.index == partition_col) { + found = true; + break; + } + } + if (!found) { + // the column is not partitioned - hive partitioning alone can't guarantee the groups are partitioned + return TablePartitionInfo::NOT_PARTITIONED; + } + } + // if all columns are in the hive partitioning set, we know that each partition will only have a single value + // i.e. if the hive partitioning is by (YEAR, MONTH), each partition will have a single unique (YEAR, MONTH) + return TablePartitionInfo::SINGLE_VALUE_PARTITIONS; +} + TableFunctionSet MultiFileReader::CreateFunctionSet(TableFunction table_function) { TableFunctionSet function_set(table_function.name); function_set.AddFunction(table_function); diff --git a/src/duckdb/src/common/opener_file_system.cpp b/src/duckdb/src/common/opener_file_system.cpp new file mode 100644 index 000000000..8f55d6898 --- /dev/null +++ b/src/duckdb/src/common/opener_file_system.cpp @@ -0,0 +1,37 @@ +#include "duckdb/common/opener_file_system.hpp" +#include "duckdb/common/file_opener.hpp" +#include "duckdb/main/database.hpp" +#include "duckdb/main/config.hpp" + +namespace duckdb { + +void OpenerFileSystem::VerifyNoOpener(optional_ptr opener) { + if (opener) { + throw InternalException("OpenerFileSystem cannot take an opener - the opener is pushed automatically"); + } +} +void OpenerFileSystem::VerifyCanAccessFileInternal(const string &path, FileType type) { + auto opener = GetOpener(); + if (!opener) { + return; + } + auto db = opener->TryGetDatabase(); + if (!db) { + return; + } + auto &config = db->config; + if (!config.CanAccessFile(path, type)) { + throw PermissionException("Cannot access %s \"%s\" - file system operations are disabled by configuration", + type == FileType::FILE_TYPE_DIR ? "directory" : "file", path); + } +} + +void OpenerFileSystem::VerifyCanAccessFile(const string &path) { + VerifyCanAccessFileInternal(path, FileType::FILE_TYPE_REGULAR); +} + +void OpenerFileSystem::VerifyCanAccessDirectory(const string &path) { + VerifyCanAccessFileInternal(path, FileType::FILE_TYPE_DIR); +} + +} // namespace duckdb diff --git a/src/duckdb/src/common/radix_partitioning.cpp b/src/duckdb/src/common/radix_partitioning.cpp index 3e8dee30d..d62a1329a 100644 --- a/src/duckdb/src/common/radix_partitioning.cpp +++ b/src/duckdb/src/common/radix_partitioning.cpp @@ -112,6 +112,7 @@ RadixPartitionedColumnData::RadixPartitionedColumnData(ClientContext &context_p, allocators->allocators.reserve(num_partitions); for (idx_t i = 0; i < num_partitions; i++) { CreateAllocator(); + allocators->allocators.back()->SetPartitionIndex(i); } D_ASSERT(allocators->allocators.size() == num_partitions); } @@ -174,8 +175,10 @@ RadixPartitionedTupleData::~RadixPartitionedTupleData() { } void RadixPartitionedTupleData::Initialize() { - for (idx_t i = 0; i < RadixPartitioning::NumberOfPartitions(radix_bits); i++) { + const auto num_partitions = RadixPartitioning::NumberOfPartitions(radix_bits); + for (idx_t i = 0; i < num_partitions; i++) { partitions.emplace_back(CreatePartitionCollection(i)); + partitions.back()->SetPartitionIndex(i); } } diff --git a/src/duckdb/src/common/random_engine.cpp b/src/duckdb/src/common/random_engine.cpp index e51f71001..704992f0d 100644 --- a/src/duckdb/src/common/random_engine.cpp +++ b/src/duckdb/src/common/random_engine.cpp @@ -29,12 +29,28 @@ double RandomEngine::NextRandom(double min, double max) { } double RandomEngine::NextRandom() { - return std::ldexp(random_state->pcg(), -32); + auto uint64 = NextRandomInteger64(); + return std::ldexp(uint64, -64); } + +double RandomEngine::NextRandom32(double min, double max) { + D_ASSERT(max >= min); + return min + (NextRandom32() * (max - min)); +} + +double RandomEngine::NextRandom32() { + auto uint32 = NextRandomInteger(); + return std::ldexp(uint32, -32); +} + uint32_t RandomEngine::NextRandomInteger() { return random_state->pcg(); } +uint64_t RandomEngine::NextRandomInteger64() { + return (static_cast(NextRandomInteger()) << UINT64_C(32)) | static_cast(NextRandomInteger()); +} + uint32_t RandomEngine::NextRandomInteger(uint32_t min, uint32_t max) { return min + static_cast(NextRandom() * double(max - min)); } diff --git a/src/duckdb/src/common/render_tree.cpp b/src/duckdb/src/common/render_tree.cpp index 6942d6fce..582d5e1ad 100644 --- a/src/duckdb/src/common/render_tree.cpp +++ b/src/duckdb/src/common/render_tree.cpp @@ -41,29 +41,13 @@ class TreeChildrenIterator { template <> bool TreeChildrenIterator::HasChildren(const PhysicalOperator &op) { - switch (op.type) { - case PhysicalOperatorType::LEFT_DELIM_JOIN: - case PhysicalOperatorType::RIGHT_DELIM_JOIN: - case PhysicalOperatorType::POSITIONAL_SCAN: - return true; - default: - return !op.children.empty(); - } + return !op.GetChildren().empty(); } template <> void TreeChildrenIterator::Iterate(const PhysicalOperator &op, const std::function &callback) { - for (auto &child : op.children) { - callback(*child); - } - if (op.type == PhysicalOperatorType::LEFT_DELIM_JOIN || op.type == PhysicalOperatorType::RIGHT_DELIM_JOIN) { - auto &delim = op.Cast(); - callback(*delim.join); - } else if ((op.type == PhysicalOperatorType::POSITIONAL_SCAN)) { - auto &pscan = op.Cast(); - for (auto &table : pscan.child_tables) { - callback(*table); - } + for (auto &child : op.GetChildren()) { + callback(child); } } diff --git a/src/duckdb/src/common/sort/partition_state.cpp b/src/duckdb/src/common/sort/partition_state.cpp index d87e31fd7..9c4379695 100644 --- a/src/duckdb/src/common/sort/partition_state.cpp +++ b/src/duckdb/src/common/sort/partition_state.cpp @@ -92,7 +92,7 @@ PartitionGlobalSinkState::PartitionGlobalSinkState(ClientContext &context, GenerateOrderings(partitions, orders, partition_bys, order_bys, partition_stats); memory_per_thread = PhysicalOperator::GetMaxThreadMemory(context); - external = ClientConfig::GetConfig(context).force_external; + external = ClientConfig::GetConfig(context).GetSetting(context); const auto thread_pages = PreviousPowerOfTwo(memory_per_thread / (4 * buffer_manager.GetBlockAllocSize())); while (max_bits < 10 && (thread_pages >> max_bits) > 1) { @@ -148,7 +148,7 @@ void PartitionGlobalSinkState::ResizeGroupingData(idx_t cardinality) { return; } // Is the average partition size too large? - const idx_t partition_size = STANDARD_ROW_GROUPS_SIZE; + const idx_t partition_size = DEFAULT_ROW_GROUP_SIZE; const auto bits = grouping_data ? grouping_data->GetRadixBits() : 0; auto new_bits = bits ? bits : 4; while (new_bits < max_bits && (cardinality / RadixPartitioning::NumberOfPartitions(new_bits)) > partition_size) { diff --git a/src/duckdb/src/common/string_util.cpp b/src/duckdb/src/common/string_util.cpp index dd57bda7b..666cfbc11 100644 --- a/src/duckdb/src/common/string_util.cpp +++ b/src/duckdb/src/common/string_util.cpp @@ -4,8 +4,9 @@ #include "duckdb/common/pair.hpp" #include "duckdb/common/to_string.hpp" #include "duckdb/common/helper.hpp" -#include "duckdb/function/scalar/string_functions.hpp" +#include "duckdb/common/exception/parser_exception.hpp" #include "jaro_winkler.hpp" +#include "utf8proc_wrapper.hpp" #include #include @@ -254,7 +255,7 @@ bool StringUtil::CIEquals(const string &l1, const string &l2) { if (l1.size() != l2.size()) { return false; } - const auto charmap = LowerFun::ASCII_TO_LOWER_MAP; + const auto charmap = ASCII_TO_LOWER_MAP; for (idx_t c = 0; c < l1.size(); c++) { if (charmap[(uint8_t)l1[c]] != charmap[(uint8_t)l2[c]]) { return false; @@ -264,7 +265,7 @@ bool StringUtil::CIEquals(const string &l1, const string &l2) { } bool StringUtil::CILessThan(const string &s1, const string &s2) { - const auto charmap = UpperFun::ASCII_TO_UPPER_MAP; + const auto charmap = ASCII_TO_UPPER_MAP; unsigned char u1 {}, u2 {}; @@ -713,4 +714,60 @@ string StringUtil::URLDecode(const string &input, bool plus_to_space) { return string(result_data.get(), result_size); } +uint32_t StringUtil::StringToEnum(const EnumStringLiteral enum_list[], idx_t enum_count, const char *enum_name, + const char *str_value) { + for (idx_t i = 0; i < enum_count; i++) { + if (CIEquals(enum_list[i].string, str_value)) { + return enum_list[i].number; + } + } + // string to enum conversion failed - generate candidates + vector candidates; + for (idx_t i = 0; i < enum_count; i++) { + candidates.push_back(enum_list[i].string); + } + auto closest_values = TopNJaroWinkler(candidates, str_value); + auto message = CandidatesMessage(closest_values, "Candidates"); + throw NotImplementedException("Enum value: unrecognized value \"%s\" for enum \"%s\"\n%s", str_value, enum_name, + message); +} + +const char *StringUtil::EnumToString(const EnumStringLiteral enum_list[], idx_t enum_count, const char *enum_name, + uint32_t enum_value) { + for (idx_t i = 0; i < enum_count; i++) { + if (enum_list[i].number == enum_value) { + return enum_list[i].string; + } + } + throw NotImplementedException("Enum value: unrecognized enum value \"%d\" for enum \"%s\"", enum_value, enum_name); +} + +const uint8_t StringUtil::ASCII_TO_UPPER_MAP[] = { + 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, 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, 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, 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}; + +const uint8_t StringUtil::ASCII_TO_LOWER_MAP[] = { + 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, 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}; + } // namespace duckdb diff --git a/src/duckdb/src/common/types.cpp b/src/duckdb/src/common/types.cpp index a440b4961..278be4094 100644 --- a/src/duckdb/src/common/types.cpp +++ b/src/duckdb/src/common/types.cpp @@ -559,7 +559,7 @@ LogicalType TransformStringToLogicalType(const string &str) { "INT2", "SHORT", "TIME", - "TIMESTAMPTZ ", + "TIMESTAMPTZ", "TIMESTAMP", "DATETIME", "TINYINT", 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 bec0751e0..66a1e612f 100644 --- a/src/duckdb/src/common/types/column/column_data_allocator.cpp +++ b/src/duckdb/src/common/types/column/column_data_allocator.cpp @@ -1,5 +1,6 @@ #include "duckdb/common/types/column/column_data_allocator.hpp" +#include "duckdb/common/radix_partitioning.hpp" #include "duckdb/common/types/column/column_data_collection_segment.hpp" #include "duckdb/storage/buffer/block_handle.hpp" #include "duckdb/storage/buffer/buffer_pool.hpp" @@ -84,6 +85,9 @@ BufferHandle ColumnDataAllocator::AllocateBlock(idx_t size) { auto pin = alloc.buffer_manager->Allocate(MemoryTag::COLUMN_DATA, max_size, false); data.handle = pin.GetBlockHandle(); blocks.push_back(std::move(data)); + if (partition_index.IsValid()) { // Set the eviction queue index logarithmically using RadixBits + blocks.back().handle->SetEvictionQueueIndex(RadixPartitioning::RadixBits(partition_index.GetIndex())); + } allocated_size += max_size; return pin; } 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 c3740444a..14a8071c9 100644 --- a/src/duckdb/src/common/types/column/column_data_collection.cpp +++ b/src/duckdb/src/common/types/column/column_data_collection.cpp @@ -119,6 +119,13 @@ idx_t ColumnDataCollection::AllocationSize() const { return total_size; } +void ColumnDataCollection::SetPartitionIndex(const idx_t index) { + D_ASSERT(!partition_index.IsValid()); + D_ASSERT(Count() == 0); + partition_index = index; + allocator->SetPartitionIndex(index); +} + //===--------------------------------------------------------------------===// // ColumnDataRow //===--------------------------------------------------------------------===// @@ -401,7 +408,7 @@ static void TemplatedColumnDataCopy(ColumnDataMetaData &meta_data, const Unified auto base_ptr = segment.allocator->GetDataPointer(append_state.current_chunk_state, current_segment.block_id, current_segment.offset); - auto validity_data = ColumnDataCollectionSegment::GetValidityPointer(base_ptr, OP::TypeSize()); + auto validity_data = ColumnDataCollectionSegment::GetValidityPointerForWriting(base_ptr, OP::TypeSize()); ValidityMask result_validity(validity_data); if (current_segment.count == 0) { @@ -517,7 +524,7 @@ void ColumnDataCopy(ColumnDataMetaData &meta_data, const UnifiedVector auto ¤t_segment = segment.GetVectorData(current_index); auto base_ptr = segment.allocator->GetDataPointer(append_state.current_chunk_state, current_segment.block_id, current_segment.offset); - auto validity_data = ColumnDataCollectionSegment::GetValidityPointer(base_ptr, sizeof(string_t)); + auto validity_data = ColumnDataCollectionSegment::GetValidityPointerForWriting(base_ptr, sizeof(string_t)); ValidityMask target_validity(validity_data); if (current_segment.count == 0) { // first time appending to this vector @@ -923,6 +930,29 @@ bool ColumnDataCollection::NextScanIndex(ColumnDataScanState &state, idx_t &chun return true; } +bool ColumnDataCollection::PrevScanIndex(ColumnDataScanState &state, idx_t &chunk_index, idx_t &segment_index, + idx_t &row_index) const { + // check within the current segment if we still have chunks to scan + // Note that state.chunk_index is 1-indexed, with 0 as undefined. + while (state.chunk_index <= 1) { + if (!state.segment_index) { + return false; + } + + --state.segment_index; + state.chunk_index = segments[state.segment_index]->chunk_data.size() + 1; + state.current_chunk_state.handles.clear(); + } + + --state.chunk_index; + segment_index = state.segment_index; + chunk_index = state.chunk_index - 1; + state.next_row_index = state.current_row_index; + state.current_row_index -= segments[state.segment_index]->chunk_data[chunk_index].count; + row_index = state.current_row_index; + return true; +} + void ColumnDataCollection::ScanAtIndex(ColumnDataParallelScanState &state, ColumnDataLocalScanState &lstate, DataChunk &result, idx_t chunk_index, idx_t segment_index, idx_t row_index) const { @@ -955,6 +985,38 @@ bool ColumnDataCollection::Scan(ColumnDataScanState &state, DataChunk &result) c return true; } +bool ColumnDataCollection::Seek(idx_t seek_idx, ColumnDataScanState &state, DataChunk &result) const { + // Idempotency: Don't change anything if the row is already in range + if (state.current_row_index <= seek_idx && seek_idx < state.next_row_index) { + return true; + } + + result.Reset(); + + // Linear scan for now. We could use a current_row_index => chunk map at some point + // but most use cases should be pretty local + idx_t chunk_index; + idx_t segment_index; + idx_t row_index; + while (seek_idx < state.current_row_index) { + if (!PrevScanIndex(state, chunk_index, segment_index, row_index)) { + return false; + } + } + while (state.next_row_index <= seek_idx) { + if (!NextScanIndex(state, chunk_index, segment_index, row_index)) { + return false; + } + } + + // found a chunk to scan -> scan it + auto &segment = *segments[segment_index]; + state.current_chunk_state.properties = state.properties; + segment.ReadChunk(chunk_index, state.current_chunk_state, result, state.column_ids); + result.Verify(); + return true; +} + ColumnDataRowCollection ColumnDataCollection::GetRows() const { return ColumnDataRowCollection(*this); } diff --git a/src/duckdb/src/common/types/column/column_data_collection_segment.cpp b/src/duckdb/src/common/types/column/column_data_collection_segment.cpp index fd2e39fff..44c4126c5 100644 --- a/src/duckdb/src/common/types/column/column_data_collection_segment.cpp +++ b/src/duckdb/src/common/types/column/column_data_collection_segment.cpp @@ -14,10 +14,31 @@ idx_t ColumnDataCollectionSegment::GetDataSize(idx_t type_size) { return AlignValue(type_size * STANDARD_VECTOR_SIZE); } -validity_t *ColumnDataCollectionSegment::GetValidityPointer(data_ptr_t base_ptr, idx_t type_size) { +validity_t *ColumnDataCollectionSegment::GetValidityPointerForWriting(data_ptr_t base_ptr, idx_t type_size) { return reinterpret_cast(base_ptr + GetDataSize(type_size)); } +validity_t *ColumnDataCollectionSegment::GetValidityPointer(data_ptr_t base_ptr, idx_t type_size, idx_t count) { + auto validity_mask = reinterpret_cast(base_ptr + GetDataSize(type_size)); + + // Optimized check to see if all entries are valid + for (idx_t i = 0; i < (count / ValidityMask::BITS_PER_VALUE); i++) { + if (!ValidityMask::AllValid(validity_mask[i])) { + return validity_mask; + } + } + + if ((count % ValidityMask::BITS_PER_VALUE) != 0) { + // Create a mask with the lower `bits_to_check` bits set to 1 + validity_t mask = (1ULL << (count % ValidityMask::BITS_PER_VALUE)) - 1; + if ((validity_mask[(count / ValidityMask::BITS_PER_VALUE)] & mask) != mask) { + return validity_mask; + } + } + // All entries are valid, no need to initialize the validity mask + return nullptr; +} + VectorDataIndex ColumnDataCollectionSegment::AllocateVectorInternal(const LogicalType &type, ChunkMetaData &chunk_meta, ChunkManagementState *chunk_state) { VectorMetaData meta_data; @@ -141,7 +162,7 @@ idx_t ColumnDataCollectionSegment::ReadVectorInternal(ChunkManagementState &stat auto &vdata = GetVectorData(vector_index); auto base_ptr = allocator->GetDataPointer(state, vdata.block_id, vdata.offset); - auto validity_data = GetValidityPointer(base_ptr, type_size); + auto validity_data = GetValidityPointer(base_ptr, type_size, vdata.count); if (!vdata.next_data.IsValid() && state.properties != ColumnDataScanProperties::DISALLOW_ZERO_COPY) { // no next data, we can do a zero-copy read of this vector FlatVector::SetData(result, base_ptr); @@ -169,7 +190,7 @@ idx_t ColumnDataCollectionSegment::ReadVectorInternal(ChunkManagementState &stat while (next_index.IsValid()) { auto ¤t_vdata = GetVectorData(next_index); base_ptr = allocator->GetDataPointer(state, current_vdata.block_id, current_vdata.offset); - validity_data = GetValidityPointer(base_ptr, type_size); + validity_data = GetValidityPointer(base_ptr, type_size, current_vdata.count); if (type_size > 0) { memcpy(target_data + current_offset * type_size, base_ptr, current_vdata.count * type_size); } diff --git a/src/duckdb/src/common/types/row/partitioned_tuple_data.cpp b/src/duckdb/src/common/types/row/partitioned_tuple_data.cpp index 17cd306f4..b77463d8c 100644 --- a/src/duckdb/src/common/types/row/partitioned_tuple_data.cpp +++ b/src/duckdb/src/common/types/row/partitioned_tuple_data.cpp @@ -262,15 +262,8 @@ void PartitionedTupleData::Repartition(PartitionedTupleData &new_partitioned_dat PartitionedTupleDataAppendState append_state; new_partitioned_data.InitializeAppendState(append_state); - const auto reverse = RepartitionReverseOrder(); - const idx_t start_idx = reverse ? partitions.size() : 0; - const idx_t end_idx = reverse ? 0 : partitions.size(); - const int64_t update = reverse ? -1 : 1; - const int64_t adjustment = reverse ? -1 : 0; - - for (idx_t partition_idx = start_idx; partition_idx != end_idx; partition_idx += idx_t(update)) { - auto actual_partition_idx = partition_idx + idx_t(adjustment); - auto &partition = *partitions[actual_partition_idx]; + for (idx_t partition_idx = 0; partition_idx < partitions.size(); partition_idx++) { + auto &partition = *partitions[partition_idx]; if (partition.Count() > 0) { TupleDataChunkIterator iterator(partition, TupleDataPinProperties::DESTROY_AFTER_DONE, true); @@ -279,9 +272,9 @@ void PartitionedTupleData::Repartition(PartitionedTupleData &new_partitioned_dat new_partitioned_data.Append(append_state, chunk_state, iterator.GetCurrentChunkCount()); } while (iterator.Next()); - RepartitionFinalizeStates(*this, new_partitioned_data, append_state, actual_partition_idx); + RepartitionFinalizeStates(*this, new_partitioned_data, append_state, partition_idx); } - partitions[actual_partition_idx]->Reset(); + partitions[partition_idx]->Reset(); } new_partitioned_data.FlushAppendState(append_state); 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 8f391c498..11895e977 100644 --- a/src/duckdb/src/common/types/row/tuple_data_allocator.cpp +++ b/src/duckdb/src/common/types/row/tuple_data_allocator.cpp @@ -1,6 +1,7 @@ #include "duckdb/common/types/row/tuple_data_allocator.hpp" #include "duckdb/common/fast_mem.hpp" +#include "duckdb/common/radix_partitioning.hpp" #include "duckdb/common/types/row/tuple_data_segment.hpp" #include "duckdb/common/types/row/tuple_data_states.hpp" #include "duckdb/storage/buffer/block_handle.hpp" @@ -73,6 +74,12 @@ idx_t TupleDataAllocator::HeapBlockCount() const { return heap_blocks.size(); } +void TupleDataAllocator::SetPartitionIndex(const idx_t index) { + D_ASSERT(!partition_index.IsValid()); + D_ASSERT(row_blocks.empty() && heap_blocks.empty()); + partition_index = index; +} + void TupleDataAllocator::Build(TupleDataSegment &segment, TupleDataPinState &pin_state, TupleDataChunkState &chunk_state, const idx_t append_offset, const idx_t append_count) { D_ASSERT(this == segment.allocator.get()); @@ -142,6 +149,9 @@ TupleDataChunkPart TupleDataAllocator::BuildChunkPart(TupleDataPinState &pin_sta // Allocate row block (if needed) if (row_blocks.empty() || row_blocks.back().RemainingCapacity() < layout.GetRowWidth()) { row_blocks.emplace_back(buffer_manager, block_size); + if (partition_index.IsValid()) { // Set the eviction queue index logarithmically using RadixBits + row_blocks.back().handle->SetEvictionQueueIndex(RadixPartitioning::RadixBits(partition_index.GetIndex())); + } } result.row_block_index = NumericCast(row_blocks.size() - 1); auto &row_block = row_blocks[result.row_block_index]; @@ -188,6 +198,10 @@ TupleDataChunkPart TupleDataAllocator::BuildChunkPart(TupleDataPinState &pin_sta if (heap_blocks.empty() || heap_blocks.back().RemainingCapacity() < heap_sizes[append_offset]) { const auto size = MaxValue(block_size, heap_sizes[append_offset]); heap_blocks.emplace_back(buffer_manager, size); + if (partition_index.IsValid()) { // Set the eviction queue index logarithmically using RadixBits + heap_blocks.back().handle->SetEvictionQueueIndex( + RadixPartitioning::RadixBits(partition_index.GetIndex())); + } } result.heap_block_index = NumericCast(heap_blocks.size() - 1); auto &heap_block = heap_blocks[result.heap_block_index]; 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 a5215d030..c44732847 100644 --- a/src/duckdb/src/common/types/row/tuple_data_collection.cpp +++ b/src/duckdb/src/common/types/row/tuple_data_collection.cpp @@ -79,6 +79,13 @@ void TupleDataCollection::Unpin() { } } +void TupleDataCollection::SetPartitionIndex(const idx_t index) { + D_ASSERT(!partition_index.IsValid()); + D_ASSERT(Count() == 0); + partition_index = index; + allocator->SetPartitionIndex(index); +} + // LCOV_EXCL_START void VerifyAppendColumns(const TupleDataLayout &layout, const vector &column_ids) { #ifdef DEBUG diff --git a/src/duckdb/src/common/types/validity_mask.cpp b/src/duckdb/src/common/types/validity_mask.cpp index fac6fea4b..6ee5532ee 100644 --- a/src/duckdb/src/common/types/validity_mask.cpp +++ b/src/duckdb/src/common/types/validity_mask.cpp @@ -114,6 +114,10 @@ void ValidityMask::CopySel(const ValidityMask &other, const SelectionVector &sel } void ValidityMask::SliceInPlace(const ValidityMask &other, idx_t target_offset, idx_t source_offset, idx_t count) { + if (AllValid() && other.AllValid()) { + // Both validity masks are uninitialized, nothing to do + return; + } EnsureWritable(); const idx_t ragged = count % BITS_PER_VALUE; const idx_t entire_units = count / BITS_PER_VALUE; diff --git a/src/duckdb/src/common/types/value.cpp b/src/duckdb/src/common/types/value.cpp index 5d893b6c2..ffbbae43f 100644 --- a/src/duckdb/src/common/types/value.cpp +++ b/src/duckdb/src/common/types/value.cpp @@ -1503,8 +1503,13 @@ string Value::ToSQLString() const { case LogicalTypeId::BLOB: return "'" + ToString() + "'::" + type_.ToString(); case LogicalTypeId::VARCHAR: - case LogicalTypeId::ENUM: + case LogicalTypeId::ENUM: { + auto str_val = ToString(); + if (str_val.size() == 1 && str_val[0] == '\0') { + return "chr(0)"; + } return "'" + StringUtil::Replace(ToString(), "'", "''") + "'"; + } case LogicalTypeId::STRUCT: { bool is_unnamed = StructType::IsUnnamed(type_); string ret = is_unnamed ? "(" : "{"; 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 e9a31ee0e..d66f6a8fc 100644 --- a/src/duckdb/src/common/vector_operations/is_distinct_from.cpp +++ b/src/duckdb/src/common/vector_operations/is_distinct_from.cpp @@ -65,17 +65,26 @@ static void DistinctExecute(Vector &left, Vector &right, Vector &result, idx_t c DistinctExecuteSwitch(left, right, result, count); } +#ifndef DUCKDB_SMALLER_BINARY template +#else +template +#endif static inline idx_t DistinctSelectGenericLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata, const SelectionVector *__restrict lsel, const SelectionVector *__restrict rsel, const SelectionVector *__restrict result_sel, idx_t count, ValidityMask &lmask, ValidityMask &rmask, SelectionVector *true_sel, SelectionVector *false_sel) { +#ifdef DUCKDB_SMALLER_BINARY + bool HAS_TRUE_SEL = true_sel; + bool HAS_FALSE_SEL = false_sel; +#endif idx_t true_count = 0, false_count = 0; for (idx_t i = 0; i < count; i++) { auto result_idx = result_sel->get_index(i); auto lindex = lsel->get_index(i); auto rindex = rsel->get_index(i); +#ifndef DUCKDB_SMALLER_BINARY if (NO_NULL) { if (OP::Operation(ldata[lindex], rdata[rindex], false, false)) { if (HAS_TRUE_SEL) { @@ -86,7 +95,9 @@ DistinctSelectGenericLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *_ false_sel->set_index(false_count++, result_idx); } } - } else { + } else +#endif + { if (OP::Operation(ldata[lindex], rdata[rindex], !lmask.RowIsValid(lindex), !rmask.RowIsValid(rindex))) { if (HAS_TRUE_SEL) { true_sel->set_index(true_count++, result_idx); @@ -104,6 +115,8 @@ DistinctSelectGenericLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *_ return count - false_count; } } + +#ifndef DUCKDB_SMALLER_BINARY template static inline idx_t DistinctSelectGenericLoopSelSwitch(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata, @@ -122,6 +135,7 @@ DistinctSelectGenericLoopSelSwitch(const LEFT_TYPE *__restrict ldata, const RIGH ldata, rdata, lsel, rsel, result_sel, count, lmask, rmask, true_sel, false_sel); } } +#endif template static inline idx_t @@ -129,6 +143,7 @@ DistinctSelectGenericLoopSwitch(const LEFT_TYPE *__restrict ldata, const RIGHT_T const SelectionVector *__restrict lsel, const SelectionVector *__restrict rsel, const SelectionVector *__restrict result_sel, idx_t count, ValidityMask &lmask, ValidityMask &rmask, SelectionVector *true_sel, SelectionVector *false_sel) { +#ifndef DUCKDB_SMALLER_BINARY if (!lmask.AllValid() || !rmask.AllValid()) { return DistinctSelectGenericLoopSelSwitch( ldata, rdata, lsel, rsel, result_sel, count, lmask, rmask, true_sel, false_sel); @@ -136,6 +151,10 @@ DistinctSelectGenericLoopSwitch(const LEFT_TYPE *__restrict ldata, const RIGHT_T return DistinctSelectGenericLoopSelSwitch( ldata, rdata, lsel, rsel, result_sel, count, lmask, rmask, true_sel, false_sel); } +#else + return DistinctSelectGenericLoop(ldata, rdata, lsel, rsel, result_sel, count, lmask, + rmask, true_sel, false_sel); +#endif } template @@ -150,6 +169,8 @@ static idx_t DistinctSelectGeneric(Vector &left, Vector &right, const SelectionV UnifiedVectorFormat::GetData(ldata), UnifiedVectorFormat::GetData(rdata), ldata.sel, rdata.sel, sel, count, ldata.validity, rdata.validity, true_sel, false_sel); } + +#ifndef DUCKDB_SMALLER_BINARY template static inline idx_t DistinctSelectFlatLoop(LEFT_TYPE *__restrict ldata, RIGHT_TYPE *__restrict rdata, @@ -205,6 +226,7 @@ static inline idx_t DistinctSelectFlatLoopSwitch(LEFT_TYPE *__restrict ldata, RI return DistinctSelectFlatLoopSelSwitch( ldata, rdata, sel, count, lmask, rmask, true_sel, false_sel); } + template static idx_t DistinctSelectFlat(Vector &left, Vector &right, const SelectionVector *sel, idx_t count, SelectionVector *true_sel, SelectionVector *false_sel) { @@ -229,6 +251,8 @@ static idx_t DistinctSelectFlat(Vector &left, Vector &right, const SelectionVect ldata, rdata, sel, count, FlatVector::Validity(left), FlatVector::Validity(right), true_sel, false_sel); } } +#endif + template static idx_t DistinctSelectConstant(Vector &left, Vector &right, const SelectionVector *sel, idx_t count, SelectionVector *true_sel, SelectionVector *false_sel) { @@ -287,6 +311,7 @@ static idx_t DistinctSelect(Vector &left, Vector &right, const SelectionVector * if (left.GetVectorType() == VectorType::CONSTANT_VECTOR && right.GetVectorType() == VectorType::CONSTANT_VECTOR) { return DistinctSelectConstant(left, right, sel, count, true_sel, false_sel); +#ifndef DUCKDB_SMALLER_BINARY } else if (left.GetVectorType() == VectorType::CONSTANT_VECTOR && right.GetVectorType() == VectorType::FLAT_VECTOR) { return DistinctSelectFlat(left, right, sel, count, true_sel, false_sel); @@ -296,6 +321,7 @@ static idx_t DistinctSelect(Vector &left, Vector &right, const SelectionVector * } else if (left.GetVectorType() == VectorType::FLAT_VECTOR && right.GetVectorType() == VectorType::FLAT_VECTOR) { return DistinctSelectFlat(left, right, sel, count, true_sel, false_sel); +#endif } else { return DistinctSelectGeneric(left, right, sel, count, true_sel, false_sel); } @@ -476,16 +502,6 @@ idx_t PositionComparator::Final(Vector &left, Vector & return VectorOperations::DistinctGreaterThan(right, left, &sel, count, true_sel, false_sel, null_mask); } -template <> -idx_t PositionComparator::Final(Vector &left, Vector &right, - const SelectionVector &sel, idx_t count, - optional_ptr true_sel, - optional_ptr false_sel, - optional_ptr null_mask) { - // DistinctGreaterThan has NULLs last - return VectorOperations::DistinctGreaterThan(right, left, &sel, count, true_sel, false_sel, null_mask); -} - template <> idx_t PositionComparator::Final(Vector &left, Vector &right, const SelectionVector &sel, idx_t count, optional_ptr true_sel, @@ -494,16 +510,6 @@ idx_t PositionComparator::Final(Vector &left, Vecto return VectorOperations::DistinctGreaterThan(left, right, &sel, count, true_sel, false_sel, null_mask); } -template <> -idx_t PositionComparator::Final(Vector &left, Vector &right, - const SelectionVector &sel, idx_t count, - optional_ptr true_sel, - optional_ptr false_sel, - optional_ptr null_mask) { - // DistinctLessThan has NULLs last - return VectorOperations::DistinctLessThan(right, left, &sel, count, true_sel, false_sel, null_mask); -} - using StructEntries = vector>; static void ExtractNestedSelection(const SelectionVector &slice_sel, const idx_t count, const SelectionVector &sel, @@ -1172,15 +1178,6 @@ idx_t VectorOperations::DistinctGreaterThan(Vector &left, Vector &right, optiona null_mask); } -// true := A > B with nulls being minimal -idx_t VectorOperations::DistinctGreaterThanNullsFirst(Vector &left, Vector &right, - optional_ptr sel, idx_t count, - optional_ptr true_sel, - optional_ptr false_sel, - optional_ptr null_mask) { - return TemplatedDistinctSelectOperation(left, right, sel, count, true_sel, - false_sel, null_mask); -} // true := A >= B with nulls being maximal idx_t VectorOperations::DistinctGreaterThanEquals(Vector &left, Vector &right, optional_ptr sel, idx_t count, optional_ptr true_sel, @@ -1198,15 +1195,6 @@ idx_t VectorOperations::DistinctLessThan(Vector &left, Vector &right, optional_p null_mask); } -// true := A < B with nulls being minimal -idx_t VectorOperations::DistinctLessThanNullsFirst(Vector &left, Vector &right, optional_ptr sel, - idx_t count, optional_ptr true_sel, - optional_ptr false_sel, - optional_ptr null_mask) { - return TemplatedDistinctSelectOperation(right, left, sel, count, true_sel, - false_sel, nullptr); -} - // true := A <= B with nulls being maximal idx_t VectorOperations::DistinctLessThanEquals(Vector &left, Vector &right, optional_ptr sel, idx_t count, optional_ptr true_sel, diff --git a/src/duckdb/src/core_functions/aggregate/algebraic/avg.cpp b/src/duckdb/src/core_functions/aggregate/algebraic/avg.cpp deleted file mode 100644 index d00e743ff..000000000 --- a/src/duckdb/src/core_functions/aggregate/algebraic/avg.cpp +++ /dev/null @@ -1,196 +0,0 @@ -#include "duckdb/core_functions/aggregate/algebraic_functions.hpp" -#include "duckdb/core_functions/aggregate/sum_helpers.hpp" -#include "duckdb/common/types/hugeint.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/function/function_set.hpp" -#include "duckdb/planner/expression.hpp" - -namespace duckdb { - -template -struct AvgState { - uint64_t count; - T value; - - void Initialize() { - this->count = 0; - } - - void Combine(const AvgState &other) { - this->count += other.count; - this->value += other.value; - } -}; - -struct KahanAvgState { - uint64_t count; - double value; - double err; - - void Initialize() { - this->count = 0; - this->err = 0.0; - } - - void Combine(const KahanAvgState &other) { - this->count += other.count; - KahanAddInternal(other.value, this->value, this->err); - KahanAddInternal(other.err, this->value, this->err); - } -}; - -struct AverageDecimalBindData : public FunctionData { - explicit AverageDecimalBindData(double scale) : scale(scale) { - } - - double scale; - -public: - unique_ptr Copy() const override { - return make_uniq(scale); - }; - - bool Equals(const FunctionData &other_p) const override { - auto &other = other_p.Cast(); - return scale == other.scale; - } -}; - -struct AverageSetOperation { - template - static void Initialize(STATE &state) { - state.Initialize(); - } - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - target.Combine(source); - } - template - static void AddValues(STATE &state, idx_t count) { - state.count += count; - } -}; - -template -static T GetAverageDivident(uint64_t count, optional_ptr bind_data) { - T divident = T(count); - if (bind_data) { - auto &avg_bind_data = bind_data->Cast(); - divident *= avg_bind_data.scale; - } - return divident; -} - -struct IntegerAverageOperation : public BaseSumOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.count == 0) { - finalize_data.ReturnNull(); - } else { - double divident = GetAverageDivident(state.count, finalize_data.input.bind_data); - target = double(state.value) / divident; - } - } -}; - -struct IntegerAverageOperationHugeint : public BaseSumOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.count == 0) { - finalize_data.ReturnNull(); - } else { - long double divident = GetAverageDivident(state.count, finalize_data.input.bind_data); - target = Hugeint::Cast(state.value) / divident; - } - } -}; - -struct HugeintAverageOperation : public BaseSumOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.count == 0) { - finalize_data.ReturnNull(); - } else { - long double divident = GetAverageDivident(state.count, finalize_data.input.bind_data); - target = Hugeint::Cast(state.value) / divident; - } - } -}; - -struct NumericAverageOperation : public BaseSumOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.count == 0) { - finalize_data.ReturnNull(); - } else { - target = state.value / state.count; - } - } -}; - -struct KahanAverageOperation : public BaseSumOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.count == 0) { - finalize_data.ReturnNull(); - } else { - target = (state.value / state.count) + (state.err / state.count); - } - } -}; - -AggregateFunction GetAverageAggregate(PhysicalType type) { - switch (type) { - case PhysicalType::INT16: { - return AggregateFunction::UnaryAggregate, int16_t, double, IntegerAverageOperation>( - LogicalType::SMALLINT, LogicalType::DOUBLE); - } - case PhysicalType::INT32: { - return AggregateFunction::UnaryAggregate, int32_t, double, IntegerAverageOperationHugeint>( - LogicalType::INTEGER, LogicalType::DOUBLE); - } - case PhysicalType::INT64: { - return AggregateFunction::UnaryAggregate, int64_t, double, IntegerAverageOperationHugeint>( - LogicalType::BIGINT, LogicalType::DOUBLE); - } - case PhysicalType::INT128: { - return AggregateFunction::UnaryAggregate, hugeint_t, double, HugeintAverageOperation>( - LogicalType::HUGEINT, LogicalType::DOUBLE); - } - default: - throw InternalException("Unimplemented average aggregate"); - } -} - -unique_ptr BindDecimalAvg(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - auto decimal_type = arguments[0]->return_type; - function = GetAverageAggregate(decimal_type.InternalType()); - function.name = "avg"; - function.arguments[0] = decimal_type; - function.return_type = LogicalType::DOUBLE; - return make_uniq( - Hugeint::Cast(Hugeint::POWERS_OF_TEN[DecimalType::GetScale(decimal_type)])); -} - -AggregateFunctionSet AvgFun::GetFunctions() { - AggregateFunctionSet avg; - - avg.AddFunction(AggregateFunction({LogicalTypeId::DECIMAL}, LogicalTypeId::DECIMAL, nullptr, nullptr, nullptr, - nullptr, nullptr, FunctionNullHandling::DEFAULT_NULL_HANDLING, nullptr, - BindDecimalAvg)); - avg.AddFunction(GetAverageAggregate(PhysicalType::INT16)); - avg.AddFunction(GetAverageAggregate(PhysicalType::INT32)); - avg.AddFunction(GetAverageAggregate(PhysicalType::INT64)); - avg.AddFunction(GetAverageAggregate(PhysicalType::INT128)); - avg.AddFunction(AggregateFunction::UnaryAggregate, double, double, NumericAverageOperation>( - LogicalType::DOUBLE, LogicalType::DOUBLE)); - return avg; -} - -AggregateFunction FAvgFun::GetFunction() { - return AggregateFunction::UnaryAggregate(LogicalType::DOUBLE, - LogicalType::DOUBLE); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/algebraic/corr.cpp b/src/duckdb/src/core_functions/aggregate/algebraic/corr.cpp deleted file mode 100644 index 61678684a..000000000 --- a/src/duckdb/src/core_functions/aggregate/algebraic/corr.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "duckdb/core_functions/aggregate/algebraic_functions.hpp" -#include "duckdb/core_functions/aggregate/algebraic/covar.hpp" -#include "duckdb/core_functions/aggregate/algebraic/stddev.hpp" -#include "duckdb/core_functions/aggregate/algebraic/corr.hpp" -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -AggregateFunction CorrFun::GetFunction() { - return AggregateFunction::BinaryAggregate( - LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE); -} -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/algebraic/covar.cpp b/src/duckdb/src/core_functions/aggregate/algebraic/covar.cpp deleted file mode 100644 index ced7d8be6..000000000 --- a/src/duckdb/src/core_functions/aggregate/algebraic/covar.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "duckdb/core_functions/aggregate/algebraic_functions.hpp" -#include "duckdb/common/types/null_value.hpp" -#include "duckdb/core_functions/aggregate/algebraic/covar.hpp" - -namespace duckdb { - -AggregateFunction CovarPopFun::GetFunction() { - return AggregateFunction::BinaryAggregate( - LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE); -} - -AggregateFunction CovarSampFun::GetFunction() { - return AggregateFunction::BinaryAggregate( - LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/algebraic/stddev.cpp b/src/duckdb/src/core_functions/aggregate/algebraic/stddev.cpp deleted file mode 100644 index b21467eeb..000000000 --- a/src/duckdb/src/core_functions/aggregate/algebraic/stddev.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "duckdb/core_functions/aggregate/algebraic_functions.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/function/function_set.hpp" -#include "duckdb/core_functions/aggregate/algebraic/stddev.hpp" -#include - -namespace duckdb { - -AggregateFunction StdDevSampFun::GetFunction() { - return AggregateFunction::UnaryAggregate(LogicalType::DOUBLE, - LogicalType::DOUBLE); -} - -AggregateFunction StdDevPopFun::GetFunction() { - return AggregateFunction::UnaryAggregate(LogicalType::DOUBLE, - LogicalType::DOUBLE); -} - -AggregateFunction VarPopFun::GetFunction() { - return AggregateFunction::UnaryAggregate(LogicalType::DOUBLE, - LogicalType::DOUBLE); -} - -AggregateFunction VarSampFun::GetFunction() { - return AggregateFunction::UnaryAggregate(LogicalType::DOUBLE, - LogicalType::DOUBLE); -} - -AggregateFunction StandardErrorOfTheMeanFun::GetFunction() { - return AggregateFunction::UnaryAggregate( - LogicalType::DOUBLE, LogicalType::DOUBLE); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/distributive/approx_count.cpp b/src/duckdb/src/core_functions/aggregate/distributive/approx_count.cpp deleted file mode 100644 index 13d33220b..000000000 --- a/src/duckdb/src/core_functions/aggregate/distributive/approx_count.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "duckdb/common/exception.hpp" -#include "duckdb/common/types/hash.hpp" -#include "duckdb/common/types/hyperloglog.hpp" -#include "duckdb/core_functions/aggregate/distributive_functions.hpp" -#include "duckdb/function/function_set.hpp" -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "hyperloglog.hpp" - -namespace duckdb { - -// Algorithms from -// "New cardinality estimation algorithms for HyperLogLog sketches" -// Otmar Ertl, arXiv:1702.01284 -struct ApproxDistinctCountState { - HyperLogLog hll; -}; - -struct ApproxCountDistinctFunction { - template - static void Initialize(STATE &state) { - new (&state) STATE(); - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - target.hll.Merge(source.hll); - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - target = UnsafeNumericCast(state.hll.Count()); - } - - static bool IgnoreNull() { - return true; - } -}; - -static void ApproxCountDistinctSimpleUpdateFunction(Vector inputs[], AggregateInputData &, idx_t input_count, - data_ptr_t state, idx_t count) { - D_ASSERT(input_count == 1); - auto &input = inputs[0]; - - if (count > STANDARD_VECTOR_SIZE) { - throw InternalException("ApproxCountDistinct - count must be at most vector size"); - } - Vector hash_vec(LogicalType::HASH, count); - VectorOperations::Hash(input, hash_vec, count); - - auto agg_state = reinterpret_cast(state); - agg_state->hll.Update(input, hash_vec, count); -} - -static void ApproxCountDistinctUpdateFunction(Vector inputs[], AggregateInputData &, idx_t input_count, - Vector &state_vector, idx_t count) { - D_ASSERT(input_count == 1); - auto &input = inputs[0]; - UnifiedVectorFormat idata; - input.ToUnifiedFormat(count, idata); - - if (count > STANDARD_VECTOR_SIZE) { - throw InternalException("ApproxCountDistinct - count must be at most vector size"); - } - Vector hash_vec(LogicalType::HASH, count); - VectorOperations::Hash(input, hash_vec, count); - - UnifiedVectorFormat sdata; - state_vector.ToUnifiedFormat(count, sdata); - const auto states = UnifiedVectorFormat::GetDataNoConst(sdata); - - UnifiedVectorFormat hdata; - hash_vec.ToUnifiedFormat(count, hdata); - const auto *hashes = UnifiedVectorFormat::GetData(hdata); - for (idx_t i = 0; i < count; i++) { - if (idata.validity.RowIsValid(idata.sel->get_index(i))) { - auto agg_state = states[sdata.sel->get_index(i)]; - const auto hash = hashes[hdata.sel->get_index(i)]; - agg_state->hll.InsertElement(hash); - } - } -} - -AggregateFunction GetApproxCountDistinctFunction(const LogicalType &input_type) { - auto fun = AggregateFunction( - {input_type}, LogicalTypeId::BIGINT, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, - ApproxCountDistinctUpdateFunction, - AggregateFunction::StateCombine, - AggregateFunction::StateFinalize, - ApproxCountDistinctSimpleUpdateFunction); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return fun; -} - -AggregateFunction ApproxCountDistinctFun::GetFunction() { - return GetApproxCountDistinctFunction(LogicalType::ANY); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/distributive/arg_min_max.cpp b/src/duckdb/src/core_functions/aggregate/distributive/arg_min_max.cpp deleted file mode 100644 index be64b065f..000000000 --- a/src/duckdb/src/core_functions/aggregate/distributive/arg_min_max.cpp +++ /dev/null @@ -1,694 +0,0 @@ -#include "duckdb/common/exception.hpp" -#include "duckdb/common/operator/comparison_operators.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/core_functions/aggregate/distributive_functions.hpp" -#include "duckdb/function/cast/cast_function_set.hpp" -#include "duckdb/function/function_set.hpp" -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "duckdb/planner/expression/bound_comparison_expression.hpp" -#include "duckdb/planner/expression_binder.hpp" -#include "duckdb/core_functions/create_sort_key.hpp" -#include "duckdb/core_functions/aggregate/minmax_n_helpers.hpp" - -namespace duckdb { - -struct ArgMinMaxStateBase { - ArgMinMaxStateBase() : is_initialized(false), arg_null(false) { - } - - template - static inline void CreateValue(T &value) { - } - - template - static inline void DestroyValue(T &value) { - } - - template - static inline void AssignValue(T &target, T new_value) { - target = new_value; - } - - template - static inline void ReadValue(Vector &result, T &arg, T &target) { - target = arg; - } - - bool is_initialized; - bool arg_null; -}; - -// Out-of-line specialisations -template <> -void ArgMinMaxStateBase::CreateValue(string_t &value) { - value = string_t(uint32_t(0)); -} - -template <> -void ArgMinMaxStateBase::DestroyValue(string_t &value) { - if (!value.IsInlined()) { - delete[] value.GetData(); - } -} - -template <> -void ArgMinMaxStateBase::AssignValue(string_t &target, string_t new_value) { - DestroyValue(target); - if (new_value.IsInlined()) { - target = new_value; - } else { - // non-inlined string, need to allocate space for it - auto len = new_value.GetSize(); - auto ptr = new char[len]; - memcpy(ptr, new_value.GetData(), len); - - target = string_t(ptr, UnsafeNumericCast(len)); - } -} - -template <> -void ArgMinMaxStateBase::ReadValue(Vector &result, string_t &arg, string_t &target) { - target = StringVector::AddStringOrBlob(result, arg); -} - -template -struct ArgMinMaxState : public ArgMinMaxStateBase { - using ARG_TYPE = A; - using BY_TYPE = B; - - ARG_TYPE arg; - BY_TYPE value; - - ArgMinMaxState() { - CreateValue(arg); - CreateValue(value); - } - - ~ArgMinMaxState() { - if (is_initialized) { - DestroyValue(arg); - DestroyValue(value); - is_initialized = false; - } - } -}; - -template -struct ArgMinMaxBase { - template - static void Initialize(STATE &state) { - new (&state) STATE; - } - - template - static void Destroy(STATE &state, AggregateInputData &aggr_input_data) { - state.~STATE(); - } - - template - static void Assign(STATE &state, const A_TYPE &x, const B_TYPE &y, const bool x_null) { - if (IGNORE_NULL) { - STATE::template AssignValue(state.arg, x); - STATE::template AssignValue(state.value, y); - } else { - state.arg_null = x_null; - if (!state.arg_null) { - STATE::template AssignValue(state.arg, x); - } - STATE::template AssignValue(state.value, y); - } - } - - template - static void Operation(STATE &state, const A_TYPE &x, const B_TYPE &y, AggregateBinaryInput &binary) { - if (!state.is_initialized) { - if (IGNORE_NULL || binary.right_mask.RowIsValid(binary.ridx)) { - Assign(state, x, y, !binary.left_mask.RowIsValid(binary.lidx)); - state.is_initialized = true; - } - } else { - OP::template Execute(state, x, y, binary); - } - } - - template - static void Execute(STATE &state, A_TYPE x_data, B_TYPE y_data, AggregateBinaryInput &binary) { - if ((IGNORE_NULL || binary.right_mask.RowIsValid(binary.ridx)) && COMPARATOR::Operation(y_data, state.value)) { - Assign(state, x_data, y_data, !binary.left_mask.RowIsValid(binary.lidx)); - } - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - if (!source.is_initialized) { - return; - } - if (!target.is_initialized || COMPARATOR::Operation(source.value, target.value)) { - Assign(target, source.arg, source.value, source.arg_null); - target.is_initialized = true; - } - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (!state.is_initialized || state.arg_null) { - finalize_data.ReturnNull(); - } else { - STATE::template ReadValue(finalize_data.result, state.arg, target); - } - } - - static bool IgnoreNull() { - return IGNORE_NULL; - } - - static unique_ptr Bind(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - if (arguments[1]->return_type.InternalType() == PhysicalType::VARCHAR) { - ExpressionBinder::PushCollation(context, arguments[1], arguments[1]->return_type); - } - function.arguments[0] = arguments[0]->return_type; - function.return_type = arguments[0]->return_type; - return nullptr; - } -}; - -struct SpecializedGenericArgMinMaxState { - static bool CreateExtraState(idx_t count) { - // nop extra state - return false; - } - - static void PrepareData(Vector &by, idx_t count, bool &, UnifiedVectorFormat &result) { - by.ToUnifiedFormat(count, result); - } -}; - -template -struct GenericArgMinMaxState { - static Vector CreateExtraState(idx_t count) { - return Vector(LogicalType::BLOB, count); - } - - static void PrepareData(Vector &by, idx_t count, Vector &extra_state, UnifiedVectorFormat &result) { - OrderModifiers modifiers(ORDER_TYPE, OrderByNullType::NULLS_LAST); - CreateSortKeyHelpers::CreateSortKeyWithValidity(by, extra_state, modifiers, count); - extra_state.ToUnifiedFormat(count, result); - } -}; - -template -struct VectorArgMinMaxBase : ArgMinMaxBase { - template - static void Update(Vector inputs[], AggregateInputData &, idx_t input_count, Vector &state_vector, idx_t count) { - auto &arg = inputs[0]; - UnifiedVectorFormat adata; - arg.ToUnifiedFormat(count, adata); - - using ARG_TYPE = typename STATE::ARG_TYPE; - using BY_TYPE = typename STATE::BY_TYPE; - auto &by = inputs[1]; - UnifiedVectorFormat bdata; - auto extra_state = UPDATE_TYPE::CreateExtraState(count); - UPDATE_TYPE::PrepareData(by, count, extra_state, bdata); - const auto bys = UnifiedVectorFormat::GetData(bdata); - - UnifiedVectorFormat sdata; - state_vector.ToUnifiedFormat(count, sdata); - - STATE *last_state = nullptr; - sel_t assign_sel[STANDARD_VECTOR_SIZE]; - idx_t assign_count = 0; - - auto states = UnifiedVectorFormat::GetData(sdata); - for (idx_t i = 0; i < count; i++) { - const auto bidx = bdata.sel->get_index(i); - if (!bdata.validity.RowIsValid(bidx)) { - continue; - } - const auto bval = bys[bidx]; - - const auto aidx = adata.sel->get_index(i); - const auto arg_null = !adata.validity.RowIsValid(aidx); - if (IGNORE_NULL && arg_null) { - continue; - } - - const auto sidx = sdata.sel->get_index(i); - auto &state = *states[sidx]; - if (!state.is_initialized || COMPARATOR::template Operation(bval, state.value)) { - STATE::template AssignValue(state.value, bval); - state.arg_null = arg_null; - // micro-adaptivity: it is common we overwrite the same state repeatedly - // e.g. when running arg_max(val, ts) and ts is sorted in ascending order - // this check essentially says: - // "if we are overriding the same state as the last row, the last write was pointless" - // hence we skip the last write altogether - if (!arg_null) { - if (&state == last_state) { - assign_count--; - } - assign_sel[assign_count++] = UnsafeNumericCast(i); - last_state = &state; - } - state.is_initialized = true; - } - } - if (assign_count == 0) { - // no need to assign anything: nothing left to do - return; - } - Vector sort_key(LogicalType::BLOB); - auto modifiers = OrderModifiers(ORDER_TYPE, OrderByNullType::NULLS_LAST); - // slice with a selection vector and generate sort keys - SelectionVector sel(assign_sel); - Vector sliced_input(arg, sel, assign_count); - CreateSortKeyHelpers::CreateSortKey(sliced_input, assign_count, modifiers, sort_key); - auto sort_key_data = FlatVector::GetData(sort_key); - - // now assign sort keys - for (idx_t i = 0; i < assign_count; i++) { - const auto sidx = sdata.sel->get_index(sel.get_index(i)); - auto &state = *states[sidx]; - STATE::template AssignValue(state.arg, sort_key_data[i]); - } - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - if (!source.is_initialized) { - return; - } - if (!target.is_initialized || COMPARATOR::Operation(source.value, target.value)) { - STATE::template AssignValue(target.value, source.value); - target.arg_null = source.arg_null; - if (!target.arg_null) { - STATE::template AssignValue(target.arg, source.arg); - ; - } - target.is_initialized = true; - } - } - - template - static void Finalize(STATE &state, AggregateFinalizeData &finalize_data) { - if (!state.is_initialized || state.arg_null) { - finalize_data.ReturnNull(); - } else { - CreateSortKeyHelpers::DecodeSortKey(state.arg, finalize_data.result, finalize_data.result_idx, - OrderModifiers(ORDER_TYPE, OrderByNullType::NULLS_LAST)); - } - } - - static unique_ptr Bind(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - function.arguments[0] = arguments[0]->return_type; - function.return_type = arguments[0]->return_type; - return nullptr; - } -}; - -template -AggregateFunction GetVectorArgMinMaxFunctionInternal(const LogicalType &by_type, const LogicalType &type) { - using STATE = ArgMinMaxState; - return AggregateFunction( - {type, by_type}, type, AggregateFunction::StateSize, AggregateFunction::StateInitialize, - OP::template Update, AggregateFunction::StateCombine, - AggregateFunction::StateVoidFinalize, nullptr, OP::Bind, AggregateFunction::StateDestroy); -} - -template -AggregateFunction GetVectorArgMinMaxFunctionBy(const LogicalType &by_type, const LogicalType &type) { - switch (by_type.InternalType()) { - case PhysicalType::INT32: - return GetVectorArgMinMaxFunctionInternal(by_type, type); - case PhysicalType::INT64: - return GetVectorArgMinMaxFunctionInternal(by_type, type); - case PhysicalType::INT128: - return GetVectorArgMinMaxFunctionInternal(by_type, type); - case PhysicalType::DOUBLE: - return GetVectorArgMinMaxFunctionInternal(by_type, type); - case PhysicalType::VARCHAR: - return GetVectorArgMinMaxFunctionInternal(by_type, type); - default: - throw InternalException("Unimplemented arg_min/arg_max aggregate"); - } -} - -static const vector ArgMaxByTypes() { - vector types = {LogicalType::INTEGER, LogicalType::BIGINT, LogicalType::HUGEINT, - LogicalType::DOUBLE, LogicalType::VARCHAR, LogicalType::DATE, - LogicalType::TIMESTAMP, LogicalType::TIMESTAMP_TZ, LogicalType::BLOB}; - return types; -} - -template -void AddVectorArgMinMaxFunctionBy(AggregateFunctionSet &fun, const LogicalType &type) { - auto by_types = ArgMaxByTypes(); - for (const auto &by_type : by_types) { - fun.AddFunction(GetVectorArgMinMaxFunctionBy(by_type, type)); - } -} - -template -AggregateFunction GetArgMinMaxFunctionInternal(const LogicalType &by_type, const LogicalType &type) { - using STATE = ArgMinMaxState; - auto function = AggregateFunction::BinaryAggregate(type, by_type, type); - if (type.InternalType() == PhysicalType::VARCHAR || by_type.InternalType() == PhysicalType::VARCHAR) { - function.destructor = AggregateFunction::StateDestroy; - } - function.bind = OP::Bind; - return function; -} - -template -AggregateFunction GetArgMinMaxFunctionBy(const LogicalType &by_type, const LogicalType &type) { - switch (by_type.InternalType()) { - case PhysicalType::INT32: - return GetArgMinMaxFunctionInternal(by_type, type); - case PhysicalType::INT64: - return GetArgMinMaxFunctionInternal(by_type, type); - case PhysicalType::INT128: - return GetArgMinMaxFunctionInternal(by_type, type); - case PhysicalType::DOUBLE: - return GetArgMinMaxFunctionInternal(by_type, type); - case PhysicalType::VARCHAR: - return GetArgMinMaxFunctionInternal(by_type, type); - default: - throw InternalException("Unimplemented arg_min/arg_max by aggregate"); - } -} - -template -void AddArgMinMaxFunctionBy(AggregateFunctionSet &fun, const LogicalType &type) { - auto by_types = ArgMaxByTypes(); - for (const auto &by_type : by_types) { - fun.AddFunction(GetArgMinMaxFunctionBy(by_type, type)); - } -} - -template -static AggregateFunction GetDecimalArgMinMaxFunction(const LogicalType &by_type, const LogicalType &type) { - D_ASSERT(type.id() == LogicalTypeId::DECIMAL); - switch (type.InternalType()) { - case PhysicalType::INT16: - return GetArgMinMaxFunctionBy(by_type, type); - case PhysicalType::INT32: - return GetArgMinMaxFunctionBy(by_type, type); - case PhysicalType::INT64: - return GetArgMinMaxFunctionBy(by_type, type); - default: - return GetArgMinMaxFunctionBy(by_type, type); - } -} - -template -static unique_ptr BindDecimalArgMinMax(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - auto decimal_type = arguments[0]->return_type; - auto by_type = arguments[1]->return_type; - - // To avoid a combinatorial explosion, cast the ordering argument to one from the list - auto by_types = ArgMaxByTypes(); - idx_t best_target = DConstants::INVALID_INDEX; - int64_t lowest_cost = NumericLimits::Maximum(); - for (idx_t i = 0; i < by_types.size(); ++i) { - // Before falling back to casting, check for a physical type match for the by_type - if (by_types[i].InternalType() == by_type.InternalType()) { - lowest_cost = 0; - best_target = DConstants::INVALID_INDEX; - break; - } - - auto cast_cost = CastFunctionSet::Get(context).ImplicitCastCost(by_type, by_types[i]); - if (cast_cost < 0) { - continue; - } - if (cast_cost < lowest_cost) { - best_target = i; - } - } - - if (best_target != DConstants::INVALID_INDEX) { - by_type = by_types[best_target]; - } - - auto name = std::move(function.name); - function = GetDecimalArgMinMaxFunction(by_type, decimal_type); - function.name = std::move(name); - function.return_type = decimal_type; - return nullptr; -} - -template -void AddDecimalArgMinMaxFunctionBy(AggregateFunctionSet &fun, const LogicalType &by_type) { - fun.AddFunction(AggregateFunction({LogicalTypeId::DECIMAL, by_type}, LogicalTypeId::DECIMAL, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, BindDecimalArgMinMax)); -} - -template -void AddGenericArgMinMaxFunction(AggregateFunctionSet &fun) { - using STATE = ArgMinMaxState; - fun.AddFunction( - AggregateFunction({LogicalType::ANY, LogicalType::ANY}, LogicalType::ANY, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, OP::template Update, - AggregateFunction::StateCombine, AggregateFunction::StateVoidFinalize, - nullptr, OP::Bind, AggregateFunction::StateDestroy)); -} - -template -static void AddArgMinMaxFunctions(AggregateFunctionSet &fun) { - using OP = ArgMinMaxBase; - AddArgMinMaxFunctionBy(fun, LogicalType::INTEGER); - AddArgMinMaxFunctionBy(fun, LogicalType::BIGINT); - AddArgMinMaxFunctionBy(fun, LogicalType::DOUBLE); - AddArgMinMaxFunctionBy(fun, LogicalType::VARCHAR); - AddArgMinMaxFunctionBy(fun, LogicalType::DATE); - AddArgMinMaxFunctionBy(fun, LogicalType::TIMESTAMP); - AddArgMinMaxFunctionBy(fun, LogicalType::TIMESTAMP_TZ); - AddArgMinMaxFunctionBy(fun, LogicalType::BLOB); - - auto by_types = ArgMaxByTypes(); - for (const auto &by_type : by_types) { - AddDecimalArgMinMaxFunctionBy(fun, by_type); - } - - using VECTOR_OP = VectorArgMinMaxBase; - AddVectorArgMinMaxFunctionBy(fun, LogicalType::ANY); - - // we always use LessThan when using sort keys because the ORDER_TYPE takes care of selecting the lowest or highest - using GENERIC_VECTOR_OP = VectorArgMinMaxBase>; - AddGenericArgMinMaxFunction(fun); -} - -//------------------------------------------------------------------------------ -// ArgMinMax(N) Function -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -// State -//------------------------------------------------------------------------------ - -template -class ArgMinMaxNState { -public: - using VAL_TYPE = A; - using ARG_TYPE = B; - - using V = typename VAL_TYPE::TYPE; - using K = typename ARG_TYPE::TYPE; - - BinaryAggregateHeap heap; - - bool is_initialized = false; - void Initialize(idx_t nval) { - heap.Initialize(nval); - is_initialized = true; - } -}; - -//------------------------------------------------------------------------------ -// Operation -//------------------------------------------------------------------------------ -template -static void ArgMinMaxNUpdate(Vector inputs[], AggregateInputData &aggr_input, idx_t input_count, Vector &state_vector, - idx_t count) { - - auto &val_vector = inputs[0]; - auto &arg_vector = inputs[1]; - auto &n_vector = inputs[2]; - - UnifiedVectorFormat val_format; - UnifiedVectorFormat arg_format; - UnifiedVectorFormat n_format; - UnifiedVectorFormat state_format; - - auto val_extra_state = STATE::VAL_TYPE::CreateExtraState(val_vector, count); - auto arg_extra_state = STATE::ARG_TYPE::CreateExtraState(arg_vector, count); - - STATE::VAL_TYPE::PrepareData(val_vector, count, val_extra_state, val_format); - STATE::ARG_TYPE::PrepareData(arg_vector, count, arg_extra_state, arg_format); - - n_vector.ToUnifiedFormat(count, n_format); - state_vector.ToUnifiedFormat(count, state_format); - - auto states = UnifiedVectorFormat::GetData(state_format); - - for (idx_t i = 0; i < count; i++) { - const auto arg_idx = arg_format.sel->get_index(i); - const auto val_idx = val_format.sel->get_index(i); - if (!arg_format.validity.RowIsValid(arg_idx) || !val_format.validity.RowIsValid(val_idx)) { - continue; - } - const auto state_idx = state_format.sel->get_index(i); - auto &state = *states[state_idx]; - - // Initialize the heap if necessary and add the input to the heap - if (!state.is_initialized) { - static constexpr int64_t MAX_N = 1000000; - const auto nidx = n_format.sel->get_index(i); - if (!n_format.validity.RowIsValid(nidx)) { - throw InvalidInputException("Invalid input for arg_min/arg_max: n value cannot be NULL"); - } - const auto nval = UnifiedVectorFormat::GetData(n_format)[nidx]; - if (nval <= 0) { - throw InvalidInputException("Invalid input for arg_min/arg_max: n value must be > 0"); - } - if (nval >= MAX_N) { - throw InvalidInputException("Invalid input for arg_min/arg_max: n value must be < %d", MAX_N); - } - state.Initialize(UnsafeNumericCast(nval)); - } - - // Now add the input to the heap - auto arg_val = STATE::ARG_TYPE::Create(arg_format, arg_idx); - auto val_val = STATE::VAL_TYPE::Create(val_format, val_idx); - - state.heap.Insert(aggr_input.allocator, arg_val, val_val); - } -} - -//------------------------------------------------------------------------------ -// Bind -//------------------------------------------------------------------------------ -template -static void SpecializeArgMinMaxNFunction(AggregateFunction &function) { - using STATE = ArgMinMaxNState; - using OP = MinMaxNOperation; - - function.state_size = AggregateFunction::StateSize; - function.initialize = AggregateFunction::StateInitialize; - function.combine = AggregateFunction::StateCombine; - function.destructor = AggregateFunction::StateDestroy; - - function.finalize = MinMaxNOperation::Finalize; - function.update = ArgMinMaxNUpdate; -} - -template -static void SpecializeArgMinMaxNFunction(PhysicalType arg_type, AggregateFunction &function) { - switch (arg_type) { - case PhysicalType::VARCHAR: - SpecializeArgMinMaxNFunction(function); - break; - case PhysicalType::INT32: - SpecializeArgMinMaxNFunction, COMPARATOR>(function); - break; - case PhysicalType::INT64: - SpecializeArgMinMaxNFunction, COMPARATOR>(function); - break; - case PhysicalType::FLOAT: - SpecializeArgMinMaxNFunction, COMPARATOR>(function); - break; - case PhysicalType::DOUBLE: - SpecializeArgMinMaxNFunction, COMPARATOR>(function); - break; - default: - SpecializeArgMinMaxNFunction(function); - break; - } -} - -template -static void SpecializeArgMinMaxNFunction(PhysicalType val_type, PhysicalType arg_type, AggregateFunction &function) { - switch (val_type) { - case PhysicalType::VARCHAR: - SpecializeArgMinMaxNFunction(arg_type, function); - break; - case PhysicalType::INT32: - SpecializeArgMinMaxNFunction, COMPARATOR>(arg_type, function); - break; - case PhysicalType::INT64: - SpecializeArgMinMaxNFunction, COMPARATOR>(arg_type, function); - break; - case PhysicalType::FLOAT: - SpecializeArgMinMaxNFunction, COMPARATOR>(arg_type, function); - break; - case PhysicalType::DOUBLE: - SpecializeArgMinMaxNFunction, COMPARATOR>(arg_type, function); - break; - default: - SpecializeArgMinMaxNFunction(arg_type, function); - break; - } -} - -template -unique_ptr ArgMinMaxNBind(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - for (auto &arg : arguments) { - if (arg->return_type.id() == LogicalTypeId::UNKNOWN) { - throw ParameterNotResolvedException(); - } - } - - const auto val_type = arguments[0]->return_type.InternalType(); - const auto arg_type = arguments[1]->return_type.InternalType(); - - // Specialize the function based on the input types - SpecializeArgMinMaxNFunction(val_type, arg_type, function); - - function.return_type = LogicalType::LIST(arguments[0]->return_type); - return nullptr; -} - -template -static void AddArgMinMaxNFunction(AggregateFunctionSet &set) { - AggregateFunction function({LogicalTypeId::ANY, LogicalTypeId::ANY, LogicalType::BIGINT}, - LogicalType::LIST(LogicalType::ANY), nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, ArgMinMaxNBind); - - return set.AddFunction(function); -} - -//------------------------------------------------------------------------------ -// Function Registration -//------------------------------------------------------------------------------ - -AggregateFunctionSet ArgMinFun::GetFunctions() { - AggregateFunctionSet fun; - AddArgMinMaxFunctions(fun); - AddArgMinMaxNFunction(fun); - return fun; -} - -AggregateFunctionSet ArgMaxFun::GetFunctions() { - AggregateFunctionSet fun; - AddArgMinMaxFunctions(fun); - AddArgMinMaxNFunction(fun); - return fun; -} - -AggregateFunctionSet ArgMinNullFun::GetFunctions() { - AggregateFunctionSet fun; - AddArgMinMaxFunctions(fun); - return fun; -} - -AggregateFunctionSet ArgMaxNullFun::GetFunctions() { - AggregateFunctionSet fun; - AddArgMinMaxFunctions(fun); - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/distributive/bitagg.cpp b/src/duckdb/src/core_functions/aggregate/distributive/bitagg.cpp deleted file mode 100644 index af3056359..000000000 --- a/src/duckdb/src/core_functions/aggregate/distributive/bitagg.cpp +++ /dev/null @@ -1,231 +0,0 @@ -#include "duckdb/core_functions/aggregate/distributive_functions.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/types/null_value.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/vector_operations/aggregate_executor.hpp" -#include "duckdb/common/types/bit.hpp" -#include "duckdb/common/types/cast_helpers.hpp" - -namespace duckdb { - -template -struct BitState { - using TYPE = T; - bool is_set; - T value; -}; - -template -static AggregateFunction GetBitfieldUnaryAggregate(LogicalType type) { - switch (type.id()) { - case LogicalTypeId::TINYINT: - return AggregateFunction::UnaryAggregate, int8_t, int8_t, OP>(type, type); - case LogicalTypeId::SMALLINT: - return AggregateFunction::UnaryAggregate, int16_t, int16_t, OP>(type, type); - case LogicalTypeId::INTEGER: - return AggregateFunction::UnaryAggregate, int32_t, int32_t, OP>(type, type); - case LogicalTypeId::BIGINT: - return AggregateFunction::UnaryAggregate, int64_t, int64_t, OP>(type, type); - case LogicalTypeId::HUGEINT: - return AggregateFunction::UnaryAggregate, hugeint_t, hugeint_t, OP>(type, type); - case LogicalTypeId::UTINYINT: - return AggregateFunction::UnaryAggregate, uint8_t, uint8_t, OP>(type, type); - case LogicalTypeId::USMALLINT: - return AggregateFunction::UnaryAggregate, uint16_t, uint16_t, OP>(type, type); - case LogicalTypeId::UINTEGER: - return AggregateFunction::UnaryAggregate, uint32_t, uint32_t, OP>(type, type); - case LogicalTypeId::UBIGINT: - return AggregateFunction::UnaryAggregate, uint64_t, uint64_t, OP>(type, type); - case LogicalTypeId::UHUGEINT: - return AggregateFunction::UnaryAggregate, uhugeint_t, uhugeint_t, OP>(type, type); - default: - throw InternalException("Unimplemented bitfield type for unary aggregate"); - } -} - -struct BitwiseOperation { - template - static void Initialize(STATE &state) { - // If there are no matching rows, returns a null value. - state.is_set = false; - } - - template - static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &) { - if (!state.is_set) { - OP::template Assign(state, input); - state.is_set = true; - } else { - OP::template Execute(state, input); - } - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, - idx_t count) { - OP::template Operation(state, input, unary_input); - } - - template - static void Assign(STATE &state, INPUT_TYPE input) { - state.value = typename STATE::TYPE(input); - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - if (!source.is_set) { - // source is NULL, nothing to do. - return; - } - if (!target.is_set) { - // target is NULL, use source value directly. - OP::template Assign(target, source.value); - target.is_set = true; - } else { - OP::template Execute(target, source.value); - } - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (!state.is_set) { - finalize_data.ReturnNull(); - } else { - target = T(state.value); - } - } - - static bool IgnoreNull() { - return true; - } -}; - -struct BitAndOperation : public BitwiseOperation { - template - static void Execute(STATE &state, INPUT_TYPE input) { - state.value &= typename STATE::TYPE(input); - ; - } -}; - -struct BitOrOperation : public BitwiseOperation { - template - static void Execute(STATE &state, INPUT_TYPE input) { - state.value |= typename STATE::TYPE(input); - ; - } -}; - -struct BitXorOperation : public BitwiseOperation { - template - static void Execute(STATE &state, INPUT_TYPE input) { - state.value ^= typename STATE::TYPE(input); - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, - idx_t count) { - for (idx_t i = 0; i < count; i++) { - Operation(state, input, unary_input); - } - } -}; - -struct BitStringBitwiseOperation : public BitwiseOperation { - template - static void Destroy(STATE &state, AggregateInputData &aggr_input_data) { - if (state.is_set && !state.value.IsInlined()) { - delete[] state.value.GetData(); - } - } - - template - static void Assign(STATE &state, INPUT_TYPE input) { - D_ASSERT(state.is_set == false); - if (input.IsInlined()) { - state.value = input; - } else { // non-inlined string, need to allocate space for it - auto len = input.GetSize(); - auto ptr = new char[len]; - memcpy(ptr, input.GetData(), len); - - state.value = string_t(ptr, UnsafeNumericCast(len)); - } - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (!state.is_set) { - finalize_data.ReturnNull(); - } else { - target = finalize_data.ReturnString(state.value); - } - } -}; - -struct BitStringAndOperation : public BitStringBitwiseOperation { - - template - static void Execute(STATE &state, INPUT_TYPE input) { - Bit::BitwiseAnd(input, state.value, state.value); - } -}; - -struct BitStringOrOperation : public BitStringBitwiseOperation { - - template - static void Execute(STATE &state, INPUT_TYPE input) { - Bit::BitwiseOr(input, state.value, state.value); - } -}; - -struct BitStringXorOperation : public BitStringBitwiseOperation { - template - static void Execute(STATE &state, INPUT_TYPE input) { - Bit::BitwiseXor(input, state.value, state.value); - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, - idx_t count) { - for (idx_t i = 0; i < count; i++) { - Operation(state, input, unary_input); - } - } -}; - -AggregateFunctionSet BitAndFun::GetFunctions() { - AggregateFunctionSet bit_and; - for (auto &type : LogicalType::Integral()) { - bit_and.AddFunction(GetBitfieldUnaryAggregate(type)); - } - - bit_and.AddFunction( - AggregateFunction::UnaryAggregateDestructor, string_t, string_t, BitStringAndOperation>( - LogicalType::BIT, LogicalType::BIT)); - return bit_and; -} - -AggregateFunctionSet BitOrFun::GetFunctions() { - AggregateFunctionSet bit_or; - for (auto &type : LogicalType::Integral()) { - bit_or.AddFunction(GetBitfieldUnaryAggregate(type)); - } - bit_or.AddFunction( - AggregateFunction::UnaryAggregateDestructor, string_t, string_t, BitStringOrOperation>( - LogicalType::BIT, LogicalType::BIT)); - return bit_or; -} - -AggregateFunctionSet BitXorFun::GetFunctions() { - AggregateFunctionSet bit_xor; - for (auto &type : LogicalType::Integral()) { - bit_xor.AddFunction(GetBitfieldUnaryAggregate(type)); - } - bit_xor.AddFunction( - AggregateFunction::UnaryAggregateDestructor, string_t, string_t, BitStringXorOperation>( - LogicalType::BIT, LogicalType::BIT)); - return bit_xor; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/distributive/bitstring_agg.cpp b/src/duckdb/src/core_functions/aggregate/distributive/bitstring_agg.cpp deleted file mode 100644 index f01cc50a8..000000000 --- a/src/duckdb/src/core_functions/aggregate/distributive/bitstring_agg.cpp +++ /dev/null @@ -1,322 +0,0 @@ -#include "duckdb/core_functions/aggregate/distributive_functions.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/types/null_value.hpp" -#include "duckdb/common/vector_operations/aggregate_executor.hpp" -#include "duckdb/common/types/bit.hpp" -#include "duckdb/common/types/uhugeint.hpp" -#include "duckdb/storage/statistics/base_statistics.hpp" -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/common/types/cast_helpers.hpp" -#include "duckdb/common/operator/subtract.hpp" -#include "duckdb/common/serializer/deserializer.hpp" -#include "duckdb/common/serializer/serializer.hpp" - -namespace duckdb { - -template -struct BitAggState { - bool is_set; - string_t value; - INPUT_TYPE min; - INPUT_TYPE max; -}; - -struct BitstringAggBindData : public FunctionData { - Value min; - Value max; - - BitstringAggBindData() { - } - - BitstringAggBindData(Value min, Value max) : min(std::move(min)), max(std::move(max)) { - } - - unique_ptr Copy() const override { - return make_uniq(*this); - } - - bool Equals(const FunctionData &other_p) const override { - auto &other = other_p.Cast(); - if (min.IsNull() && other.min.IsNull() && max.IsNull() && other.max.IsNull()) { - return true; - } - if (Value::NotDistinctFrom(min, other.min) && Value::NotDistinctFrom(max, other.max)) { - return true; - } - return false; - } - - static void Serialize(Serializer &serializer, const optional_ptr bind_data_p, - const AggregateFunction &) { - auto &bind_data = bind_data_p->Cast(); - serializer.WriteProperty(100, "min", bind_data.min); - serializer.WriteProperty(101, "max", bind_data.max); - } - - static unique_ptr Deserialize(Deserializer &deserializer, AggregateFunction &) { - Value min; - Value max; - deserializer.ReadProperty(100, "min", min); - deserializer.ReadProperty(101, "max", max); - return make_uniq(min, max); - } -}; - -struct BitStringAggOperation { - static constexpr const idx_t MAX_BIT_RANGE = 1000000000; // for now capped at 1 billion bits - - template - static void Initialize(STATE &state) { - state.is_set = false; - } - - template - static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input) { - auto &bind_agg_data = unary_input.input.bind_data->template Cast(); - if (!state.is_set) { - if (bind_agg_data.min.IsNull() || bind_agg_data.max.IsNull()) { - throw BinderException( - "Could not retrieve required statistics. Alternatively, try by providing the statistics " - "explicitly: BITSTRING_AGG(col, min, max) "); - } - state.min = bind_agg_data.min.GetValue(); - state.max = bind_agg_data.max.GetValue(); - if (state.min > state.max) { - throw InvalidInputException("Invalid explicit bitstring range: Minimum (%s) > maximum (%s)", - NumericHelper::ToString(state.min), NumericHelper::ToString(state.max)); - } - idx_t bit_range = - GetRange(bind_agg_data.min.GetValue(), bind_agg_data.max.GetValue()); - if (bit_range > MAX_BIT_RANGE) { - throw OutOfRangeException( - "The range between min and max value (%s <-> %s) is too large for bitstring aggregation", - NumericHelper::ToString(state.min), NumericHelper::ToString(state.max)); - } - idx_t len = Bit::ComputeBitstringLen(bit_range); - auto target = len > string_t::INLINE_LENGTH ? string_t(new char[len], UnsafeNumericCast(len)) - : string_t(UnsafeNumericCast(len)); - Bit::SetEmptyBitString(target, bit_range); - - state.value = target; - state.is_set = true; - } - if (input >= state.min && input <= state.max) { - Execute(state, input, bind_agg_data.min.GetValue()); - } else { - throw OutOfRangeException("Value %s is outside of provided min and max range (%s <-> %s)", - NumericHelper::ToString(input), NumericHelper::ToString(state.min), - NumericHelper::ToString(state.max)); - } - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, - idx_t count) { - OP::template Operation(state, input, unary_input); - } - - template - static idx_t GetRange(INPUT_TYPE min, INPUT_TYPE max) { - if (min > max) { - throw InvalidInputException("Invalid explicit bitstring range: Minimum (%d) > maximum (%d)", min, max); - } - INPUT_TYPE result; - if (!TrySubtractOperator::Operation(max, min, result)) { - return NumericLimits::Maximum(); - } - auto val = NumericCast(result); - if (val == NumericLimits::Maximum()) { - return val; - } - return val + 1; - } - - template - static void Execute(STATE &state, INPUT_TYPE input, INPUT_TYPE min) { - Bit::SetBit(state.value, UnsafeNumericCast(input - min), 1); - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - if (!source.is_set) { - return; - } - if (!target.is_set) { - Assign(target, source.value); - target.is_set = true; - target.min = source.min; - target.max = source.max; - } else { - Bit::BitwiseOr(source.value, target.value, target.value); - } - } - - template - static void Assign(STATE &state, INPUT_TYPE input) { - D_ASSERT(state.is_set == false); - if (input.IsInlined()) { - state.value = input; - } else { // non-inlined string, need to allocate space for it - auto len = input.GetSize(); - auto ptr = new char[len]; - memcpy(ptr, input.GetData(), len); - state.value = string_t(ptr, UnsafeNumericCast(len)); - } - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (!state.is_set) { - finalize_data.ReturnNull(); - } else { - target = StringVector::AddStringOrBlob(finalize_data.result, state.value); - } - } - - template - static void Destroy(STATE &state, AggregateInputData &aggr_input_data) { - if (state.is_set && !state.value.IsInlined()) { - delete[] state.value.GetData(); - } - } - - static bool IgnoreNull() { - return true; - } -}; - -template <> -void BitStringAggOperation::Execute(BitAggState &state, hugeint_t input, hugeint_t min) { - idx_t val; - if (Hugeint::TryCast(input - min, val)) { - Bit::SetBit(state.value, val, 1); - } else { - throw OutOfRangeException("Range too large for bitstring aggregation"); - } -} - -template <> -idx_t BitStringAggOperation::GetRange(hugeint_t min, hugeint_t max) { - hugeint_t result; - if (!TrySubtractOperator::Operation(max, min, result)) { - return NumericLimits::Maximum(); - } - idx_t range; - if (!Hugeint::TryCast(result + 1, range) || result == NumericLimits::Maximum()) { - return NumericLimits::Maximum(); - } - return range; -} - -template <> -void BitStringAggOperation::Execute(BitAggState &state, uhugeint_t input, uhugeint_t min) { - idx_t val; - if (Uhugeint::TryCast(input - min, val)) { - Bit::SetBit(state.value, val, 1); - } else { - throw OutOfRangeException("Range too large for bitstring aggregation"); - } -} - -template <> -idx_t BitStringAggOperation::GetRange(uhugeint_t min, uhugeint_t max) { - uhugeint_t result; - if (!TrySubtractOperator::Operation(max, min, result)) { - return NumericLimits::Maximum(); - } - idx_t range; - if (!Uhugeint::TryCast(result + 1, range) || result == NumericLimits::Maximum()) { - return NumericLimits::Maximum(); - } - return range; -} - -unique_ptr BitstringPropagateStats(ClientContext &context, BoundAggregateExpression &expr, - AggregateStatisticsInput &input) { - - if (!NumericStats::HasMinMax(input.child_stats[0])) { - throw BinderException("Could not retrieve required statistics. Alternatively, try by providing the statistics " - "explicitly: BITSTRING_AGG(col, min, max) "); - } - auto &bind_agg_data = input.bind_data->Cast(); - bind_agg_data.min = NumericStats::Min(input.child_stats[0]); - bind_agg_data.max = NumericStats::Max(input.child_stats[0]); - return nullptr; -} - -unique_ptr BindBitstringAgg(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - if (arguments.size() == 3) { - if (!arguments[1]->IsFoldable() || !arguments[2]->IsFoldable()) { - throw BinderException("bitstring_agg requires a constant min and max argument"); - } - auto min = ExpressionExecutor::EvaluateScalar(context, *arguments[1]); - auto max = ExpressionExecutor::EvaluateScalar(context, *arguments[2]); - Function::EraseArgument(function, arguments, 2); - Function::EraseArgument(function, arguments, 1); - return make_uniq(min, max); - } - return make_uniq(); -} - -template -static void BindBitString(AggregateFunctionSet &bitstring_agg, const LogicalTypeId &type) { - auto function = - AggregateFunction::UnaryAggregateDestructor, TYPE, string_t, BitStringAggOperation>( - type, LogicalType::BIT); - function.bind = BindBitstringAgg; // create new a 'BitstringAggBindData' - function.serialize = BitstringAggBindData::Serialize; - function.deserialize = BitstringAggBindData::Deserialize; - function.statistics = BitstringPropagateStats; // stores min and max from column stats in BitstringAggBindData - bitstring_agg.AddFunction(function); // uses the BitstringAggBindData to access statistics for creating bitstring - function.arguments = {type, type, type}; - function.statistics = nullptr; // min and max are provided as arguments - bitstring_agg.AddFunction(function); -} - -void GetBitStringAggregate(const LogicalType &type, AggregateFunctionSet &bitstring_agg) { - switch (type.id()) { - case LogicalType::TINYINT: { - return BindBitString(bitstring_agg, type.id()); - } - case LogicalType::SMALLINT: { - return BindBitString(bitstring_agg, type.id()); - } - case LogicalType::INTEGER: { - return BindBitString(bitstring_agg, type.id()); - } - case LogicalType::BIGINT: { - return BindBitString(bitstring_agg, type.id()); - } - case LogicalType::HUGEINT: { - return BindBitString(bitstring_agg, type.id()); - } - case LogicalType::UTINYINT: { - return BindBitString(bitstring_agg, type.id()); - } - case LogicalType::USMALLINT: { - return BindBitString(bitstring_agg, type.id()); - } - case LogicalType::UINTEGER: { - return BindBitString(bitstring_agg, type.id()); - } - case LogicalType::UBIGINT: { - return BindBitString(bitstring_agg, type.id()); - } - case LogicalType::UHUGEINT: { - return BindBitString(bitstring_agg, type.id()); - } - default: - throw InternalException("Unimplemented bitstring aggregate"); - } -} - -AggregateFunctionSet BitstringAggFun::GetFunctions() { - AggregateFunctionSet bitstring_agg("bitstring_agg"); - for (auto &type : LogicalType::Integral()) { - GetBitStringAggregate(type, bitstring_agg); - } - return bitstring_agg; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/distributive/bool.cpp b/src/duckdb/src/core_functions/aggregate/distributive/bool.cpp deleted file mode 100644 index 20f2f3bac..000000000 --- a/src/duckdb/src/core_functions/aggregate/distributive/bool.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "duckdb/core_functions/aggregate/distributive_functions.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct BoolState { - bool empty; - bool val; -}; - -struct BoolAndFunFunction { - template - static void Initialize(STATE &state) { - state.val = true; - state.empty = true; - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - target.val = target.val && source.val; - target.empty = target.empty && source.empty; - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.empty) { - finalize_data.ReturnNull(); - return; - } - target = state.val; - } - - template - static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input) { - state.empty = false; - state.val = input && state.val; - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, - idx_t count) { - for (idx_t i = 0; i < count; i++) { - Operation(state, input, unary_input); - } - } - static bool IgnoreNull() { - return true; - } -}; - -struct BoolOrFunFunction { - template - static void Initialize(STATE &state) { - state.val = false; - state.empty = true; - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - target.val = target.val || source.val; - target.empty = target.empty && source.empty; - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.empty) { - finalize_data.ReturnNull(); - return; - } - target = state.val; - } - template - static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input) { - state.empty = false; - state.val = input || state.val; - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, - idx_t count) { - for (idx_t i = 0; i < count; i++) { - Operation(state, input, unary_input); - } - } - - static bool IgnoreNull() { - return true; - } -}; - -AggregateFunction BoolOrFun::GetFunction() { - auto fun = AggregateFunction::UnaryAggregate( - LogicalType(LogicalTypeId::BOOLEAN), LogicalType::BOOLEAN); - fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - return fun; -} - -AggregateFunction BoolAndFun::GetFunction() { - auto fun = AggregateFunction::UnaryAggregate( - LogicalType(LogicalTypeId::BOOLEAN), LogicalType::BOOLEAN); - fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/distributive/entropy.cpp b/src/duckdb/src/core_functions/aggregate/distributive/entropy.cpp deleted file mode 100644 index 426d4498c..000000000 --- a/src/duckdb/src/core_functions/aggregate/distributive/entropy.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include "duckdb/core_functions/aggregate/distributive_functions.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "duckdb/function/function_set.hpp" -#include "duckdb/common/algorithm.hpp" -#include "duckdb/common/unordered_map.hpp" - -namespace duckdb { - -template -struct EntropyState { - using DistinctMap = unordered_map; - - idx_t count; - DistinctMap *distinct; - - EntropyState &operator=(const EntropyState &other) = delete; - - EntropyState &Assign(const EntropyState &other) { - D_ASSERT(!distinct); - distinct = new DistinctMap(*other.distinct); - count = other.count; - return *this; - } -}; - -struct EntropyFunctionBase { - template - static void Initialize(STATE &state) { - state.distinct = nullptr; - state.count = 0; - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - if (!source.distinct) { - return; - } - if (!target.distinct) { - target.Assign(source); - return; - } - for (auto &val : *source.distinct) { - auto value = val.first; - (*target.distinct)[value] += val.second; - } - target.count += source.count; - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - double count = static_cast(state.count); - if (state.distinct) { - double entropy = 0; - for (auto &val : *state.distinct) { - double val_sec = static_cast(val.second); - entropy += (val_sec / count) * log2(count / val_sec); - } - target = entropy; - } else { - target = 0; - } - } - - static bool IgnoreNull() { - return true; - } - template - static void Destroy(STATE &state, AggregateInputData &aggr_input_data) { - if (state.distinct) { - delete state.distinct; - } - } -}; - -struct EntropyFunction : EntropyFunctionBase { - template - static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input) { - if (!state.distinct) { - state.distinct = new unordered_map(); - } - (*state.distinct)[input]++; - state.count++; - } - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, - idx_t count) { - for (idx_t i = 0; i < count; i++) { - Operation(state, input, unary_input); - } - } -}; - -struct EntropyFunctionString : EntropyFunctionBase { - template - static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input) { - if (!state.distinct) { - state.distinct = new unordered_map(); - } - auto value = input.GetString(); - (*state.distinct)[value]++; - state.count++; - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, - idx_t count) { - for (idx_t i = 0; i < count; i++) { - Operation(state, input, unary_input); - } - } -}; - -template -AggregateFunction GetEntropyFunction(const LogicalType &input_type, const LogicalType &result_type) { - auto fun = - AggregateFunction::UnaryAggregateDestructor, INPUT_TYPE, RESULT_TYPE, EntropyFunction>( - input_type, result_type); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return fun; -} - -AggregateFunction GetEntropyFunctionInternal(PhysicalType type) { - switch (type) { - case PhysicalType::UINT16: - return AggregateFunction::UnaryAggregateDestructor, uint16_t, double, EntropyFunction>( - LogicalType::USMALLINT, LogicalType::DOUBLE); - case PhysicalType::UINT32: - return AggregateFunction::UnaryAggregateDestructor, uint32_t, double, EntropyFunction>( - LogicalType::UINTEGER, LogicalType::DOUBLE); - case PhysicalType::UINT64: - return AggregateFunction::UnaryAggregateDestructor, uint64_t, double, EntropyFunction>( - LogicalType::UBIGINT, LogicalType::DOUBLE); - case PhysicalType::INT16: - return AggregateFunction::UnaryAggregateDestructor, int16_t, double, EntropyFunction>( - LogicalType::SMALLINT, LogicalType::DOUBLE); - case PhysicalType::INT32: - return AggregateFunction::UnaryAggregateDestructor, int32_t, double, EntropyFunction>( - LogicalType::INTEGER, LogicalType::DOUBLE); - case PhysicalType::INT64: - return AggregateFunction::UnaryAggregateDestructor, int64_t, double, EntropyFunction>( - LogicalType::BIGINT, LogicalType::DOUBLE); - case PhysicalType::FLOAT: - return AggregateFunction::UnaryAggregateDestructor, float, double, EntropyFunction>( - LogicalType::FLOAT, LogicalType::DOUBLE); - case PhysicalType::DOUBLE: - return AggregateFunction::UnaryAggregateDestructor, double, double, EntropyFunction>( - LogicalType::DOUBLE, LogicalType::DOUBLE); - case PhysicalType::VARCHAR: { - return AggregateFunction::UnaryAggregateDestructor, string_t, double, - EntropyFunctionString>( - LogicalType::ANY_PARAMS(LogicalType::VARCHAR, 150), LogicalType::DOUBLE); - } - - default: - throw InternalException("Unimplemented approximate_count aggregate"); - } -} - -AggregateFunction GetEntropyFunction(PhysicalType type) { - auto fun = GetEntropyFunctionInternal(type); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return fun; -} - -AggregateFunctionSet EntropyFun::GetFunctions() { - AggregateFunctionSet entropy("entropy"); - entropy.AddFunction(GetEntropyFunction(PhysicalType::UINT16)); - entropy.AddFunction(GetEntropyFunction(PhysicalType::UINT32)); - entropy.AddFunction(GetEntropyFunction(PhysicalType::UINT64)); - entropy.AddFunction(GetEntropyFunction(PhysicalType::FLOAT)); - entropy.AddFunction(GetEntropyFunction(PhysicalType::INT16)); - entropy.AddFunction(GetEntropyFunction(PhysicalType::INT32)); - entropy.AddFunction(GetEntropyFunction(PhysicalType::INT64)); - entropy.AddFunction(GetEntropyFunction(PhysicalType::DOUBLE)); - entropy.AddFunction(GetEntropyFunction(PhysicalType::VARCHAR)); - entropy.AddFunction(GetEntropyFunction(LogicalType::TIMESTAMP, LogicalType::DOUBLE)); - entropy.AddFunction(GetEntropyFunction(LogicalType::TIMESTAMP_TZ, LogicalType::DOUBLE)); - return entropy; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/distributive/kurtosis.cpp b/src/duckdb/src/core_functions/aggregate/distributive/kurtosis.cpp deleted file mode 100644 index bca51bd16..000000000 --- a/src/duckdb/src/core_functions/aggregate/distributive/kurtosis.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include "duckdb/core_functions/aggregate/distributive_functions.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "duckdb/common/algorithm.hpp" - -namespace duckdb { - -struct KurtosisState { - idx_t n; - double sum; - double sum_sqr; - double sum_cub; - double sum_four; -}; - -struct KurtosisFlagBiasCorrection {}; - -struct KurtosisFlagNoBiasCorrection {}; - -template -struct KurtosisOperation { - template - static void Initialize(STATE &state) { - state.n = 0; - state.sum = state.sum_sqr = state.sum_cub = state.sum_four = 0.0; - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, - idx_t count) { - for (idx_t i = 0; i < count; i++) { - Operation(state, input, unary_input); - } - } - - template - static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input) { - state.n++; - state.sum += input; - state.sum_sqr += pow(input, 2); - state.sum_cub += pow(input, 3); - state.sum_four += pow(input, 4); - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - if (source.n == 0) { - return; - } - target.n += source.n; - target.sum += source.sum; - target.sum_sqr += source.sum_sqr; - target.sum_cub += source.sum_cub; - target.sum_four += source.sum_four; - } - - template - static void Finalize(STATE &state, TARGET_TYPE &target, AggregateFinalizeData &finalize_data) { - auto n = (double)state.n; - if (n <= 1) { - finalize_data.ReturnNull(); - return; - } - if (std::is_same::value && n <= 3) { - finalize_data.ReturnNull(); - return; - } - double temp = 1 / n; - //! This is necessary due to linux 32 bits - long double temp_aux = 1 / n; - if (state.sum_sqr - state.sum * state.sum * temp == 0 || - state.sum_sqr - state.sum * state.sum * temp_aux == 0) { - finalize_data.ReturnNull(); - return; - } - double m4 = - temp * (state.sum_four - 4 * state.sum_cub * state.sum * temp + - 6 * state.sum_sqr * state.sum * state.sum * temp * temp - 3 * pow(state.sum, 4) * pow(temp, 3)); - - double m2 = temp * (state.sum_sqr - state.sum * state.sum * temp); - if (m2 <= 0) { // m2 shouldn't be below 0 but floating points are weird - finalize_data.ReturnNull(); - return; - } - if (std::is_same::value) { - target = m4 / (m2 * m2) - 3; - } else { - target = (n - 1) * ((n + 1) * m4 / (m2 * m2) - 3 * (n - 1)) / ((n - 2) * (n - 3)); - } - if (!Value::DoubleIsFinite(target)) { - throw OutOfRangeException("Kurtosis is out of range!"); - } - } - - static bool IgnoreNull() { - return true; - } -}; - -AggregateFunction KurtosisFun::GetFunction() { - return AggregateFunction::UnaryAggregate>(LogicalType::DOUBLE, - LogicalType::DOUBLE); -} - -AggregateFunction KurtosisPopFun::GetFunction() { - return AggregateFunction::UnaryAggregate>(LogicalType::DOUBLE, - LogicalType::DOUBLE); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/distributive/product.cpp b/src/duckdb/src/core_functions/aggregate/distributive/product.cpp deleted file mode 100644 index fbe76617a..000000000 --- a/src/duckdb/src/core_functions/aggregate/distributive/product.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "duckdb/core_functions/aggregate/distributive_functions.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct ProductState { - bool empty; - double val; -}; - -struct ProductFunction { - template - static void Initialize(STATE &state) { - state.val = 1; - state.empty = true; - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - target.val *= source.val; - target.empty = target.empty && source.empty; - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.empty) { - finalize_data.ReturnNull(); - return; - } - target = state.val; - } - template - static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input) { - if (state.empty) { - state.empty = false; - } - state.val *= input; - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, - idx_t count) { - for (idx_t i = 0; i < count; i++) { - Operation(state, input, unary_input); - } - } - - static bool IgnoreNull() { - return true; - } -}; - -AggregateFunction ProductFun::GetFunction() { - return AggregateFunction::UnaryAggregate( - LogicalType(LogicalTypeId::DOUBLE), LogicalType::DOUBLE); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/distributive/skew.cpp b/src/duckdb/src/core_functions/aggregate/distributive/skew.cpp deleted file mode 100644 index ef42dce44..000000000 --- a/src/duckdb/src/core_functions/aggregate/distributive/skew.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "duckdb/core_functions/aggregate/distributive_functions.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "duckdb/common/algorithm.hpp" - -namespace duckdb { - -struct SkewState { - size_t n; - double sum; - double sum_sqr; - double sum_cub; -}; - -struct SkewnessOperation { - template - static void Initialize(STATE &state) { - state.n = 0; - state.sum = state.sum_sqr = state.sum_cub = 0; - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, - idx_t count) { - for (idx_t i = 0; i < count; i++) { - Operation(state, input, unary_input); - } - } - - template - static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input) { - state.n++; - state.sum += input; - state.sum_sqr += pow(input, 2); - state.sum_cub += pow(input, 3); - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - if (source.n == 0) { - return; - } - - target.n += source.n; - target.sum += source.sum; - target.sum_sqr += source.sum_sqr; - target.sum_cub += source.sum_cub; - } - - template - static void Finalize(STATE &state, TARGET_TYPE &target, AggregateFinalizeData &finalize_data) { - if (state.n <= 2) { - finalize_data.ReturnNull(); - return; - } - double n = state.n; - double temp = 1 / n; - auto p = std::pow(temp * (state.sum_sqr - state.sum * state.sum * temp), 3); - if (p < 0) { - p = 0; // Shouldn't be below 0 but floating points are weird - } - double div = std::sqrt(p); - if (div == 0) { - finalize_data.ReturnNull(); - return; - } - double temp1 = std::sqrt(n * (n - 1)) / (n - 2); - target = temp1 * temp * - (state.sum_cub - 3 * state.sum_sqr * state.sum * temp + 2 * pow(state.sum, 3) * temp * temp) / div; - if (!Value::DoubleIsFinite(target)) { - throw OutOfRangeException("SKEW is out of range!"); - } - } - - static bool IgnoreNull() { - return true; - } -}; - -AggregateFunction SkewnessFun::GetFunction() { - return AggregateFunction::UnaryAggregate(LogicalType::DOUBLE, - LogicalType::DOUBLE); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/distributive/string_agg.cpp b/src/duckdb/src/core_functions/aggregate/distributive/string_agg.cpp deleted file mode 100644 index f2caa8901..000000000 --- a/src/duckdb/src/core_functions/aggregate/distributive/string_agg.cpp +++ /dev/null @@ -1,175 +0,0 @@ -#include "duckdb/core_functions/aggregate/distributive_functions.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/types/null_value.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/algorithm.hpp" -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" -#include "duckdb/common/serializer/serializer.hpp" -#include "duckdb/common/serializer/deserializer.hpp" - -namespace duckdb { - -struct StringAggState { - idx_t size; - idx_t alloc_size; - char *dataptr; -}; - -struct StringAggBindData : public FunctionData { - explicit StringAggBindData(string sep_p) : sep(std::move(sep_p)) { - } - - string sep; - - unique_ptr Copy() const override { - return make_uniq(sep); - } - bool Equals(const FunctionData &other_p) const override { - auto &other = other_p.Cast(); - return sep == other.sep; - } -}; - -struct StringAggFunction { - template - static void Initialize(STATE &state) { - state.dataptr = nullptr; - state.alloc_size = 0; - state.size = 0; - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (!state.dataptr) { - finalize_data.ReturnNull(); - } else { - target = StringVector::AddString(finalize_data.result, state.dataptr, state.size); - } - } - - template - static void Destroy(STATE &state, AggregateInputData &aggr_input_data) { - if (state.dataptr) { - delete[] state.dataptr; - } - } - - static bool IgnoreNull() { - return true; - } - - static inline void PerformOperation(StringAggState &state, const char *str, const char *sep, idx_t str_size, - idx_t sep_size) { - if (!state.dataptr) { - // first iteration: allocate space for the string and copy it into the state - state.alloc_size = MaxValue(8, NextPowerOfTwo(str_size)); - state.dataptr = new char[state.alloc_size]; - state.size = str_size; - memcpy(state.dataptr, str, str_size); - } else { - // subsequent iteration: first check if we have space to place the string and separator - idx_t required_size = state.size + str_size + sep_size; - if (required_size > state.alloc_size) { - // no space! allocate extra space - while (state.alloc_size < required_size) { - state.alloc_size *= 2; - } - auto new_data = new char[state.alloc_size]; - memcpy(new_data, state.dataptr, state.size); - delete[] state.dataptr; - state.dataptr = new_data; - } - // copy the separator - memcpy(state.dataptr + state.size, sep, sep_size); - state.size += sep_size; - // copy the string - memcpy(state.dataptr + state.size, str, str_size); - state.size += str_size; - } - } - - static inline void PerformOperation(StringAggState &state, string_t str, optional_ptr data_p) { - auto &data = data_p->Cast(); - PerformOperation(state, str.GetData(), data.sep.c_str(), str.GetSize(), data.sep.size()); - } - - template - static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input) { - PerformOperation(state, input, unary_input.input.bind_data); - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, - idx_t count) { - for (idx_t i = 0; i < count; i++) { - Operation(state, input, unary_input); - } - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &aggr_input_data) { - if (!source.dataptr) { - // source is not set: skip combining - return; - } - PerformOperation(target, string_t(source.dataptr, UnsafeNumericCast(source.size)), - aggr_input_data.bind_data); - } -}; - -unique_ptr StringAggBind(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - if (arguments.size() == 1) { - // single argument: default to comma - return make_uniq(","); - } - D_ASSERT(arguments.size() == 2); - if (arguments[1]->HasParameter()) { - throw ParameterNotResolvedException(); - } - if (!arguments[1]->IsFoldable()) { - throw BinderException("Separator argument to StringAgg must be a constant"); - } - auto separator_val = ExpressionExecutor::EvaluateScalar(context, *arguments[1]); - string separator_string = ","; - if (separator_val.IsNull()) { - arguments[0] = make_uniq(Value(LogicalType::VARCHAR)); - } else { - separator_string = separator_val.ToString(); - } - Function::EraseArgument(function, arguments, arguments.size() - 1); - return make_uniq(std::move(separator_string)); -} - -static void StringAggSerialize(Serializer &serializer, const optional_ptr bind_data_p, - const AggregateFunction &function) { - auto bind_data = bind_data_p->Cast(); - serializer.WriteProperty(100, "separator", bind_data.sep); -} - -unique_ptr StringAggDeserialize(Deserializer &deserializer, AggregateFunction &bound_function) { - auto sep = deserializer.ReadProperty(100, "separator"); - return make_uniq(std::move(sep)); -} - -AggregateFunctionSet StringAggFun::GetFunctions() { - AggregateFunctionSet string_agg; - AggregateFunction string_agg_param( - {LogicalType::ANY_PARAMS(LogicalType::VARCHAR)}, LogicalType::VARCHAR, - AggregateFunction::StateSize, - AggregateFunction::StateInitialize, - AggregateFunction::UnaryScatterUpdate, - AggregateFunction::StateCombine, - AggregateFunction::StateFinalize, - AggregateFunction::UnaryUpdate, StringAggBind, - AggregateFunction::StateDestroy); - string_agg_param.serialize = StringAggSerialize; - string_agg_param.deserialize = StringAggDeserialize; - string_agg.AddFunction(string_agg_param); - string_agg_param.arguments.emplace_back(LogicalType::VARCHAR); - string_agg.AddFunction(string_agg_param); - return string_agg; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/distributive/sum.cpp b/src/duckdb/src/core_functions/aggregate/distributive/sum.cpp deleted file mode 100644 index 3aa254e34..000000000 --- a/src/duckdb/src/core_functions/aggregate/distributive/sum.cpp +++ /dev/null @@ -1,234 +0,0 @@ -#include "duckdb/core_functions/aggregate/distributive_functions.hpp" -#include "duckdb/core_functions/aggregate/sum_helpers.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/types/decimal.hpp" -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "duckdb/common/serializer/deserializer.hpp" - -namespace duckdb { - -struct SumSetOperation { - template - static void Initialize(STATE &state) { - state.Initialize(); - } - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - target.Combine(source); - } - template - static void AddValues(STATE &state, idx_t count) { - state.isset = true; - } -}; - -struct IntegerSumOperation : public BaseSumOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (!state.isset) { - finalize_data.ReturnNull(); - } else { - target = Hugeint::Convert(state.value); - } - } -}; - -struct SumToHugeintOperation : public BaseSumOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (!state.isset) { - finalize_data.ReturnNull(); - } else { - target = state.value; - } - } -}; - -template -struct DoubleSumOperation : public BaseSumOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (!state.isset) { - finalize_data.ReturnNull(); - } else { - target = state.value; - } - } -}; - -using NumericSumOperation = DoubleSumOperation; -using KahanSumOperation = DoubleSumOperation; - -struct HugeintSumOperation : public BaseSumOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (!state.isset) { - finalize_data.ReturnNull(); - } else { - target = state.value; - } - } -}; - -unique_ptr SumNoOverflowBind(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - throw BinderException("sum_no_overflow is for internal use only!"); -} - -void SumNoOverflowSerialize(Serializer &serializer, const optional_ptr bind_data, - const AggregateFunction &function) { - return; -} - -unique_ptr SumNoOverflowDeserialize(Deserializer &deserializer, AggregateFunction &function) { - function.return_type = deserializer.Get(); - return nullptr; -} - -AggregateFunction GetSumAggregateNoOverflow(PhysicalType type) { - switch (type) { - case PhysicalType::INT32: { - auto function = AggregateFunction::UnaryAggregate, int32_t, hugeint_t, IntegerSumOperation>( - LogicalType::INTEGER, LogicalType::HUGEINT); - function.name = "sum_no_overflow"; - function.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - function.bind = SumNoOverflowBind; - function.serialize = SumNoOverflowSerialize; - function.deserialize = SumNoOverflowDeserialize; - return function; - } - case PhysicalType::INT64: { - auto function = AggregateFunction::UnaryAggregate, int64_t, hugeint_t, IntegerSumOperation>( - LogicalType::BIGINT, LogicalType::HUGEINT); - function.name = "sum_no_overflow"; - function.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - function.bind = SumNoOverflowBind; - function.serialize = SumNoOverflowSerialize; - function.deserialize = SumNoOverflowDeserialize; - return function; - } - default: - throw BinderException("Unsupported internal type for sum_no_overflow"); - } -} - -AggregateFunction GetSumAggregateNoOverflowDecimal() { - AggregateFunction aggr({LogicalTypeId::DECIMAL}, LogicalTypeId::DECIMAL, nullptr, nullptr, nullptr, nullptr, - nullptr, FunctionNullHandling::DEFAULT_NULL_HANDLING, nullptr, SumNoOverflowBind); - aggr.serialize = SumNoOverflowSerialize; - aggr.deserialize = SumNoOverflowDeserialize; - return aggr; -} - -unique_ptr SumPropagateStats(ClientContext &context, BoundAggregateExpression &expr, - AggregateStatisticsInput &input) { - if (input.node_stats && input.node_stats->has_max_cardinality) { - auto &numeric_stats = input.child_stats[0]; - if (!NumericStats::HasMinMax(numeric_stats)) { - return nullptr; - } - auto internal_type = numeric_stats.GetType().InternalType(); - hugeint_t max_negative; - hugeint_t max_positive; - switch (internal_type) { - case PhysicalType::INT32: - max_negative = NumericStats::Min(numeric_stats).GetValueUnsafe(); - max_positive = NumericStats::Max(numeric_stats).GetValueUnsafe(); - break; - case PhysicalType::INT64: - max_negative = NumericStats::Min(numeric_stats).GetValueUnsafe(); - max_positive = NumericStats::Max(numeric_stats).GetValueUnsafe(); - break; - default: - throw InternalException("Unsupported type for propagate sum stats"); - } - auto max_sum_negative = max_negative * Hugeint::Convert(input.node_stats->max_cardinality); - auto max_sum_positive = max_positive * Hugeint::Convert(input.node_stats->max_cardinality); - if (max_sum_positive >= NumericLimits::Maximum() || - max_sum_negative <= NumericLimits::Minimum()) { - // sum can potentially exceed int64_t bounds: use hugeint sum - return nullptr; - } - // total sum is guaranteed to fit in a single int64: use int64 sum instead of hugeint sum - expr.function = GetSumAggregateNoOverflow(internal_type); - } - return nullptr; -} - -AggregateFunction GetSumAggregate(PhysicalType type) { - switch (type) { - case PhysicalType::INT16: { - auto function = AggregateFunction::UnaryAggregate, int16_t, hugeint_t, IntegerSumOperation>( - LogicalType::SMALLINT, LogicalType::HUGEINT); - function.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - return function; - } - - case PhysicalType::INT32: { - auto function = - AggregateFunction::UnaryAggregate, int32_t, hugeint_t, SumToHugeintOperation>( - LogicalType::INTEGER, LogicalType::HUGEINT); - function.statistics = SumPropagateStats; - function.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - return function; - } - case PhysicalType::INT64: { - auto function = - AggregateFunction::UnaryAggregate, int64_t, hugeint_t, SumToHugeintOperation>( - LogicalType::BIGINT, LogicalType::HUGEINT); - function.statistics = SumPropagateStats; - function.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - return function; - } - case PhysicalType::INT128: { - auto function = - AggregateFunction::UnaryAggregate, hugeint_t, hugeint_t, HugeintSumOperation>( - LogicalType::HUGEINT, LogicalType::HUGEINT); - function.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - return function; - } - default: - throw InternalException("Unimplemented sum aggregate"); - } -} - -unique_ptr BindDecimalSum(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - auto decimal_type = arguments[0]->return_type; - function = GetSumAggregate(decimal_type.InternalType()); - function.name = "sum"; - function.arguments[0] = decimal_type; - function.return_type = LogicalType::DECIMAL(Decimal::MAX_WIDTH_DECIMAL, DecimalType::GetScale(decimal_type)); - function.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - return nullptr; -} - -AggregateFunctionSet SumFun::GetFunctions() { - AggregateFunctionSet sum; - // decimal - sum.AddFunction(AggregateFunction({LogicalTypeId::DECIMAL}, LogicalTypeId::DECIMAL, nullptr, nullptr, nullptr, - nullptr, nullptr, FunctionNullHandling::DEFAULT_NULL_HANDLING, nullptr, - BindDecimalSum)); - sum.AddFunction(GetSumAggregate(PhysicalType::INT16)); - sum.AddFunction(GetSumAggregate(PhysicalType::INT32)); - sum.AddFunction(GetSumAggregate(PhysicalType::INT64)); - sum.AddFunction(GetSumAggregate(PhysicalType::INT128)); - sum.AddFunction(AggregateFunction::UnaryAggregate, double, double, NumericSumOperation>( - LogicalType::DOUBLE, LogicalType::DOUBLE)); - return sum; -} - -AggregateFunctionSet SumNoOverflowFun::GetFunctions() { - AggregateFunctionSet sum_no_overflow; - sum_no_overflow.AddFunction(GetSumAggregateNoOverflow(PhysicalType::INT32)); - sum_no_overflow.AddFunction(GetSumAggregateNoOverflow(PhysicalType::INT64)); - sum_no_overflow.AddFunction(GetSumAggregateNoOverflowDecimal()); - return sum_no_overflow; -} - -AggregateFunction KahanSumFun::GetFunction() { - return AggregateFunction::UnaryAggregate(LogicalType::DOUBLE, - LogicalType::DOUBLE); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/holistic/approx_top_k.cpp b/src/duckdb/src/core_functions/aggregate/holistic/approx_top_k.cpp deleted file mode 100644 index b1cf41e08..000000000 --- a/src/duckdb/src/core_functions/aggregate/holistic/approx_top_k.cpp +++ /dev/null @@ -1,413 +0,0 @@ -#include "duckdb/core_functions/aggregate/histogram_helpers.hpp" -#include "duckdb/core_functions/aggregate/holistic_functions.hpp" -#include "duckdb/core_functions/aggregate/sort_key_helpers.hpp" -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/common/string_map_set.hpp" -#include "duckdb/common/printer.hpp" - -namespace duckdb { - -struct ApproxTopKString { - ApproxTopKString() : str(UINT32_C(0)), hash(0) { - } - ApproxTopKString(string_t str_p, hash_t hash_p) : str(str_p), hash(hash_p) { - } - - string_t str; - hash_t hash; -}; - -struct ApproxTopKHash { - std::size_t operator()(const ApproxTopKString &k) const { - return k.hash; - } -}; - -struct ApproxTopKEquality { - bool operator()(const ApproxTopKString &a, const ApproxTopKString &b) const { - return Equals::Operation(a.str, b.str); - } -}; - -template -using approx_topk_map_t = unordered_map; - -// approx top k algorithm based on "A parallel space saving algorithm for frequent items and the Hurwitz zeta -// distribution" arxiv link - https://arxiv.org/pdf/1401.0702 -// together with the filter extension (Filtered Space-Saving) from "Estimating Top-k Destinations in Data Streams" -struct ApproxTopKValue { - //! The counter - idx_t count = 0; - //! Index in the values array - idx_t index = 0; - //! The string value - ApproxTopKString str_val; - //! Allocated data - char *dataptr = nullptr; - uint32_t size = 0; - uint32_t capacity = 0; -}; - -struct InternalApproxTopKState { - // the top-k data structure has two components - // a list of k values sorted on "count" (i.e. values[0] has the lowest count) - // a lookup map: string_t -> idx in "values" array - unsafe_unique_array stored_values; - unsafe_vector> values; - approx_topk_map_t> lookup_map; - unsafe_vector filter; - idx_t k = 0; - idx_t capacity = 0; - idx_t filter_mask; - - void Initialize(idx_t kval) { - static constexpr idx_t MONITORED_VALUES_RATIO = 3; - static constexpr idx_t FILTER_RATIO = 8; - - D_ASSERT(values.empty()); - D_ASSERT(lookup_map.empty()); - k = kval; - capacity = kval * MONITORED_VALUES_RATIO; - stored_values = make_unsafe_uniq_array_uninitialized(capacity); - values.reserve(capacity); - - // we scale the filter based on the amount of values we are monitoring - idx_t filter_size = NextPowerOfTwo(capacity * FILTER_RATIO); - filter_mask = filter_size - 1; - filter.resize(filter_size); - } - - static void CopyValue(ApproxTopKValue &value, const ApproxTopKString &input, AggregateInputData &input_data) { - value.str_val.hash = input.hash; - if (input.str.IsInlined()) { - // no need to copy - value.str_val = input; - return; - } - value.size = UnsafeNumericCast(input.str.GetSize()); - if (value.size > value.capacity) { - // need to re-allocate for this value - value.capacity = UnsafeNumericCast(NextPowerOfTwo(value.size)); - value.dataptr = char_ptr_cast(input_data.allocator.Allocate(value.capacity)); - } - // copy over the data - memcpy(value.dataptr, input.str.GetData(), value.size); - value.str_val.str = string_t(value.dataptr, value.size); - } - - void InsertOrReplaceEntry(const ApproxTopKString &input, AggregateInputData &aggr_input, idx_t increment = 1) { - if (values.size() < capacity) { - D_ASSERT(increment > 0); - // we can always add this entry - auto &val = stored_values[values.size()]; - val.index = values.size(); - values.push_back(val); - } - auto &value = values.back().get(); - if (value.count > 0) { - // the capacity is reached - we need to replace an entry - - // we use the filter as an early out - // based on the hash - we find a slot in the filter - // instead of monitoring the value immediately, we add to the slot in the filter - // ONLY when the value in the filter exceeds the current min value, we start monitoring the value - // this speeds up the algorithm as switching monitor values means we need to erase/insert in the hash table - auto &filter_value = filter[input.hash & filter_mask]; - if (filter_value + increment < value.count) { - // if the filter has a lower count than the current min count - // we can skip adding this entry (for now) - filter_value += increment; - return; - } - // the filter exceeds the min value - start monitoring this value - // erase the existing entry from the map - // and set the filter for the minimum value back to the current minimum value - filter[value.str_val.hash & filter_mask] = value.count; - lookup_map.erase(value.str_val); - } - CopyValue(value, input, aggr_input); - lookup_map.insert(make_pair(value.str_val, reference(value))); - IncrementCount(value, increment); - } - - void IncrementCount(ApproxTopKValue &value, idx_t increment = 1) { - value.count += increment; - // maintain sortedness of "values" - // swap while we have a higher count than the next entry - while (value.index > 0 && values[value.index].get().count > values[value.index - 1].get().count) { - // swap the elements around - auto &left = values[value.index]; - auto &right = values[value.index - 1]; - std::swap(left.get().index, right.get().index); - std::swap(left, right); - } - } - - void Verify() const { -#ifdef DEBUG - if (values.empty()) { - D_ASSERT(lookup_map.empty()); - return; - } - D_ASSERT(values.size() <= capacity); - for (idx_t k = 0; k < values.size(); k++) { - auto &val = values[k].get(); - D_ASSERT(val.count > 0); - // verify map exists - auto entry = lookup_map.find(val.str_val); - D_ASSERT(entry != lookup_map.end()); - // verify the index is correct - D_ASSERT(val.index == k); - if (k > 0) { - // sortedness - D_ASSERT(val.count <= values[k - 1].get().count); - } - } - // verify lookup map does not contain extra entries - D_ASSERT(lookup_map.size() == values.size()); -#endif - } -}; - -struct ApproxTopKState { - InternalApproxTopKState *state; - - InternalApproxTopKState &GetState() { - if (!state) { - state = new InternalApproxTopKState(); - } - return *state; - } - - const InternalApproxTopKState &GetState() const { - if (!state) { - throw InternalException("No state available"); - } - return *state; - } -}; - -struct ApproxTopKOperation { - template - static void Initialize(STATE &state) { - state.state = nullptr; - } - - template - static void Operation(STATE &aggr_state, const TYPE &input, AggregateInputData &aggr_input, Vector &top_k_vector, - idx_t offset, idx_t count) { - auto &state = aggr_state.GetState(); - if (state.values.empty()) { - static constexpr int64_t MAX_APPROX_K = 1000000; - // not initialized yet - initialize the K value and set all counters to 0 - UnifiedVectorFormat kdata; - top_k_vector.ToUnifiedFormat(count, kdata); - auto kidx = kdata.sel->get_index(offset); - if (!kdata.validity.RowIsValid(kidx)) { - throw InvalidInputException("Invalid input for approx_top_k: k value cannot be NULL"); - } - auto kval = UnifiedVectorFormat::GetData(kdata)[kidx]; - if (kval <= 0) { - throw InvalidInputException("Invalid input for approx_top_k: k value must be > 0"); - } - if (kval >= MAX_APPROX_K) { - throw InvalidInputException("Invalid input for approx_top_k: k value must be < %d", MAX_APPROX_K); - } - state.Initialize(UnsafeNumericCast(kval)); - } - ApproxTopKString topk_string(input, Hash(input)); - auto entry = state.lookup_map.find(topk_string); - if (entry != state.lookup_map.end()) { - // the input is monitored - increment the count - state.IncrementCount(entry->second.get()); - } else { - // the input is not monitored - replace the first entry with the current entry and increment - state.InsertOrReplaceEntry(topk_string, aggr_input); - } - } - - template - static void Combine(const STATE &aggr_source, STATE &aggr_target, AggregateInputData &aggr_input) { - if (!aggr_source.state) { - // source state is empty - return; - } - auto &source = aggr_source.GetState(); - auto &target = aggr_target.GetState(); - if (source.values.empty()) { - // source is empty - return; - } - source.Verify(); - auto min_source = source.values.back().get().count; - idx_t min_target; - if (target.values.empty()) { - min_target = 0; - target.Initialize(source.k); - } else { - if (source.k != target.k) { - throw NotImplementedException("Approx Top K - cannot combine approx_top_K with different k values. " - "K values must be the same for all entries within the same group"); - } - min_target = target.values.back().get().count; - } - // for all entries in target - // check if they are tracked in source - // if they do - add the tracked count - // if they do not - add the minimum count - for (idx_t target_idx = 0; target_idx < target.values.size(); target_idx++) { - auto &val = target.values[target_idx].get(); - auto source_entry = source.lookup_map.find(val.str_val); - idx_t increment = min_source; - if (source_entry != source.lookup_map.end()) { - increment = source_entry->second.get().count; - } - if (increment == 0) { - continue; - } - target.IncrementCount(val, increment); - } - // now for each entry in source, if it is not tracked by the target, at the target minimum - for (auto &source_entry : source.values) { - auto &source_val = source_entry.get(); - auto target_entry = target.lookup_map.find(source_val.str_val); - if (target_entry != target.lookup_map.end()) { - // already tracked - no need to add anything - continue; - } - auto new_count = source_val.count + min_target; - idx_t increment; - if (target.values.size() >= target.capacity) { - idx_t current_min = target.values.empty() ? 0 : target.values.back().get().count; - D_ASSERT(target.values.size() == target.capacity); - // target already has capacity values - // check if we should insert this entry - if (new_count <= current_min) { - // if we do not we can skip this entry - continue; - } - increment = new_count - current_min; - } else { - // target does not have capacity entries yet - // just add this entry with the full count - increment = new_count; - } - target.InsertOrReplaceEntry(source_val.str_val, aggr_input, increment); - } - // copy over the filter - D_ASSERT(source.filter.size() == target.filter.size()); - for (idx_t filter_idx = 0; filter_idx < source.filter.size(); filter_idx++) { - target.filter[filter_idx] += source.filter[filter_idx]; - } - target.Verify(); - } - - template - static void Destroy(STATE &state, AggregateInputData &aggr_input_data) { - delete state.state; - } - - static bool IgnoreNull() { - return true; - } -}; - -template -static void ApproxTopKUpdate(Vector inputs[], AggregateInputData &aggr_input, idx_t input_count, Vector &state_vector, - idx_t count) { - using STATE = ApproxTopKState; - auto &input = inputs[0]; - UnifiedVectorFormat sdata; - state_vector.ToUnifiedFormat(count, sdata); - - auto &top_k_vector = inputs[1]; - - auto extra_state = OP::CreateExtraState(count); - UnifiedVectorFormat input_data; - OP::PrepareData(input, count, extra_state, input_data); - - auto states = UnifiedVectorFormat::GetData(sdata); - auto data = UnifiedVectorFormat::GetData(input_data); - for (idx_t i = 0; i < count; i++) { - auto idx = input_data.sel->get_index(i); - if (!input_data.validity.RowIsValid(idx)) { - continue; - } - auto &state = *states[sdata.sel->get_index(i)]; - ApproxTopKOperation::Operation(state, data[idx], aggr_input, top_k_vector, i, count); - } -} - -template -static void ApproxTopKFinalize(Vector &state_vector, AggregateInputData &, Vector &result, idx_t count, idx_t offset) { - UnifiedVectorFormat sdata; - state_vector.ToUnifiedFormat(count, sdata); - auto states = UnifiedVectorFormat::GetData(sdata); - - auto &mask = FlatVector::Validity(result); - auto old_len = ListVector::GetListSize(result); - idx_t new_entries = 0; - // figure out how much space we need - for (idx_t i = 0; i < count; i++) { - auto &state = states[sdata.sel->get_index(i)]->GetState(); - if (state.values.empty()) { - continue; - } - // get up to k values for each state - // this can be less of fewer unique values were found - new_entries += MinValue(state.values.size(), state.k); - } - // reserve space in the list vector - ListVector::Reserve(result, old_len + new_entries); - auto list_entries = FlatVector::GetData(result); - auto &child_data = ListVector::GetEntry(result); - - idx_t current_offset = old_len; - for (idx_t i = 0; i < count; i++) { - const auto rid = i + offset; - auto &state = states[sdata.sel->get_index(i)]->GetState(); - if (state.values.empty()) { - mask.SetInvalid(rid); - continue; - } - auto &list_entry = list_entries[rid]; - list_entry.offset = current_offset; - for (idx_t val_idx = 0; val_idx < MinValue(state.values.size(), state.k); val_idx++) { - auto &val = state.values[val_idx].get(); - D_ASSERT(val.count > 0); - OP::template HistogramFinalize(val.str_val.str, child_data, current_offset); - current_offset++; - } - list_entry.length = current_offset - list_entry.offset; - } - D_ASSERT(current_offset == old_len + new_entries); - ListVector::SetListSize(result, current_offset); - result.Verify(count); -} - -unique_ptr ApproxTopKBind(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - for (auto &arg : arguments) { - if (arg->return_type.id() == LogicalTypeId::UNKNOWN) { - throw ParameterNotResolvedException(); - } - } - if (arguments[0]->return_type.id() == LogicalTypeId::VARCHAR) { - function.update = ApproxTopKUpdate; - function.finalize = ApproxTopKFinalize; - } - function.return_type = LogicalType::LIST(arguments[0]->return_type); - return nullptr; -} - -AggregateFunction ApproxTopKFun::GetFunction() { - using STATE = ApproxTopKState; - using OP = ApproxTopKOperation; - return AggregateFunction("approx_top_k", {LogicalTypeId::ANY, LogicalType::BIGINT}, - LogicalType::LIST(LogicalType::ANY), AggregateFunction::StateSize, - AggregateFunction::StateInitialize, ApproxTopKUpdate, - AggregateFunction::StateCombine, ApproxTopKFinalize, nullptr, ApproxTopKBind, - AggregateFunction::StateDestroy); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/holistic/approximate_quantile.cpp b/src/duckdb/src/core_functions/aggregate/holistic/approximate_quantile.cpp deleted file mode 100644 index 5b6abcd20..000000000 --- a/src/duckdb/src/core_functions/aggregate/holistic/approximate_quantile.cpp +++ /dev/null @@ -1,408 +0,0 @@ -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/core_functions/aggregate/holistic_functions.hpp" -#include "t_digest.hpp" -#include "duckdb/planner/expression.hpp" -#include "duckdb/common/operator/cast_operators.hpp" -#include "duckdb/common/serializer/serializer.hpp" -#include "duckdb/common/serializer/deserializer.hpp" - -#include -#include -#include - -namespace duckdb { - -struct ApproxQuantileState { - duckdb_tdigest::TDigest *h; - idx_t pos; -}; - -struct ApproximateQuantileBindData : public FunctionData { - ApproximateQuantileBindData() { - } - explicit ApproximateQuantileBindData(float quantile_p) : quantiles(1, quantile_p) { - } - - explicit ApproximateQuantileBindData(vector quantiles_p) : quantiles(std::move(quantiles_p)) { - } - - unique_ptr Copy() const override { - return make_uniq(quantiles); - } - - bool Equals(const FunctionData &other_p) const override { - auto &other = other_p.Cast(); - // return quantiles == other.quantiles; - if (quantiles != other.quantiles) { - return false; - } - return true; - } - - static void Serialize(Serializer &serializer, const optional_ptr bind_data_p, - const AggregateFunction &function) { - auto &bind_data = bind_data_p->Cast(); - serializer.WriteProperty(100, "quantiles", bind_data.quantiles); - } - - static unique_ptr Deserialize(Deserializer &deserializer, AggregateFunction &function) { - auto result = make_uniq(); - deserializer.ReadProperty(100, "quantiles", result->quantiles); - return std::move(result); - } - - vector quantiles; -}; - -struct ApproxQuantileOperation { - using SAVE_TYPE = duckdb_tdigest::Value; - - template - static void Initialize(STATE &state) { - state.pos = 0; - state.h = nullptr; - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, - idx_t count) { - for (idx_t i = 0; i < count; i++) { - Operation(state, input, unary_input); - } - } - - template - static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input) { - auto val = Cast::template Operation(input); - if (!Value::DoubleIsFinite(val)) { - return; - } - if (!state.h) { - state.h = new duckdb_tdigest::TDigest(100); - } - state.h->add(val); - state.pos++; - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - if (source.pos == 0) { - return; - } - D_ASSERT(source.h); - if (!target.h) { - target.h = new duckdb_tdigest::TDigest(100); - } - target.h->merge(source.h); - target.pos += source.pos; - } - - template - static void Destroy(STATE &state, AggregateInputData &aggr_input_data) { - if (state.h) { - delete state.h; - } - } - - static bool IgnoreNull() { - return true; - } -}; - -struct ApproxQuantileScalarOperation : public ApproxQuantileOperation { - template - static void Finalize(STATE &state, TARGET_TYPE &target, AggregateFinalizeData &finalize_data) { - if (state.pos == 0) { - finalize_data.ReturnNull(); - return; - } - D_ASSERT(state.h); - D_ASSERT(finalize_data.input.bind_data); - state.h->compress(); - auto &bind_data = finalize_data.input.bind_data->template Cast(); - D_ASSERT(bind_data.quantiles.size() == 1); - // The result is approximate, so clamp instead of overflowing. - const auto source = state.h->quantile(bind_data.quantiles[0]); - if (TryCast::Operation(source, target, false)) { - return; - } else if (source < 0) { - target = NumericLimits::Minimum(); - } else { - target = NumericLimits::Maximum(); - } - } -}; - -static AggregateFunction GetApproximateQuantileAggregateFunction(const LogicalType &type) { - // Not binary comparable - if (type == LogicalType::TIME_TZ) { - return AggregateFunction::UnaryAggregateDestructor(type, type); - } - switch (type.InternalType()) { - case PhysicalType::INT8: - return AggregateFunction::UnaryAggregateDestructor(type, type); - case PhysicalType::INT16: - return AggregateFunction::UnaryAggregateDestructor(type, type); - case PhysicalType::INT32: - return AggregateFunction::UnaryAggregateDestructor(type, type); - case PhysicalType::INT64: - return AggregateFunction::UnaryAggregateDestructor(type, type); - case PhysicalType::INT128: - return AggregateFunction::UnaryAggregateDestructor(type, type); - case PhysicalType::FLOAT: - return AggregateFunction::UnaryAggregateDestructor(type, type); - case PhysicalType::DOUBLE: - return AggregateFunction::UnaryAggregateDestructor(type, type); - default: - throw InternalException("Unimplemented quantile aggregate"); - } -} - -static AggregateFunction GetApproximateQuantileDecimalAggregateFunction(const LogicalType &type) { - switch (type.InternalType()) { - case PhysicalType::INT8: - return GetApproximateQuantileAggregateFunction(LogicalType::TINYINT); - case PhysicalType::INT16: - return GetApproximateQuantileAggregateFunction(LogicalType::SMALLINT); - case PhysicalType::INT32: - return GetApproximateQuantileAggregateFunction(LogicalType::INTEGER); - case PhysicalType::INT64: - return GetApproximateQuantileAggregateFunction(LogicalType::BIGINT); - case PhysicalType::INT128: - return GetApproximateQuantileAggregateFunction(LogicalType::HUGEINT); - default: - throw InternalException("Unimplemented quantile decimal aggregate"); - } -} - -static float CheckApproxQuantile(const Value &quantile_val) { - if (quantile_val.IsNull()) { - throw BinderException("APPROXIMATE QUANTILE parameter cannot be NULL"); - } - auto quantile = quantile_val.GetValue(); - if (quantile < 0 || quantile > 1) { - throw BinderException("APPROXIMATE QUANTILE can only take parameters in range [0, 1]"); - } - - return quantile; -} - -unique_ptr BindApproxQuantile(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - if (arguments[1]->HasParameter()) { - throw ParameterNotResolvedException(); - } - if (!arguments[1]->IsFoldable()) { - throw BinderException("APPROXIMATE QUANTILE can only take constant quantile parameters"); - } - Value quantile_val = ExpressionExecutor::EvaluateScalar(context, *arguments[1]); - if (quantile_val.IsNull()) { - throw BinderException("APPROXIMATE QUANTILE parameter list cannot be NULL"); - } - - vector quantiles; - switch (quantile_val.type().id()) { - case LogicalTypeId::LIST: - for (const auto &element_val : ListValue::GetChildren(quantile_val)) { - quantiles.push_back(CheckApproxQuantile(element_val)); - } - break; - case LogicalTypeId::ARRAY: - for (const auto &element_val : ArrayValue::GetChildren(quantile_val)) { - quantiles.push_back(CheckApproxQuantile(element_val)); - } - break; - default: - quantiles.push_back(CheckApproxQuantile(quantile_val)); - break; - } - - // remove the quantile argument so we can use the unary aggregate - Function::EraseArgument(function, arguments, arguments.size() - 1); - return make_uniq(quantiles); -} - -unique_ptr BindApproxQuantileDecimal(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - auto bind_data = BindApproxQuantile(context, function, arguments); - function = GetApproximateQuantileDecimalAggregateFunction(arguments[0]->return_type); - function.name = "approx_quantile"; - function.serialize = ApproximateQuantileBindData::Serialize; - function.deserialize = ApproximateQuantileBindData::Deserialize; - return bind_data; -} - -AggregateFunction GetApproximateQuantileAggregate(const LogicalType &type) { - auto fun = GetApproximateQuantileAggregateFunction(type); - fun.bind = BindApproxQuantile; - fun.serialize = ApproximateQuantileBindData::Serialize; - fun.deserialize = ApproximateQuantileBindData::Deserialize; - // temporarily push an argument so we can bind the actual quantile - fun.arguments.emplace_back(LogicalType::FLOAT); - return fun; -} - -template -struct ApproxQuantileListOperation : public ApproxQuantileOperation { - - template - static void Finalize(STATE &state, RESULT_TYPE &target, AggregateFinalizeData &finalize_data) { - if (state.pos == 0) { - finalize_data.ReturnNull(); - return; - } - - D_ASSERT(finalize_data.input.bind_data); - auto &bind_data = finalize_data.input.bind_data->template Cast(); - - auto &result = ListVector::GetEntry(finalize_data.result); - auto ridx = ListVector::GetListSize(finalize_data.result); - ListVector::Reserve(finalize_data.result, ridx + bind_data.quantiles.size()); - auto rdata = FlatVector::GetData(result); - - D_ASSERT(state.h); - state.h->compress(); - - auto &entry = target; - entry.offset = ridx; - entry.length = bind_data.quantiles.size(); - for (size_t q = 0; q < entry.length; ++q) { - const auto &quantile = bind_data.quantiles[q]; - rdata[ridx + q] = Cast::template Operation(state.h->quantile(quantile)); - } - - ListVector::SetListSize(finalize_data.result, entry.offset + entry.length); - } -}; - -template -static AggregateFunction ApproxQuantileListAggregate(const LogicalType &input_type, const LogicalType &child_type) { - LogicalType result_type = LogicalType::LIST(child_type); - return AggregateFunction( - {input_type}, result_type, AggregateFunction::StateSize, AggregateFunction::StateInitialize, - AggregateFunction::UnaryScatterUpdate, AggregateFunction::StateCombine, - AggregateFunction::StateFinalize, AggregateFunction::UnaryUpdate, - nullptr, AggregateFunction::StateDestroy); -} - -template -AggregateFunction GetTypedApproxQuantileListAggregateFunction(const LogicalType &type) { - using STATE = ApproxQuantileState; - using OP = ApproxQuantileListOperation; - auto fun = ApproxQuantileListAggregate(type, type); - fun.serialize = ApproximateQuantileBindData::Serialize; - fun.deserialize = ApproximateQuantileBindData::Deserialize; - return fun; -} - -AggregateFunction GetApproxQuantileListAggregateFunction(const LogicalType &type) { - switch (type.id()) { - case LogicalTypeId::TINYINT: - return GetTypedApproxQuantileListAggregateFunction(type); - case LogicalTypeId::SMALLINT: - return GetTypedApproxQuantileListAggregateFunction(type); - case LogicalTypeId::INTEGER: - case LogicalTypeId::DATE: - case LogicalTypeId::TIME: - return GetTypedApproxQuantileListAggregateFunction(type); - case LogicalTypeId::BIGINT: - case LogicalTypeId::TIMESTAMP: - case LogicalTypeId::TIMESTAMP_TZ: - return GetTypedApproxQuantileListAggregateFunction(type); - case LogicalTypeId::TIME_TZ: - // Not binary comparable - return GetTypedApproxQuantileListAggregateFunction(type); - case LogicalTypeId::HUGEINT: - return GetTypedApproxQuantileListAggregateFunction(type); - case LogicalTypeId::FLOAT: - return GetTypedApproxQuantileListAggregateFunction(type); - case LogicalTypeId::DOUBLE: - return GetTypedApproxQuantileListAggregateFunction(type); - case LogicalTypeId::DECIMAL: - switch (type.InternalType()) { - case PhysicalType::INT16: - return GetTypedApproxQuantileListAggregateFunction(type); - case PhysicalType::INT32: - return GetTypedApproxQuantileListAggregateFunction(type); - case PhysicalType::INT64: - return GetTypedApproxQuantileListAggregateFunction(type); - case PhysicalType::INT128: - return GetTypedApproxQuantileListAggregateFunction(type); - default: - throw NotImplementedException("Unimplemented approximate quantile list decimal aggregate"); - } - default: - throw NotImplementedException("Unimplemented approximate quantile list aggregate"); - } -} - -unique_ptr BindApproxQuantileDecimalList(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - auto bind_data = BindApproxQuantile(context, function, arguments); - function = GetApproxQuantileListAggregateFunction(arguments[0]->return_type); - function.name = "approx_quantile"; - function.serialize = ApproximateQuantileBindData::Serialize; - function.deserialize = ApproximateQuantileBindData::Deserialize; - return bind_data; -} - -AggregateFunction GetApproxQuantileListAggregate(const LogicalType &type) { - auto fun = GetApproxQuantileListAggregateFunction(type); - fun.bind = BindApproxQuantile; - fun.serialize = ApproximateQuantileBindData::Serialize; - fun.deserialize = ApproximateQuantileBindData::Deserialize; - // temporarily push an argument so we can bind the actual quantile - auto list_of_float = LogicalType::LIST(LogicalType::FLOAT); - fun.arguments.push_back(list_of_float); - return fun; -} - -AggregateFunctionSet ApproxQuantileFun::GetFunctions() { - AggregateFunctionSet approx_quantile; - approx_quantile.AddFunction(AggregateFunction({LogicalTypeId::DECIMAL, LogicalType::FLOAT}, LogicalTypeId::DECIMAL, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - BindApproxQuantileDecimal)); - - approx_quantile.AddFunction(GetApproximateQuantileAggregate(LogicalType::SMALLINT)); - approx_quantile.AddFunction(GetApproximateQuantileAggregate(LogicalType::INTEGER)); - approx_quantile.AddFunction(GetApproximateQuantileAggregate(LogicalType::BIGINT)); - approx_quantile.AddFunction(GetApproximateQuantileAggregate(LogicalType::HUGEINT)); - approx_quantile.AddFunction(GetApproximateQuantileAggregate(LogicalType::DOUBLE)); - - approx_quantile.AddFunction(GetApproximateQuantileAggregate(LogicalType::DATE)); - approx_quantile.AddFunction(GetApproximateQuantileAggregate(LogicalType::TIME)); - approx_quantile.AddFunction(GetApproximateQuantileAggregate(LogicalType::TIME_TZ)); - approx_quantile.AddFunction(GetApproximateQuantileAggregate(LogicalType::TIMESTAMP)); - approx_quantile.AddFunction(GetApproximateQuantileAggregate(LogicalType::TIMESTAMP_TZ)); - - // List variants - approx_quantile.AddFunction(AggregateFunction({LogicalTypeId::DECIMAL, LogicalType::LIST(LogicalType::FLOAT)}, - LogicalType::LIST(LogicalTypeId::DECIMAL), nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, BindApproxQuantileDecimalList)); - - approx_quantile.AddFunction(GetApproxQuantileListAggregate(LogicalTypeId::TINYINT)); - approx_quantile.AddFunction(GetApproxQuantileListAggregate(LogicalTypeId::SMALLINT)); - approx_quantile.AddFunction(GetApproxQuantileListAggregate(LogicalTypeId::INTEGER)); - approx_quantile.AddFunction(GetApproxQuantileListAggregate(LogicalTypeId::BIGINT)); - approx_quantile.AddFunction(GetApproxQuantileListAggregate(LogicalTypeId::HUGEINT)); - approx_quantile.AddFunction(GetApproxQuantileListAggregate(LogicalTypeId::FLOAT)); - approx_quantile.AddFunction(GetApproxQuantileListAggregate(LogicalTypeId::DOUBLE)); - - approx_quantile.AddFunction(GetApproxQuantileListAggregate(LogicalType::DATE)); - approx_quantile.AddFunction(GetApproxQuantileListAggregate(LogicalType::TIME)); - approx_quantile.AddFunction(GetApproxQuantileListAggregate(LogicalType::TIME_TZ)); - approx_quantile.AddFunction(GetApproxQuantileListAggregate(LogicalType::TIMESTAMP)); - approx_quantile.AddFunction(GetApproxQuantileListAggregate(LogicalType::TIMESTAMP_TZ)); - - return approx_quantile; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/holistic/mad.cpp b/src/duckdb/src/core_functions/aggregate/holistic/mad.cpp deleted file mode 100644 index 8be7415ff..000000000 --- a/src/duckdb/src/core_functions/aggregate/holistic/mad.cpp +++ /dev/null @@ -1,330 +0,0 @@ -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/core_functions/aggregate/holistic_functions.hpp" -#include "duckdb/planner/expression.hpp" -#include "duckdb/common/operator/cast_operators.hpp" -#include "duckdb/common/operator/abs.hpp" -#include "duckdb/core_functions/aggregate/quantile_state.hpp" - -namespace duckdb { - -struct FrameSet { - inline explicit FrameSet(const SubFrames &frames_p) : frames(frames_p) { - } - - inline idx_t Size() const { - idx_t result = 0; - for (const auto &frame : frames) { - result += frame.end - frame.start; - } - - return result; - } - - inline bool Contains(idx_t i) const { - for (idx_t f = 0; f < frames.size(); ++f) { - const auto &frame = frames[f]; - if (frame.start <= i && i < frame.end) { - return true; - } - } - return false; - } - const SubFrames &frames; -}; - -struct QuantileReuseUpdater { - idx_t *index; - idx_t j; - - inline QuantileReuseUpdater(idx_t *index, idx_t j) : index(index), j(j) { - } - - inline void Neither(idx_t begin, idx_t end) { - } - - inline void Left(idx_t begin, idx_t end) { - } - - inline void Right(idx_t begin, idx_t end) { - for (; begin < end; ++begin) { - index[j++] = begin; - } - } - - inline void Both(idx_t begin, idx_t end) { - } -}; - -void ReuseIndexes(idx_t *index, const SubFrames &currs, const SubFrames &prevs) { - - // Copy overlapping indices by scanning the previous set and copying down into holes. - // We copy instead of leaving gaps in case there are fewer values in the current frame. - FrameSet prev_set(prevs); - FrameSet curr_set(currs); - const auto prev_count = prev_set.Size(); - idx_t j = 0; - for (idx_t p = 0; p < prev_count; ++p) { - auto idx = index[p]; - - // Shift down into any hole - if (j != p) { - index[j] = idx; - } - - // Skip overlapping values - if (curr_set.Contains(idx)) { - ++j; - } - } - - // Insert new indices - if (j > 0) { - QuantileReuseUpdater updater(index, j); - AggregateExecutor::IntersectFrames(prevs, currs, updater); - } else { - // No overlap: overwrite with new values - for (const auto &curr : currs) { - for (auto idx = curr.start; idx < curr.end; ++idx) { - index[j++] = idx; - } - } - } -} - -//===--------------------------------------------------------------------===// -// Median Absolute Deviation -//===--------------------------------------------------------------------===// -template -struct MadAccessor { - using INPUT_TYPE = T; - using RESULT_TYPE = R; - const MEDIAN_TYPE &median; - explicit MadAccessor(const MEDIAN_TYPE &median_p) : median(median_p) { - } - - inline RESULT_TYPE operator()(const INPUT_TYPE &input) const { - const RESULT_TYPE delta = input - UnsafeNumericCast(median); - return TryAbsOperator::Operation(delta); - } -}; - -// hugeint_t - double => undefined -template <> -struct MadAccessor { - using INPUT_TYPE = hugeint_t; - using RESULT_TYPE = double; - using MEDIAN_TYPE = double; - const MEDIAN_TYPE &median; - explicit MadAccessor(const MEDIAN_TYPE &median_p) : median(median_p) { - } - inline RESULT_TYPE operator()(const INPUT_TYPE &input) const { - const auto delta = Hugeint::Cast(input) - median; - return TryAbsOperator::Operation(delta); - } -}; - -// date_t - timestamp_t => interval_t -template <> -struct MadAccessor { - using INPUT_TYPE = date_t; - using RESULT_TYPE = interval_t; - using MEDIAN_TYPE = timestamp_t; - const MEDIAN_TYPE &median; - explicit MadAccessor(const MEDIAN_TYPE &median_p) : median(median_p) { - } - inline RESULT_TYPE operator()(const INPUT_TYPE &input) const { - const auto dt = Cast::Operation(input); - const auto delta = dt - median; - return Interval::FromMicro(TryAbsOperator::Operation(delta)); - } -}; - -// timestamp_t - timestamp_t => int64_t -template <> -struct MadAccessor { - using INPUT_TYPE = timestamp_t; - using RESULT_TYPE = interval_t; - using MEDIAN_TYPE = timestamp_t; - const MEDIAN_TYPE &median; - explicit MadAccessor(const MEDIAN_TYPE &median_p) : median(median_p) { - } - inline RESULT_TYPE operator()(const INPUT_TYPE &input) const { - const auto delta = input - median; - return Interval::FromMicro(TryAbsOperator::Operation(delta)); - } -}; - -// dtime_t - dtime_t => int64_t -template <> -struct MadAccessor { - using INPUT_TYPE = dtime_t; - using RESULT_TYPE = interval_t; - using MEDIAN_TYPE = dtime_t; - const MEDIAN_TYPE &median; - explicit MadAccessor(const MEDIAN_TYPE &median_p) : median(median_p) { - } - inline RESULT_TYPE operator()(const INPUT_TYPE &input) const { - const auto delta = input - median; - return Interval::FromMicro(TryAbsOperator::Operation(delta)); - } -}; - -template -struct MedianAbsoluteDeviationOperation : QuantileOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.v.empty()) { - finalize_data.ReturnNull(); - return; - } - using INPUT_TYPE = typename STATE::InputType; - D_ASSERT(finalize_data.input.bind_data); - auto &bind_data = finalize_data.input.bind_data->Cast(); - D_ASSERT(bind_data.quantiles.size() == 1); - const auto &q = bind_data.quantiles[0]; - Interpolator interp(q, state.v.size(), false); - const auto med = interp.template Operation(state.v.data(), finalize_data.result); - - MadAccessor accessor(med); - target = interp.template Operation(state.v.data(), finalize_data.result, accessor); - } - - template - static void Window(const INPUT_TYPE *data, const ValidityMask &fmask, const ValidityMask &dmask, - AggregateInputData &aggr_input_data, STATE &state, const SubFrames &frames, Vector &result, - idx_t ridx, const STATE *gstate) { - auto rdata = FlatVector::GetData(result); - - QuantileIncluded included(fmask, dmask); - const auto n = FrameSize(included, frames); - - if (!n) { - auto &rmask = FlatVector::Validity(result); - rmask.Set(ridx, false); - return; - } - - // Compute the median - D_ASSERT(aggr_input_data.bind_data); - auto &bind_data = aggr_input_data.bind_data->Cast(); - - D_ASSERT(bind_data.quantiles.size() == 1); - const auto &quantile = bind_data.quantiles[0]; - auto &window_state = state.GetOrCreateWindowState(); - MEDIAN_TYPE med; - if (gstate && gstate->HasTrees()) { - med = gstate->GetWindowState().template WindowScalar(data, frames, n, result, quantile); - } else { - window_state.UpdateSkip(data, frames, included); - med = window_state.template WindowScalar(data, frames, n, result, quantile); - } - - // Lazily initialise frame state - window_state.SetCount(frames.back().end - frames.front().start); - auto index2 = window_state.m.data(); - D_ASSERT(index2); - - // The replacement trick does not work on the second index because if - // the median has changed, the previous order is not correct. - // It is probably close, however, and so reuse is helpful. - auto &prevs = window_state.prevs; - ReuseIndexes(index2, frames, prevs); - std::partition(index2, index2 + window_state.count, included); - - Interpolator interp(quantile, n, false); - - // Compute mad from the second index - using ID = QuantileIndirect; - ID indirect(data); - - using MAD = MadAccessor; - MAD mad(med); - - using MadIndirect = QuantileComposed; - MadIndirect mad_indirect(mad, indirect); - rdata[ridx] = interp.template Operation(index2, result, mad_indirect); - - // Prev is used by both skip lists and increments - prevs = frames; - } -}; - -unique_ptr BindMAD(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - return make_uniq(Value::DECIMAL(int16_t(5), 2, 1)); -} - -template -AggregateFunction GetTypedMedianAbsoluteDeviationAggregateFunction(const LogicalType &input_type, - const LogicalType &target_type) { - using STATE = QuantileState; - using OP = MedianAbsoluteDeviationOperation; - auto fun = AggregateFunction::UnaryAggregateDestructor(input_type, target_type); - fun.bind = BindMAD; - fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - fun.window = AggregateFunction::UnaryWindow; - fun.window_init = OP::template WindowInit; - return fun; -} - -AggregateFunction GetMedianAbsoluteDeviationAggregateFunction(const LogicalType &type) { - switch (type.id()) { - case LogicalTypeId::FLOAT: - return GetTypedMedianAbsoluteDeviationAggregateFunction(type, type); - case LogicalTypeId::DOUBLE: - return GetTypedMedianAbsoluteDeviationAggregateFunction(type, type); - case LogicalTypeId::DECIMAL: - switch (type.InternalType()) { - case PhysicalType::INT16: - return GetTypedMedianAbsoluteDeviationAggregateFunction(type, type); - case PhysicalType::INT32: - return GetTypedMedianAbsoluteDeviationAggregateFunction(type, type); - case PhysicalType::INT64: - return GetTypedMedianAbsoluteDeviationAggregateFunction(type, type); - case PhysicalType::INT128: - return GetTypedMedianAbsoluteDeviationAggregateFunction(type, type); - default: - throw NotImplementedException("Unimplemented Median Absolute Deviation DECIMAL aggregate"); - } - break; - - case LogicalTypeId::DATE: - return GetTypedMedianAbsoluteDeviationAggregateFunction(type, - LogicalType::INTERVAL); - case LogicalTypeId::TIMESTAMP: - case LogicalTypeId::TIMESTAMP_TZ: - return GetTypedMedianAbsoluteDeviationAggregateFunction( - type, LogicalType::INTERVAL); - case LogicalTypeId::TIME: - case LogicalTypeId::TIME_TZ: - return GetTypedMedianAbsoluteDeviationAggregateFunction(type, - LogicalType::INTERVAL); - - default: - throw NotImplementedException("Unimplemented Median Absolute Deviation aggregate"); - } -} - -unique_ptr BindMedianAbsoluteDeviationDecimal(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - function = GetMedianAbsoluteDeviationAggregateFunction(arguments[0]->return_type); - function.name = "mad"; - function.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - return BindMAD(context, function, arguments); -} - -AggregateFunctionSet MadFun::GetFunctions() { - AggregateFunctionSet mad("mad"); - mad.AddFunction(AggregateFunction({LogicalTypeId::DECIMAL}, LogicalTypeId::DECIMAL, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, BindMedianAbsoluteDeviationDecimal)); - - const vector MAD_TYPES = {LogicalType::FLOAT, LogicalType::DOUBLE, LogicalType::DATE, - LogicalType::TIMESTAMP, LogicalType::TIME, LogicalType::TIMESTAMP_TZ, - LogicalType::TIME_TZ}; - for (const auto &type : MAD_TYPES) { - mad.AddFunction(GetMedianAbsoluteDeviationAggregateFunction(type)); - } - return mad; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/holistic/mode.cpp b/src/duckdb/src/core_functions/aggregate/holistic/mode.cpp deleted file mode 100644 index a8d0dbf1e..000000000 --- a/src/duckdb/src/core_functions/aggregate/holistic/mode.cpp +++ /dev/null @@ -1,429 +0,0 @@ -#include "duckdb/common/exception.hpp" -#include "duckdb/common/uhugeint.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/operator/comparison_operators.hpp" -#include "duckdb/core_functions/aggregate/holistic_functions.hpp" -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "duckdb/common/unordered_map.hpp" -#include "duckdb/common/owning_string_map.hpp" -#include "duckdb/core_functions/create_sort_key.hpp" -#include "duckdb/core_functions/aggregate/sort_key_helpers.hpp" -#include - -// MODE( ) -// Returns the most frequent value for the values within expr1. -// NULL values are ignored. If all the values are NULL, or there are 0 rows, then the function returns NULL. - -namespace std { - -template <> -struct hash { - inline size_t operator()(const duckdb::interval_t &val) const { - int64_t months, days, micros; - val.Normalize(months, days, micros); - return hash {}(duckdb::UnsafeNumericCast(days)) ^ - hash {}(duckdb::UnsafeNumericCast(months)) ^ hash {}(micros); - } -}; - -template <> -struct hash { - inline size_t operator()(const duckdb::hugeint_t &val) const { - return hash {}(val.upper) ^ hash {}(val.lower); - } -}; - -template <> -struct hash { - inline size_t operator()(const duckdb::uhugeint_t &val) const { - return hash {}(val.upper) ^ hash {}(val.lower); - } -}; - -} // namespace std - -namespace duckdb { - -struct ModeAttr { - ModeAttr() : count(0), first_row(std::numeric_limits::max()) { - } - size_t count; - idx_t first_row; -}; - -template -struct ModeStandard { - using MAP_TYPE = unordered_map; - - static MAP_TYPE *CreateEmpty(ArenaAllocator &) { - return new MAP_TYPE(); - } - static MAP_TYPE *CreateEmpty(Allocator &) { - return new MAP_TYPE(); - } - - template - static RESULT_TYPE Assign(Vector &result, INPUT_TYPE input) { - return RESULT_TYPE(input); - } -}; - -struct ModeString { - using MAP_TYPE = OwningStringMap; - - static MAP_TYPE *CreateEmpty(ArenaAllocator &allocator) { - return new MAP_TYPE(allocator); - } - static MAP_TYPE *CreateEmpty(Allocator &allocator) { - return new MAP_TYPE(allocator); - } - - template - static RESULT_TYPE Assign(Vector &result, INPUT_TYPE input) { - return StringVector::AddStringOrBlob(result, input); - } -}; - -template -struct ModeState { - using Counts = typename TYPE_OP::MAP_TYPE; - - ModeState() { - } - - SubFrames prevs; - Counts *frequency_map = nullptr; - KEY_TYPE *mode = nullptr; - size_t nonzero = 0; - bool valid = false; - size_t count = 0; - - ~ModeState() { - if (frequency_map) { - delete frequency_map; - } - if (mode) { - delete mode; - } - } - - void Reset() { - if (frequency_map) { - frequency_map->clear(); - } - nonzero = 0; - count = 0; - valid = false; - } - - void ModeAdd(const KEY_TYPE &key, idx_t row) { - auto &attr = (*frequency_map)[key]; - auto new_count = (attr.count += 1); - if (new_count == 1) { - ++nonzero; - attr.first_row = row; - } else { - attr.first_row = MinValue(row, attr.first_row); - } - if (new_count > count) { - valid = true; - count = new_count; - if (mode) { - *mode = key; - } else { - mode = new KEY_TYPE(key); - } - } - } - - void ModeRm(const KEY_TYPE &key, idx_t frame) { - auto &attr = (*frequency_map)[key]; - auto old_count = attr.count; - nonzero -= size_t(old_count == 1); - - attr.count -= 1; - if (count == old_count && key == *mode) { - valid = false; - } - } - - typename Counts::const_iterator Scan() const { - //! Initialize control variables to first variable of the frequency map - auto highest_frequency = frequency_map->begin(); - for (auto i = highest_frequency; i != frequency_map->end(); ++i) { - // Tie break with the lowest insert position - if (i->second.count > highest_frequency->second.count || - (i->second.count == highest_frequency->second.count && - i->second.first_row < highest_frequency->second.first_row)) { - highest_frequency = i; - } - } - return highest_frequency; - } -}; - -struct ModeIncluded { - inline explicit ModeIncluded(const ValidityMask &fmask_p, const ValidityMask &dmask_p) - : fmask(fmask_p), dmask(dmask_p) { - } - - inline bool operator()(const idx_t &idx) const { - return fmask.RowIsValid(idx) && dmask.RowIsValid(idx); - } - const ValidityMask &fmask; - const ValidityMask &dmask; -}; - -template -struct BaseModeFunction { - template - static void Initialize(STATE &state) { - new (&state) STATE(); - } - - template - static void Execute(STATE &state, const INPUT_TYPE &key, AggregateInputData &input_data) { - if (!state.frequency_map) { - state.frequency_map = TYPE_OP::CreateEmpty(input_data.allocator); - } - auto &i = (*state.frequency_map)[key]; - ++i.count; - i.first_row = MinValue(i.first_row, state.count); - ++state.count; - } - - template - static void Operation(STATE &state, const INPUT_TYPE &key, AggregateUnaryInput &aggr_input) { - Execute(state, key, aggr_input.input); - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - if (!source.frequency_map) { - return; - } - if (!target.frequency_map) { - // Copy - don't destroy! Otherwise windowing will break. - target.frequency_map = new typename STATE::Counts(*source.frequency_map); - return; - } - for (auto &val : *source.frequency_map) { - auto &i = (*target.frequency_map)[val.first]; - i.count += val.second.count; - i.first_row = MinValue(i.first_row, val.second.first_row); - } - target.count += source.count; - } - - static bool IgnoreNull() { - return true; - } - - template - static void Destroy(STATE &state, AggregateInputData &aggr_input_data) { - state.~STATE(); - } -}; - -template -struct ModeFunction : BaseModeFunction { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (!state.frequency_map) { - finalize_data.ReturnNull(); - return; - } - auto highest_frequency = state.Scan(); - if (highest_frequency != state.frequency_map->end()) { - target = TYPE_OP::template Assign(finalize_data.result, highest_frequency->first); - } else { - finalize_data.ReturnNull(); - } - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &key, AggregateUnaryInput &aggr_input, idx_t count) { - if (!state.frequency_map) { - state.frequency_map = TYPE_OP::CreateEmpty(aggr_input.input.allocator); - } - auto &i = (*state.frequency_map)[key]; - i.count += count; - i.first_row = MinValue(i.first_row, state.count); - state.count += count; - } - - template - struct UpdateWindowState { - STATE &state; - const INPUT_TYPE *data; - ModeIncluded &included; - - inline UpdateWindowState(STATE &state, const INPUT_TYPE *data, ModeIncluded &included) - : state(state), data(data), included(included) { - } - - inline void Neither(idx_t begin, idx_t end) { - } - - inline void Left(idx_t begin, idx_t end) { - for (; begin < end; ++begin) { - if (included(begin)) { - state.ModeRm(data[begin], begin); - } - } - } - - inline void Right(idx_t begin, idx_t end) { - for (; begin < end; ++begin) { - if (included(begin)) { - state.ModeAdd(data[begin], begin); - } - } - } - - inline void Both(idx_t begin, idx_t end) { - } - }; - - template - static void Window(const INPUT_TYPE *data, const ValidityMask &fmask, const ValidityMask &dmask, - AggregateInputData &aggr_input_data, STATE &state, const SubFrames &frames, Vector &result, - idx_t rid, const STATE *gstate) { - auto rdata = FlatVector::GetData(result); - auto &rmask = FlatVector::Validity(result); - auto &prevs = state.prevs; - if (prevs.empty()) { - prevs.resize(1); - } - - ModeIncluded included(fmask, dmask); - - if (!state.frequency_map) { - state.frequency_map = TYPE_OP::CreateEmpty(Allocator::DefaultAllocator()); - } - const size_t tau_inverse = 4; // tau==0.25 - if (state.nonzero <= (state.frequency_map->size() / tau_inverse) || prevs.back().end <= frames.front().start || - frames.back().end <= prevs.front().start) { - state.Reset(); - // for f ∈ F do - for (const auto &frame : frames) { - for (auto i = frame.start; i < frame.end; ++i) { - if (included(i)) { - state.ModeAdd(data[i], i); - } - } - } - } else { - using Updater = UpdateWindowState; - Updater updater(state, data, included); - AggregateExecutor::IntersectFrames(prevs, frames, updater); - } - - if (!state.valid) { - // Rescan - auto highest_frequency = state.Scan(); - if (highest_frequency != state.frequency_map->end()) { - *(state.mode) = highest_frequency->first; - state.count = highest_frequency->second.count; - state.valid = (state.count > 0); - } - } - - if (state.valid) { - rdata[rid] = TYPE_OP::template Assign(result, *state.mode); - } else { - rmask.Set(rid, false); - } - - prevs = frames; - } -}; - -template -struct ModeFallbackFunction : BaseModeFunction { - template - static void Finalize(STATE &state, AggregateFinalizeData &finalize_data) { - if (!state.frequency_map) { - finalize_data.ReturnNull(); - return; - } - auto highest_frequency = state.Scan(); - if (highest_frequency != state.frequency_map->end()) { - CreateSortKeyHelpers::DecodeSortKey(highest_frequency->first, finalize_data.result, - finalize_data.result_idx, - OrderModifiers(OrderType::ASCENDING, OrderByNullType::NULLS_LAST)); - } else { - finalize_data.ReturnNull(); - } - } -}; - -template > -AggregateFunction GetTypedModeFunction(const LogicalType &type) { - using STATE = ModeState; - using OP = ModeFunction; - auto func = AggregateFunction::UnaryAggregateDestructor(type, type); - func.window = AggregateFunction::UnaryWindow; - return func; -} - -AggregateFunction GetFallbackModeFunction(const LogicalType &type) { - using STATE = ModeState; - using OP = ModeFallbackFunction; - AggregateFunction aggr({type}, type, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, - AggregateSortKeyHelpers::UnaryUpdate, AggregateFunction::StateCombine, - AggregateFunction::StateVoidFinalize, nullptr); - aggr.destructor = AggregateFunction::StateDestroy; - return aggr; -} - -AggregateFunction GetModeAggregate(const LogicalType &type) { - switch (type.InternalType()) { - case PhysicalType::INT8: - return GetTypedModeFunction(type); - case PhysicalType::UINT8: - return GetTypedModeFunction(type); - case PhysicalType::INT16: - return GetTypedModeFunction(type); - case PhysicalType::UINT16: - return GetTypedModeFunction(type); - case PhysicalType::INT32: - return GetTypedModeFunction(type); - case PhysicalType::UINT32: - return GetTypedModeFunction(type); - case PhysicalType::INT64: - return GetTypedModeFunction(type); - case PhysicalType::UINT64: - return GetTypedModeFunction(type); - case PhysicalType::INT128: - return GetTypedModeFunction(type); - case PhysicalType::UINT128: - return GetTypedModeFunction(type); - case PhysicalType::FLOAT: - return GetTypedModeFunction(type); - case PhysicalType::DOUBLE: - return GetTypedModeFunction(type); - case PhysicalType::INTERVAL: - return GetTypedModeFunction(type); - case PhysicalType::VARCHAR: - return GetTypedModeFunction(type); - default: - return GetFallbackModeFunction(type); - } -} - -unique_ptr BindModeAggregate(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - function = GetModeAggregate(arguments[0]->return_type); - function.name = "mode"; - return nullptr; -} - -AggregateFunctionSet ModeFun::GetFunctions() { - AggregateFunctionSet mode; - mode.AddFunction(AggregateFunction({LogicalTypeId::ANY}, LogicalTypeId::ANY, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, BindModeAggregate)); - return mode; -} -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/holistic/quantile.cpp b/src/duckdb/src/core_functions/aggregate/holistic/quantile.cpp deleted file mode 100644 index 779ce4de4..000000000 --- a/src/duckdb/src/core_functions/aggregate/holistic/quantile.cpp +++ /dev/null @@ -1,846 +0,0 @@ -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/core_functions/aggregate/holistic_functions.hpp" -#include "duckdb/core_functions/aggregate/quantile_enum.hpp" -#include "duckdb/planner/expression.hpp" -#include "duckdb/common/operator/cast_operators.hpp" -#include "duckdb/common/operator/abs.hpp" -#include "duckdb/core_functions/aggregate/quantile_state.hpp" -#include "duckdb/common/types/timestamp.hpp" -#include "duckdb/common/queue.hpp" -#include "duckdb/common/serializer/serializer.hpp" -#include "duckdb/common/serializer/deserializer.hpp" -#include "duckdb/core_functions/aggregate/sort_key_helpers.hpp" - -namespace duckdb { - -template -struct IndirectLess { - inline explicit IndirectLess(const INPUT_TYPE *inputs_p) : inputs(inputs_p) { - } - - inline bool operator()(const idx_t &lhi, const idx_t &rhi) const { - return inputs[lhi] < inputs[rhi]; - } - - const INPUT_TYPE *inputs; -}; - -template -static inline T QuantileAbs(const T &t) { - return AbsOperator::Operation(t); -} - -template <> -inline Value QuantileAbs(const Value &v) { - const auto &type = v.type(); - switch (type.id()) { - case LogicalTypeId::DECIMAL: { - const auto integral = IntegralValue::Get(v); - const auto width = DecimalType::GetWidth(type); - const auto scale = DecimalType::GetScale(type); - switch (type.InternalType()) { - case PhysicalType::INT16: - return Value::DECIMAL(QuantileAbs(Cast::Operation(integral)), width, scale); - case PhysicalType::INT32: - return Value::DECIMAL(QuantileAbs(Cast::Operation(integral)), width, scale); - case PhysicalType::INT64: - return Value::DECIMAL(QuantileAbs(Cast::Operation(integral)), width, scale); - case PhysicalType::INT128: - return Value::DECIMAL(QuantileAbs(integral), width, scale); - default: - throw InternalException("Unknown DECIMAL type"); - } - } - default: - return Value::DOUBLE(QuantileAbs(v.GetValue())); - } -} - -//===--------------------------------------------------------------------===// -// Quantile Bind Data -//===--------------------------------------------------------------------===// -QuantileBindData::QuantileBindData() { -} - -QuantileBindData::QuantileBindData(const Value &quantile_p) - : quantiles(1, QuantileValue(QuantileAbs(quantile_p))), order(1, 0), desc(quantile_p < 0) { -} - -QuantileBindData::QuantileBindData(const vector &quantiles_p) { - vector normalised; - size_t pos = 0; - size_t neg = 0; - for (idx_t i = 0; i < quantiles_p.size(); ++i) { - const auto &q = quantiles_p[i]; - pos += (q > 0); - neg += (q < 0); - normalised.emplace_back(QuantileAbs(q)); - order.push_back(i); - } - if (pos && neg) { - throw BinderException("QUANTILE parameters must have consistent signs"); - } - desc = (neg > 0); - - IndirectLess lt(normalised.data()); - std::sort(order.begin(), order.end(), lt); - - for (const auto &q : normalised) { - quantiles.emplace_back(QuantileValue(q)); - } -} - -QuantileBindData::QuantileBindData(const QuantileBindData &other) : order(other.order), desc(other.desc) { - for (const auto &q : other.quantiles) { - quantiles.emplace_back(q); - } -} - -unique_ptr QuantileBindData::Copy() const { - return make_uniq(*this); -} - -bool QuantileBindData::Equals(const FunctionData &other_p) const { - auto &other = other_p.Cast(); - return desc == other.desc && quantiles == other.quantiles && order == other.order; -} - -void QuantileBindData::Serialize(Serializer &serializer, const optional_ptr bind_data_p, - const AggregateFunction &function) { - auto &bind_data = bind_data_p->Cast(); - vector raw; - for (const auto &q : bind_data.quantiles) { - raw.emplace_back(q.val); - } - serializer.WriteProperty(100, "quantiles", raw); - serializer.WriteProperty(101, "order", bind_data.order); - serializer.WriteProperty(102, "desc", bind_data.desc); -} - -unique_ptr QuantileBindData::Deserialize(Deserializer &deserializer, AggregateFunction &function) { - auto result = make_uniq(); - vector raw; - deserializer.ReadProperty(100, "quantiles", raw); - deserializer.ReadProperty(101, "order", result->order); - deserializer.ReadProperty(102, "desc", result->desc); - QuantileSerializationType deserialization_type; - deserializer.ReadPropertyWithExplicitDefault(103, "quantile_type", deserialization_type, - QuantileSerializationType::NON_DECIMAL); - - if (deserialization_type != QuantileSerializationType::NON_DECIMAL) { - deserializer.ReadDeletedProperty(104, "logical_type"); - } - - for (const auto &r : raw) { - result->quantiles.emplace_back(QuantileValue(r)); - } - return std::move(result); -} - -//===--------------------------------------------------------------------===// -// Cast Interpolation -//===--------------------------------------------------------------------===// -template <> -interval_t CastInterpolation::Cast(const dtime_t &src, Vector &result) { - return {0, 0, src.micros}; -} - -template <> -double CastInterpolation::Interpolate(const double &lo, const double d, const double &hi) { - return lo * (1.0 - d) + hi * d; -} - -template <> -dtime_t CastInterpolation::Interpolate(const dtime_t &lo, const double d, const dtime_t &hi) { - return dtime_t(std::llround(static_cast(lo.micros) * (1.0 - d) + static_cast(hi.micros) * d)); -} - -template <> -timestamp_t CastInterpolation::Interpolate(const timestamp_t &lo, const double d, const timestamp_t &hi) { - return timestamp_t(std::llround(static_cast(lo.value) * (1.0 - d) + static_cast(hi.value) * d)); -} - -template <> -hugeint_t CastInterpolation::Interpolate(const hugeint_t &lo, const double d, const hugeint_t &hi) { - return Hugeint::Convert(Interpolate(Hugeint::Cast(lo), d, Hugeint::Cast(hi))); -} - -static interval_t MultiplyByDouble(const interval_t &i, const double &d) { // NOLINT - D_ASSERT(d >= 0 && d <= 1); - return Interval::FromMicro(std::llround(static_cast(Interval::GetMicro(i)) * d)); -} - -inline interval_t operator+(const interval_t &lhs, const interval_t &rhs) { - return Interval::FromMicro(Interval::GetMicro(lhs) + Interval::GetMicro(rhs)); -} - -inline interval_t operator-(const interval_t &lhs, const interval_t &rhs) { - return Interval::FromMicro(Interval::GetMicro(lhs) - Interval::GetMicro(rhs)); -} - -template <> -interval_t CastInterpolation::Interpolate(const interval_t &lo, const double d, const interval_t &hi) { - const interval_t delta = hi - lo; - return lo + MultiplyByDouble(delta, d); -} - -template <> -string_t CastInterpolation::Cast(const string_t &src, Vector &result) { - return StringVector::AddStringOrBlob(result, src); -} - -//===--------------------------------------------------------------------===// -// Scalar Quantile -//===--------------------------------------------------------------------===// -template -struct QuantileScalarOperation : public QuantileOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.v.empty()) { - finalize_data.ReturnNull(); - return; - } - D_ASSERT(finalize_data.input.bind_data); - auto &bind_data = finalize_data.input.bind_data->Cast(); - D_ASSERT(bind_data.quantiles.size() == 1); - Interpolator interp(bind_data.quantiles[0], state.v.size(), bind_data.desc); - target = interp.template Operation(state.v.data(), finalize_data.result); - } - - template - static void Window(const INPUT_TYPE *data, const ValidityMask &fmask, const ValidityMask &dmask, - AggregateInputData &aggr_input_data, STATE &state, const SubFrames &frames, Vector &result, - idx_t ridx, const STATE *gstate) { - QuantileIncluded included(fmask, dmask); - const auto n = FrameSize(included, frames); - - D_ASSERT(aggr_input_data.bind_data); - auto &bind_data = aggr_input_data.bind_data->Cast(); - - auto rdata = FlatVector::GetData(result); - auto &rmask = FlatVector::Validity(result); - - if (!n) { - rmask.Set(ridx, false); - return; - } - - const auto &quantile = bind_data.quantiles[0]; - if (gstate && gstate->HasTrees()) { - rdata[ridx] = gstate->GetWindowState().template WindowScalar(data, frames, n, result, - quantile); - } else { - auto &window_state = state.GetOrCreateWindowState(); - - // Update the skip list - window_state.UpdateSkip(data, frames, included); - - // Find the position(s) needed - rdata[ridx] = window_state.template WindowScalar(data, frames, n, result, quantile); - - // Save the previous state for next time - window_state.prevs = frames; - } - } -}; - -struct QuantileScalarFallback : QuantileOperation { - template - static void Execute(STATE &state, const INPUT_TYPE &key, AggregateInputData &input_data) { - state.AddElement(key, input_data); - } - - template - static void Finalize(STATE &state, AggregateFinalizeData &finalize_data) { - if (state.v.empty()) { - finalize_data.ReturnNull(); - return; - } - D_ASSERT(finalize_data.input.bind_data); - auto &bind_data = finalize_data.input.bind_data->Cast(); - D_ASSERT(bind_data.quantiles.size() == 1); - Interpolator interp(bind_data.quantiles[0], state.v.size(), bind_data.desc); - auto interpolation_result = interp.InterpolateInternal(state.v.data()); - CreateSortKeyHelpers::DecodeSortKey(interpolation_result, finalize_data.result, finalize_data.result_idx, - OrderModifiers(OrderType::ASCENDING, OrderByNullType::NULLS_LAST)); - } -}; - -//===--------------------------------------------------------------------===// -// Quantile List -//===--------------------------------------------------------------------===// -template -struct QuantileListOperation : QuantileOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.v.empty()) { - finalize_data.ReturnNull(); - return; - } - - D_ASSERT(finalize_data.input.bind_data); - auto &bind_data = finalize_data.input.bind_data->Cast(); - - auto &result = ListVector::GetEntry(finalize_data.result); - auto ridx = ListVector::GetListSize(finalize_data.result); - ListVector::Reserve(finalize_data.result, ridx + bind_data.quantiles.size()); - auto rdata = FlatVector::GetData(result); - - auto v_t = state.v.data(); - D_ASSERT(v_t); - - auto &entry = target; - entry.offset = ridx; - idx_t lower = 0; - for (const auto &q : bind_data.order) { - const auto &quantile = bind_data.quantiles[q]; - Interpolator interp(quantile, state.v.size(), bind_data.desc); - interp.begin = lower; - rdata[ridx + q] = interp.template Operation(v_t, result); - lower = interp.FRN; - } - entry.length = bind_data.quantiles.size(); - - ListVector::SetListSize(finalize_data.result, entry.offset + entry.length); - } - - template - static void Window(const INPUT_TYPE *data, const ValidityMask &fmask, const ValidityMask &dmask, - AggregateInputData &aggr_input_data, STATE &state, const SubFrames &frames, Vector &list, - idx_t lidx, const STATE *gstate) { - D_ASSERT(aggr_input_data.bind_data); - auto &bind_data = aggr_input_data.bind_data->Cast(); - - QuantileIncluded included(fmask, dmask); - const auto n = FrameSize(included, frames); - - // Result is a constant LIST with a fixed length - if (!n) { - auto &lmask = FlatVector::Validity(list); - lmask.Set(lidx, false); - return; - } - - if (gstate && gstate->HasTrees()) { - gstate->GetWindowState().template WindowList(data, frames, n, list, lidx, bind_data); - } else { - auto &window_state = state.GetOrCreateWindowState(); - window_state.UpdateSkip(data, frames, included); - window_state.template WindowList(data, frames, n, list, lidx, bind_data); - window_state.prevs = frames; - } - } -}; - -struct QuantileListFallback : QuantileOperation { - template - static void Execute(STATE &state, const INPUT_TYPE &key, AggregateInputData &input_data) { - state.AddElement(key, input_data); - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.v.empty()) { - finalize_data.ReturnNull(); - return; - } - - D_ASSERT(finalize_data.input.bind_data); - auto &bind_data = finalize_data.input.bind_data->Cast(); - - auto &result = ListVector::GetEntry(finalize_data.result); - auto ridx = ListVector::GetListSize(finalize_data.result); - ListVector::Reserve(finalize_data.result, ridx + bind_data.quantiles.size()); - - D_ASSERT(state.v.data()); - - auto &entry = target; - entry.offset = ridx; - idx_t lower = 0; - for (const auto &q : bind_data.order) { - const auto &quantile = bind_data.quantiles[q]; - Interpolator interp(quantile, state.v.size(), bind_data.desc); - interp.begin = lower; - auto interpolation_result = interp.InterpolateInternal(state.v.data()); - CreateSortKeyHelpers::DecodeSortKey(interpolation_result, result, ridx + q, - OrderModifiers(OrderType::ASCENDING, OrderByNullType::NULLS_LAST)); - lower = interp.FRN; - } - entry.length = bind_data.quantiles.size(); - - ListVector::SetListSize(finalize_data.result, entry.offset + entry.length); - } -}; - -//===--------------------------------------------------------------------===// -// Discrete Quantiles -//===--------------------------------------------------------------------===// -template -AggregateFunction GetDiscreteQuantileTemplated(const LogicalType &type) { - switch (type.InternalType()) { - case PhysicalType::INT8: - return OP::template GetFunction(type); - case PhysicalType::INT16: - return OP::template GetFunction(type); - case PhysicalType::INT32: - return OP::template GetFunction(type); - case PhysicalType::INT64: - return OP::template GetFunction(type); - case PhysicalType::INT128: - return OP::template GetFunction(type); - case PhysicalType::FLOAT: - return OP::template GetFunction(type); - case PhysicalType::DOUBLE: - return OP::template GetFunction(type); - case PhysicalType::INTERVAL: - return OP::template GetFunction(type); - case PhysicalType::VARCHAR: - return OP::template GetFunction(type); - default: - return OP::GetFallback(type); - } -} - -struct ScalarDiscreteQuantile { - template - static AggregateFunction GetFunction(const LogicalType &type) { - using STATE = QuantileState; - using OP = QuantileScalarOperation; - auto fun = AggregateFunction::UnaryAggregateDestructor(type, type); - fun.window = AggregateFunction::UnaryWindow; - fun.window_init = OP::WindowInit; - return fun; - } - - static AggregateFunction GetFallback(const LogicalType &type) { - using STATE = QuantileState; - using OP = QuantileScalarFallback; - - AggregateFunction fun( - {type}, type, AggregateFunction::StateSize, AggregateFunction::StateInitialize, - AggregateSortKeyHelpers::UnaryUpdate, AggregateFunction::StateCombine, - AggregateFunction::StateVoidFinalize, nullptr, nullptr, - AggregateFunction::StateDestroy); - return fun; - } -}; - -template -static AggregateFunction QuantileListAggregate(const LogicalType &input_type, const LogicalType &child_type) { // NOLINT - LogicalType result_type = LogicalType::LIST(child_type); - return AggregateFunction( - {input_type}, result_type, AggregateFunction::StateSize, AggregateFunction::StateInitialize, - AggregateFunction::UnaryScatterUpdate, AggregateFunction::StateCombine, - AggregateFunction::StateFinalize, AggregateFunction::UnaryUpdate, - nullptr, AggregateFunction::StateDestroy); -} - -struct ListDiscreteQuantile { - template - static AggregateFunction GetFunction(const LogicalType &type) { - using STATE = QuantileState; - using OP = QuantileListOperation; - auto fun = QuantileListAggregate(type, type); - fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - fun.window = AggregateFunction::UnaryWindow; - fun.window_init = OP::template WindowInit; - return fun; - } - - static AggregateFunction GetFallback(const LogicalType &type) { - using STATE = QuantileState; - using OP = QuantileListFallback; - - AggregateFunction fun( - {type}, LogicalType::LIST(type), AggregateFunction::StateSize, - AggregateFunction::StateInitialize, AggregateSortKeyHelpers::UnaryUpdate, - AggregateFunction::StateCombine, AggregateFunction::StateFinalize, - nullptr, nullptr, AggregateFunction::StateDestroy); - return fun; - } -}; - -AggregateFunction GetDiscreteQuantile(const LogicalType &type) { - return GetDiscreteQuantileTemplated(type); -} - -AggregateFunction GetDiscreteQuantileList(const LogicalType &type) { - return GetDiscreteQuantileTemplated(type); -} - -//===--------------------------------------------------------------------===// -// Continuous Quantiles -//===--------------------------------------------------------------------===// -template -AggregateFunction GetContinuousQuantileTemplated(const LogicalType &type) { - switch (type.id()) { - case LogicalTypeId::TINYINT: - return OP::template GetFunction(type, LogicalType::DOUBLE); - case LogicalTypeId::SMALLINT: - return OP::template GetFunction(type, LogicalType::DOUBLE); - case LogicalTypeId::SQLNULL: - case LogicalTypeId::INTEGER: - return OP::template GetFunction(type, LogicalType::DOUBLE); - case LogicalTypeId::BIGINT: - return OP::template GetFunction(type, LogicalType::DOUBLE); - case LogicalTypeId::HUGEINT: - return OP::template GetFunction(type, LogicalType::DOUBLE); - case LogicalTypeId::FLOAT: - return OP::template GetFunction(type, type); - case LogicalTypeId::UTINYINT: - case LogicalTypeId::USMALLINT: - case LogicalTypeId::UINTEGER: - case LogicalTypeId::UBIGINT: - case LogicalTypeId::UHUGEINT: - case LogicalTypeId::DOUBLE: - return OP::template GetFunction(LogicalType::DOUBLE, LogicalType::DOUBLE); - case LogicalTypeId::DECIMAL: - switch (type.InternalType()) { - case PhysicalType::INT16: - return OP::template GetFunction(type, type); - case PhysicalType::INT32: - return OP::template GetFunction(type, type); - case PhysicalType::INT64: - return OP::template GetFunction(type, type); - case PhysicalType::INT128: - return OP::template GetFunction(type, type); - default: - throw NotImplementedException("Unimplemented continuous quantile DECIMAL aggregate"); - } - case LogicalTypeId::DATE: - return OP::template GetFunction(type, LogicalType::TIMESTAMP); - case LogicalTypeId::TIMESTAMP: - case LogicalTypeId::TIMESTAMP_TZ: - case LogicalTypeId::TIMESTAMP_SEC: - case LogicalTypeId::TIMESTAMP_MS: - case LogicalTypeId::TIMESTAMP_NS: - return OP::template GetFunction(type, type); - case LogicalTypeId::TIME: - case LogicalTypeId::TIME_TZ: - return OP::template GetFunction(type, type); - default: - throw NotImplementedException("Unimplemented continuous quantile aggregate"); - } -} - -struct ScalarContinuousQuantile { - template - static AggregateFunction GetFunction(const LogicalType &input_type, const LogicalType &target_type) { - using STATE = QuantileState; - using OP = QuantileScalarOperation; - auto fun = - AggregateFunction::UnaryAggregateDestructor(input_type, target_type); - fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - fun.window = AggregateFunction::UnaryWindow; - fun.window_init = OP::template WindowInit; - return fun; - } -}; - -struct ListContinuousQuantile { - template - static AggregateFunction GetFunction(const LogicalType &input_type, const LogicalType &target_type) { - using STATE = QuantileState; - using OP = QuantileListOperation; - auto fun = QuantileListAggregate(input_type, target_type); - fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - fun.window = AggregateFunction::UnaryWindow; - fun.window_init = OP::template WindowInit; - return fun; - } -}; - -AggregateFunction GetContinuousQuantile(const LogicalType &type) { - return GetContinuousQuantileTemplated(type); -} - -AggregateFunction GetContinuousQuantileList(const LogicalType &type) { - return GetContinuousQuantileTemplated(type); -} - -//===--------------------------------------------------------------------===// -// Quantile binding -//===--------------------------------------------------------------------===// -static const Value &CheckQuantile(const Value &quantile_val) { - if (quantile_val.IsNull()) { - throw BinderException("QUANTILE parameter cannot be NULL"); - } - auto quantile = quantile_val.GetValue(); - if (quantile < -1 || quantile > 1) { - throw BinderException("QUANTILE can only take parameters in the range [-1, 1]"); - } - if (Value::IsNan(quantile)) { - throw BinderException("QUANTILE parameter cannot be NaN"); - } - - return quantile_val; -} - -unique_ptr BindQuantile(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - if (arguments.size() < 2) { - throw BinderException("QUANTILE requires a range argument between [0, 1]"); - } - if (arguments[1]->HasParameter()) { - throw ParameterNotResolvedException(); - } - if (!arguments[1]->IsFoldable()) { - throw BinderException("QUANTILE can only take constant parameters"); - } - Value quantile_val = ExpressionExecutor::EvaluateScalar(context, *arguments[1]); - if (quantile_val.IsNull()) { - throw BinderException("QUANTILE argument must not be NULL"); - } - vector quantiles; - switch (quantile_val.type().id()) { - case LogicalTypeId::LIST: - for (const auto &element_val : ListValue::GetChildren(quantile_val)) { - quantiles.push_back(CheckQuantile(element_val)); - } - break; - case LogicalTypeId::ARRAY: - for (const auto &element_val : ArrayValue::GetChildren(quantile_val)) { - quantiles.push_back(CheckQuantile(element_val)); - } - break; - default: - quantiles.push_back(CheckQuantile(quantile_val)); - break; - } - - Function::EraseArgument(function, arguments, arguments.size() - 1); - return make_uniq(quantiles); -} - -//===--------------------------------------------------------------------===// -// Function definitions -//===--------------------------------------------------------------------===// -static bool CanInterpolate(const LogicalType &type) { - if (type.HasAlias()) { - return false; - } - switch (type.id()) { - case LogicalTypeId::DECIMAL: - case LogicalTypeId::SQLNULL: - case LogicalTypeId::TINYINT: - case LogicalTypeId::SMALLINT: - case LogicalTypeId::INTEGER: - case LogicalTypeId::UTINYINT: - case LogicalTypeId::USMALLINT: - case LogicalTypeId::UINTEGER: - case LogicalTypeId::UBIGINT: - case LogicalTypeId::BIGINT: - case LogicalTypeId::UHUGEINT: - case LogicalTypeId::HUGEINT: - case LogicalTypeId::FLOAT: - case LogicalTypeId::DOUBLE: - case LogicalTypeId::DATE: - case LogicalTypeId::TIMESTAMP: - case LogicalTypeId::TIMESTAMP_TZ: - case LogicalTypeId::TIMESTAMP_SEC: - case LogicalTypeId::TIMESTAMP_MS: - case LogicalTypeId::TIMESTAMP_NS: - case LogicalTypeId::TIME: - case LogicalTypeId::TIME_TZ: - return true; - default: - return false; - } -} - -struct MedianFunction { - static AggregateFunction GetAggregate(const LogicalType &type) { - auto fun = CanInterpolate(type) ? GetContinuousQuantile(type) : GetDiscreteQuantile(type); - fun.name = "median"; - fun.serialize = QuantileBindData::Serialize; - fun.deserialize = Deserialize; - return fun; - } - - static unique_ptr Deserialize(Deserializer &deserializer, AggregateFunction &function) { - auto bind_data = QuantileBindData::Deserialize(deserializer, function); - - auto &input_type = function.arguments[0]; - function = GetAggregate(input_type); - return bind_data; - } - - static unique_ptr Bind(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - function = GetAggregate(arguments[0]->return_type); - return make_uniq(Value::DECIMAL(int16_t(5), 2, 1)); - } -}; - -struct DiscreteQuantileListFunction { - static AggregateFunction GetAggregate(const LogicalType &type) { - auto fun = GetDiscreteQuantileList(type); - fun.name = "quantile_disc"; - fun.bind = Bind; - fun.serialize = QuantileBindData::Serialize; - fun.deserialize = Deserialize; - // temporarily push an argument so we can bind the actual quantile - fun.arguments.emplace_back(LogicalType::LIST(LogicalType::DOUBLE)); - fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - return fun; - } - - static unique_ptr Deserialize(Deserializer &deserializer, AggregateFunction &function) { - auto bind_data = QuantileBindData::Deserialize(deserializer, function); - - auto &input_type = function.arguments[0]; - function = GetAggregate(input_type); - return bind_data; - } - - static unique_ptr Bind(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - function = GetAggregate(arguments[0]->return_type); - return BindQuantile(context, function, arguments); - } -}; - -struct DiscreteQuantileFunction { - static AggregateFunction GetAggregate(const LogicalType &type) { - auto fun = GetDiscreteQuantile(type); - fun.name = "quantile_disc"; - fun.bind = Bind; - fun.serialize = QuantileBindData::Serialize; - fun.deserialize = Deserialize; - // temporarily push an argument so we can bind the actual quantile - fun.arguments.emplace_back(LogicalType::DOUBLE); - fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - return fun; - } - - static unique_ptr Deserialize(Deserializer &deserializer, AggregateFunction &function) { - auto bind_data = QuantileBindData::Deserialize(deserializer, function); - auto &quantile_data = bind_data->Cast(); - - auto &input_type = function.arguments[0]; - if (quantile_data.quantiles.size() == 1) { - function = GetAggregate(input_type); - } else { - function = DiscreteQuantileListFunction::GetAggregate(input_type); - } - return bind_data; - } - - static unique_ptr Bind(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - function = GetAggregate(arguments[0]->return_type); - return BindQuantile(context, function, arguments); - } -}; - -struct ContinuousQuantileFunction { - static AggregateFunction GetAggregate(const LogicalType &type) { - auto fun = GetContinuousQuantile(type); - fun.name = "quantile_cont"; - fun.bind = Bind; - fun.serialize = QuantileBindData::Serialize; - fun.deserialize = Deserialize; - // temporarily push an argument so we can bind the actual quantile - fun.arguments.emplace_back(LogicalType::DOUBLE); - fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - return fun; - } - - static unique_ptr Deserialize(Deserializer &deserializer, AggregateFunction &function) { - auto bind_data = QuantileBindData::Deserialize(deserializer, function); - - auto &input_type = function.arguments[0]; - function = GetAggregate(input_type); - return bind_data; - } - - static unique_ptr Bind(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - function = GetAggregate(function.arguments[0].id() == LogicalTypeId::DECIMAL ? arguments[0]->return_type - : function.arguments[0]); - return BindQuantile(context, function, arguments); - } -}; - -struct ContinuousQuantileListFunction { - static AggregateFunction GetAggregate(const LogicalType &type) { - auto fun = GetContinuousQuantileList(type); - fun.name = "quantile_cont"; - fun.bind = Bind; - fun.serialize = QuantileBindData::Serialize; - fun.deserialize = Deserialize; - // temporarily push an argument so we can bind the actual quantile - auto list_of_double = LogicalType::LIST(LogicalType::DOUBLE); - fun.arguments.push_back(list_of_double); - fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - return fun; - } - - static unique_ptr Deserialize(Deserializer &deserializer, AggregateFunction &function) { - auto bind_data = QuantileBindData::Deserialize(deserializer, function); - - auto &input_type = function.arguments[0]; - function = GetAggregate(input_type); - return bind_data; - } - - static unique_ptr Bind(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - function = GetAggregate(function.arguments[0].id() == LogicalTypeId::DECIMAL ? arguments[0]->return_type - : function.arguments[0]); - return BindQuantile(context, function, arguments); - } -}; - -template -AggregateFunction EmptyQuantileFunction(LogicalType input, LogicalType result, const LogicalType &extra_arg) { - AggregateFunction fun({std::move(input)}, std::move(result), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - OP::Bind); - if (extra_arg.id() != LogicalTypeId::INVALID) { - fun.arguments.push_back(extra_arg); - } - fun.serialize = QuantileBindData::Serialize; - fun.deserialize = OP::Deserialize; - fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - return fun; -} - -AggregateFunctionSet MedianFun::GetFunctions() { - AggregateFunctionSet set("median"); - set.AddFunction(EmptyQuantileFunction(LogicalType::ANY, LogicalType::ANY, LogicalTypeId::INVALID)); - return set; -} - -AggregateFunctionSet QuantileDiscFun::GetFunctions() { - AggregateFunctionSet set("quantile_disc"); - set.AddFunction( - EmptyQuantileFunction(LogicalType::ANY, LogicalType::ANY, LogicalType::DOUBLE)); - set.AddFunction(EmptyQuantileFunction(LogicalType::ANY, LogicalType::ANY, - LogicalType::LIST(LogicalType::DOUBLE))); - // this function is here for deserialization - it cannot be called by users - set.AddFunction( - EmptyQuantileFunction(LogicalType::ANY, LogicalType::ANY, LogicalType::INVALID)); - return set; -} - -vector GetContinuousQuantileTypes() { - return {LogicalType::TINYINT, LogicalType::SMALLINT, LogicalType::INTEGER, LogicalType::BIGINT, - LogicalType::HUGEINT, LogicalType::FLOAT, LogicalType::DOUBLE, LogicalType::DATE, - LogicalType::TIMESTAMP, LogicalType::TIME, LogicalType::TIMESTAMP_TZ, LogicalType::TIME_TZ}; -} - -AggregateFunctionSet QuantileContFun::GetFunctions() { - AggregateFunctionSet quantile_cont("quantile_cont"); - quantile_cont.AddFunction(EmptyQuantileFunction( - LogicalTypeId::DECIMAL, LogicalTypeId::DECIMAL, LogicalType::DOUBLE)); - quantile_cont.AddFunction(EmptyQuantileFunction( - LogicalTypeId::DECIMAL, LogicalTypeId::DECIMAL, LogicalType::LIST(LogicalType::DOUBLE))); - for (const auto &type : GetContinuousQuantileTypes()) { - quantile_cont.AddFunction(EmptyQuantileFunction(type, type, LogicalType::DOUBLE)); - quantile_cont.AddFunction( - EmptyQuantileFunction(type, type, LogicalType::LIST(LogicalType::DOUBLE))); - } - return quantile_cont; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/holistic/reservoir_quantile.cpp b/src/duckdb/src/core_functions/aggregate/holistic/reservoir_quantile.cpp deleted file mode 100644 index b96100ded..000000000 --- a/src/duckdb/src/core_functions/aggregate/holistic/reservoir_quantile.cpp +++ /dev/null @@ -1,449 +0,0 @@ -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/execution/reservoir_sample.hpp" -#include "duckdb/core_functions/aggregate/holistic_functions.hpp" -#include "duckdb/planner/expression.hpp" -#include "duckdb/common/queue.hpp" -#include "duckdb/common/serializer/serializer.hpp" -#include "duckdb/common/serializer/deserializer.hpp" - -#include -#include - -namespace duckdb { - -template -struct ReservoirQuantileState { - T *v; - idx_t len; - idx_t pos; - BaseReservoirSampling *r_samp; - - void Resize(idx_t new_len) { - if (new_len <= len) { - return; - } - T *old_v = v; - v = (T *)realloc(v, new_len * sizeof(T)); - if (!v) { - free(old_v); - throw InternalException("Memory allocation failure"); - } - len = new_len; - } - - void ReplaceElement(T &input) { - v[r_samp->min_weighted_entry_index] = input; - r_samp->ReplaceElement(); - } - - void FillReservoir(idx_t sample_size, T element) { - if (pos < sample_size) { - v[pos++] = element; - r_samp->InitializeReservoir(pos, len); - } else { - D_ASSERT(r_samp->next_index_to_sample >= r_samp->num_entries_to_skip_b4_next_sample); - if (r_samp->next_index_to_sample == r_samp->num_entries_to_skip_b4_next_sample) { - ReplaceElement(element); - } - } - } -}; - -struct ReservoirQuantileBindData : public FunctionData { - ReservoirQuantileBindData() { - } - ReservoirQuantileBindData(double quantile_p, idx_t sample_size_p) - : quantiles(1, quantile_p), sample_size(sample_size_p) { - } - - ReservoirQuantileBindData(vector quantiles_p, idx_t sample_size_p) - : quantiles(std::move(quantiles_p)), sample_size(sample_size_p) { - } - - unique_ptr Copy() const override { - return make_uniq(quantiles, sample_size); - } - - bool Equals(const FunctionData &other_p) const override { - auto &other = other_p.Cast(); - return quantiles == other.quantiles && sample_size == other.sample_size; - } - - static void Serialize(Serializer &serializer, const optional_ptr bind_data_p, - const AggregateFunction &function) { - auto &bind_data = bind_data_p->Cast(); - serializer.WriteProperty(100, "quantiles", bind_data.quantiles); - serializer.WriteProperty(101, "sample_size", bind_data.sample_size); - } - - static unique_ptr Deserialize(Deserializer &deserializer, AggregateFunction &function) { - auto result = make_uniq(); - deserializer.ReadProperty(100, "quantiles", result->quantiles); - deserializer.ReadProperty(101, "sample_size", result->sample_size); - return std::move(result); - } - - vector quantiles; - idx_t sample_size; -}; - -struct ReservoirQuantileOperation { - template - static void Initialize(STATE &state) { - state.v = nullptr; - state.len = 0; - state.pos = 0; - state.r_samp = nullptr; - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, - idx_t count) { - for (idx_t i = 0; i < count; i++) { - Operation(state, input, unary_input); - } - } - - template - static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input) { - auto &bind_data = unary_input.input.bind_data->template Cast(); - if (state.pos == 0) { - state.Resize(bind_data.sample_size); - } - if (!state.r_samp) { - state.r_samp = new BaseReservoirSampling(); - } - D_ASSERT(state.v); - state.FillReservoir(bind_data.sample_size, input); - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - if (source.pos == 0) { - return; - } - if (target.pos == 0) { - target.Resize(source.len); - } - if (!target.r_samp) { - target.r_samp = new BaseReservoirSampling(); - } - for (idx_t src_idx = 0; src_idx < source.pos; src_idx++) { - target.FillReservoir(target.len, source.v[src_idx]); - } - } - - template - static void Destroy(STATE &state, AggregateInputData &aggr_input_data) { - if (state.v) { - free(state.v); - state.v = nullptr; - } - if (state.r_samp) { - delete state.r_samp; - state.r_samp = nullptr; - } - } - - static bool IgnoreNull() { - return true; - } -}; - -struct ReservoirQuantileScalarOperation : public ReservoirQuantileOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.pos == 0) { - finalize_data.ReturnNull(); - return; - } - D_ASSERT(state.v); - D_ASSERT(finalize_data.input.bind_data); - auto &bind_data = finalize_data.input.bind_data->template Cast(); - auto v_t = state.v; - D_ASSERT(bind_data.quantiles.size() == 1); - auto offset = (idx_t)((double)(state.pos - 1) * bind_data.quantiles[0]); - std::nth_element(v_t, v_t + offset, v_t + state.pos); - target = v_t[offset]; - } -}; - -AggregateFunction GetReservoirQuantileAggregateFunction(PhysicalType type) { - switch (type) { - case PhysicalType::INT8: - return AggregateFunction::UnaryAggregateDestructor, int8_t, int8_t, - ReservoirQuantileScalarOperation>(LogicalType::TINYINT, - LogicalType::TINYINT); - - case PhysicalType::INT16: - return AggregateFunction::UnaryAggregateDestructor, int16_t, int16_t, - ReservoirQuantileScalarOperation>(LogicalType::SMALLINT, - LogicalType::SMALLINT); - - case PhysicalType::INT32: - return AggregateFunction::UnaryAggregateDestructor, int32_t, int32_t, - ReservoirQuantileScalarOperation>(LogicalType::INTEGER, - LogicalType::INTEGER); - - case PhysicalType::INT64: - return AggregateFunction::UnaryAggregateDestructor, int64_t, int64_t, - ReservoirQuantileScalarOperation>(LogicalType::BIGINT, - LogicalType::BIGINT); - - case PhysicalType::INT128: - return AggregateFunction::UnaryAggregateDestructor, hugeint_t, hugeint_t, - ReservoirQuantileScalarOperation>(LogicalType::HUGEINT, - LogicalType::HUGEINT); - case PhysicalType::FLOAT: - return AggregateFunction::UnaryAggregateDestructor, float, float, - ReservoirQuantileScalarOperation>(LogicalType::FLOAT, - LogicalType::FLOAT); - case PhysicalType::DOUBLE: - return AggregateFunction::UnaryAggregateDestructor, double, double, - ReservoirQuantileScalarOperation>(LogicalType::DOUBLE, - LogicalType::DOUBLE); - default: - throw InternalException("Unimplemented reservoir quantile aggregate"); - } -} - -template -struct ReservoirQuantileListOperation : public ReservoirQuantileOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.pos == 0) { - finalize_data.ReturnNull(); - return; - } - - D_ASSERT(finalize_data.input.bind_data); - auto &bind_data = finalize_data.input.bind_data->template Cast(); - - auto &result = ListVector::GetEntry(finalize_data.result); - auto ridx = ListVector::GetListSize(finalize_data.result); - ListVector::Reserve(finalize_data.result, ridx + bind_data.quantiles.size()); - auto rdata = FlatVector::GetData(result); - - auto v_t = state.v; - D_ASSERT(v_t); - - auto &entry = target; - entry.offset = ridx; - entry.length = bind_data.quantiles.size(); - for (size_t q = 0; q < entry.length; ++q) { - const auto &quantile = bind_data.quantiles[q]; - auto offset = (idx_t)((double)(state.pos - 1) * quantile); - std::nth_element(v_t, v_t + offset, v_t + state.pos); - rdata[ridx + q] = v_t[offset]; - } - - ListVector::SetListSize(finalize_data.result, entry.offset + entry.length); - } -}; - -template -static AggregateFunction ReservoirQuantileListAggregate(const LogicalType &input_type, const LogicalType &child_type) { - LogicalType result_type = LogicalType::LIST(child_type); - return AggregateFunction( - {input_type}, result_type, AggregateFunction::StateSize, AggregateFunction::StateInitialize, - AggregateFunction::UnaryScatterUpdate, AggregateFunction::StateCombine, - AggregateFunction::StateFinalize, AggregateFunction::UnaryUpdate, - nullptr, AggregateFunction::StateDestroy); -} - -template -AggregateFunction GetTypedReservoirQuantileListAggregateFunction(const LogicalType &type) { - using STATE = ReservoirQuantileState; - using OP = ReservoirQuantileListOperation; - auto fun = ReservoirQuantileListAggregate(type, type); - return fun; -} - -AggregateFunction GetReservoirQuantileListAggregateFunction(const LogicalType &type) { - switch (type.id()) { - case LogicalTypeId::TINYINT: - return GetTypedReservoirQuantileListAggregateFunction(type); - case LogicalTypeId::SMALLINT: - return GetTypedReservoirQuantileListAggregateFunction(type); - case LogicalTypeId::INTEGER: - return GetTypedReservoirQuantileListAggregateFunction(type); - case LogicalTypeId::BIGINT: - return GetTypedReservoirQuantileListAggregateFunction(type); - case LogicalTypeId::HUGEINT: - return GetTypedReservoirQuantileListAggregateFunction(type); - case LogicalTypeId::FLOAT: - return GetTypedReservoirQuantileListAggregateFunction(type); - case LogicalTypeId::DOUBLE: - return GetTypedReservoirQuantileListAggregateFunction(type); - case LogicalTypeId::DECIMAL: - switch (type.InternalType()) { - case PhysicalType::INT16: - return GetTypedReservoirQuantileListAggregateFunction(type); - case PhysicalType::INT32: - return GetTypedReservoirQuantileListAggregateFunction(type); - case PhysicalType::INT64: - return GetTypedReservoirQuantileListAggregateFunction(type); - case PhysicalType::INT128: - return GetTypedReservoirQuantileListAggregateFunction(type); - default: - throw NotImplementedException("Unimplemented reservoir quantile list aggregate"); - } - default: - // TODO: Add quantitative temporal types - throw NotImplementedException("Unimplemented reservoir quantile list aggregate"); - } -} - -static double CheckReservoirQuantile(const Value &quantile_val) { - if (quantile_val.IsNull()) { - throw BinderException("RESERVOIR_QUANTILE QUANTILE parameter cannot be NULL"); - } - auto quantile = quantile_val.GetValue(); - if (quantile < 0 || quantile > 1) { - throw BinderException("RESERVOIR_QUANTILE can only take parameters in the range [0, 1]"); - } - return quantile; -} - -unique_ptr BindReservoirQuantile(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - D_ASSERT(arguments.size() >= 2); - if (arguments[1]->HasParameter()) { - throw ParameterNotResolvedException(); - } - if (!arguments[1]->IsFoldable()) { - throw BinderException("RESERVOIR_QUANTILE can only take constant quantile parameters"); - } - Value quantile_val = ExpressionExecutor::EvaluateScalar(context, *arguments[1]); - vector quantiles; - if (quantile_val.type().id() != LogicalTypeId::LIST) { - quantiles.push_back(CheckReservoirQuantile(quantile_val)); - } else { - for (const auto &element_val : ListValue::GetChildren(quantile_val)) { - quantiles.push_back(CheckReservoirQuantile(element_val)); - } - } - - if (arguments.size() == 2) { - // remove the quantile argument so we can use the unary aggregate - if (function.arguments.size() == 2) { - Function::EraseArgument(function, arguments, arguments.size() - 1); - } else { - arguments.pop_back(); - } - return make_uniq(quantiles, 8192ULL); - } - if (!arguments[2]->IsFoldable()) { - throw BinderException("RESERVOIR_QUANTILE can only take constant sample size parameters"); - } - Value sample_size_val = ExpressionExecutor::EvaluateScalar(context, *arguments[2]); - if (sample_size_val.IsNull()) { - throw BinderException("Size of the RESERVOIR_QUANTILE sample cannot be NULL"); - } - auto sample_size = sample_size_val.GetValue(); - - if (sample_size_val.IsNull() || sample_size <= 0) { - throw BinderException("Size of the RESERVOIR_QUANTILE sample must be bigger than 0"); - } - - // remove the quantile arguments so we can use the unary aggregate - if (function.arguments.size() == arguments.size()) { - Function::EraseArgument(function, arguments, arguments.size() - 1); - Function::EraseArgument(function, arguments, arguments.size() - 1); - } else { - arguments.pop_back(); - arguments.pop_back(); - } - return make_uniq(quantiles, NumericCast(sample_size)); -} - -unique_ptr BindReservoirQuantileDecimal(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - function = GetReservoirQuantileAggregateFunction(arguments[0]->return_type.InternalType()); - auto bind_data = BindReservoirQuantile(context, function, arguments); - function.name = "reservoir_quantile"; - function.serialize = ReservoirQuantileBindData::Serialize; - function.deserialize = ReservoirQuantileBindData::Deserialize; - return bind_data; -} - -AggregateFunction GetReservoirQuantileAggregate(PhysicalType type) { - auto fun = GetReservoirQuantileAggregateFunction(type); - fun.bind = BindReservoirQuantile; - fun.serialize = ReservoirQuantileBindData::Serialize; - fun.deserialize = ReservoirQuantileBindData::Deserialize; - // temporarily push an argument so we can bind the actual quantile - fun.arguments.emplace_back(LogicalType::DOUBLE); - return fun; -} - -unique_ptr BindReservoirQuantileDecimalList(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - function = GetReservoirQuantileListAggregateFunction(arguments[0]->return_type); - auto bind_data = BindReservoirQuantile(context, function, arguments); - function.serialize = ReservoirQuantileBindData::Serialize; - function.deserialize = ReservoirQuantileBindData::Deserialize; - function.name = "reservoir_quantile"; - return bind_data; -} - -AggregateFunction GetReservoirQuantileListAggregate(const LogicalType &type) { - auto fun = GetReservoirQuantileListAggregateFunction(type); - fun.bind = BindReservoirQuantile; - fun.serialize = ReservoirQuantileBindData::Serialize; - fun.deserialize = ReservoirQuantileBindData::Deserialize; - // temporarily push an argument so we can bind the actual quantile - auto list_of_double = LogicalType::LIST(LogicalType::DOUBLE); - fun.arguments.push_back(list_of_double); - return fun; -} - -static void DefineReservoirQuantile(AggregateFunctionSet &set, const LogicalType &type) { - // Four versions: type, scalar/list[, count] - auto fun = GetReservoirQuantileAggregate(type.InternalType()); - set.AddFunction(fun); - - fun.arguments.emplace_back(LogicalType::INTEGER); - set.AddFunction(fun); - - // List variants - fun = GetReservoirQuantileListAggregate(type); - set.AddFunction(fun); - - fun.arguments.emplace_back(LogicalType::INTEGER); - set.AddFunction(fun); -} - -static void GetReservoirQuantileDecimalFunction(AggregateFunctionSet &set, const vector &arguments, - const LogicalType &return_value) { - AggregateFunction fun(arguments, return_value, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - BindReservoirQuantileDecimal); - fun.serialize = ReservoirQuantileBindData::Serialize; - fun.deserialize = ReservoirQuantileBindData::Deserialize; - set.AddFunction(fun); - - fun.arguments.emplace_back(LogicalType::INTEGER); - set.AddFunction(fun); -} - -AggregateFunctionSet ReservoirQuantileFun::GetFunctions() { - AggregateFunctionSet reservoir_quantile; - - // DECIMAL - GetReservoirQuantileDecimalFunction(reservoir_quantile, {LogicalTypeId::DECIMAL, LogicalType::DOUBLE}, - LogicalTypeId::DECIMAL); - GetReservoirQuantileDecimalFunction(reservoir_quantile, - {LogicalTypeId::DECIMAL, LogicalType::LIST(LogicalType::DOUBLE)}, - LogicalType::LIST(LogicalTypeId::DECIMAL)); - - DefineReservoirQuantile(reservoir_quantile, LogicalTypeId::TINYINT); - DefineReservoirQuantile(reservoir_quantile, LogicalTypeId::SMALLINT); - DefineReservoirQuantile(reservoir_quantile, LogicalTypeId::INTEGER); - DefineReservoirQuantile(reservoir_quantile, LogicalTypeId::BIGINT); - DefineReservoirQuantile(reservoir_quantile, LogicalTypeId::HUGEINT); - DefineReservoirQuantile(reservoir_quantile, LogicalTypeId::FLOAT); - DefineReservoirQuantile(reservoir_quantile, LogicalTypeId::DOUBLE); - return reservoir_quantile; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/nested/binned_histogram.cpp b/src/duckdb/src/core_functions/aggregate/nested/binned_histogram.cpp deleted file mode 100644 index b639475ab..000000000 --- a/src/duckdb/src/core_functions/aggregate/nested/binned_histogram.cpp +++ /dev/null @@ -1,405 +0,0 @@ -#include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/core_functions/aggregate/nested_functions.hpp" -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "duckdb/common/types/vector.hpp" -#include "duckdb/core_functions/aggregate/histogram_helpers.hpp" -#include "duckdb/core_functions/scalar/generic_functions.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/algorithm.hpp" - -namespace duckdb { - -template -struct HistogramBinState { - using TYPE = T; - - unsafe_vector *bin_boundaries; - unsafe_vector *counts; - - void Initialize() { - bin_boundaries = nullptr; - counts = nullptr; - } - - void Destroy() { - if (bin_boundaries) { - delete bin_boundaries; - bin_boundaries = nullptr; - } - if (counts) { - delete counts; - counts = nullptr; - } - } - - bool IsSet() { - return bin_boundaries; - } - - template - void InitializeBins(Vector &bin_vector, idx_t count, idx_t pos, AggregateInputData &aggr_input) { - bin_boundaries = new unsafe_vector(); - counts = new unsafe_vector(); - UnifiedVectorFormat bin_data; - bin_vector.ToUnifiedFormat(count, bin_data); - auto bin_counts = UnifiedVectorFormat::GetData(bin_data); - auto bin_index = bin_data.sel->get_index(pos); - auto bin_list = bin_counts[bin_index]; - if (!bin_data.validity.RowIsValid(bin_index)) { - throw BinderException("Histogram bin list cannot be NULL"); - } - - auto &bin_child = ListVector::GetEntry(bin_vector); - auto bin_count = ListVector::GetListSize(bin_vector); - UnifiedVectorFormat bin_child_data; - auto extra_state = OP::CreateExtraState(bin_count); - OP::PrepareData(bin_child, bin_count, extra_state, bin_child_data); - - bin_boundaries->reserve(bin_list.length); - for (idx_t i = 0; i < bin_list.length; i++) { - auto bin_child_idx = bin_child_data.sel->get_index(bin_list.offset + i); - if (!bin_child_data.validity.RowIsValid(bin_child_idx)) { - throw BinderException("Histogram bin entry cannot be NULL"); - } - bin_boundaries->push_back(OP::template ExtractValue(bin_child_data, bin_list.offset + i, aggr_input)); - } - // sort the bin boundaries - std::sort(bin_boundaries->begin(), bin_boundaries->end()); - // ensure there are no duplicate bin boundaries - for (idx_t i = 1; i < bin_boundaries->size(); i++) { - if (Equals::Operation((*bin_boundaries)[i - 1], (*bin_boundaries)[i])) { - bin_boundaries->erase_at(i); - i--; - } - } - - counts->resize(bin_list.length + 1); - } -}; - -struct HistogramBinFunction { - template - static void Initialize(STATE &state) { - state.Initialize(); - } - - template - static void Destroy(STATE &state, AggregateInputData &aggr_input_data) { - state.Destroy(); - } - - static bool IgnoreNull() { - return true; - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &input_data) { - if (!source.bin_boundaries) { - // nothing to combine - return; - } - if (!target.bin_boundaries) { - // target does not have bin boundaries - copy everything over - target.bin_boundaries = new unsafe_vector(); - target.counts = new unsafe_vector(); - *target.bin_boundaries = *source.bin_boundaries; - *target.counts = *source.counts; - } else { - // both source and target have bin boundaries - if (*target.bin_boundaries != *source.bin_boundaries) { - throw NotImplementedException( - "Histogram - cannot combine histograms with different bin boundaries. " - "Bin boundaries must be the same for all histograms within the same group"); - } - if (target.counts->size() != source.counts->size()) { - throw InternalException("Histogram combine - bin boundaries are the same but counts are different"); - } - D_ASSERT(target.counts->size() == source.counts->size()); - for (idx_t bin_idx = 0; bin_idx < target.counts->size(); bin_idx++) { - (*target.counts)[bin_idx] += (*source.counts)[bin_idx]; - } - } - } -}; - -struct HistogramRange { - static constexpr bool EXACT = false; - - template - static idx_t GetBin(T value, const unsafe_vector &bin_boundaries) { - auto entry = std::lower_bound(bin_boundaries.begin(), bin_boundaries.end(), value); - return UnsafeNumericCast(entry - bin_boundaries.begin()); - } -}; - -struct HistogramExact { - static constexpr bool EXACT = true; - - template - static idx_t GetBin(T value, const unsafe_vector &bin_boundaries) { - auto entry = std::lower_bound(bin_boundaries.begin(), bin_boundaries.end(), value); - if (entry == bin_boundaries.end() || !(*entry == value)) { - // entry not found - return last bucket - return bin_boundaries.size(); - } - return UnsafeNumericCast(entry - bin_boundaries.begin()); - } -}; - -template -static void HistogramBinUpdateFunction(Vector inputs[], AggregateInputData &aggr_input, idx_t input_count, - Vector &state_vector, idx_t count) { - auto &input = inputs[0]; - UnifiedVectorFormat sdata; - state_vector.ToUnifiedFormat(count, sdata); - - auto &bin_vector = inputs[1]; - - auto extra_state = OP::CreateExtraState(count); - UnifiedVectorFormat input_data; - OP::PrepareData(input, count, extra_state, input_data); - - auto states = UnifiedVectorFormat::GetData *>(sdata); - auto data = UnifiedVectorFormat::GetData(input_data); - for (idx_t i = 0; i < count; i++) { - auto idx = input_data.sel->get_index(i); - if (!input_data.validity.RowIsValid(idx)) { - continue; - } - auto &state = *states[sdata.sel->get_index(i)]; - if (!state.IsSet()) { - state.template InitializeBins(bin_vector, count, i, aggr_input); - } - auto bin_entry = HIST::template GetBin(data[idx], *state.bin_boundaries); - ++(*state.counts)[bin_entry]; - } -} - -static bool SupportsOtherBucket(const LogicalType &type) { - if (type.HasAlias()) { - return false; - } - switch (type.id()) { - case LogicalTypeId::TINYINT: - case LogicalTypeId::SMALLINT: - case LogicalTypeId::INTEGER: - case LogicalTypeId::BIGINT: - case LogicalTypeId::HUGEINT: - case LogicalTypeId::FLOAT: - case LogicalTypeId::DOUBLE: - case LogicalTypeId::DECIMAL: - case LogicalTypeId::UTINYINT: - case LogicalTypeId::USMALLINT: - case LogicalTypeId::UINTEGER: - case LogicalTypeId::UBIGINT: - case LogicalTypeId::UHUGEINT: - case LogicalTypeId::TIME: - case LogicalTypeId::TIME_TZ: - case LogicalTypeId::DATE: - case LogicalTypeId::TIMESTAMP: - case LogicalTypeId::TIMESTAMP_TZ: - case LogicalTypeId::TIMESTAMP_SEC: - case LogicalTypeId::TIMESTAMP_MS: - case LogicalTypeId::TIMESTAMP_NS: - case LogicalTypeId::VARCHAR: - case LogicalTypeId::BLOB: - case LogicalTypeId::STRUCT: - case LogicalTypeId::LIST: - return true; - default: - return false; - } -} -static Value OtherBucketValue(const LogicalType &type) { - switch (type.id()) { - case LogicalTypeId::TINYINT: - case LogicalTypeId::SMALLINT: - case LogicalTypeId::INTEGER: - case LogicalTypeId::BIGINT: - case LogicalTypeId::HUGEINT: - case LogicalTypeId::DECIMAL: - case LogicalTypeId::UTINYINT: - case LogicalTypeId::USMALLINT: - case LogicalTypeId::UINTEGER: - case LogicalTypeId::UBIGINT: - case LogicalTypeId::UHUGEINT: - case LogicalTypeId::TIME: - case LogicalTypeId::TIME_TZ: - return Value::MaximumValue(type); - case LogicalTypeId::DATE: - case LogicalTypeId::TIMESTAMP: - case LogicalTypeId::TIMESTAMP_TZ: - case LogicalTypeId::TIMESTAMP_SEC: - case LogicalTypeId::TIMESTAMP_MS: - case LogicalTypeId::TIMESTAMP_NS: - case LogicalTypeId::FLOAT: - case LogicalTypeId::DOUBLE: - return Value::Infinity(type); - case LogicalTypeId::VARCHAR: - return Value(""); - case LogicalTypeId::BLOB: - return Value::BLOB(""); - case LogicalTypeId::STRUCT: { - // for structs we can set all child members to NULL - auto &child_types = StructType::GetChildTypes(type); - child_list_t child_list; - for (auto &child_type : child_types) { - child_list.push_back(make_pair(child_type.first, Value(child_type.second))); - } - return Value::STRUCT(std::move(child_list)); - } - case LogicalTypeId::LIST: - return Value::EMPTYLIST(ListType::GetChildType(type)); - default: - throw InternalException("Unsupported type for other bucket"); - } -} - -static void IsHistogramOtherBinFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &input_type = args.data[0].GetType(); - if (!SupportsOtherBucket(input_type)) { - result.Reference(Value::BOOLEAN(false)); - return; - } - auto v = OtherBucketValue(input_type); - Vector ref(v); - VectorOperations::NotDistinctFrom(args.data[0], ref, result, args.size()); -} - -template -static void HistogramBinFinalizeFunction(Vector &state_vector, AggregateInputData &, Vector &result, idx_t count, - idx_t offset) { - UnifiedVectorFormat sdata; - state_vector.ToUnifiedFormat(count, sdata); - auto states = UnifiedVectorFormat::GetData *>(sdata); - - auto &mask = FlatVector::Validity(result); - auto old_len = ListVector::GetListSize(result); - idx_t new_entries = 0; - bool supports_other_bucket = SupportsOtherBucket(MapType::KeyType(result.GetType())); - // figure out how much space we need - for (idx_t i = 0; i < count; i++) { - auto &state = *states[sdata.sel->get_index(i)]; - if (!state.bin_boundaries) { - continue; - } - new_entries += state.bin_boundaries->size(); - if (state.counts->back() > 0 && supports_other_bucket) { - // overflow bucket has entries - new_entries++; - } - } - // reserve space in the list vector - ListVector::Reserve(result, old_len + new_entries); - auto &keys = MapVector::GetKeys(result); - auto &values = MapVector::GetValues(result); - auto list_entries = FlatVector::GetData(result); - auto count_entries = FlatVector::GetData(values); - - idx_t current_offset = old_len; - for (idx_t i = 0; i < count; i++) { - const auto rid = i + offset; - auto &state = *states[sdata.sel->get_index(i)]; - if (!state.bin_boundaries) { - mask.SetInvalid(rid); - continue; - } - - auto &list_entry = list_entries[rid]; - list_entry.offset = current_offset; - for (idx_t bin_idx = 0; bin_idx < state.bin_boundaries->size(); bin_idx++) { - OP::template HistogramFinalize((*state.bin_boundaries)[bin_idx], keys, current_offset); - count_entries[current_offset] = (*state.counts)[bin_idx]; - current_offset++; - } - if (state.counts->back() > 0 && supports_other_bucket) { - // add overflow bucket ("others") - // set bin boundary to NULL for overflow bucket - keys.SetValue(current_offset, OtherBucketValue(keys.GetType())); - count_entries[current_offset] = state.counts->back(); - current_offset++; - } - list_entry.length = current_offset - list_entry.offset; - } - D_ASSERT(current_offset == old_len + new_entries); - ListVector::SetListSize(result, current_offset); - result.Verify(count); -} - -template -static AggregateFunction GetHistogramBinFunction(const LogicalType &type) { - using STATE_TYPE = HistogramBinState; - - const char *function_name = HIST::EXACT ? "histogram_exact" : "histogram"; - - auto struct_type = LogicalType::MAP(type, LogicalType::UBIGINT); - return AggregateFunction( - function_name, {type, LogicalType::LIST(type)}, struct_type, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, HistogramBinUpdateFunction, - AggregateFunction::StateCombine, HistogramBinFinalizeFunction, nullptr, - nullptr, AggregateFunction::StateDestroy); -} - -template -AggregateFunction GetHistogramBinFunction(const LogicalType &type) { - switch (type.InternalType()) { - case PhysicalType::BOOL: - return GetHistogramBinFunction(type); - case PhysicalType::UINT8: - return GetHistogramBinFunction(type); - case PhysicalType::UINT16: - return GetHistogramBinFunction(type); - case PhysicalType::UINT32: - return GetHistogramBinFunction(type); - case PhysicalType::UINT64: - return GetHistogramBinFunction(type); - case PhysicalType::INT8: - return GetHistogramBinFunction(type); - case PhysicalType::INT16: - return GetHistogramBinFunction(type); - case PhysicalType::INT32: - return GetHistogramBinFunction(type); - case PhysicalType::INT64: - return GetHistogramBinFunction(type); - case PhysicalType::FLOAT: - return GetHistogramBinFunction(type); - case PhysicalType::DOUBLE: - return GetHistogramBinFunction(type); - case PhysicalType::VARCHAR: - return GetHistogramBinFunction(type); - default: - return GetHistogramBinFunction(type); - } -} - -template -unique_ptr HistogramBinBindFunction(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - for (auto &arg : arguments) { - if (arg->return_type.id() == LogicalTypeId::UNKNOWN) { - throw ParameterNotResolvedException(); - } - } - - function = GetHistogramBinFunction(arguments[0]->return_type); - return nullptr; -} - -AggregateFunction HistogramFun::BinnedHistogramFunction() { - return AggregateFunction("histogram", {LogicalType::ANY, LogicalType::LIST(LogicalType::ANY)}, LogicalTypeId::MAP, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - HistogramBinBindFunction, nullptr); -} - -AggregateFunction HistogramExactFun::GetFunction() { - return AggregateFunction("histogram_exact", {LogicalType::ANY, LogicalType::LIST(LogicalType::ANY)}, - LogicalTypeId::MAP, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - HistogramBinBindFunction, nullptr); -} - -ScalarFunction IsHistogramOtherBinFun::GetFunction() { - return ScalarFunction("is_histogram_other_bin", {LogicalType::ANY}, LogicalType::BOOLEAN, - IsHistogramOtherBinFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/nested/histogram.cpp b/src/duckdb/src/core_functions/aggregate/nested/histogram.cpp deleted file mode 100644 index 447e8d0d2..000000000 --- a/src/duckdb/src/core_functions/aggregate/nested/histogram.cpp +++ /dev/null @@ -1,234 +0,0 @@ -#include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/core_functions/aggregate/nested_functions.hpp" -#include "duckdb/common/types/vector.hpp" -#include "duckdb/common/string_map_set.hpp" -#include "duckdb/core_functions/aggregate/histogram_helpers.hpp" -#include "duckdb/common/owning_string_map.hpp" - -namespace duckdb { - -template -struct HistogramFunction { - template - static void Initialize(STATE &state) { - state.hist = nullptr; - } - - template - static void Destroy(STATE &state, AggregateInputData &) { - if (state.hist) { - delete state.hist; - } - } - - static bool IgnoreNull() { - return true; - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &input_data) { - if (!source.hist) { - return; - } - if (!target.hist) { - target.hist = MAP_TYPE::CreateEmpty(input_data.allocator); - } - for (auto &entry : *source.hist) { - (*target.hist)[entry.first] += entry.second; - } - } -}; - -template -struct DefaultMapType { - using MAP_TYPE = TYPE; - - static TYPE *CreateEmpty(ArenaAllocator &) { - return new TYPE(); - } -}; - -template -struct StringMapType { - using MAP_TYPE = TYPE; - - static TYPE *CreateEmpty(ArenaAllocator &allocator) { - return new TYPE(allocator); - } -}; - -template -static void HistogramUpdateFunction(Vector inputs[], AggregateInputData &aggr_input, idx_t input_count, - Vector &state_vector, idx_t count) { - - D_ASSERT(input_count == 1); - - auto &input = inputs[0]; - UnifiedVectorFormat sdata; - state_vector.ToUnifiedFormat(count, sdata); - - auto extra_state = OP::CreateExtraState(count); - UnifiedVectorFormat input_data; - OP::PrepareData(input, count, extra_state, input_data); - - auto states = UnifiedVectorFormat::GetData *>(sdata); - auto input_values = UnifiedVectorFormat::GetData(input_data); - for (idx_t i = 0; i < count; i++) { - auto idx = input_data.sel->get_index(i); - if (!input_data.validity.RowIsValid(idx)) { - continue; - } - auto &state = *states[sdata.sel->get_index(i)]; - if (!state.hist) { - state.hist = MAP_TYPE::CreateEmpty(aggr_input.allocator); - } - auto &input_value = input_values[idx]; - ++(*state.hist)[input_value]; - } -} - -template -static void HistogramFinalizeFunction(Vector &state_vector, AggregateInputData &, Vector &result, idx_t count, - idx_t offset) { - using HIST_STATE = HistogramAggState; - - UnifiedVectorFormat sdata; - state_vector.ToUnifiedFormat(count, sdata); - auto states = UnifiedVectorFormat::GetData(sdata); - - auto &mask = FlatVector::Validity(result); - auto old_len = ListVector::GetListSize(result); - idx_t new_entries = 0; - // figure out how much space we need - for (idx_t i = 0; i < count; i++) { - auto &state = *states[sdata.sel->get_index(i)]; - if (!state.hist) { - continue; - } - new_entries += state.hist->size(); - } - // reserve space in the list vector - ListVector::Reserve(result, old_len + new_entries); - auto &keys = MapVector::GetKeys(result); - auto &values = MapVector::GetValues(result); - auto list_entries = FlatVector::GetData(result); - auto count_entries = FlatVector::GetData(values); - - idx_t current_offset = old_len; - for (idx_t i = 0; i < count; i++) { - const auto rid = i + offset; - auto &state = *states[sdata.sel->get_index(i)]; - if (!state.hist) { - mask.SetInvalid(rid); - continue; - } - - auto &list_entry = list_entries[rid]; - list_entry.offset = current_offset; - for (auto &entry : *state.hist) { - OP::template HistogramFinalize(entry.first, keys, current_offset); - count_entries[current_offset] = entry.second; - current_offset++; - } - list_entry.length = current_offset - list_entry.offset; - } - D_ASSERT(current_offset == old_len + new_entries); - ListVector::SetListSize(result, current_offset); - result.Verify(count); -} - -template -static AggregateFunction GetHistogramFunction(const LogicalType &type) { - using STATE_TYPE = HistogramAggState; - using HIST_FUNC = HistogramFunction; - - auto struct_type = LogicalType::MAP(type, LogicalType::UBIGINT); - return AggregateFunction( - "histogram", {type}, struct_type, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, HistogramUpdateFunction, - AggregateFunction::StateCombine, HistogramFinalizeFunction, nullptr, - nullptr, AggregateFunction::StateDestroy); -} - -template -AggregateFunction GetMapTypeInternal(const LogicalType &type) { - return GetHistogramFunction(type); -} - -template -AggregateFunction GetMapType(const LogicalType &type) { - if (IS_ORDERED) { - return GetMapTypeInternal>>(type); - } - return GetMapTypeInternal>>(type); -} - -template -AggregateFunction GetStringMapType(const LogicalType &type) { - if (IS_ORDERED) { - return GetMapTypeInternal>>(type); - } else { - return GetMapTypeInternal>>(type); - } -} - -template -AggregateFunction GetHistogramFunction(const LogicalType &type) { - switch (type.InternalType()) { - case PhysicalType::BOOL: - return GetMapType(type); - case PhysicalType::UINT8: - return GetMapType(type); - case PhysicalType::UINT16: - return GetMapType(type); - case PhysicalType::UINT32: - return GetMapType(type); - case PhysicalType::UINT64: - return GetMapType(type); - case PhysicalType::INT8: - return GetMapType(type); - case PhysicalType::INT16: - return GetMapType(type); - case PhysicalType::INT32: - return GetMapType(type); - case PhysicalType::INT64: - return GetMapType(type); - case PhysicalType::FLOAT: - return GetMapType(type); - case PhysicalType::DOUBLE: - return GetMapType(type); - case PhysicalType::VARCHAR: - return GetStringMapType(type); - default: - return GetStringMapType(type); - } -} - -template -unique_ptr HistogramBindFunction(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - - D_ASSERT(arguments.size() == 1); - - if (arguments[0]->return_type.id() == LogicalTypeId::UNKNOWN) { - throw ParameterNotResolvedException(); - } - function = GetHistogramFunction(arguments[0]->return_type); - return make_uniq(function.return_type); -} - -AggregateFunctionSet HistogramFun::GetFunctions() { - AggregateFunctionSet fun; - AggregateFunction histogram_function("histogram", {LogicalType::ANY}, LogicalTypeId::MAP, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, HistogramBindFunction, nullptr); - fun.AddFunction(HistogramFun::BinnedHistogramFunction()); - fun.AddFunction(histogram_function); - return fun; -} - -AggregateFunction HistogramFun::GetHistogramUnorderedMap(LogicalType &type) { - return AggregateFunction("histogram", {LogicalType::ANY}, LogicalTypeId::MAP, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, HistogramBindFunction, nullptr); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/nested/list.cpp b/src/duckdb/src/core_functions/aggregate/nested/list.cpp deleted file mode 100644 index 3ac865739..000000000 --- a/src/duckdb/src/core_functions/aggregate/nested/list.cpp +++ /dev/null @@ -1,212 +0,0 @@ -#include "duckdb/common/pair.hpp" -#include "duckdb/common/types/list_segment.hpp" -#include "duckdb/core_functions/aggregate/nested_functions.hpp" -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" - -namespace duckdb { - -struct ListBindData : public FunctionData { - explicit ListBindData(const LogicalType &stype_p); - ~ListBindData() override; - - LogicalType stype; - ListSegmentFunctions functions; - - unique_ptr Copy() const override { - return make_uniq(stype); - } - - bool Equals(const FunctionData &other_p) const override { - auto &other = other_p.Cast(); - return stype == other.stype; - } -}; - -ListBindData::ListBindData(const LogicalType &stype_p) : stype(stype_p) { - // always unnest once because the result vector is of type LIST - auto type = ListType::GetChildType(stype_p); - GetSegmentDataFunctions(functions, type); -} - -ListBindData::~ListBindData() { -} - -struct ListAggState { - LinkedList linked_list; -}; - -struct ListFunction { - template - static void Initialize(STATE &state) { - state.linked_list.total_capacity = 0; - state.linked_list.first_segment = nullptr; - state.linked_list.last_segment = nullptr; - } - static bool IgnoreNull() { - return false; - } -}; - -static void ListUpdateFunction(Vector inputs[], AggregateInputData &aggr_input_data, idx_t input_count, - Vector &state_vector, idx_t count) { - - D_ASSERT(input_count == 1); - auto &input = inputs[0]; - RecursiveUnifiedVectorFormat input_data; - Vector::RecursiveToUnifiedFormat(input, count, input_data); - - UnifiedVectorFormat states_data; - state_vector.ToUnifiedFormat(count, states_data); - auto states = UnifiedVectorFormat::GetData(states_data); - - auto &list_bind_data = aggr_input_data.bind_data->Cast(); - - for (idx_t i = 0; i < count; i++) { - auto &state = *states[states_data.sel->get_index(i)]; - aggr_input_data.allocator.AlignNext(); - list_bind_data.functions.AppendRow(aggr_input_data.allocator, state.linked_list, input_data, i); - } -} - -static void ListAbsorbFunction(Vector &states_vector, Vector &combined, AggregateInputData &aggr_input_data, - idx_t count) { - D_ASSERT(aggr_input_data.combine_type == AggregateCombineType::ALLOW_DESTRUCTIVE); - - UnifiedVectorFormat states_data; - states_vector.ToUnifiedFormat(count, states_data); - auto states_ptr = UnifiedVectorFormat::GetData(states_data); - - auto combined_ptr = FlatVector::GetData(combined); - for (idx_t i = 0; i < count; i++) { - - auto &state = *states_ptr[states_data.sel->get_index(i)]; - if (state.linked_list.total_capacity == 0) { - // NULL, no need to append - // this can happen when adding a FILTER to the grouping, e.g., - // LIST(i) FILTER (WHERE i <> 3) - continue; - } - - if (combined_ptr[i]->linked_list.total_capacity == 0) { - combined_ptr[i]->linked_list = state.linked_list; - continue; - } - - // append the linked list - combined_ptr[i]->linked_list.last_segment->next = state.linked_list.first_segment; - combined_ptr[i]->linked_list.last_segment = state.linked_list.last_segment; - combined_ptr[i]->linked_list.total_capacity += state.linked_list.total_capacity; - } -} - -static void ListFinalize(Vector &states_vector, AggregateInputData &aggr_input_data, Vector &result, idx_t count, - idx_t offset) { - - UnifiedVectorFormat states_data; - states_vector.ToUnifiedFormat(count, states_data); - auto states = UnifiedVectorFormat::GetData(states_data); - - D_ASSERT(result.GetType().id() == LogicalTypeId::LIST); - - auto &mask = FlatVector::Validity(result); - auto result_data = FlatVector::GetData(result); - size_t total_len = ListVector::GetListSize(result); - - auto &list_bind_data = aggr_input_data.bind_data->Cast(); - - // first iterate over all entries and set up the list entries, and get the newly required total length - for (idx_t i = 0; i < count; i++) { - - auto &state = *states[states_data.sel->get_index(i)]; - const auto rid = i + offset; - result_data[rid].offset = total_len; - if (state.linked_list.total_capacity == 0) { - mask.SetInvalid(rid); - result_data[rid].length = 0; - continue; - } - - // set the length and offset of this list in the result vector - auto total_capacity = state.linked_list.total_capacity; - result_data[rid].length = total_capacity; - total_len += total_capacity; - } - - // reserve capacity, then iterate over all entries again and copy over the data to the child vector - ListVector::Reserve(result, total_len); - auto &result_child = ListVector::GetEntry(result); - for (idx_t i = 0; i < count; i++) { - - auto &state = *states[states_data.sel->get_index(i)]; - const auto rid = i + offset; - if (state.linked_list.total_capacity == 0) { - continue; - } - - idx_t current_offset = result_data[rid].offset; - list_bind_data.functions.BuildListVector(state.linked_list, result_child, current_offset); - } - - ListVector::SetListSize(result, total_len); -} - -static void ListCombineFunction(Vector &states_vector, Vector &combined, AggregateInputData &aggr_input_data, - idx_t count) { - - // Can we use destructive combining? - if (aggr_input_data.combine_type == AggregateCombineType::ALLOW_DESTRUCTIVE) { - ListAbsorbFunction(states_vector, combined, aggr_input_data, count); - return; - } - - UnifiedVectorFormat states_data; - states_vector.ToUnifiedFormat(count, states_data); - auto states_ptr = UnifiedVectorFormat::GetData(states_data); - auto combined_ptr = FlatVector::GetData(combined); - - auto &list_bind_data = aggr_input_data.bind_data->Cast(); - auto result_type = ListType::GetChildType(list_bind_data.stype); - - for (idx_t i = 0; i < count; i++) { - auto &source = *states_ptr[states_data.sel->get_index(i)]; - auto &target = *combined_ptr[i]; - - const auto entry_count = source.linked_list.total_capacity; - Vector input(result_type, source.linked_list.total_capacity); - list_bind_data.functions.BuildListVector(source.linked_list, input, 0); - - RecursiveUnifiedVectorFormat input_data; - Vector::RecursiveToUnifiedFormat(input, entry_count, input_data); - - for (idx_t entry_idx = 0; entry_idx < entry_count; ++entry_idx) { - aggr_input_data.allocator.AlignNext(); - list_bind_data.functions.AppendRow(aggr_input_data.allocator, target.linked_list, input_data, entry_idx); - } - } -} - -unique_ptr ListBindFunction(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - D_ASSERT(arguments.size() == 1); - D_ASSERT(function.arguments.size() == 1); - - if (arguments[0]->return_type.id() == LogicalTypeId::UNKNOWN) { - function.arguments[0] = LogicalTypeId::UNKNOWN; - function.return_type = LogicalType::SQLNULL; - return nullptr; - } - - function.return_type = LogicalType::LIST(arguments[0]->return_type); - return make_uniq(function.return_type); -} - -AggregateFunction ListFun::GetFunction() { - auto func = - AggregateFunction({LogicalType::ANY}, LogicalTypeId::LIST, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, ListUpdateFunction, - ListCombineFunction, ListFinalize, nullptr, ListBindFunction, nullptr, nullptr, nullptr); - - return func; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/regression/regr_avg.cpp b/src/duckdb/src/core_functions/aggregate/regression/regr_avg.cpp deleted file mode 100644 index 4136ab034..000000000 --- a/src/duckdb/src/core_functions/aggregate/regression/regr_avg.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/core_functions/aggregate/regression_functions.hpp" -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "duckdb/function/function_set.hpp" - -namespace duckdb { -struct RegrState { - double sum; - size_t count; -}; - -struct RegrAvgFunction { - template - static void Initialize(STATE &state) { - state.sum = 0; - state.count = 0; - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - target.sum += source.sum; - target.count += source.count; - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.count == 0) { - finalize_data.ReturnNull(); - } else { - target = state.sum / (double)state.count; - } - } - static bool IgnoreNull() { - return true; - } -}; -struct RegrAvgXFunction : RegrAvgFunction { - template - static void Operation(STATE &state, const A_TYPE &y, const B_TYPE &x, AggregateBinaryInput &idata) { - state.sum += x; - state.count++; - } -}; - -struct RegrAvgYFunction : RegrAvgFunction { - template - static void Operation(STATE &state, const A_TYPE &y, const B_TYPE &x, AggregateBinaryInput &idata) { - state.sum += y; - state.count++; - } -}; - -AggregateFunction RegrAvgxFun::GetFunction() { - return AggregateFunction::BinaryAggregate( - LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE); -} - -AggregateFunction RegrAvgyFun::GetFunction() { - return AggregateFunction::BinaryAggregate( - LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/regression/regr_count.cpp b/src/duckdb/src/core_functions/aggregate/regression/regr_count.cpp deleted file mode 100644 index 333bef41b..000000000 --- a/src/duckdb/src/core_functions/aggregate/regression/regr_count.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/core_functions/aggregate/regression_functions.hpp" -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "duckdb/core_functions/aggregate/regression/regr_count.hpp" -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -AggregateFunction RegrCountFun::GetFunction() { - auto regr_count = AggregateFunction::BinaryAggregate( - LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::UINTEGER); - regr_count.name = "regr_count"; - regr_count.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return regr_count; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/regression/regr_intercept.cpp b/src/duckdb/src/core_functions/aggregate/regression/regr_intercept.cpp deleted file mode 100644 index a3a117456..000000000 --- a/src/duckdb/src/core_functions/aggregate/regression/regr_intercept.cpp +++ /dev/null @@ -1,63 +0,0 @@ -//! AVG(y)-REGR_SLOPE(y,x)*AVG(x) - -#include "duckdb/core_functions/aggregate/regression_functions.hpp" -#include "duckdb/core_functions/aggregate/regression/regr_slope.hpp" -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct RegrInterceptState { - size_t count; - double sum_x; - double sum_y; - RegrSlopeState slope; -}; - -struct RegrInterceptOperation { - template - static void Initialize(STATE &state) { - state.count = 0; - state.sum_x = 0; - state.sum_y = 0; - RegrSlopeOperation::Initialize(state.slope); - } - - template - static void Operation(STATE &state, const A_TYPE &y, const B_TYPE &x, AggregateBinaryInput &idata) { - state.count++; - state.sum_x += x; - state.sum_y += y; - RegrSlopeOperation::Operation(state.slope, y, x, idata); - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &aggr_input_data) { - target.count += source.count; - target.sum_x += source.sum_x; - target.sum_y += source.sum_y; - RegrSlopeOperation::Combine(source.slope, target.slope, aggr_input_data); - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.count == 0) { - finalize_data.ReturnNull(); - return; - } - RegrSlopeOperation::Finalize(state.slope, target, finalize_data); - auto x_avg = state.sum_x / state.count; - auto y_avg = state.sum_y / state.count; - target = y_avg - target * x_avg; - } - - static bool IgnoreNull() { - return true; - } -}; - -AggregateFunction RegrInterceptFun::GetFunction() { - return AggregateFunction::BinaryAggregate( - LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/regression/regr_r2.cpp b/src/duckdb/src/core_functions/aggregate/regression/regr_r2.cpp deleted file mode 100644 index 4d68225e8..000000000 --- a/src/duckdb/src/core_functions/aggregate/regression/regr_r2.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// REGR_R2(y, x) -// Returns the coefficient of determination for non-null pairs in a group. -// It is computed for non-null pairs using the following formula: -// null if var_pop(x) = 0, else -// 1 if var_pop(y) = 0 and var_pop(x) <> 0, else -// power(corr(y,x), 2) - -#include "duckdb/core_functions/aggregate/algebraic/corr.hpp" -#include "duckdb/function/function_set.hpp" -#include "duckdb/core_functions/aggregate/regression_functions.hpp" - -namespace duckdb { -struct RegrR2State { - CorrState corr; - StddevState var_pop_x; - StddevState var_pop_y; -}; - -struct RegrR2Operation { - template - static void Initialize(STATE &state) { - CorrOperation::Initialize(state.corr); - STDDevBaseOperation::Initialize(state.var_pop_x); - STDDevBaseOperation::Initialize(state.var_pop_y); - } - - template - static void Operation(STATE &state, const A_TYPE &y, const B_TYPE &x, AggregateBinaryInput &idata) { - CorrOperation::Operation(state.corr, y, x, idata); - STDDevBaseOperation::Execute(state.var_pop_x, x); - STDDevBaseOperation::Execute(state.var_pop_y, y); - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &aggr_input_data) { - CorrOperation::Combine(source.corr, target.corr, aggr_input_data); - STDDevBaseOperation::Combine(source.var_pop_x, target.var_pop_x, aggr_input_data); - STDDevBaseOperation::Combine(source.var_pop_y, target.var_pop_y, aggr_input_data); - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - auto var_pop_x = state.var_pop_x.count > 1 ? (state.var_pop_x.dsquared / state.var_pop_x.count) : 0; - if (!Value::DoubleIsFinite(var_pop_x)) { - throw OutOfRangeException("VARPOP(X) is out of range!"); - } - if (var_pop_x == 0) { - finalize_data.ReturnNull(); - return; - } - auto var_pop_y = state.var_pop_y.count > 1 ? (state.var_pop_y.dsquared / state.var_pop_y.count) : 0; - if (!Value::DoubleIsFinite(var_pop_y)) { - throw OutOfRangeException("VARPOP(Y) is out of range!"); - } - if (var_pop_y == 0) { - target = 1; - return; - } - CorrOperation::Finalize(state.corr, target, finalize_data); - target = pow(target, 2); - } - - static bool IgnoreNull() { - return true; - } -}; - -AggregateFunction RegrR2Fun::GetFunction() { - return AggregateFunction::BinaryAggregate( - LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE); -} -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/regression/regr_slope.cpp b/src/duckdb/src/core_functions/aggregate/regression/regr_slope.cpp deleted file mode 100644 index 1e86b011d..000000000 --- a/src/duckdb/src/core_functions/aggregate/regression/regr_slope.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// REGR_SLOPE(y, x) -// Returns the slope of the linear regression line for non-null pairs in a group. -// It is computed for non-null pairs using the following formula: -// COVAR_POP(x,y) / VAR_POP(x) - -//! Input : Any numeric type -//! Output : Double - -#include "duckdb/core_functions/aggregate/regression/regr_slope.hpp" -#include "duckdb/function/function_set.hpp" -#include "duckdb/core_functions/aggregate/regression_functions.hpp" - -namespace duckdb { - -AggregateFunction RegrSlopeFun::GetFunction() { - return AggregateFunction::BinaryAggregate( - LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/regression/regr_sxx_syy.cpp b/src/duckdb/src/core_functions/aggregate/regression/regr_sxx_syy.cpp deleted file mode 100644 index e789172d2..000000000 --- a/src/duckdb/src/core_functions/aggregate/regression/regr_sxx_syy.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// REGR_SXX(y, x) -// Returns REGR_COUNT(y, x) * VAR_POP(x) for non-null pairs. -// REGR_SYY(y, x) -// Returns REGR_COUNT(y, x) * VAR_POP(y) for non-null pairs. - -#include "duckdb/core_functions/aggregate/regression/regr_count.hpp" -#include "duckdb/function/function_set.hpp" -#include "duckdb/core_functions/aggregate/regression_functions.hpp" - -namespace duckdb { - -struct RegrSState { - size_t count; - StddevState var_pop; -}; - -struct RegrBaseOperation { - template - static void Initialize(STATE &state) { - RegrCountFunction::Initialize(state.count); - STDDevBaseOperation::Initialize(state.var_pop); - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &aggr_input_data) { - RegrCountFunction::Combine(source.count, target.count, aggr_input_data); - STDDevBaseOperation::Combine(source.var_pop, target.var_pop, aggr_input_data); - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.var_pop.count == 0) { - finalize_data.ReturnNull(); - return; - } - auto var_pop = state.var_pop.count > 1 ? (state.var_pop.dsquared / state.var_pop.count) : 0; - if (!Value::DoubleIsFinite(var_pop)) { - throw OutOfRangeException("VARPOP is out of range!"); - } - RegrCountFunction::Finalize(state.count, target, finalize_data); - target *= var_pop; - } - - static bool IgnoreNull() { - return true; - } -}; - -struct RegrSXXOperation : RegrBaseOperation { - template - static void Operation(STATE &state, const A_TYPE &y, const B_TYPE &x, AggregateBinaryInput &idata) { - RegrCountFunction::Operation(state.count, y, x, idata); - STDDevBaseOperation::Execute(state.var_pop, x); - } -}; - -struct RegrSYYOperation : RegrBaseOperation { - template - static void Operation(STATE &state, const A_TYPE &y, const B_TYPE &x, AggregateBinaryInput &idata) { - RegrCountFunction::Operation(state.count, y, x, idata); - STDDevBaseOperation::Execute(state.var_pop, y); - } -}; - -AggregateFunction RegrSXXFun::GetFunction() { - return AggregateFunction::BinaryAggregate( - LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE); -} - -AggregateFunction RegrSYYFun::GetFunction() { - return AggregateFunction::BinaryAggregate( - LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/regression/regr_sxy.cpp b/src/duckdb/src/core_functions/aggregate/regression/regr_sxy.cpp deleted file mode 100644 index e3f3d4ae9..000000000 --- a/src/duckdb/src/core_functions/aggregate/regression/regr_sxy.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// REGR_SXY(y, x) -// Returns REGR_COUNT(expr1, expr2) * COVAR_POP(expr1, expr2) for non-null pairs. - -#include "duckdb/core_functions/aggregate/regression/regr_count.hpp" -#include "duckdb/core_functions/aggregate/algebraic/covar.hpp" -#include "duckdb/core_functions/aggregate/regression_functions.hpp" -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct RegrSXyState { - size_t count; - CovarState cov_pop; -}; - -struct RegrSXYOperation { - template - static void Initialize(STATE &state) { - RegrCountFunction::Initialize(state.count); - CovarOperation::Initialize(state.cov_pop); - } - - template - static void Operation(STATE &state, const A_TYPE &y, const B_TYPE &x, AggregateBinaryInput &idata) { - RegrCountFunction::Operation(state.count, y, x, idata); - CovarOperation::Operation(state.cov_pop, y, x, idata); - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &aggr_input_data) { - CovarOperation::Combine(source.cov_pop, target.cov_pop, aggr_input_data); - RegrCountFunction::Combine(source.count, target.count, aggr_input_data); - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - CovarPopOperation::Finalize(state.cov_pop, target, finalize_data); - auto cov_pop = target; - RegrCountFunction::Finalize(state.count, target, finalize_data); - target *= cov_pop; - } - - static bool IgnoreNull() { - return true; - } -}; - -AggregateFunction RegrSXYFun::GetFunction() { - return AggregateFunction::BinaryAggregate( - LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/function_list.cpp b/src/duckdb/src/core_functions/function_list.cpp deleted file mode 100644 index ca77e0309..000000000 --- a/src/duckdb/src/core_functions/function_list.cpp +++ /dev/null @@ -1,428 +0,0 @@ -#include "duckdb/core_functions/function_list.hpp" -#include "duckdb/core_functions/aggregate/algebraic_functions.hpp" -#include "duckdb/core_functions/aggregate/distributive_functions.hpp" -#include "duckdb/core_functions/aggregate/holistic_functions.hpp" -#include "duckdb/core_functions/aggregate/nested_functions.hpp" -#include "duckdb/core_functions/aggregate/regression_functions.hpp" -#include "duckdb/core_functions/scalar/bit_functions.hpp" -#include "duckdb/core_functions/scalar/blob_functions.hpp" -#include "duckdb/core_functions/scalar/date_functions.hpp" -#include "duckdb/core_functions/scalar/enum_functions.hpp" -#include "duckdb/core_functions/scalar/generic_functions.hpp" -#include "duckdb/core_functions/scalar/list_functions.hpp" -#include "duckdb/core_functions/scalar/map_functions.hpp" -#include "duckdb/core_functions/scalar/math_functions.hpp" -#include "duckdb/core_functions/scalar/operators_functions.hpp" -#include "duckdb/core_functions/scalar/random_functions.hpp" -#include "duckdb/core_functions/scalar/secret_functions.hpp" -#include "duckdb/core_functions/scalar/string_functions.hpp" -#include "duckdb/core_functions/scalar/struct_functions.hpp" -#include "duckdb/core_functions/scalar/union_functions.hpp" -#include "duckdb/core_functions/scalar/array_functions.hpp" -#include "duckdb/core_functions/scalar/debug_functions.hpp" - -namespace duckdb { - -// Scalar Function -#define DUCKDB_SCALAR_FUNCTION_BASE(_PARAM, _NAME) \ - { _NAME, _PARAM::Parameters, _PARAM::Description, _PARAM::Example, _PARAM::GetFunction, nullptr, nullptr, nullptr } -#define DUCKDB_SCALAR_FUNCTION(_PARAM) DUCKDB_SCALAR_FUNCTION_BASE(_PARAM, _PARAM::Name) -#define DUCKDB_SCALAR_FUNCTION_ALIAS(_PARAM) DUCKDB_SCALAR_FUNCTION_BASE(_PARAM::ALIAS, _PARAM::Name) -// Scalar Function Set -#define DUCKDB_SCALAR_FUNCTION_SET_BASE(_PARAM, _NAME) \ - { _NAME, _PARAM::Parameters, _PARAM::Description, _PARAM::Example, nullptr, _PARAM::GetFunctions, nullptr, nullptr } -#define DUCKDB_SCALAR_FUNCTION_SET(_PARAM) DUCKDB_SCALAR_FUNCTION_SET_BASE(_PARAM, _PARAM::Name) -#define DUCKDB_SCALAR_FUNCTION_SET_ALIAS(_PARAM) DUCKDB_SCALAR_FUNCTION_SET_BASE(_PARAM::ALIAS, _PARAM::Name) -// Aggregate Function -#define DUCKDB_AGGREGATE_FUNCTION_BASE(_PARAM, _NAME) \ - { _NAME, _PARAM::Parameters, _PARAM::Description, _PARAM::Example, nullptr, nullptr, _PARAM::GetFunction, nullptr } -#define DUCKDB_AGGREGATE_FUNCTION(_PARAM) DUCKDB_AGGREGATE_FUNCTION_BASE(_PARAM, _PARAM::Name) -#define DUCKDB_AGGREGATE_FUNCTION_ALIAS(_PARAM) DUCKDB_AGGREGATE_FUNCTION_BASE(_PARAM::ALIAS, _PARAM::Name) -// Aggregate Function Set -#define DUCKDB_AGGREGATE_FUNCTION_SET_BASE(_PARAM, _NAME) \ - { _NAME, _PARAM::Parameters, _PARAM::Description, _PARAM::Example, nullptr, nullptr, nullptr, _PARAM::GetFunctions } -#define DUCKDB_AGGREGATE_FUNCTION_SET(_PARAM) DUCKDB_AGGREGATE_FUNCTION_SET_BASE(_PARAM, _PARAM::Name) -#define DUCKDB_AGGREGATE_FUNCTION_SET_ALIAS(_PARAM) DUCKDB_AGGREGATE_FUNCTION_SET_BASE(_PARAM::ALIAS, _PARAM::Name) -#define FINAL_FUNCTION \ - { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr } - -// this list is generated by scripts/generate_functions.py -static const StaticFunctionDefinition internal_functions[] = { - DUCKDB_SCALAR_FUNCTION(FactorialOperatorFun), - DUCKDB_SCALAR_FUNCTION_SET(BitwiseAndFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ListHasAnyFunAlias), - DUCKDB_SCALAR_FUNCTION(PowOperatorFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ListDistanceFunAlias), - DUCKDB_SCALAR_FUNCTION_SET(LeftShiftFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ListCosineDistanceFunAlias), - DUCKDB_SCALAR_FUNCTION_ALIAS(ListHasAllFunAlias2), - DUCKDB_SCALAR_FUNCTION_SET(RightShiftFun), - DUCKDB_SCALAR_FUNCTION_SET(AbsOperatorFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ListHasAllFunAlias), - DUCKDB_SCALAR_FUNCTION_ALIAS(PowOperatorFunAlias), - DUCKDB_SCALAR_FUNCTION(StartsWithOperatorFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(AbsFun), - DUCKDB_SCALAR_FUNCTION(AcosFun), - DUCKDB_SCALAR_FUNCTION(AcoshFun), - DUCKDB_SCALAR_FUNCTION_SET(AgeFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(AggregateFun), - DUCKDB_SCALAR_FUNCTION(AliasFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ApplyFun), - DUCKDB_AGGREGATE_FUNCTION(ApproxCountDistinctFun), - DUCKDB_AGGREGATE_FUNCTION_SET(ApproxQuantileFun), - DUCKDB_AGGREGATE_FUNCTION(ApproxTopKFun), - DUCKDB_AGGREGATE_FUNCTION_SET(ArgMaxFun), - DUCKDB_AGGREGATE_FUNCTION_SET(ArgMaxNullFun), - DUCKDB_AGGREGATE_FUNCTION_SET(ArgMinFun), - DUCKDB_AGGREGATE_FUNCTION_SET(ArgMinNullFun), - DUCKDB_AGGREGATE_FUNCTION_SET_ALIAS(ArgmaxFun), - DUCKDB_AGGREGATE_FUNCTION_SET_ALIAS(ArgminFun), - DUCKDB_AGGREGATE_FUNCTION_ALIAS(ArrayAggFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayAggrFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayAggregateFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayApplyFun), - DUCKDB_SCALAR_FUNCTION_SET(ArrayCosineDistanceFun), - DUCKDB_SCALAR_FUNCTION_SET(ArrayCosineSimilarityFun), - DUCKDB_SCALAR_FUNCTION_SET(ArrayCrossProductFun), - DUCKDB_SCALAR_FUNCTION_SET(ArrayDistanceFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayDistinctFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ArrayDotProductFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayFilterFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ArrayGradeUpFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayHasAllFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayHasAnyFun), - DUCKDB_SCALAR_FUNCTION_SET(ArrayInnerProductFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ArrayNegativeDotProductFun), - DUCKDB_SCALAR_FUNCTION_SET(ArrayNegativeInnerProductFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayReduceFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ArrayReverseSortFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ArraySliceFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ArraySortFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayTransformFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayUniqueFun), - DUCKDB_SCALAR_FUNCTION(ArrayValueFun), - DUCKDB_SCALAR_FUNCTION(ASCIIFun), - DUCKDB_SCALAR_FUNCTION(AsinFun), - DUCKDB_SCALAR_FUNCTION(AsinhFun), - DUCKDB_SCALAR_FUNCTION(AtanFun), - DUCKDB_SCALAR_FUNCTION(Atan2Fun), - DUCKDB_SCALAR_FUNCTION(AtanhFun), - DUCKDB_AGGREGATE_FUNCTION_SET(AvgFun), - DUCKDB_SCALAR_FUNCTION_SET(BarFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(Base64Fun), - DUCKDB_SCALAR_FUNCTION_SET(BinFun), - DUCKDB_AGGREGATE_FUNCTION_SET(BitAndFun), - DUCKDB_SCALAR_FUNCTION_SET(BitCountFun), - DUCKDB_AGGREGATE_FUNCTION_SET(BitOrFun), - DUCKDB_SCALAR_FUNCTION(BitPositionFun), - DUCKDB_AGGREGATE_FUNCTION_SET(BitXorFun), - DUCKDB_SCALAR_FUNCTION_SET(BitStringFun), - DUCKDB_AGGREGATE_FUNCTION_SET(BitstringAggFun), - DUCKDB_AGGREGATE_FUNCTION(BoolAndFun), - DUCKDB_AGGREGATE_FUNCTION(BoolOrFun), - DUCKDB_SCALAR_FUNCTION(CanCastImplicitlyFun), - DUCKDB_SCALAR_FUNCTION(CardinalityFun), - DUCKDB_SCALAR_FUNCTION(CbrtFun), - DUCKDB_SCALAR_FUNCTION_SET(CeilFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(CeilingFun), - DUCKDB_SCALAR_FUNCTION_SET(CenturyFun), - DUCKDB_SCALAR_FUNCTION(ChrFun), - DUCKDB_AGGREGATE_FUNCTION(CorrFun), - DUCKDB_SCALAR_FUNCTION(CosFun), - DUCKDB_SCALAR_FUNCTION(CoshFun), - DUCKDB_SCALAR_FUNCTION(CotFun), - DUCKDB_AGGREGATE_FUNCTION(CovarPopFun), - DUCKDB_AGGREGATE_FUNCTION(CovarSampFun), - DUCKDB_SCALAR_FUNCTION(CreateSortKeyFun), - DUCKDB_SCALAR_FUNCTION(CurrentDatabaseFun), - DUCKDB_SCALAR_FUNCTION(CurrentDateFun), - DUCKDB_SCALAR_FUNCTION(CurrentQueryFun), - DUCKDB_SCALAR_FUNCTION(CurrentSchemaFun), - DUCKDB_SCALAR_FUNCTION(CurrentSchemasFun), - DUCKDB_SCALAR_FUNCTION(CurrentSettingFun), - DUCKDB_SCALAR_FUNCTION(DamerauLevenshteinFun), - DUCKDB_SCALAR_FUNCTION_SET(DateDiffFun), - DUCKDB_SCALAR_FUNCTION_SET(DatePartFun), - DUCKDB_SCALAR_FUNCTION_SET(DateSubFun), - DUCKDB_SCALAR_FUNCTION_SET(DateTruncFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(DatediffFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(DatepartFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(DatesubFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(DatetruncFun), - DUCKDB_SCALAR_FUNCTION_SET(DayFun), - DUCKDB_SCALAR_FUNCTION_SET(DayNameFun), - DUCKDB_SCALAR_FUNCTION_SET(DayOfMonthFun), - DUCKDB_SCALAR_FUNCTION_SET(DayOfWeekFun), - DUCKDB_SCALAR_FUNCTION_SET(DayOfYearFun), - DUCKDB_SCALAR_FUNCTION_SET(DecadeFun), - DUCKDB_SCALAR_FUNCTION(DecodeFun), - DUCKDB_SCALAR_FUNCTION(DegreesFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(Editdist3Fun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ElementAtFun), - DUCKDB_SCALAR_FUNCTION(EncodeFun), - DUCKDB_AGGREGATE_FUNCTION_SET(EntropyFun), - DUCKDB_SCALAR_FUNCTION(EnumCodeFun), - DUCKDB_SCALAR_FUNCTION(EnumFirstFun), - DUCKDB_SCALAR_FUNCTION(EnumLastFun), - DUCKDB_SCALAR_FUNCTION(EnumRangeFun), - DUCKDB_SCALAR_FUNCTION(EnumRangeBoundaryFun), - DUCKDB_SCALAR_FUNCTION_SET(EpochFun), - DUCKDB_SCALAR_FUNCTION_SET(EpochMsFun), - DUCKDB_SCALAR_FUNCTION_SET(EpochNsFun), - DUCKDB_SCALAR_FUNCTION_SET(EpochUsFun), - DUCKDB_SCALAR_FUNCTION_SET(EquiWidthBinsFun), - DUCKDB_SCALAR_FUNCTION_SET(EraFun), - DUCKDB_SCALAR_FUNCTION(ErrorFun), - DUCKDB_SCALAR_FUNCTION(EvenFun), - DUCKDB_SCALAR_FUNCTION(ExpFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(FactorialFun), - DUCKDB_AGGREGATE_FUNCTION(FAvgFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(FilterFun), - DUCKDB_SCALAR_FUNCTION(ListFlattenFun), - DUCKDB_SCALAR_FUNCTION_SET(FloorFun), - DUCKDB_SCALAR_FUNCTION(FormatFun), - DUCKDB_SCALAR_FUNCTION(FormatreadabledecimalsizeFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(FormatreadablesizeFun), - DUCKDB_SCALAR_FUNCTION(FormatBytesFun), - DUCKDB_SCALAR_FUNCTION(FromBase64Fun), - DUCKDB_SCALAR_FUNCTION_ALIAS(FromBinaryFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(FromHexFun), - DUCKDB_AGGREGATE_FUNCTION_ALIAS(FsumFun), - DUCKDB_SCALAR_FUNCTION(GammaFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(GcdFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(GenRandomUuidFun), - DUCKDB_SCALAR_FUNCTION_SET(GenerateSeriesFun), - DUCKDB_SCALAR_FUNCTION(GetBitFun), - DUCKDB_SCALAR_FUNCTION(CurrentTimeFun), - DUCKDB_SCALAR_FUNCTION(GetCurrentTimestampFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(GradeUpFun), - DUCKDB_SCALAR_FUNCTION_SET(GreatestFun), - DUCKDB_SCALAR_FUNCTION_SET(GreatestCommonDivisorFun), - DUCKDB_AGGREGATE_FUNCTION_SET_ALIAS(GroupConcatFun), - DUCKDB_SCALAR_FUNCTION(HammingFun), - DUCKDB_SCALAR_FUNCTION(HashFun), - DUCKDB_SCALAR_FUNCTION_SET(HexFun), - DUCKDB_AGGREGATE_FUNCTION_SET(HistogramFun), - DUCKDB_AGGREGATE_FUNCTION(HistogramExactFun), - DUCKDB_SCALAR_FUNCTION_SET(HoursFun), - DUCKDB_SCALAR_FUNCTION(InSearchPathFun), - DUCKDB_SCALAR_FUNCTION(InstrFun), - DUCKDB_SCALAR_FUNCTION(IsHistogramOtherBinFun), - DUCKDB_SCALAR_FUNCTION_SET(IsFiniteFun), - DUCKDB_SCALAR_FUNCTION_SET(IsInfiniteFun), - DUCKDB_SCALAR_FUNCTION_SET(IsNanFun), - DUCKDB_SCALAR_FUNCTION_SET(ISODayOfWeekFun), - DUCKDB_SCALAR_FUNCTION_SET(ISOYearFun), - DUCKDB_SCALAR_FUNCTION(JaccardFun), - DUCKDB_SCALAR_FUNCTION(JaroSimilarityFun), - DUCKDB_SCALAR_FUNCTION(JaroWinklerSimilarityFun), - DUCKDB_SCALAR_FUNCTION_SET(JulianDayFun), - DUCKDB_AGGREGATE_FUNCTION(KahanSumFun), - DUCKDB_AGGREGATE_FUNCTION(KurtosisFun), - DUCKDB_AGGREGATE_FUNCTION(KurtosisPopFun), - DUCKDB_SCALAR_FUNCTION_SET(LastDayFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(LcmFun), - DUCKDB_SCALAR_FUNCTION_SET(LeastFun), - DUCKDB_SCALAR_FUNCTION_SET(LeastCommonMultipleFun), - DUCKDB_SCALAR_FUNCTION(LeftFun), - DUCKDB_SCALAR_FUNCTION(LeftGraphemeFun), - DUCKDB_SCALAR_FUNCTION(LevenshteinFun), - DUCKDB_SCALAR_FUNCTION(LogGammaFun), - DUCKDB_AGGREGATE_FUNCTION(ListFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ListAggrFun), - DUCKDB_SCALAR_FUNCTION(ListAggregateFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ListApplyFun), - DUCKDB_SCALAR_FUNCTION_SET(ListCosineDistanceFun), - DUCKDB_SCALAR_FUNCTION_SET(ListCosineSimilarityFun), - DUCKDB_SCALAR_FUNCTION_SET(ListDistanceFun), - DUCKDB_SCALAR_FUNCTION(ListDistinctFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ListDotProductFun), - DUCKDB_SCALAR_FUNCTION(ListFilterFun), - DUCKDB_SCALAR_FUNCTION_SET(ListGradeUpFun), - DUCKDB_SCALAR_FUNCTION(ListHasAllFun), - DUCKDB_SCALAR_FUNCTION(ListHasAnyFun), - DUCKDB_SCALAR_FUNCTION_SET(ListInnerProductFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ListNegativeDotProductFun), - DUCKDB_SCALAR_FUNCTION_SET(ListNegativeInnerProductFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ListPackFun), - DUCKDB_SCALAR_FUNCTION(ListReduceFun), - DUCKDB_SCALAR_FUNCTION_SET(ListReverseSortFun), - DUCKDB_SCALAR_FUNCTION_SET(ListSliceFun), - DUCKDB_SCALAR_FUNCTION_SET(ListSortFun), - DUCKDB_SCALAR_FUNCTION(ListTransformFun), - DUCKDB_SCALAR_FUNCTION(ListUniqueFun), - DUCKDB_SCALAR_FUNCTION(ListValueFun), - DUCKDB_AGGREGATE_FUNCTION_SET_ALIAS(ListaggFun), - DUCKDB_SCALAR_FUNCTION(LnFun), - DUCKDB_SCALAR_FUNCTION_SET(LogFun), - DUCKDB_SCALAR_FUNCTION(Log10Fun), - DUCKDB_SCALAR_FUNCTION(Log2Fun), - DUCKDB_SCALAR_FUNCTION(LpadFun), - DUCKDB_SCALAR_FUNCTION_SET(LtrimFun), - DUCKDB_AGGREGATE_FUNCTION_SET(MadFun), - DUCKDB_SCALAR_FUNCTION_SET(MakeDateFun), - DUCKDB_SCALAR_FUNCTION(MakeTimeFun), - DUCKDB_SCALAR_FUNCTION_SET(MakeTimestampFun), - DUCKDB_SCALAR_FUNCTION(MapFun), - DUCKDB_SCALAR_FUNCTION(MapConcatFun), - DUCKDB_SCALAR_FUNCTION(MapContainsFun), - DUCKDB_SCALAR_FUNCTION(MapEntriesFun), - DUCKDB_SCALAR_FUNCTION(MapExtractFun), - DUCKDB_SCALAR_FUNCTION(MapFromEntriesFun), - DUCKDB_SCALAR_FUNCTION(MapKeysFun), - DUCKDB_SCALAR_FUNCTION(MapValuesFun), - DUCKDB_AGGREGATE_FUNCTION_SET(MaxFun), - DUCKDB_AGGREGATE_FUNCTION_SET_ALIAS(MaxByFun), - DUCKDB_SCALAR_FUNCTION_SET(MD5Fun), - DUCKDB_SCALAR_FUNCTION_SET(MD5NumberFun), - DUCKDB_AGGREGATE_FUNCTION_SET_ALIAS(MeanFun), - DUCKDB_AGGREGATE_FUNCTION_SET(MedianFun), - DUCKDB_SCALAR_FUNCTION_SET(MicrosecondsFun), - DUCKDB_SCALAR_FUNCTION_SET(MillenniumFun), - DUCKDB_SCALAR_FUNCTION_SET(MillisecondsFun), - DUCKDB_AGGREGATE_FUNCTION_SET(MinFun), - DUCKDB_AGGREGATE_FUNCTION_SET_ALIAS(MinByFun), - DUCKDB_SCALAR_FUNCTION_SET(MinutesFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(MismatchesFun), - DUCKDB_AGGREGATE_FUNCTION_SET(ModeFun), - DUCKDB_SCALAR_FUNCTION_SET(MonthFun), - DUCKDB_SCALAR_FUNCTION_SET(MonthNameFun), - DUCKDB_SCALAR_FUNCTION_SET(NanosecondsFun), - DUCKDB_SCALAR_FUNCTION_SET(NextAfterFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(NowFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(OrdFun), - DUCKDB_SCALAR_FUNCTION_SET(ParseDirnameFun), - DUCKDB_SCALAR_FUNCTION_SET(ParseDirpathFun), - DUCKDB_SCALAR_FUNCTION_SET(ParseFilenameFun), - DUCKDB_SCALAR_FUNCTION_SET(ParsePathFun), - DUCKDB_SCALAR_FUNCTION(PiFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(PositionFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(PowFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(PowerFun), - DUCKDB_SCALAR_FUNCTION(PrintfFun), - DUCKDB_AGGREGATE_FUNCTION(ProductFun), - DUCKDB_AGGREGATE_FUNCTION_SET_ALIAS(QuantileFun), - DUCKDB_AGGREGATE_FUNCTION_SET(QuantileContFun), - DUCKDB_AGGREGATE_FUNCTION_SET(QuantileDiscFun), - DUCKDB_SCALAR_FUNCTION_SET(QuarterFun), - DUCKDB_SCALAR_FUNCTION(RadiansFun), - DUCKDB_SCALAR_FUNCTION(RandomFun), - DUCKDB_SCALAR_FUNCTION_SET(ListRangeFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ReduceFun), - DUCKDB_SCALAR_FUNCTION(RegexpEscapeFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(RegexpSplitToArrayFun), - DUCKDB_AGGREGATE_FUNCTION(RegrAvgxFun), - DUCKDB_AGGREGATE_FUNCTION(RegrAvgyFun), - DUCKDB_AGGREGATE_FUNCTION(RegrCountFun), - DUCKDB_AGGREGATE_FUNCTION(RegrInterceptFun), - DUCKDB_AGGREGATE_FUNCTION(RegrR2Fun), - DUCKDB_AGGREGATE_FUNCTION(RegrSlopeFun), - DUCKDB_AGGREGATE_FUNCTION(RegrSXXFun), - DUCKDB_AGGREGATE_FUNCTION(RegrSXYFun), - DUCKDB_AGGREGATE_FUNCTION(RegrSYYFun), - DUCKDB_SCALAR_FUNCTION_SET(RepeatFun), - DUCKDB_SCALAR_FUNCTION(ReplaceFun), - DUCKDB_AGGREGATE_FUNCTION_SET(ReservoirQuantileFun), - DUCKDB_SCALAR_FUNCTION(ReverseFun), - DUCKDB_SCALAR_FUNCTION(RightFun), - DUCKDB_SCALAR_FUNCTION(RightGraphemeFun), - DUCKDB_SCALAR_FUNCTION_SET(RoundFun), - DUCKDB_SCALAR_FUNCTION(RowFun), - DUCKDB_SCALAR_FUNCTION(RpadFun), - DUCKDB_SCALAR_FUNCTION_SET(RtrimFun), - DUCKDB_SCALAR_FUNCTION_SET(SecondsFun), - DUCKDB_AGGREGATE_FUNCTION(StandardErrorOfTheMeanFun), - DUCKDB_SCALAR_FUNCTION(SetBitFun), - DUCKDB_SCALAR_FUNCTION(SetseedFun), - DUCKDB_SCALAR_FUNCTION_SET(SHA1Fun), - DUCKDB_SCALAR_FUNCTION_SET(SHA256Fun), - DUCKDB_SCALAR_FUNCTION_SET(SignFun), - DUCKDB_SCALAR_FUNCTION_SET(SignBitFun), - DUCKDB_SCALAR_FUNCTION(SinFun), - DUCKDB_SCALAR_FUNCTION(SinhFun), - DUCKDB_AGGREGATE_FUNCTION(SkewnessFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(SplitFun), - DUCKDB_SCALAR_FUNCTION(SqrtFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(StartsWithFun), - DUCKDB_SCALAR_FUNCTION(StatsFun), - DUCKDB_AGGREGATE_FUNCTION_ALIAS(StddevFun), - DUCKDB_AGGREGATE_FUNCTION(StdDevPopFun), - DUCKDB_AGGREGATE_FUNCTION(StdDevSampFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(StrSplitFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(StrSplitRegexFun), - DUCKDB_SCALAR_FUNCTION_SET(StrfTimeFun), - DUCKDB_AGGREGATE_FUNCTION_SET(StringAggFun), - DUCKDB_SCALAR_FUNCTION(StringSplitFun), - DUCKDB_SCALAR_FUNCTION_SET(StringSplitRegexFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(StringToArrayFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(StrposFun), - DUCKDB_SCALAR_FUNCTION_SET(StrpTimeFun), - DUCKDB_SCALAR_FUNCTION(StructInsertFun), - DUCKDB_SCALAR_FUNCTION(StructPackFun), - DUCKDB_AGGREGATE_FUNCTION_SET(SumFun), - DUCKDB_AGGREGATE_FUNCTION_SET(SumNoOverflowFun), - DUCKDB_AGGREGATE_FUNCTION_ALIAS(SumkahanFun), - DUCKDB_SCALAR_FUNCTION(TanFun), - DUCKDB_SCALAR_FUNCTION(TanhFun), - DUCKDB_SCALAR_FUNCTION_SET(TimeBucketFun), - DUCKDB_SCALAR_FUNCTION(TimeTZSortKeyFun), - DUCKDB_SCALAR_FUNCTION_SET(TimezoneFun), - DUCKDB_SCALAR_FUNCTION_SET(TimezoneHourFun), - DUCKDB_SCALAR_FUNCTION_SET(TimezoneMinuteFun), - DUCKDB_SCALAR_FUNCTION_SET(ToBaseFun), - DUCKDB_SCALAR_FUNCTION(ToBase64Fun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ToBinaryFun), - DUCKDB_SCALAR_FUNCTION(ToCenturiesFun), - DUCKDB_SCALAR_FUNCTION(ToDaysFun), - DUCKDB_SCALAR_FUNCTION(ToDecadesFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ToHexFun), - DUCKDB_SCALAR_FUNCTION(ToHoursFun), - DUCKDB_SCALAR_FUNCTION(ToMicrosecondsFun), - DUCKDB_SCALAR_FUNCTION(ToMillenniaFun), - DUCKDB_SCALAR_FUNCTION(ToMillisecondsFun), - DUCKDB_SCALAR_FUNCTION(ToMinutesFun), - DUCKDB_SCALAR_FUNCTION(ToMonthsFun), - DUCKDB_SCALAR_FUNCTION(ToQuartersFun), - DUCKDB_SCALAR_FUNCTION(ToSecondsFun), - DUCKDB_SCALAR_FUNCTION(ToTimestampFun), - DUCKDB_SCALAR_FUNCTION(ToWeeksFun), - DUCKDB_SCALAR_FUNCTION(ToYearsFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(TodayFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(TransactionTimestampFun), - DUCKDB_SCALAR_FUNCTION(TranslateFun), - DUCKDB_SCALAR_FUNCTION_SET(TrimFun), - DUCKDB_SCALAR_FUNCTION_SET(TruncFun), - DUCKDB_SCALAR_FUNCTION_SET(TryStrpTimeFun), - DUCKDB_SCALAR_FUNCTION(CurrentTransactionIdFun), - DUCKDB_SCALAR_FUNCTION(TypeOfFun), - DUCKDB_SCALAR_FUNCTION(UnbinFun), - DUCKDB_SCALAR_FUNCTION(UnhexFun), - DUCKDB_SCALAR_FUNCTION(UnicodeFun), - DUCKDB_SCALAR_FUNCTION(UnionExtractFun), - DUCKDB_SCALAR_FUNCTION(UnionTagFun), - DUCKDB_SCALAR_FUNCTION(UnionValueFun), - DUCKDB_SCALAR_FUNCTION(UnpivotListFun), - DUCKDB_SCALAR_FUNCTION(UrlDecodeFun), - DUCKDB_SCALAR_FUNCTION(UrlEncodeFun), - DUCKDB_SCALAR_FUNCTION(UUIDFun), - DUCKDB_AGGREGATE_FUNCTION(VarPopFun), - DUCKDB_AGGREGATE_FUNCTION(VarSampFun), - DUCKDB_AGGREGATE_FUNCTION_ALIAS(VarianceFun), - DUCKDB_SCALAR_FUNCTION(VectorTypeFun), - DUCKDB_SCALAR_FUNCTION(VersionFun), - DUCKDB_SCALAR_FUNCTION_SET(WeekFun), - DUCKDB_SCALAR_FUNCTION_SET(WeekDayFun), - DUCKDB_SCALAR_FUNCTION_SET(WeekOfYearFun), - DUCKDB_SCALAR_FUNCTION_SET(BitwiseXorFun), - DUCKDB_SCALAR_FUNCTION_SET(YearFun), - DUCKDB_SCALAR_FUNCTION_SET(YearWeekFun), - DUCKDB_SCALAR_FUNCTION_SET(BitwiseOrFun), - DUCKDB_SCALAR_FUNCTION_SET(BitwiseNotFun), - FINAL_FUNCTION -}; - -const StaticFunctionDefinition *StaticFunctionDefinition::GetFunctionList() { - return internal_functions; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/lambda_functions.cpp b/src/duckdb/src/core_functions/lambda_functions.cpp deleted file mode 100644 index 9a3a03102..000000000 --- a/src/duckdb/src/core_functions/lambda_functions.cpp +++ /dev/null @@ -1,414 +0,0 @@ -#include "duckdb/core_functions/lambda_functions.hpp" - -#include "duckdb/common/serializer/serializer.hpp" -#include "duckdb/common/serializer/deserializer.hpp" - -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/planner/expression/bound_cast_expression.hpp" - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// Helper functions -//===--------------------------------------------------------------------===// - -//! LambdaExecuteInfo holds information for executing the lambda expression on an input chunk and -//! a resulting lambda chunk. -struct LambdaExecuteInfo { - LambdaExecuteInfo(ClientContext &context, const Expression &lambda_expr, const DataChunk &args, - const bool has_index, const Vector &child_vector) - : has_index(has_index) { - - expr_executor = make_uniq(context, lambda_expr); - - // get the input types for the input chunk - vector input_types; - if (has_index) { - input_types.push_back(LogicalType::BIGINT); - } - input_types.push_back(child_vector.GetType()); - for (idx_t i = 1; i < args.ColumnCount(); i++) { - input_types.push_back(args.data[i].GetType()); - } - - // get the result types - vector result_types {lambda_expr.return_type}; - - // initialize the data chunks - input_chunk.InitializeEmpty(input_types); - lambda_chunk.Initialize(Allocator::DefaultAllocator(), result_types); - }; - - //! The expression executor that executes the lambda expression - unique_ptr expr_executor; - //! The input chunk on which we execute the lambda expression - DataChunk input_chunk; - //! The chunk holding the result of executing the lambda expression - DataChunk lambda_chunk; - //! True, if this lambda expression expects an index vector in the input chunk - bool has_index; -}; - -//! A helper struct with information that is specific to the list_filter function -struct ListFilterInfo { - //! The new list lengths after filtering out elements - vector entry_lengths; - //! The length of the current list - idx_t length = 0; - //! The offset of the current list - idx_t offset = 0; - //! The current row index - idx_t row_idx = 0; - //! The length of the source list - idx_t src_length = 0; -}; - -//! ListTransformFunctor contains list_transform specific functionality -struct ListTransformFunctor { - static void ReserveNewLengths(vector &, const idx_t) { - // NOP - } - static void PushEmptyList(vector &) { - // NOP - } - //! Sets the list entries of the result vector - static void SetResultEntry(list_entry_t *result_entries, idx_t &offset, const list_entry_t &entry, - const idx_t row_idx, vector &) { - result_entries[row_idx].offset = offset; - result_entries[row_idx].length = entry.length; - offset += entry.length; - } - //! Appends the lambda vector to the result's child vector - static void AppendResult(Vector &result, Vector &lambda_vector, const idx_t elem_cnt, list_entry_t *, - ListFilterInfo &, LambdaExecuteInfo &) { - ListVector::Append(result, lambda_vector, elem_cnt, 0); - } -}; - -//! ListFilterFunctor contains list_filter specific functionality -struct ListFilterFunctor { - //! Initializes the entry_lengths vector - static void ReserveNewLengths(vector &entry_lengths, const idx_t row_count) { - entry_lengths.reserve(row_count); - } - //! Pushes an empty list to the entry_lengths vector - static void PushEmptyList(vector &entry_lengths) { - entry_lengths.emplace_back(0); - } - //! Pushes the length of the original list to the entry_lengths vector - static void SetResultEntry(list_entry_t *, idx_t &, const list_entry_t &entry, const idx_t, - vector &entry_lengths) { - entry_lengths.push_back(entry.length); - } - //! Uses the lambda vector to filter the incoming list and to append the filtered list to the result vector - static void AppendResult(Vector &result, Vector &lambda_vector, const idx_t elem_cnt, list_entry_t *result_entries, - ListFilterInfo &info, LambdaExecuteInfo &execute_info) { - - idx_t count = 0; - SelectionVector sel(elem_cnt); - UnifiedVectorFormat lambda_data; - lambda_vector.ToUnifiedFormat(elem_cnt, lambda_data); - - auto lambda_values = UnifiedVectorFormat::GetData(lambda_data); - auto &lambda_validity = lambda_data.validity; - - // compute the new lengths and offsets, and create a selection vector - for (idx_t i = 0; i < elem_cnt; i++) { - auto entry_idx = lambda_data.sel->get_index(i); - - // set length and offset of empty lists - while (info.row_idx < info.entry_lengths.size() && !info.entry_lengths[info.row_idx]) { - result_entries[info.row_idx].offset = info.offset; - result_entries[info.row_idx].length = 0; - info.row_idx++; - } - - // found a true value - if (lambda_validity.RowIsValid(entry_idx) && lambda_values[entry_idx]) { - sel.set_index(count++, i); - info.length++; - } - - info.src_length++; - - // we traversed the entire source list - if (info.entry_lengths[info.row_idx] == info.src_length) { - // set the offset and length of the result entry - result_entries[info.row_idx].offset = info.offset; - result_entries[info.row_idx].length = info.length; - - // reset all other fields - info.offset += info.length; - info.row_idx++; - info.length = 0; - info.src_length = 0; - } - } - - // set length and offset of all remaining empty lists - while (info.row_idx < info.entry_lengths.size() && !info.entry_lengths[info.row_idx]) { - result_entries[info.row_idx].offset = info.offset; - result_entries[info.row_idx].length = 0; - info.row_idx++; - } - - // slice the input chunk's corresponding vector to get the new lists - // and append them to the result - idx_t source_list_idx = execute_info.has_index ? 1 : 0; - Vector result_lists(execute_info.input_chunk.data[source_list_idx], sel, count); - ListVector::Append(result, result_lists, count, 0); - } -}; - -vector LambdaFunctions::GetColumnInfo(DataChunk &args, const idx_t row_count) { - vector data; - // skip the input list and then insert all remaining input vectors - for (idx_t i = 1; i < args.ColumnCount(); i++) { - data.emplace_back(args.data[i]); - args.data[i].ToUnifiedFormat(row_count, data.back().format); - } - return data; -} - -vector> -LambdaFunctions::GetMutableColumnInfo(vector &data) { - vector> inconstant_info; - for (auto &entry : data) { - if (entry.vector.get().GetVectorType() != VectorType::CONSTANT_VECTOR) { - inconstant_info.push_back(entry); - } - } - return inconstant_info; -} - -void ExecuteExpression(const idx_t elem_cnt, const LambdaFunctions::ColumnInfo &column_info, - const vector &column_infos, const Vector &index_vector, - LambdaExecuteInfo &info) { - - info.input_chunk.SetCardinality(elem_cnt); - info.lambda_chunk.SetCardinality(elem_cnt); - - // slice the child vector - Vector slice(column_info.vector, column_info.sel, elem_cnt); - - // reference the child vector (and the index vector) - if (info.has_index) { - info.input_chunk.data[0].Reference(index_vector); - info.input_chunk.data[1].Reference(slice); - } else { - info.input_chunk.data[0].Reference(slice); - } - idx_t slice_offset = info.has_index ? 2 : 1; - - // (slice and) reference the other columns - vector slices; - for (idx_t i = 0; i < column_infos.size(); i++) { - - if (column_infos[i].vector.get().GetVectorType() == VectorType::CONSTANT_VECTOR) { - // only reference constant vectorsl - info.input_chunk.data[i + slice_offset].Reference(column_infos[i].vector); - - } else { - // slice inconstant vectors - slices.emplace_back(column_infos[i].vector, column_infos[i].sel, elem_cnt); - info.input_chunk.data[i + slice_offset].Reference(slices.back()); - } - } - - // execute the lambda expression - info.expr_executor->Execute(info.input_chunk, info.lambda_chunk); -} - -//===--------------------------------------------------------------------===// -// ListLambdaBindData -//===--------------------------------------------------------------------===// - -unique_ptr ListLambdaBindData::Copy() const { - auto lambda_expr_copy = lambda_expr ? lambda_expr->Copy() : nullptr; - return make_uniq(return_type, std::move(lambda_expr_copy), has_index); -} - -bool ListLambdaBindData::Equals(const FunctionData &other_p) const { - auto &other = other_p.Cast(); - return Expression::Equals(lambda_expr, other.lambda_expr) && return_type == other.return_type && - has_index == other.has_index; -} - -void ListLambdaBindData::Serialize(Serializer &serializer, const optional_ptr bind_data_p, - const ScalarFunction &) { - auto &bind_data = bind_data_p->Cast(); - serializer.WriteProperty(100, "return_type", bind_data.return_type); - serializer.WritePropertyWithDefault(101, "lambda_expr", bind_data.lambda_expr, unique_ptr()); - serializer.WriteProperty(102, "has_index", bind_data.has_index); -} - -unique_ptr ListLambdaBindData::Deserialize(Deserializer &deserializer, ScalarFunction &) { - auto return_type = deserializer.ReadProperty(100, "return_type"); - auto lambda_expr = deserializer.ReadPropertyWithExplicitDefault>(101, "lambda_expr", - unique_ptr()); - auto has_index = deserializer.ReadProperty(102, "has_index"); - return make_uniq(return_type, std::move(lambda_expr), has_index); -} - -//===--------------------------------------------------------------------===// -// LambdaFunctions -//===--------------------------------------------------------------------===// - -LogicalType LambdaFunctions::BindBinaryLambda(const idx_t parameter_idx, const LogicalType &list_child_type) { - switch (parameter_idx) { - case 0: - return list_child_type; - case 1: - return LogicalType::BIGINT; - default: - throw BinderException("This lambda function only supports up to two lambda parameters!"); - } -} - -LogicalType LambdaFunctions::BindTernaryLambda(const idx_t parameter_idx, const LogicalType &list_child_type) { - switch (parameter_idx) { - case 0: - return list_child_type; - case 1: - return list_child_type; - case 2: - return LogicalType::BIGINT; - default: - throw BinderException("This lambda function only supports up to three lambda parameters!"); - } -} - -template -void ExecuteLambda(DataChunk &args, ExpressionState &state, Vector &result) { - - bool result_is_null = false; - LambdaFunctions::LambdaInfo info(args, state, result, result_is_null); - if (result_is_null) { - return; - } - - auto result_entries = FlatVector::GetData(result); - auto mutable_column_infos = LambdaFunctions::GetMutableColumnInfo(info.column_infos); - - // special-handling for the child_vector - auto child_vector_size = ListVector::GetListSize(args.data[0]); - LambdaFunctions::ColumnInfo child_info(*info.child_vector); - info.child_vector->ToUnifiedFormat(child_vector_size, child_info.format); - - // get the expression executor - LambdaExecuteInfo execute_info(state.GetContext(), *info.lambda_expr, args, info.has_index, *info.child_vector); - - // get list_filter specific info - ListFilterInfo list_filter_info; - FUNCTION_FUNCTOR::ReserveNewLengths(list_filter_info.entry_lengths, info.row_count); - - // additional index vector - Vector index_vector(LogicalType::BIGINT); - - // loop over the child entries and create chunks to be executed by the expression executor - idx_t elem_cnt = 0; - idx_t offset = 0; - for (idx_t row_idx = 0; row_idx < info.row_count; row_idx++) { - - auto list_idx = info.list_column_format.sel->get_index(row_idx); - const auto &list_entry = info.list_entries[list_idx]; - - // set the result to NULL for this row - if (!info.list_column_format.validity.RowIsValid(list_idx)) { - info.result_validity->SetInvalid(row_idx); - FUNCTION_FUNCTOR::PushEmptyList(list_filter_info.entry_lengths); - continue; - } - - FUNCTION_FUNCTOR::SetResultEntry(result_entries, offset, list_entry, row_idx, list_filter_info.entry_lengths); - - // empty list, nothing to execute - if (list_entry.length == 0) { - continue; - } - - // iterate the elements of the current list and create the corresponding selection vectors - for (idx_t child_idx = 0; child_idx < list_entry.length; child_idx++) { - - // reached STANDARD_VECTOR_SIZE elements - if (elem_cnt == STANDARD_VECTOR_SIZE) { - - execute_info.lambda_chunk.Reset(); - ExecuteExpression(elem_cnt, child_info, info.column_infos, index_vector, execute_info); - auto &lambda_vector = execute_info.lambda_chunk.data[0]; - - FUNCTION_FUNCTOR::AppendResult(result, lambda_vector, elem_cnt, result_entries, list_filter_info, - execute_info); - elem_cnt = 0; - } - - // FIXME: reuse same selection vector for inconstant rows - // adjust indexes for slicing - child_info.sel.set_index(elem_cnt, list_entry.offset + child_idx); - for (auto &entry : mutable_column_infos) { - entry.get().sel.set_index(elem_cnt, row_idx); - } - - // set the index vector - if (info.has_index) { - index_vector.SetValue(elem_cnt, Value::BIGINT(NumericCast(child_idx + 1))); - } - - elem_cnt++; - } - } - - execute_info.lambda_chunk.Reset(); - ExecuteExpression(elem_cnt, child_info, info.column_infos, index_vector, execute_info); - auto &lambda_vector = execute_info.lambda_chunk.data[0]; - - FUNCTION_FUNCTOR::AppendResult(result, lambda_vector, elem_cnt, result_entries, list_filter_info, execute_info); - - if (info.is_all_constant && !info.is_volatile) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } -} - -unique_ptr LambdaFunctions::ListLambdaPrepareBind(vector> &arguments, - ClientContext &context, - ScalarFunction &bound_function) { - // NULL list parameter - if (arguments[0]->return_type.id() == LogicalTypeId::SQLNULL) { - bound_function.arguments[0] = LogicalType::SQLNULL; - bound_function.return_type = LogicalType::SQLNULL; - return make_uniq(bound_function.return_type, nullptr); - } - // prepared statements - if (arguments[0]->return_type.id() == LogicalTypeId::UNKNOWN) { - throw ParameterNotResolvedException(); - } - - arguments[0] = BoundCastExpression::AddArrayCastToList(context, std::move(arguments[0])); - D_ASSERT(arguments[0]->return_type.id() == LogicalTypeId::LIST); - return nullptr; -} - -unique_ptr LambdaFunctions::ListLambdaBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments, - const bool has_index) { - unique_ptr bind_data = ListLambdaPrepareBind(arguments, context, bound_function); - if (bind_data) { - return bind_data; - } - - // get the lambda expression and put it in the bind info - auto &bound_lambda_expr = arguments[1]->Cast(); - auto lambda_expr = std::move(bound_lambda_expr.lambda_expr); - - return make_uniq(bound_function.return_type, std::move(lambda_expr), has_index); -} - -void LambdaFunctions::ListTransformFunction(DataChunk &args, ExpressionState &state, Vector &result) { - ExecuteLambda(args, state, result); -} - -void LambdaFunctions::ListFilterFunction(DataChunk &args, ExpressionState &state, Vector &result) { - ExecuteLambda(args, state, result); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/array/array_functions.cpp b/src/duckdb/src/core_functions/scalar/array/array_functions.cpp deleted file mode 100644 index 347ffcbd1..000000000 --- a/src/duckdb/src/core_functions/scalar/array/array_functions.cpp +++ /dev/null @@ -1,273 +0,0 @@ -#include "duckdb/core_functions/scalar/array_functions.hpp" -#include "duckdb/core_functions/array_kernels.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" - -namespace duckdb { - -static unique_ptr ArrayGenericBinaryBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - - const auto lhs_is_param = arguments[0]->HasParameter(); - const auto rhs_is_param = arguments[1]->HasParameter(); - - if (lhs_is_param && rhs_is_param) { - throw ParameterNotResolvedException(); - } - - const auto &lhs_type = arguments[0]->return_type; - const auto &rhs_type = arguments[1]->return_type; - - bound_function.arguments[0] = lhs_is_param ? rhs_type : lhs_type; - bound_function.arguments[1] = rhs_is_param ? lhs_type : rhs_type; - - if (bound_function.arguments[0].id() != LogicalTypeId::ARRAY || - bound_function.arguments[1].id() != LogicalTypeId::ARRAY) { - throw InvalidInputException( - StringUtil::Format("%s: Arguments must be arrays of FLOAT or DOUBLE", bound_function.name)); - } - - const auto lhs_size = ArrayType::GetSize(bound_function.arguments[0]); - const auto rhs_size = ArrayType::GetSize(bound_function.arguments[1]); - - if (lhs_size != rhs_size) { - throw BinderException("%s: Array arguments must be of the same size", bound_function.name); - } - - const auto &lhs_element_type = ArrayType::GetChildType(bound_function.arguments[0]); - const auto &rhs_element_type = ArrayType::GetChildType(bound_function.arguments[1]); - - // Resolve common type - LogicalType common_type; - if (!LogicalType::TryGetMaxLogicalType(context, lhs_element_type, rhs_element_type, common_type)) { - throw BinderException("%s: Cannot infer common element type (left = '%s', right = '%s')", bound_function.name, - lhs_element_type.ToString(), rhs_element_type.ToString()); - } - - // Ensure it is float or double - if (common_type.id() != LogicalTypeId::FLOAT && common_type.id() != LogicalTypeId::DOUBLE) { - throw BinderException("%s: Arguments must be arrays of FLOAT or DOUBLE", bound_function.name); - } - - // The important part is just that we resolve the size of the input arrays - bound_function.arguments[0] = LogicalType::ARRAY(common_type, lhs_size); - bound_function.arguments[1] = LogicalType::ARRAY(common_type, rhs_size); - - return nullptr; -} - -//------------------------------------------------------------------------------ -// Element-wise combine functions -//------------------------------------------------------------------------------ -// Given two arrays of the same size, combine their elements into a single array -// of the same size as the input arrays. - -struct CrossProductOp { - template - static void Operation(const TYPE *lhs_data, const TYPE *rhs_data, TYPE *res_data, idx_t size) { - D_ASSERT(size == 3); - - auto lx = lhs_data[0]; - auto ly = lhs_data[1]; - auto lz = lhs_data[2]; - - auto rx = rhs_data[0]; - auto ry = rhs_data[1]; - auto rz = rhs_data[2]; - - res_data[0] = ly * rz - lz * ry; - res_data[1] = lz * rx - lx * rz; - res_data[2] = lx * ry - ly * rx; - } -}; - -template -static void ArrayFixedCombine(DataChunk &args, ExpressionState &state, Vector &result) { - const auto &lstate = state.Cast(); - const auto &expr = lstate.expr.Cast(); - const auto &func_name = expr.function.name; - - const auto count = args.size(); - auto &lhs_child = ArrayVector::GetEntry(args.data[0]); - auto &rhs_child = ArrayVector::GetEntry(args.data[1]); - auto &res_child = ArrayVector::GetEntry(result); - - const auto &lhs_child_validity = FlatVector::Validity(lhs_child); - const auto &rhs_child_validity = FlatVector::Validity(rhs_child); - - UnifiedVectorFormat lhs_format; - UnifiedVectorFormat rhs_format; - - args.data[0].ToUnifiedFormat(count, lhs_format); - args.data[1].ToUnifiedFormat(count, rhs_format); - - auto lhs_data = FlatVector::GetData(lhs_child); - auto rhs_data = FlatVector::GetData(rhs_child); - auto res_data = FlatVector::GetData(res_child); - - for (idx_t i = 0; i < count; i++) { - const auto lhs_idx = lhs_format.sel->get_index(i); - const auto rhs_idx = rhs_format.sel->get_index(i); - - if (!lhs_format.validity.RowIsValid(lhs_idx) || !rhs_format.validity.RowIsValid(rhs_idx)) { - FlatVector::SetNull(result, i, true); - continue; - } - - const auto left_offset = lhs_idx * N; - if (!lhs_child_validity.CheckAllValid(left_offset + N, left_offset)) { - throw InvalidInputException(StringUtil::Format("%s: left argument can not contain NULL values", func_name)); - } - - const auto right_offset = rhs_idx * N; - if (!rhs_child_validity.CheckAllValid(right_offset + N, right_offset)) { - throw InvalidInputException( - StringUtil::Format("%s: right argument can not contain NULL values", func_name)); - } - const auto result_offset = i * N; - - const auto lhs_data_ptr = lhs_data + left_offset; - const auto rhs_data_ptr = rhs_data + right_offset; - const auto res_data_ptr = res_data + result_offset; - - OP::Operation(lhs_data_ptr, rhs_data_ptr, res_data_ptr, N); - } - - if (count == 1) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } -} - -//------------------------------------------------------------------------------ -// Generic "fold" function -//------------------------------------------------------------------------------ -// Given two arrays, combine and reduce their elements into a single scalar value. - -template -static void ArrayGenericFold(DataChunk &args, ExpressionState &state, Vector &result) { - const auto &lstate = state.Cast(); - const auto &expr = lstate.expr.Cast(); - const auto &func_name = expr.function.name; - - const auto count = args.size(); - auto &lhs_child = ArrayVector::GetEntry(args.data[0]); - auto &rhs_child = ArrayVector::GetEntry(args.data[1]); - - const auto &lhs_child_validity = FlatVector::Validity(lhs_child); - const auto &rhs_child_validity = FlatVector::Validity(rhs_child); - - UnifiedVectorFormat lhs_format; - UnifiedVectorFormat rhs_format; - - args.data[0].ToUnifiedFormat(count, lhs_format); - args.data[1].ToUnifiedFormat(count, rhs_format); - - auto lhs_data = FlatVector::GetData(lhs_child); - auto rhs_data = FlatVector::GetData(rhs_child); - auto res_data = FlatVector::GetData(result); - - const auto array_size = ArrayType::GetSize(args.data[0].GetType()); - D_ASSERT(array_size == ArrayType::GetSize(args.data[1].GetType())); - - for (idx_t i = 0; i < count; i++) { - const auto lhs_idx = lhs_format.sel->get_index(i); - const auto rhs_idx = rhs_format.sel->get_index(i); - - if (!lhs_format.validity.RowIsValid(lhs_idx) || !rhs_format.validity.RowIsValid(rhs_idx)) { - FlatVector::SetNull(result, i, true); - continue; - } - - const auto left_offset = lhs_idx * array_size; - if (!lhs_child_validity.CheckAllValid(left_offset + array_size, left_offset)) { - throw InvalidInputException(StringUtil::Format("%s: left argument can not contain NULL values", func_name)); - } - - const auto right_offset = rhs_idx * array_size; - if (!rhs_child_validity.CheckAllValid(right_offset + array_size, right_offset)) { - throw InvalidInputException( - StringUtil::Format("%s: right argument can not contain NULL values", func_name)); - } - - const auto lhs_data_ptr = lhs_data + left_offset; - const auto rhs_data_ptr = rhs_data + right_offset; - - res_data[i] = OP::Operation(lhs_data_ptr, rhs_data_ptr, array_size); - } - - if (count == 1) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } -} - -//------------------------------------------------------------------------------ -// Function Registration -//------------------------------------------------------------------------------ -// Note: In the future we could add a wrapper with a non-type template parameter to specialize for specific array sizes -// e.g. 256, 512, 1024, 2048 etc. which may allow the compiler to vectorize the loop better. Perhaps something for an -// extension. - -template -static void AddArrayFoldFunction(ScalarFunctionSet &set, const LogicalType &type) { - const auto array = LogicalType::ARRAY(type, optional_idx()); - if (type.id() == LogicalTypeId::FLOAT) { - set.AddFunction(ScalarFunction({array, array}, type, ArrayGenericFold, ArrayGenericBinaryBind)); - } else if (type.id() == LogicalTypeId::DOUBLE) { - set.AddFunction(ScalarFunction({array, array}, type, ArrayGenericFold, ArrayGenericBinaryBind)); - } else { - throw NotImplementedException("Array function not implemented for type %s", type.ToString()); - } -} - -ScalarFunctionSet ArrayDistanceFun::GetFunctions() { - ScalarFunctionSet set("array_distance"); - for (auto &type : LogicalType::Real()) { - AddArrayFoldFunction(set, type); - } - return set; -} - -ScalarFunctionSet ArrayInnerProductFun::GetFunctions() { - ScalarFunctionSet set("array_inner_product"); - for (auto &type : LogicalType::Real()) { - AddArrayFoldFunction(set, type); - } - return set; -} - -ScalarFunctionSet ArrayNegativeInnerProductFun::GetFunctions() { - ScalarFunctionSet set("array_negative_inner_product"); - for (auto &type : LogicalType::Real()) { - AddArrayFoldFunction(set, type); - } - return set; -} - -ScalarFunctionSet ArrayCosineSimilarityFun::GetFunctions() { - ScalarFunctionSet set("array_cosine_similarity"); - for (auto &type : LogicalType::Real()) { - AddArrayFoldFunction(set, type); - } - return set; -} - -ScalarFunctionSet ArrayCosineDistanceFun::GetFunctions() { - ScalarFunctionSet set("array_cosine_distance"); - for (auto &type : LogicalType::Real()) { - AddArrayFoldFunction(set, type); - } - return set; -} - -ScalarFunctionSet ArrayCrossProductFun::GetFunctions() { - ScalarFunctionSet set("array_cross_product"); - - auto float_array = LogicalType::ARRAY(LogicalType::FLOAT, 3); - auto double_array = LogicalType::ARRAY(LogicalType::DOUBLE, 3); - set.AddFunction( - ScalarFunction({float_array, float_array}, float_array, ArrayFixedCombine)); - set.AddFunction( - ScalarFunction({double_array, double_array}, double_array, ArrayFixedCombine)); - return set; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/array/array_value.cpp b/src/duckdb/src/core_functions/scalar/array/array_value.cpp deleted file mode 100644 index ac4f0bd24..000000000 --- a/src/duckdb/src/core_functions/scalar/array/array_value.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "duckdb/core_functions/scalar/array_functions.hpp" -#include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/storage/statistics/array_stats.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" - -namespace duckdb { - -static void ArrayValueFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto array_type = result.GetType(); - - D_ASSERT(array_type.id() == LogicalTypeId::ARRAY); - D_ASSERT(args.ColumnCount() == ArrayType::GetSize(array_type)); - - auto &child_type = ArrayType::GetChildType(array_type); - - result.SetVectorType(VectorType::CONSTANT_VECTOR); - for (idx_t i = 0; i < args.ColumnCount(); i++) { - if (args.data[i].GetVectorType() != VectorType::CONSTANT_VECTOR) { - result.SetVectorType(VectorType::FLAT_VECTOR); - } - } - - auto num_rows = args.size(); - auto num_columns = args.ColumnCount(); - - auto &child = ArrayVector::GetEntry(result); - - if (num_columns > 1) { - // Ensure that the child has a validity mask of the correct size - // The SetValue call below expects the validity mask to be initialized - auto &child_validity = FlatVector::Validity(child); - child_validity.Resize(num_rows, num_rows * num_columns); - } - - for (idx_t i = 0; i < num_rows; i++) { - for (idx_t j = 0; j < num_columns; j++) { - auto val = args.GetValue(j, i).DefaultCastAs(child_type); - child.SetValue((i * num_columns) + j, val); - } - } - - result.Verify(args.size()); -} - -static unique_ptr ArrayValueBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - if (arguments.empty()) { - throw InvalidInputException("array_value requires at least one argument"); - } - - // construct return type - LogicalType child_type = arguments[0]->return_type; - for (idx_t i = 1; i < arguments.size(); i++) { - child_type = LogicalType::MaxLogicalType(context, child_type, arguments[i]->return_type); - } - - if (arguments.size() > ArrayType::MAX_ARRAY_SIZE) { - throw OutOfRangeException("Array size exceeds maximum allowed size"); - } - - // this is more for completeness reasons - bound_function.varargs = child_type; - bound_function.return_type = LogicalType::ARRAY(child_type, arguments.size()); - return make_uniq(bound_function.return_type); -} - -unique_ptr ArrayValueStats(ClientContext &context, FunctionStatisticsInput &input) { - auto &child_stats = input.child_stats; - auto &expr = input.expr; - auto list_stats = ArrayStats::CreateEmpty(expr.return_type); - auto &list_child_stats = ArrayStats::GetChildStats(list_stats); - for (idx_t i = 0; i < child_stats.size(); i++) { - list_child_stats.Merge(child_stats[i]); - } - return list_stats.ToUnique(); -} - -ScalarFunction ArrayValueFun::GetFunction() { - // the arguments and return types are actually set in the binder function - ScalarFunction fun("array_value", {}, LogicalTypeId::ARRAY, ArrayValueFunction, ArrayValueBind, nullptr, - ArrayValueStats); - fun.varargs = LogicalType::ANY; - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/bit/bitstring.cpp b/src/duckdb/src/core_functions/scalar/bit/bitstring.cpp deleted file mode 100644 index 9a9a5eae0..000000000 --- a/src/duckdb/src/core_functions/scalar/bit/bitstring.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "duckdb/core_functions/scalar/bit_functions.hpp" -#include "duckdb/common/types/bit.hpp" -#include "duckdb/common/types/cast_helpers.hpp" - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// BitStringFunction -//===--------------------------------------------------------------------===// -template -static void BitStringFunction(DataChunk &args, ExpressionState &state, Vector &result) { - BinaryExecutor::Execute( - args.data[0], args.data[1], result, args.size(), [&](string_t input, int32_t n) { - if (n < 0) { - throw InvalidInputException("The bitstring length cannot be negative"); - } - idx_t input_length; - if (FROM_STRING) { - input_length = input.GetSize(); - } else { - input_length = Bit::BitLength(input); - } - if (idx_t(n) < input_length) { - throw InvalidInputException("Length must be equal or larger than input string"); - } - idx_t len; - if (FROM_STRING) { - Bit::TryGetBitStringSize(input, len, nullptr); // string verification - } - - len = Bit::ComputeBitstringLen(UnsafeNumericCast(n)); - string_t target = StringVector::EmptyString(result, len); - if (FROM_STRING) { - Bit::BitString(input, UnsafeNumericCast(n), target); - } else { - Bit::ExtendBitString(input, UnsafeNumericCast(n), target); - } - target.Finalize(); - return target; - }); -} - -ScalarFunctionSet BitStringFun::GetFunctions() { - ScalarFunctionSet bitstring; - bitstring.AddFunction( - ScalarFunction({LogicalType::VARCHAR, LogicalType::INTEGER}, LogicalType::BIT, BitStringFunction)); - bitstring.AddFunction( - ScalarFunction({LogicalType::BIT, LogicalType::INTEGER}, LogicalType::BIT, BitStringFunction)); - return bitstring; -} - -//===--------------------------------------------------------------------===// -// get_bit -//===--------------------------------------------------------------------===// -struct GetBitOperator { - template - static inline TR Operation(TA input, TB n) { - if (n < 0 || (idx_t)n > Bit::BitLength(input) - 1) { - throw OutOfRangeException("bit index %s out of valid range (0..%s)", NumericHelper::ToString(n), - NumericHelper::ToString(Bit::BitLength(input) - 1)); - } - return UnsafeNumericCast(Bit::GetBit(input, UnsafeNumericCast(n))); - } -}; - -ScalarFunction GetBitFun::GetFunction() { - return ScalarFunction({LogicalType::BIT, LogicalType::INTEGER}, LogicalType::INTEGER, - ScalarFunction::BinaryFunction); -} - -//===--------------------------------------------------------------------===// -// set_bit -//===--------------------------------------------------------------------===// -static void SetBitOperation(DataChunk &args, ExpressionState &state, Vector &result) { - TernaryExecutor::Execute( - args.data[0], args.data[1], args.data[2], result, args.size(), - [&](string_t input, int32_t n, int32_t new_value) { - if (new_value != 0 && new_value != 1) { - throw InvalidInputException("The new bit must be 1 or 0"); - } - if (n < 0 || (idx_t)n > Bit::BitLength(input) - 1) { - throw OutOfRangeException("bit index %s out of valid range (0..%s)", NumericHelper::ToString(n), - NumericHelper::ToString(Bit::BitLength(input) - 1)); - } - string_t target = StringVector::EmptyString(result, input.GetSize()); - memcpy(target.GetDataWriteable(), input.GetData(), input.GetSize()); - Bit::SetBit(target, UnsafeNumericCast(n), UnsafeNumericCast(new_value)); - return target; - }); -} - -ScalarFunction SetBitFun::GetFunction() { - return ScalarFunction({LogicalType::BIT, LogicalType::INTEGER, LogicalType::INTEGER}, LogicalType::BIT, - SetBitOperation); -} - -//===--------------------------------------------------------------------===// -// bit_position -//===--------------------------------------------------------------------===// -struct BitPositionOperator { - template - static inline TR Operation(TA substring, TB input) { - if (substring.GetSize() > input.GetSize()) { - return 0; - } - return UnsafeNumericCast(Bit::BitPosition(substring, input)); - } -}; - -ScalarFunction BitPositionFun::GetFunction() { - return ScalarFunction({LogicalType::BIT, LogicalType::BIT}, LogicalType::INTEGER, - ScalarFunction::BinaryFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/blob/base64.cpp b/src/duckdb/src/core_functions/scalar/blob/base64.cpp deleted file mode 100644 index 3545f3b56..000000000 --- a/src/duckdb/src/core_functions/scalar/blob/base64.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "duckdb/core_functions/scalar/blob_functions.hpp" -#include "duckdb/common/types/blob.hpp" - -namespace duckdb { - -struct Base64EncodeOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - auto result_str = StringVector::EmptyString(result, Blob::ToBase64Size(input)); - Blob::ToBase64(input, result_str.GetDataWriteable()); - result_str.Finalize(); - return result_str; - } -}; - -struct Base64DecodeOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - auto result_size = Blob::FromBase64Size(input); - auto result_blob = StringVector::EmptyString(result, result_size); - Blob::FromBase64(input, data_ptr_cast(result_blob.GetDataWriteable()), result_size); - result_blob.Finalize(); - return result_blob; - } -}; - -static void Base64EncodeFunction(DataChunk &args, ExpressionState &state, Vector &result) { - // decode is also a nop cast, but requires verification if the provided string is actually - UnaryExecutor::ExecuteString(args.data[0], result, args.size()); -} - -static void Base64DecodeFunction(DataChunk &args, ExpressionState &state, Vector &result) { - // decode is also a nop cast, but requires verification if the provided string is actually - UnaryExecutor::ExecuteString(args.data[0], result, args.size()); -} - -ScalarFunction ToBase64Fun::GetFunction() { - return ScalarFunction({LogicalType::BLOB}, LogicalType::VARCHAR, Base64EncodeFunction); -} - -ScalarFunction FromBase64Fun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR}, LogicalType::BLOB, Base64DecodeFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/blob/encode.cpp b/src/duckdb/src/core_functions/scalar/blob/encode.cpp deleted file mode 100644 index ff11f2f6c..000000000 --- a/src/duckdb/src/core_functions/scalar/blob/encode.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "duckdb/core_functions/scalar/blob_functions.hpp" -#include "utf8proc_wrapper.hpp" -#include "duckdb/common/exception/conversion_exception.hpp" - -namespace duckdb { - -static void EncodeFunction(DataChunk &args, ExpressionState &state, Vector &result) { - // encode is essentially a nop cast from varchar to blob - // we only need to reinterpret the data using the blob type - result.Reinterpret(args.data[0]); -} - -struct BlobDecodeOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input) { - auto input_data = input.GetData(); - auto input_length = input.GetSize(); - if (Utf8Proc::Analyze(input_data, input_length) == UnicodeType::INVALID) { - throw ConversionException( - "Failure in decode: could not convert blob to UTF8 string, the blob contained invalid UTF8 characters"); - } - return input; - } -}; - -static void DecodeFunction(DataChunk &args, ExpressionState &state, Vector &result) { - // decode is also a nop cast, but requires verification if the provided string is actually - UnaryExecutor::Execute(args.data[0], result, args.size()); - StringVector::AddHeapReference(result, args.data[0]); -} - -ScalarFunction EncodeFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR}, LogicalType::BLOB, EncodeFunction); -} - -ScalarFunction DecodeFun::GetFunction() { - return ScalarFunction({LogicalType::BLOB}, LogicalType::VARCHAR, DecodeFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/date/age.cpp b/src/duckdb/src/core_functions/scalar/date/age.cpp deleted file mode 100644 index f8db919fc..000000000 --- a/src/duckdb/src/core_functions/scalar/date/age.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "duckdb/core_functions/scalar/date_functions.hpp" -#include "duckdb/common/types/interval.hpp" -#include "duckdb/common/types/time.hpp" -#include "duckdb/common/types/timestamp.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/vector_operations/unary_executor.hpp" -#include "duckdb/common/vector_operations/binary_executor.hpp" - -namespace duckdb { - -static void AgeFunctionStandard(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() == 1); - auto current_timestamp = Timestamp::GetCurrentTimestamp(); - - UnaryExecutor::ExecuteWithNulls(input.data[0], result, input.size(), - [&](timestamp_t input, ValidityMask &mask, idx_t idx) { - if (Timestamp::IsFinite(input)) { - return Interval::GetAge(current_timestamp, input); - } else { - mask.SetInvalid(idx); - return interval_t(); - } - }); -} - -static void AgeFunction(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() == 2); - - BinaryExecutor::ExecuteWithNulls( - input.data[0], input.data[1], result, input.size(), - [&](timestamp_t input1, timestamp_t input2, ValidityMask &mask, idx_t idx) { - if (Timestamp::IsFinite(input1) && Timestamp::IsFinite(input2)) { - return Interval::GetAge(input1, input2); - } else { - mask.SetInvalid(idx); - return interval_t(); - } - }); -} - -ScalarFunctionSet AgeFun::GetFunctions() { - ScalarFunctionSet age("age"); - age.AddFunction(ScalarFunction({LogicalType::TIMESTAMP}, LogicalType::INTERVAL, AgeFunctionStandard)); - age.AddFunction( - ScalarFunction({LogicalType::TIMESTAMP, LogicalType::TIMESTAMP}, LogicalType::INTERVAL, AgeFunction)); - return age; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/date/current.cpp b/src/duckdb/src/core_functions/scalar/date/current.cpp deleted file mode 100644 index 159575315..000000000 --- a/src/duckdb/src/core_functions/scalar/date/current.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "duckdb/core_functions/scalar/date_functions.hpp" - -#include "duckdb/common/exception.hpp" -#include "duckdb/common/types/timestamp.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/main/client_context.hpp" -#include "duckdb/transaction/meta_transaction.hpp" - -namespace duckdb { - -static timestamp_t GetTransactionTimestamp(ExpressionState &state) { - return MetaTransaction::Get(state.GetContext()).start_timestamp; -} - -static void CurrentTimeFunction(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() == 0); - auto val = Value::TIME(Timestamp::GetTime(GetTransactionTimestamp(state))); - result.Reference(val); -} - -static void CurrentDateFunction(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() == 0); - - auto val = Value::DATE(Timestamp::GetDate(GetTransactionTimestamp(state))); - result.Reference(val); -} - -static void CurrentTimestampFunction(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() == 0); - - auto val = Value::TIMESTAMPTZ(GetTransactionTimestamp(state)); - result.Reference(val); -} - -ScalarFunction CurrentTimeFun::GetFunction() { - ScalarFunction current_time({}, LogicalType::TIME, CurrentTimeFunction); - current_time.stability = FunctionStability::CONSISTENT_WITHIN_QUERY; - return current_time; -} - -ScalarFunction CurrentDateFun::GetFunction() { - ScalarFunction current_date({}, LogicalType::DATE, CurrentDateFunction); - current_date.stability = FunctionStability::CONSISTENT_WITHIN_QUERY; - return current_date; -} - -ScalarFunction GetCurrentTimestampFun::GetFunction() { - ScalarFunction current_timestamp({}, LogicalType::TIMESTAMP_TZ, CurrentTimestampFunction); - current_timestamp.stability = FunctionStability::CONSISTENT_WITHIN_QUERY; - return current_timestamp; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/date/date_diff.cpp b/src/duckdb/src/core_functions/scalar/date/date_diff.cpp deleted file mode 100644 index 36376a2b5..000000000 --- a/src/duckdb/src/core_functions/scalar/date/date_diff.cpp +++ /dev/null @@ -1,454 +0,0 @@ -#include "duckdb/core_functions/scalar/date_functions.hpp" -#include "duckdb/common/enums/date_part_specifier.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/operator/subtract.hpp" -#include "duckdb/common/types/date.hpp" -#include "duckdb/common/types/interval.hpp" -#include "duckdb/common/types/time.hpp" -#include "duckdb/common/types/timestamp.hpp" -#include "duckdb/common/vector_operations/ternary_executor.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/string_util.hpp" - -namespace duckdb { - -// This function is an implementation of the "period-crossing" date difference function from T-SQL -// https://docs.microsoft.com/en-us/sql/t-sql/functions/datediff-transact-sql?view=sql-server-ver15 -struct DateDiff { - template - static inline void BinaryExecute(Vector &left, Vector &right, Vector &result, idx_t count) { - BinaryExecutor::ExecuteWithNulls( - left, right, result, count, [&](TA startdate, TB enddate, ValidityMask &mask, idx_t idx) { - if (Value::IsFinite(startdate) && Value::IsFinite(enddate)) { - return OP::template Operation(startdate, enddate); - } else { - mask.SetInvalid(idx); - return TR(); - } - }); - } - - // We need to truncate down, not towards 0 - static inline int64_t Truncate(int64_t value, int64_t units) { - return (value + (value < 0)) / units - (value < 0); - } - static inline int64_t Diff(int64_t start, int64_t end, int64_t units) { - return Truncate(end, units) - Truncate(start, units); - } - - struct YearOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return Date::ExtractYear(enddate) - Date::ExtractYear(startdate); - } - }; - - struct MonthOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - int32_t start_year, start_month, start_day; - Date::Convert(startdate, start_year, start_month, start_day); - int32_t end_year, end_month, end_day; - Date::Convert(enddate, end_year, end_month, end_day); - - return (end_year * 12 + end_month - 1) - (start_year * 12 + start_month - 1); - } - }; - - struct DayOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return TR(Date::EpochDays(enddate)) - TR(Date::EpochDays(startdate)); - } - }; - - struct DecadeOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return Date::ExtractYear(enddate) / 10 - Date::ExtractYear(startdate) / 10; - } - }; - - struct CenturyOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return Date::ExtractYear(enddate) / 100 - Date::ExtractYear(startdate) / 100; - } - }; - - struct MilleniumOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return Date::ExtractYear(enddate) / 1000 - Date::ExtractYear(startdate) / 1000; - } - }; - - struct QuarterOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - int32_t start_year, start_month, start_day; - Date::Convert(startdate, start_year, start_month, start_day); - int32_t end_year, end_month, end_day; - Date::Convert(enddate, end_year, end_month, end_day); - - return (end_year * 12 + end_month - 1) / Interval::MONTHS_PER_QUARTER - - (start_year * 12 + start_month - 1) / Interval::MONTHS_PER_QUARTER; - } - }; - - struct WeekOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - // Weeks do not count Monday crossings, just distance - return (enddate.days - startdate.days) / Interval::DAYS_PER_WEEK; - } - }; - - struct ISOYearOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return Date::ExtractISOYearNumber(enddate) - Date::ExtractISOYearNumber(startdate); - } - }; - - struct MicrosecondsOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return Date::EpochMicroseconds(enddate) - Date::EpochMicroseconds(startdate); - } - }; - - struct MillisecondsOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return Date::EpochMicroseconds(enddate) / Interval::MICROS_PER_MSEC - - Date::EpochMicroseconds(startdate) / Interval::MICROS_PER_MSEC; - } - }; - - struct SecondsOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return Date::Epoch(enddate) - Date::Epoch(startdate); - } - }; - - struct MinutesOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return Date::Epoch(enddate) / Interval::SECS_PER_MINUTE - - Date::Epoch(startdate) / Interval::SECS_PER_MINUTE; - } - }; - - struct HoursOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return Date::Epoch(enddate) / Interval::SECS_PER_HOUR - Date::Epoch(startdate) / Interval::SECS_PER_HOUR; - } - }; -}; - -// TIMESTAMP specialisations -template <> -int64_t DateDiff::YearOperator::Operation(timestamp_t startdate, timestamp_t enddate) { - return YearOperator::Operation(Timestamp::GetDate(startdate), Timestamp::GetDate(enddate)); -} - -template <> -int64_t DateDiff::MonthOperator::Operation(timestamp_t startdate, timestamp_t enddate) { - return MonthOperator::Operation(Timestamp::GetDate(startdate), - Timestamp::GetDate(enddate)); -} - -template <> -int64_t DateDiff::DayOperator::Operation(timestamp_t startdate, timestamp_t enddate) { - return DayOperator::Operation(Timestamp::GetDate(startdate), Timestamp::GetDate(enddate)); -} - -template <> -int64_t DateDiff::DecadeOperator::Operation(timestamp_t startdate, timestamp_t enddate) { - return DecadeOperator::Operation(Timestamp::GetDate(startdate), - Timestamp::GetDate(enddate)); -} - -template <> -int64_t DateDiff::CenturyOperator::Operation(timestamp_t startdate, timestamp_t enddate) { - return CenturyOperator::Operation(Timestamp::GetDate(startdate), - Timestamp::GetDate(enddate)); -} - -template <> -int64_t DateDiff::MilleniumOperator::Operation(timestamp_t startdate, timestamp_t enddate) { - return MilleniumOperator::Operation(Timestamp::GetDate(startdate), - Timestamp::GetDate(enddate)); -} - -template <> -int64_t DateDiff::QuarterOperator::Operation(timestamp_t startdate, timestamp_t enddate) { - return QuarterOperator::Operation(Timestamp::GetDate(startdate), - Timestamp::GetDate(enddate)); -} - -template <> -int64_t DateDiff::WeekOperator::Operation(timestamp_t startdate, timestamp_t enddate) { - return WeekOperator::Operation(Timestamp::GetDate(startdate), Timestamp::GetDate(enddate)); -} - -template <> -int64_t DateDiff::ISOYearOperator::Operation(timestamp_t startdate, timestamp_t enddate) { - return ISOYearOperator::Operation(Timestamp::GetDate(startdate), - Timestamp::GetDate(enddate)); -} - -template <> -int64_t DateDiff::MicrosecondsOperator::Operation(timestamp_t startdate, timestamp_t enddate) { - const auto start = Timestamp::GetEpochMicroSeconds(startdate); - const auto end = Timestamp::GetEpochMicroSeconds(enddate); - return SubtractOperatorOverflowCheck::Operation(end, start); -} - -template <> -int64_t DateDiff::MillisecondsOperator::Operation(timestamp_t startdate, timestamp_t enddate) { - D_ASSERT(Timestamp::IsFinite(startdate)); - D_ASSERT(Timestamp::IsFinite(enddate)); - return Diff(startdate.value, enddate.value, Interval::MICROS_PER_MSEC); -} - -template <> -int64_t DateDiff::SecondsOperator::Operation(timestamp_t startdate, timestamp_t enddate) { - D_ASSERT(Timestamp::IsFinite(startdate)); - D_ASSERT(Timestamp::IsFinite(enddate)); - return Diff(startdate.value, enddate.value, Interval::MICROS_PER_SEC); -} - -template <> -int64_t DateDiff::MinutesOperator::Operation(timestamp_t startdate, timestamp_t enddate) { - D_ASSERT(Timestamp::IsFinite(startdate)); - D_ASSERT(Timestamp::IsFinite(enddate)); - return Diff(startdate.value, enddate.value, Interval::MICROS_PER_MINUTE); -} - -template <> -int64_t DateDiff::HoursOperator::Operation(timestamp_t startdate, timestamp_t enddate) { - D_ASSERT(Timestamp::IsFinite(startdate)); - D_ASSERT(Timestamp::IsFinite(enddate)); - return Diff(startdate.value, enddate.value, Interval::MICROS_PER_HOUR); -} - -// TIME specialisations -template <> -int64_t DateDiff::YearOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"year\" not recognized"); -} - -template <> -int64_t DateDiff::MonthOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"month\" not recognized"); -} - -template <> -int64_t DateDiff::DayOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"day\" not recognized"); -} - -template <> -int64_t DateDiff::DecadeOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"decade\" not recognized"); -} - -template <> -int64_t DateDiff::CenturyOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"century\" not recognized"); -} - -template <> -int64_t DateDiff::MilleniumOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"millennium\" not recognized"); -} - -template <> -int64_t DateDiff::QuarterOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"quarter\" not recognized"); -} - -template <> -int64_t DateDiff::WeekOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"week\" not recognized"); -} - -template <> -int64_t DateDiff::ISOYearOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"isoyear\" not recognized"); -} - -template <> -int64_t DateDiff::MicrosecondsOperator::Operation(dtime_t startdate, dtime_t enddate) { - return enddate.micros - startdate.micros; -} - -template <> -int64_t DateDiff::MillisecondsOperator::Operation(dtime_t startdate, dtime_t enddate) { - return enddate.micros / Interval::MICROS_PER_MSEC - startdate.micros / Interval::MICROS_PER_MSEC; -} - -template <> -int64_t DateDiff::SecondsOperator::Operation(dtime_t startdate, dtime_t enddate) { - return enddate.micros / Interval::MICROS_PER_SEC - startdate.micros / Interval::MICROS_PER_SEC; -} - -template <> -int64_t DateDiff::MinutesOperator::Operation(dtime_t startdate, dtime_t enddate) { - return enddate.micros / Interval::MICROS_PER_MINUTE - startdate.micros / Interval::MICROS_PER_MINUTE; -} - -template <> -int64_t DateDiff::HoursOperator::Operation(dtime_t startdate, dtime_t enddate) { - return enddate.micros / Interval::MICROS_PER_HOUR - startdate.micros / Interval::MICROS_PER_HOUR; -} - -template -static int64_t DifferenceDates(DatePartSpecifier type, TA startdate, TB enddate) { - switch (type) { - case DatePartSpecifier::YEAR: - return DateDiff::YearOperator::template Operation(startdate, enddate); - case DatePartSpecifier::MONTH: - return DateDiff::MonthOperator::template Operation(startdate, enddate); - case DatePartSpecifier::DAY: - case DatePartSpecifier::DOW: - case DatePartSpecifier::ISODOW: - case DatePartSpecifier::DOY: - case DatePartSpecifier::JULIAN_DAY: - return DateDiff::DayOperator::template Operation(startdate, enddate); - case DatePartSpecifier::DECADE: - return DateDiff::DecadeOperator::template Operation(startdate, enddate); - case DatePartSpecifier::CENTURY: - return DateDiff::CenturyOperator::template Operation(startdate, enddate); - case DatePartSpecifier::MILLENNIUM: - return DateDiff::MilleniumOperator::template Operation(startdate, enddate); - case DatePartSpecifier::QUARTER: - return DateDiff::QuarterOperator::template Operation(startdate, enddate); - case DatePartSpecifier::WEEK: - case DatePartSpecifier::YEARWEEK: - return DateDiff::WeekOperator::template Operation(startdate, enddate); - case DatePartSpecifier::ISOYEAR: - return DateDiff::ISOYearOperator::template Operation(startdate, enddate); - case DatePartSpecifier::MICROSECONDS: - return DateDiff::MicrosecondsOperator::template Operation(startdate, enddate); - case DatePartSpecifier::MILLISECONDS: - return DateDiff::MillisecondsOperator::template Operation(startdate, enddate); - case DatePartSpecifier::SECOND: - case DatePartSpecifier::EPOCH: - return DateDiff::SecondsOperator::template Operation(startdate, enddate); - case DatePartSpecifier::MINUTE: - return DateDiff::MinutesOperator::template Operation(startdate, enddate); - case DatePartSpecifier::HOUR: - return DateDiff::HoursOperator::template Operation(startdate, enddate); - default: - throw NotImplementedException("Specifier type not implemented for DATEDIFF"); - } -} - -struct DateDiffTernaryOperator { - template - static inline TR Operation(TS part, TA startdate, TB enddate, ValidityMask &mask, idx_t idx) { - if (Value::IsFinite(startdate) && Value::IsFinite(enddate)) { - return DifferenceDates(GetDatePartSpecifier(part.GetString()), startdate, enddate); - } else { - mask.SetInvalid(idx); - return TR(); - } - } -}; - -template -static void DateDiffBinaryExecutor(DatePartSpecifier type, Vector &left, Vector &right, Vector &result, idx_t count) { - switch (type) { - case DatePartSpecifier::YEAR: - DateDiff::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::MONTH: - DateDiff::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::DAY: - case DatePartSpecifier::DOW: - case DatePartSpecifier::ISODOW: - case DatePartSpecifier::DOY: - case DatePartSpecifier::JULIAN_DAY: - DateDiff::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::DECADE: - DateDiff::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::CENTURY: - DateDiff::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::MILLENNIUM: - DateDiff::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::QUARTER: - DateDiff::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::WEEK: - case DatePartSpecifier::YEARWEEK: - DateDiff::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::ISOYEAR: - DateDiff::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::MICROSECONDS: - DateDiff::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::MILLISECONDS: - DateDiff::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::SECOND: - case DatePartSpecifier::EPOCH: - DateDiff::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::MINUTE: - DateDiff::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::HOUR: - DateDiff::BinaryExecute(left, right, result, count); - break; - default: - throw NotImplementedException("Specifier type not implemented for DATEDIFF"); - } -} - -template -static void DateDiffFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 3); - auto &part_arg = args.data[0]; - auto &start_arg = args.data[1]; - auto &end_arg = args.data[2]; - - if (part_arg.GetVectorType() == VectorType::CONSTANT_VECTOR) { - // Common case of constant part. - if (ConstantVector::IsNull(part_arg)) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(result, true); - } else { - const auto type = GetDatePartSpecifier(ConstantVector::GetData(part_arg)->GetString()); - DateDiffBinaryExecutor(type, start_arg, end_arg, result, args.size()); - } - } else { - TernaryExecutor::ExecuteWithNulls( - part_arg, start_arg, end_arg, result, args.size(), - DateDiffTernaryOperator::Operation); - } -} - -ScalarFunctionSet DateDiffFun::GetFunctions() { - ScalarFunctionSet date_diff("date_diff"); - date_diff.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::DATE, LogicalType::DATE}, - LogicalType::BIGINT, DateDiffFunction)); - date_diff.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::TIMESTAMP, LogicalType::TIMESTAMP}, - LogicalType::BIGINT, DateDiffFunction)); - date_diff.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::TIME, LogicalType::TIME}, - LogicalType::BIGINT, DateDiffFunction)); - return date_diff; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/date/date_part.cpp b/src/duckdb/src/core_functions/scalar/date/date_part.cpp deleted file mode 100644 index ebe65f788..000000000 --- a/src/duckdb/src/core_functions/scalar/date/date_part.cpp +++ /dev/null @@ -1,2230 +0,0 @@ -#include "duckdb/core_functions/scalar/date_functions.hpp" -#include "duckdb/common/case_insensitive_map.hpp" -#include "duckdb/common/enums/date_part_specifier.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/exception/conversion_exception.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/common/enum_util.hpp" -#include "duckdb/common/types/date.hpp" -#include "duckdb/common/types/time.hpp" -#include "duckdb/common/types/timestamp.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/types/date_lookup_cache.hpp" - -namespace duckdb { - -DatePartSpecifier GetDateTypePartSpecifier(const string &specifier, LogicalType &type) { - const auto part = GetDatePartSpecifier(specifier); - switch (type.id()) { - case LogicalType::TIMESTAMP: - case LogicalType::TIMESTAMP_TZ: - return part; - case LogicalType::DATE: - switch (part) { - case DatePartSpecifier::YEAR: - case DatePartSpecifier::MONTH: - case DatePartSpecifier::DAY: - case DatePartSpecifier::DECADE: - case DatePartSpecifier::CENTURY: - case DatePartSpecifier::MILLENNIUM: - case DatePartSpecifier::DOW: - case DatePartSpecifier::ISODOW: - case DatePartSpecifier::ISOYEAR: - case DatePartSpecifier::WEEK: - case DatePartSpecifier::QUARTER: - case DatePartSpecifier::DOY: - case DatePartSpecifier::YEARWEEK: - case DatePartSpecifier::ERA: - case DatePartSpecifier::EPOCH: - case DatePartSpecifier::JULIAN_DAY: - return part; - default: - break; - } - break; - case LogicalType::TIME: - case LogicalType::TIME_TZ: - switch (part) { - case DatePartSpecifier::MICROSECONDS: - case DatePartSpecifier::MILLISECONDS: - case DatePartSpecifier::SECOND: - case DatePartSpecifier::MINUTE: - case DatePartSpecifier::HOUR: - case DatePartSpecifier::EPOCH: - case DatePartSpecifier::TIMEZONE: - case DatePartSpecifier::TIMEZONE_HOUR: - case DatePartSpecifier::TIMEZONE_MINUTE: - return part; - default: - break; - } - break; - case LogicalType::INTERVAL: - switch (part) { - case DatePartSpecifier::YEAR: - case DatePartSpecifier::MONTH: - case DatePartSpecifier::DAY: - case DatePartSpecifier::DECADE: - case DatePartSpecifier::CENTURY: - case DatePartSpecifier::QUARTER: - case DatePartSpecifier::MILLENNIUM: - case DatePartSpecifier::MICROSECONDS: - case DatePartSpecifier::MILLISECONDS: - case DatePartSpecifier::SECOND: - case DatePartSpecifier::MINUTE: - case DatePartSpecifier::HOUR: - case DatePartSpecifier::EPOCH: - return part; - default: - break; - } - break; - default: - break; - } - - throw NotImplementedException("\"%s\" units \"%s\" not recognized", EnumUtil::ToString(type.id()), specifier); -} - -template -static unique_ptr PropagateSimpleDatePartStatistics(vector &child_stats) { - // we can always propagate simple date part statistics - // since the min and max can never exceed these bounds - auto result = NumericStats::CreateEmpty(LogicalType::BIGINT); - result.CopyValidity(child_stats[0]); - NumericStats::SetMin(result, Value::BIGINT(MIN)); - NumericStats::SetMax(result, Value::BIGINT(MAX)); - return result.ToUnique(); -} - -template -struct DateCacheLocalState : public FunctionLocalState { - explicit DateCacheLocalState() { - } - - DateLookupCache cache; -}; - -template -unique_ptr InitDateCacheLocalState(ExpressionState &state, const BoundFunctionExpression &expr, - FunctionData *bind_data) { - return make_uniq>(); -} - -struct DatePart { - template - static unique_ptr PropagateDatePartStatistics(vector &child_stats, - const LogicalType &stats_type = LogicalType::BIGINT) { - // we can only propagate complex date part stats if the child has stats - auto &nstats = child_stats[0]; - if (!NumericStats::HasMinMax(nstats)) { - return nullptr; - } - // run the operator on both the min and the max, this gives us the [min, max] bound - auto min = NumericStats::GetMin(nstats); - auto max = NumericStats::GetMax(nstats); - if (min > max) { - return nullptr; - } - // Infinities prevent us from computing generic ranges - if (!Value::IsFinite(min) || !Value::IsFinite(max)) { - return nullptr; - } - TR min_part = OP::template Operation(min); - TR max_part = OP::template Operation(max); - auto result = NumericStats::CreateEmpty(stats_type); - NumericStats::SetMin(result, Value(min_part)); - NumericStats::SetMax(result, Value(max_part)); - result.CopyValidity(child_stats[0]); - return result.ToUnique(); - } - - template - struct PartOperator { - template - static inline TR Operation(TA input, ValidityMask &mask, idx_t idx, void *dataptr) { - if (Value::IsFinite(input)) { - return OP::template Operation(input); - } else { - mask.SetInvalid(idx); - return TR(); - } - } - }; - - template - static void UnaryFunction(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() >= 1); - using IOP = PartOperator; - UnaryExecutor::GenericExecute(input.data[0], result, input.size(), nullptr, true); - } - - struct YearOperator { - template - static inline TR Operation(TA input) { - return Date::ExtractYear(input); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateDatePartStatistics(input.child_stats); - } - }; - - struct MonthOperator { - template - static inline TR Operation(TA input) { - return Date::ExtractMonth(input); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - // min/max of month operator is [1, 12] - return PropagateSimpleDatePartStatistics<1, 12>(input.child_stats); - } - }; - - struct DayOperator { - template - static inline TR Operation(TA input) { - return Date::ExtractDay(input); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - // min/max of day operator is [1, 31] - return PropagateSimpleDatePartStatistics<1, 31>(input.child_stats); - } - }; - - struct DecadeOperator { - // From the PG docs: "The year field divided by 10" - template - static inline TR DecadeFromYear(TR yyyy) { - return yyyy / 10; - } - - template - static inline TR Operation(TA input) { - return DecadeFromYear(YearOperator::Operation(input)); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateDatePartStatistics(input.child_stats); - } - }; - - struct CenturyOperator { - // From the PG docs: - // "The first century starts at 0001-01-01 00:00:00 AD, although they did not know it at the time. - // This definition applies to all Gregorian calendar countries. - // There is no century number 0, you go from -1 century to 1 century. - // If you disagree with this, please write your complaint to: Pope, Cathedral Saint-Peter of Roma, Vatican." - // (To be fair, His Holiness had nothing to do with this - - // it was the lack of zero in the counting systems of the time...) - template - static inline TR CenturyFromYear(TR yyyy) { - if (yyyy > 0) { - return ((yyyy - 1) / 100) + 1; - } else { - return (yyyy / 100) - 1; - } - } - - template - static inline TR Operation(TA input) { - return CenturyFromYear(YearOperator::Operation(input)); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateDatePartStatistics(input.child_stats); - } - }; - - struct MillenniumOperator { - // See the century comment - template - static inline TR MillenniumFromYear(TR yyyy) { - if (yyyy > 0) { - return ((yyyy - 1) / 1000) + 1; - } else { - return (yyyy / 1000) - 1; - } - } - - template - static inline TR Operation(TA input) { - return MillenniumFromYear(YearOperator::Operation(input)); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateDatePartStatistics(input.child_stats); - } - }; - - struct QuarterOperator { - template - static inline TR QuarterFromMonth(TR mm) { - return (mm - 1) / Interval::MONTHS_PER_QUARTER + 1; - } - - template - static inline TR Operation(TA input) { - return QuarterFromMonth(Date::ExtractMonth(input)); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - // min/max of quarter operator is [1, 4] - return PropagateSimpleDatePartStatistics<1, 4>(input.child_stats); - } - }; - - struct DayOfWeekOperator { - template - static inline TR DayOfWeekFromISO(TR isodow) { - // day of the week (Sunday = 0, Saturday = 6) - // turn sunday into 0 by doing mod 7 - return isodow % 7; - } - - template - static inline TR Operation(TA input) { - return DayOfWeekFromISO(Date::ExtractISODayOfTheWeek(input)); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateSimpleDatePartStatistics<0, 6>(input.child_stats); - } - }; - - struct ISODayOfWeekOperator { - template - static inline TR Operation(TA input) { - // isodow (Monday = 1, Sunday = 7) - return Date::ExtractISODayOfTheWeek(input); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateSimpleDatePartStatistics<1, 7>(input.child_stats); - } - }; - - struct DayOfYearOperator { - template - static inline TR Operation(TA input) { - return Date::ExtractDayOfTheYear(input); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateSimpleDatePartStatistics<1, 366>(input.child_stats); - } - }; - - struct WeekOperator { - template - static inline TR Operation(TA input) { - return Date::ExtractISOWeekNumber(input); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateSimpleDatePartStatistics<1, 54>(input.child_stats); - } - }; - - struct ISOYearOperator { - template - static inline TR Operation(TA input) { - return Date::ExtractISOYearNumber(input); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateDatePartStatistics(input.child_stats); - } - }; - - struct YearWeekOperator { - template - static inline TR YearWeekFromParts(TR yyyy, TR ww) { - return yyyy * 100 + ((yyyy > 0) ? ww : -ww); - } - - template - static inline TR Operation(TA input) { - int32_t yyyy, ww; - Date::ExtractISOYearWeek(input, yyyy, ww); - return YearWeekFromParts(yyyy, ww); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateDatePartStatistics(input.child_stats); - } - }; - - struct EpochNanosecondsOperator { - template - static inline TR Operation(TA input) { - return Timestamp::GetEpochNanoSeconds(input); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateDatePartStatistics(input.child_stats); - } - }; - - struct EpochMicrosecondsOperator { - template - static inline TR Operation(TA input) { - return Timestamp::GetEpochMicroSeconds(input); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateDatePartStatistics(input.child_stats); - } - }; - - struct EpochMillisOperator { - template - static inline TR Operation(TA input) { - return Timestamp::GetEpochMs(input); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateDatePartStatistics(input.child_stats); - } - - static void Inverse(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() == 1); - - UnaryExecutor::Execute(input.data[0], result, input.size(), [&](int64_t input) { - // millisecond amounts provided to epoch_ms should never be considered infinite - // instead such values will just throw when converted to microseconds - return Timestamp::FromEpochMsPossiblyInfinite(input); - }); - } - }; - - struct NanosecondsOperator { - template - static inline TR Operation(TA input) { - return MicrosecondsOperator::Operation(input) * Interval::NANOS_PER_MICRO; - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateSimpleDatePartStatistics<0, 60000000000>(input.child_stats); - } - }; - - struct MicrosecondsOperator { - template - static inline TR Operation(TA input) { - return 0; - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateSimpleDatePartStatistics<0, 60000000>(input.child_stats); - } - }; - - struct MillisecondsOperator { - template - static inline TR Operation(TA input) { - return 0; - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateSimpleDatePartStatistics<0, 60000>(input.child_stats); - } - }; - - struct SecondsOperator { - template - static inline TR Operation(TA input) { - return 0; - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateSimpleDatePartStatistics<0, 60>(input.child_stats); - } - }; - - struct MinutesOperator { - template - static inline TR Operation(TA input) { - return 0; - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateSimpleDatePartStatistics<0, 60>(input.child_stats); - } - }; - - struct HoursOperator { - template - static inline TR Operation(TA input) { - return 0; - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateSimpleDatePartStatistics<0, 24>(input.child_stats); - } - }; - - struct EpochOperator { - template - static inline TR Operation(TA input) { - return TR(Date::Epoch(input)); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateDatePartStatistics(input.child_stats, LogicalType::DOUBLE); - } - }; - - struct EraOperator { - template - static inline TR EraFromYear(TR yyyy) { - return yyyy > 0 ? 1 : 0; - } - - template - static inline TR Operation(TA input) { - return EraFromYear(Date::ExtractYear(input)); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateSimpleDatePartStatistics<0, 1>(input.child_stats); - } - }; - - struct TimezoneOperator { - template - static inline TR Operation(TA input) { - // Regular timestamps are UTC. - return 0; - } - - template - static TR Operation(TA interval, TB timetz) { - auto time = Time::NormalizeTimeTZ(timetz); - date_t date(0); - time = Interval::Add(time, interval, date); - auto offset = UnsafeNumericCast(interval.micros / Interval::MICROS_PER_SEC); - return TR(time, offset); - } - - template - static void BinaryFunction(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() == 2); - auto &offset = input.data[0]; - auto &timetz = input.data[1]; - - auto func = DatePart::TimezoneOperator::Operation; - BinaryExecutor::Execute(offset, timetz, result, input.size(), func); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateSimpleDatePartStatistics<0, 0>(input.child_stats); - } - }; - - struct TimezoneHourOperator { - template - static inline TR Operation(TA input) { - // Regular timestamps are UTC. - return 0; - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateSimpleDatePartStatistics<0, 0>(input.child_stats); - } - }; - - struct TimezoneMinuteOperator { - template - static inline TR Operation(TA input) { - // Regular timestamps are UTC. - return 0; - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateSimpleDatePartStatistics<0, 0>(input.child_stats); - } - }; - - struct JulianDayOperator { - template - static inline TR Operation(TA input) { - return Timestamp::GetJulianDay(input); - } - - template - static unique_ptr PropagateStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return PropagateDatePartStatistics(input.child_stats, LogicalType::DOUBLE); - } - }; - - struct StructOperator { - using part_codes_t = vector; - using part_mask_t = uint64_t; - - enum MaskBits : uint8_t { - YMD = 1 << 0, - DOW = 1 << 1, - DOY = 1 << 2, - EPOCH = 1 << 3, - TIME = 1 << 4, - ZONE = 1 << 5, - ISO = 1 << 6, - JD = 1 << 7 - }; - - static part_mask_t GetMask(const part_codes_t &part_codes) { - part_mask_t mask = 0; - for (const auto &part_code : part_codes) { - switch (part_code) { - case DatePartSpecifier::YEAR: - case DatePartSpecifier::MONTH: - case DatePartSpecifier::DAY: - case DatePartSpecifier::DECADE: - case DatePartSpecifier::CENTURY: - case DatePartSpecifier::MILLENNIUM: - case DatePartSpecifier::QUARTER: - case DatePartSpecifier::ERA: - mask |= YMD; - break; - case DatePartSpecifier::YEARWEEK: - case DatePartSpecifier::WEEK: - case DatePartSpecifier::ISOYEAR: - mask |= ISO; - break; - case DatePartSpecifier::DOW: - case DatePartSpecifier::ISODOW: - mask |= DOW; - break; - case DatePartSpecifier::DOY: - mask |= DOY; - break; - case DatePartSpecifier::EPOCH: - mask |= EPOCH; - break; - case DatePartSpecifier::JULIAN_DAY: - mask |= JD; - break; - case DatePartSpecifier::MICROSECONDS: - case DatePartSpecifier::MILLISECONDS: - case DatePartSpecifier::SECOND: - case DatePartSpecifier::MINUTE: - case DatePartSpecifier::HOUR: - mask |= TIME; - break; - case DatePartSpecifier::TIMEZONE: - case DatePartSpecifier::TIMEZONE_HOUR: - case DatePartSpecifier::TIMEZONE_MINUTE: - mask |= ZONE; - break; - case DatePartSpecifier::INVALID: - throw InternalException("Invalid DatePartSpecifier for STRUCT mask!"); - } - } - return mask; - } - - template - static inline P HasPartValue(vector

part_values, DatePartSpecifier part) { - auto idx = size_t(part); - if (IsBigintDatepart(part)) { - return part_values[idx - size_t(DatePartSpecifier::BEGIN_BIGINT)]; - } else { - return part_values[idx - size_t(DatePartSpecifier::BEGIN_DOUBLE)]; - } - } - - using bigint_vec = vector; - using double_vec = vector; - - template - static inline void Operation(bigint_vec &bigint_values, double_vec &double_values, const TA &input, - const idx_t idx, const part_mask_t mask) { - int64_t *bigint_data; - // YMD calculations - int32_t yyyy = 1970; - int32_t mm = 0; - int32_t dd = 1; - if (mask & YMD) { - Date::Convert(input, yyyy, mm, dd); - bigint_data = HasPartValue(bigint_values, DatePartSpecifier::YEAR); - if (bigint_data) { - bigint_data[idx] = yyyy; - } - bigint_data = HasPartValue(bigint_values, DatePartSpecifier::MONTH); - if (bigint_data) { - bigint_data[idx] = mm; - } - bigint_data = HasPartValue(bigint_values, DatePartSpecifier::DAY); - if (bigint_data) { - bigint_data[idx] = dd; - } - bigint_data = HasPartValue(bigint_values, DatePartSpecifier::DECADE); - if (bigint_data) { - bigint_data[idx] = DecadeOperator::DecadeFromYear(yyyy); - } - bigint_data = HasPartValue(bigint_values, DatePartSpecifier::CENTURY); - if (bigint_data) { - bigint_data[idx] = CenturyOperator::CenturyFromYear(yyyy); - } - bigint_data = HasPartValue(bigint_values, DatePartSpecifier::MILLENNIUM); - if (bigint_data) { - bigint_data[idx] = MillenniumOperator::MillenniumFromYear(yyyy); - } - bigint_data = HasPartValue(bigint_values, DatePartSpecifier::QUARTER); - if (bigint_data) { - bigint_data[idx] = QuarterOperator::QuarterFromMonth(mm); - } - bigint_data = HasPartValue(bigint_values, DatePartSpecifier::ERA); - if (bigint_data) { - bigint_data[idx] = EraOperator::EraFromYear(yyyy); - } - } - - // Week calculations - if (mask & DOW) { - auto isodow = Date::ExtractISODayOfTheWeek(input); - bigint_data = HasPartValue(bigint_values, DatePartSpecifier::DOW); - if (bigint_data) { - bigint_data[idx] = DayOfWeekOperator::DayOfWeekFromISO(isodow); - } - bigint_data = HasPartValue(bigint_values, DatePartSpecifier::ISODOW); - if (bigint_data) { - bigint_data[idx] = isodow; - } - } - - // ISO calculations - if (mask & ISO) { - int32_t ww = 0; - int32_t iyyy = 0; - Date::ExtractISOYearWeek(input, iyyy, ww); - bigint_data = HasPartValue(bigint_values, DatePartSpecifier::WEEK); - if (bigint_data) { - bigint_data[idx] = ww; - } - bigint_data = HasPartValue(bigint_values, DatePartSpecifier::ISOYEAR); - if (bigint_data) { - bigint_data[idx] = iyyy; - } - bigint_data = HasPartValue(bigint_values, DatePartSpecifier::YEARWEEK); - if (bigint_data) { - bigint_data[idx] = YearWeekOperator::YearWeekFromParts(iyyy, ww); - } - } - - if (mask & EPOCH) { - auto double_data = HasPartValue(double_values, DatePartSpecifier::EPOCH); - if (double_data) { - double_data[idx] = double(Date::Epoch(input)); - } - } - if (mask & DOY) { - bigint_data = HasPartValue(bigint_values, DatePartSpecifier::DOY); - if (bigint_data) { - bigint_data[idx] = Date::ExtractDayOfTheYear(input); - } - } - if (mask & JD) { - auto double_data = HasPartValue(double_values, DatePartSpecifier::JULIAN_DAY); - if (double_data) { - double_data[idx] = double(Date::ExtractJulianDay(input)); - } - } - } - }; -}; - -template -static void DatePartCachedFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &lstate = ExecuteFunctionState::GetFunctionState(state)->Cast>(); - UnaryExecutor::ExecuteWithNulls( - args.data[0], result, args.size(), - [&](T input, ValidityMask &mask, idx_t idx) { return lstate.cache.ExtractElement(input, mask, idx); }); -} - -template <> -int64_t DatePart::YearOperator::Operation(timestamp_t input) { - return YearOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -int64_t DatePart::YearOperator::Operation(interval_t input) { - return input.months / Interval::MONTHS_PER_YEAR; -} - -template <> -int64_t DatePart::YearOperator::Operation(dtime_t input) { - throw NotImplementedException("\"time\" units \"year\" not recognized"); -} - -template <> -int64_t DatePart::YearOperator::Operation(dtime_tz_t input) { - return YearOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::MonthOperator::Operation(timestamp_t input) { - return MonthOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -int64_t DatePart::MonthOperator::Operation(interval_t input) { - return input.months % Interval::MONTHS_PER_YEAR; -} - -template <> -int64_t DatePart::MonthOperator::Operation(dtime_t input) { - throw NotImplementedException("\"time\" units \"month\" not recognized"); -} - -template <> -int64_t DatePart::MonthOperator::Operation(dtime_tz_t input) { - return MonthOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::DayOperator::Operation(timestamp_t input) { - return DayOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -int64_t DatePart::DayOperator::Operation(interval_t input) { - return input.days; -} - -template <> -int64_t DatePart::DayOperator::Operation(dtime_t input) { - throw NotImplementedException("\"time\" units \"day\" not recognized"); -} - -template <> -int64_t DatePart::DayOperator::Operation(dtime_tz_t input) { - return DayOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::DecadeOperator::Operation(interval_t input) { - return input.months / Interval::MONTHS_PER_DECADE; -} - -template <> -int64_t DatePart::DecadeOperator::Operation(dtime_t input) { - throw NotImplementedException("\"time\" units \"decade\" not recognized"); -} - -template <> -int64_t DatePart::DecadeOperator::Operation(dtime_tz_t input) { - return DecadeOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::CenturyOperator::Operation(interval_t input) { - return input.months / Interval::MONTHS_PER_CENTURY; -} - -template <> -int64_t DatePart::CenturyOperator::Operation(dtime_t input) { - throw NotImplementedException("\"time\" units \"century\" not recognized"); -} - -template <> -int64_t DatePart::CenturyOperator::Operation(dtime_tz_t input) { - return CenturyOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::MillenniumOperator::Operation(interval_t input) { - return input.months / Interval::MONTHS_PER_MILLENIUM; -} - -template <> -int64_t DatePart::MillenniumOperator::Operation(dtime_t input) { - throw NotImplementedException("\"time\" units \"millennium\" not recognized"); -} - -template <> -int64_t DatePart::MillenniumOperator::Operation(dtime_tz_t input) { - return MillenniumOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::QuarterOperator::Operation(timestamp_t input) { - return QuarterOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -int64_t DatePart::QuarterOperator::Operation(interval_t input) { - return MonthOperator::Operation(input) / Interval::MONTHS_PER_QUARTER + 1; -} - -template <> -int64_t DatePart::QuarterOperator::Operation(dtime_t input) { - throw NotImplementedException("\"time\" units \"quarter\" not recognized"); -} - -template <> -int64_t DatePart::QuarterOperator::Operation(dtime_tz_t input) { - return QuarterOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::DayOfWeekOperator::Operation(timestamp_t input) { - return DayOfWeekOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -int64_t DatePart::DayOfWeekOperator::Operation(interval_t input) { - throw NotImplementedException("interval units \"dow\" not recognized"); -} - -template <> -int64_t DatePart::DayOfWeekOperator::Operation(dtime_t input) { - throw NotImplementedException("\"time\" units \"dow\" not recognized"); -} - -template <> -int64_t DatePart::DayOfWeekOperator::Operation(dtime_tz_t input) { - return DayOfWeekOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::ISODayOfWeekOperator::Operation(timestamp_t input) { - return ISODayOfWeekOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -int64_t DatePart::ISODayOfWeekOperator::Operation(interval_t input) { - throw NotImplementedException("interval units \"isodow\" not recognized"); -} - -template <> -int64_t DatePart::ISODayOfWeekOperator::Operation(dtime_t input) { - throw NotImplementedException("\"time\" units \"isodow\" not recognized"); -} - -template <> -int64_t DatePart::ISODayOfWeekOperator::Operation(dtime_tz_t input) { - return ISODayOfWeekOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::DayOfYearOperator::Operation(timestamp_t input) { - return DayOfYearOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -int64_t DatePart::DayOfYearOperator::Operation(interval_t input) { - throw NotImplementedException("interval units \"doy\" not recognized"); -} - -template <> -int64_t DatePart::DayOfYearOperator::Operation(dtime_t input) { - throw NotImplementedException("\"time\" units \"doy\" not recognized"); -} - -template <> -int64_t DatePart::DayOfYearOperator::Operation(dtime_tz_t input) { - return DayOfYearOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::WeekOperator::Operation(timestamp_t input) { - return WeekOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -int64_t DatePart::WeekOperator::Operation(interval_t input) { - throw NotImplementedException("interval units \"week\" not recognized"); -} - -template <> -int64_t DatePart::WeekOperator::Operation(dtime_t input) { - throw NotImplementedException("\"time\" units \"week\" not recognized"); -} - -template <> -int64_t DatePart::WeekOperator::Operation(dtime_tz_t input) { - return WeekOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::ISOYearOperator::Operation(timestamp_t input) { - return ISOYearOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -int64_t DatePart::ISOYearOperator::Operation(interval_t input) { - throw NotImplementedException("interval units \"isoyear\" not recognized"); -} - -template <> -int64_t DatePart::ISOYearOperator::Operation(dtime_t input) { - throw NotImplementedException("\"time\" units \"isoyear\" not recognized"); -} - -template <> -int64_t DatePart::ISOYearOperator::Operation(dtime_tz_t input) { - return ISOYearOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::YearWeekOperator::Operation(timestamp_t input) { - return YearWeekOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -int64_t DatePart::YearWeekOperator::Operation(interval_t input) { - const auto yyyy = YearOperator::Operation(input); - const auto ww = WeekOperator::Operation(input); - return YearWeekOperator::YearWeekFromParts(yyyy, ww); -} - -template <> -int64_t DatePart::YearWeekOperator::Operation(dtime_t input) { - throw NotImplementedException("\"time\" units \"yearweek\" not recognized"); -} - -template <> -int64_t DatePart::YearWeekOperator::Operation(dtime_tz_t input) { - return YearWeekOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::EpochNanosecondsOperator::Operation(timestamp_t input) { - D_ASSERT(Timestamp::IsFinite(input)); - return Timestamp::GetEpochNanoSeconds(input); -} - -template <> -int64_t DatePart::EpochNanosecondsOperator::Operation(date_t input) { - D_ASSERT(Date::IsFinite(input)); - return Date::EpochNanoseconds(input); -} - -template <> -int64_t DatePart::EpochNanosecondsOperator::Operation(interval_t input) { - return Interval::GetNanoseconds(input); -} - -template <> -int64_t DatePart::EpochNanosecondsOperator::Operation(dtime_t input) { - return input.micros * Interval::NANOS_PER_MICRO; -} - -template <> -int64_t DatePart::EpochNanosecondsOperator::Operation(dtime_tz_t input) { - return DatePart::EpochNanosecondsOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::EpochMicrosecondsOperator::Operation(date_t input) { - return Date::EpochMicroseconds(input); -} - -template <> -int64_t DatePart::EpochMicrosecondsOperator::Operation(interval_t input) { - return Interval::GetMicro(input); -} - -template <> -int64_t DatePart::EpochMillisOperator::Operation(timestamp_t input) { - D_ASSERT(Timestamp::IsFinite(input)); - return Timestamp::GetEpochMs(input); -} - -template <> -int64_t DatePart::EpochMicrosecondsOperator::Operation(dtime_t input) { - return input.micros; -} - -template <> -int64_t DatePart::EpochMicrosecondsOperator::Operation(dtime_tz_t input) { - return DatePart::EpochMicrosecondsOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::EpochMillisOperator::Operation(date_t input) { - return Date::EpochMilliseconds(input); -} - -template <> -int64_t DatePart::EpochMillisOperator::Operation(interval_t input) { - return Interval::GetMilli(input); -} - -template <> -int64_t DatePart::EpochMillisOperator::Operation(dtime_t input) { - return input.micros / Interval::MICROS_PER_MSEC; -} - -template <> -int64_t DatePart::EpochMillisOperator::Operation(dtime_tz_t input) { - return DatePart::EpochMillisOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::NanosecondsOperator::Operation(timestamp_ns_t input) { - if (!Timestamp::IsFinite(input)) { - throw ConversionException("Can't get nanoseconds of infinite TIMESTAMP"); - } - date_t date; - dtime_t time; - int32_t nanos; - Timestamp::Convert(input, date, time, nanos); - // remove everything but the second & nanosecond part - return (time.micros % Interval::MICROS_PER_MINUTE) * Interval::NANOS_PER_MICRO + nanos; -} - -template <> -int64_t DatePart::MicrosecondsOperator::Operation(timestamp_t input) { - D_ASSERT(Timestamp::IsFinite(input)); - auto time = Timestamp::GetTime(input); - // remove everything but the second & microsecond part - return time.micros % Interval::MICROS_PER_MINUTE; -} - -template <> -int64_t DatePart::MicrosecondsOperator::Operation(interval_t input) { - // remove everything but the second & microsecond part - return input.micros % Interval::MICROS_PER_MINUTE; -} - -template <> -int64_t DatePart::MicrosecondsOperator::Operation(dtime_t input) { - // remove everything but the second & microsecond part - return input.micros % Interval::MICROS_PER_MINUTE; -} - -template <> -int64_t DatePart::MicrosecondsOperator::Operation(dtime_tz_t input) { - return DatePart::MicrosecondsOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::MillisecondsOperator::Operation(timestamp_t input) { - D_ASSERT(Timestamp::IsFinite(input)); - return MicrosecondsOperator::Operation(input) / Interval::MICROS_PER_MSEC; -} - -template <> -int64_t DatePart::MillisecondsOperator::Operation(interval_t input) { - return MicrosecondsOperator::Operation(input) / Interval::MICROS_PER_MSEC; -} - -template <> -int64_t DatePart::MillisecondsOperator::Operation(dtime_t input) { - return MicrosecondsOperator::Operation(input) / Interval::MICROS_PER_MSEC; -} - -template <> -int64_t DatePart::MillisecondsOperator::Operation(dtime_tz_t input) { - return DatePart::MillisecondsOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::SecondsOperator::Operation(timestamp_t input) { - D_ASSERT(Timestamp::IsFinite(input)); - return MicrosecondsOperator::Operation(input) / Interval::MICROS_PER_SEC; -} - -template <> -int64_t DatePart::SecondsOperator::Operation(interval_t input) { - return MicrosecondsOperator::Operation(input) / Interval::MICROS_PER_SEC; -} - -template <> -int64_t DatePart::SecondsOperator::Operation(dtime_t input) { - return MicrosecondsOperator::Operation(input) / Interval::MICROS_PER_SEC; -} - -template <> -int64_t DatePart::SecondsOperator::Operation(dtime_tz_t input) { - return DatePart::SecondsOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::MinutesOperator::Operation(timestamp_t input) { - D_ASSERT(Timestamp::IsFinite(input)); - auto time = Timestamp::GetTime(input); - // remove the hour part, and truncate to minutes - return (time.micros % Interval::MICROS_PER_HOUR) / Interval::MICROS_PER_MINUTE; -} - -template <> -int64_t DatePart::MinutesOperator::Operation(interval_t input) { - // remove the hour part, and truncate to minutes - return (input.micros % Interval::MICROS_PER_HOUR) / Interval::MICROS_PER_MINUTE; -} - -template <> -int64_t DatePart::MinutesOperator::Operation(dtime_t input) { - // remove the hour part, and truncate to minutes - return (input.micros % Interval::MICROS_PER_HOUR) / Interval::MICROS_PER_MINUTE; -} - -template <> -int64_t DatePart::MinutesOperator::Operation(dtime_tz_t input) { - return DatePart::MinutesOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::HoursOperator::Operation(timestamp_t input) { - D_ASSERT(Timestamp::IsFinite(input)); - return Timestamp::GetTime(input).micros / Interval::MICROS_PER_HOUR; -} - -template <> -int64_t DatePart::HoursOperator::Operation(interval_t input) { - return input.micros / Interval::MICROS_PER_HOUR; -} - -template <> -int64_t DatePart::HoursOperator::Operation(dtime_t input) { - return input.micros / Interval::MICROS_PER_HOUR; -} - -template <> -int64_t DatePart::HoursOperator::Operation(dtime_tz_t input) { - return DatePart::HoursOperator::Operation(input.time()); -} - -template <> -double DatePart::EpochOperator::Operation(timestamp_t input) { - D_ASSERT(Timestamp::IsFinite(input)); - return double(Timestamp::GetEpochMicroSeconds(input)) / double(Interval::MICROS_PER_SEC); -} - -template <> -double DatePart::EpochOperator::Operation(interval_t input) { - int64_t interval_years = input.months / Interval::MONTHS_PER_YEAR; - int64_t interval_days; - interval_days = Interval::DAYS_PER_YEAR * interval_years; - interval_days += Interval::DAYS_PER_MONTH * (input.months % Interval::MONTHS_PER_YEAR); - interval_days += input.days; - int64_t interval_epoch; - interval_epoch = interval_days * Interval::SECS_PER_DAY; - // we add 0.25 days per year to sort of account for leap days - interval_epoch += interval_years * (Interval::SECS_PER_DAY / 4); - return double(interval_epoch) + double(input.micros) / double(Interval::MICROS_PER_SEC); -} - -// TODO: We can't propagate interval statistics because we can't easily compare interval_t for order. -template <> -unique_ptr DatePart::EpochOperator::PropagateStatistics(ClientContext &context, - FunctionStatisticsInput &input) { - return nullptr; -} - -template <> -double DatePart::EpochOperator::Operation(dtime_t input) { - return double(input.micros) / double(Interval::MICROS_PER_SEC); -} - -template <> -double DatePart::EpochOperator::Operation(dtime_tz_t input) { - return DatePart::EpochOperator::Operation(input.time()); -} - -template <> -unique_ptr DatePart::EpochOperator::PropagateStatistics(ClientContext &context, - FunctionStatisticsInput &input) { - auto result = NumericStats::CreateEmpty(LogicalType::DOUBLE); - result.CopyValidity(input.child_stats[0]); - NumericStats::SetMin(result, Value::DOUBLE(0)); - NumericStats::SetMax(result, Value::DOUBLE(Interval::SECS_PER_DAY)); - return result.ToUnique(); -} - -template <> -int64_t DatePart::EraOperator::Operation(timestamp_t input) { - D_ASSERT(Timestamp::IsFinite(input)); - return EraOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -int64_t DatePart::EraOperator::Operation(interval_t input) { - throw NotImplementedException("interval units \"era\" not recognized"); -} - -template <> -int64_t DatePart::EraOperator::Operation(dtime_t input) { - throw NotImplementedException("\"time\" units \"era\" not recognized"); -} - -template <> -int64_t DatePart::EraOperator::Operation(dtime_tz_t input) { - return EraOperator::Operation(input.time()); -} - -template <> -int64_t DatePart::TimezoneOperator::Operation(date_t input) { - throw NotImplementedException("\"date\" units \"timezone\" not recognized"); -} - -template <> -int64_t DatePart::TimezoneOperator::Operation(interval_t input) { - throw NotImplementedException("\"interval\" units \"timezone\" not recognized"); -} - -template <> -int64_t DatePart::TimezoneOperator::Operation(dtime_tz_t input) { - return input.offset(); -} - -template <> -int64_t DatePart::TimezoneHourOperator::Operation(date_t input) { - throw NotImplementedException("\"date\" units \"timezone_hour\" not recognized"); -} - -template <> -int64_t DatePart::TimezoneHourOperator::Operation(interval_t input) { - throw NotImplementedException("\"interval\" units \"timezone_hour\" not recognized"); -} - -template <> -int64_t DatePart::TimezoneHourOperator::Operation(dtime_tz_t input) { - return input.offset() / Interval::SECS_PER_HOUR; -} - -template <> -int64_t DatePart::TimezoneMinuteOperator::Operation(date_t input) { - throw NotImplementedException("\"date\" units \"timezone_minute\" not recognized"); -} - -template <> -int64_t DatePart::TimezoneMinuteOperator::Operation(interval_t input) { - throw NotImplementedException("\"interval\" units \"timezone_minute\" not recognized"); -} - -template <> -int64_t DatePart::TimezoneMinuteOperator::Operation(dtime_tz_t input) { - return (input.offset() / Interval::SECS_PER_MINUTE) % Interval::MINS_PER_HOUR; -} - -template <> -double DatePart::JulianDayOperator::Operation(date_t input) { - return double(Date::ExtractJulianDay(input)); -} - -template <> -double DatePart::JulianDayOperator::Operation(interval_t input) { - throw NotImplementedException("interval units \"julian\" not recognized"); -} - -template <> -double DatePart::JulianDayOperator::Operation(dtime_t input) { - throw NotImplementedException("\"time\" units \"julian\" not recognized"); -} - -template <> -double DatePart::JulianDayOperator::Operation(dtime_tz_t input) { - return JulianDayOperator::Operation(input.time()); -} - -template <> -void DatePart::StructOperator::Operation(bigint_vec &bigint_values, double_vec &double_values, const dtime_t &input, - const idx_t idx, const part_mask_t mask) { - int64_t *part_data; - if (mask & TIME) { - const auto micros = MicrosecondsOperator::Operation(input); - part_data = HasPartValue(bigint_values, DatePartSpecifier::MICROSECONDS); - if (part_data) { - part_data[idx] = micros; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::MILLISECONDS); - if (part_data) { - part_data[idx] = micros / Interval::MICROS_PER_MSEC; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::SECOND); - if (part_data) { - part_data[idx] = micros / Interval::MICROS_PER_SEC; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::MINUTE); - if (part_data) { - part_data[idx] = MinutesOperator::Operation(input); - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::HOUR); - if (part_data) { - part_data[idx] = HoursOperator::Operation(input); - } - } - - if (mask & EPOCH) { - auto part_data = HasPartValue(double_values, DatePartSpecifier::EPOCH); - if (part_data) { - part_data[idx] = EpochOperator::Operation(input); - } - } - - if (mask & ZONE) { - part_data = HasPartValue(bigint_values, DatePartSpecifier::TIMEZONE); - if (part_data) { - part_data[idx] = 0; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::TIMEZONE_HOUR); - if (part_data) { - part_data[idx] = 0; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::TIMEZONE_MINUTE); - if (part_data) { - part_data[idx] = 0; - } - } -} - -template <> -void DatePart::StructOperator::Operation(bigint_vec &bigint_values, double_vec &double_values, const dtime_tz_t &input, - const idx_t idx, const part_mask_t mask) { - int64_t *part_data; - if (mask & TIME) { - const auto micros = MicrosecondsOperator::Operation(input); - part_data = HasPartValue(bigint_values, DatePartSpecifier::MICROSECONDS); - if (part_data) { - part_data[idx] = micros; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::MILLISECONDS); - if (part_data) { - part_data[idx] = micros / Interval::MICROS_PER_MSEC; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::SECOND); - if (part_data) { - part_data[idx] = micros / Interval::MICROS_PER_SEC; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::MINUTE); - if (part_data) { - part_data[idx] = MinutesOperator::Operation(input); - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::HOUR); - if (part_data) { - part_data[idx] = HoursOperator::Operation(input); - } - } - - if (mask & EPOCH) { - auto part_data = HasPartValue(double_values, DatePartSpecifier::EPOCH); - if (part_data) { - part_data[idx] = EpochOperator::Operation(input); - } - } - - if (mask & ZONE) { - part_data = HasPartValue(bigint_values, DatePartSpecifier::TIMEZONE); - if (part_data) { - part_data[idx] = TimezoneOperator::Operation(input); - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::TIMEZONE_HOUR); - if (part_data) { - part_data[idx] = TimezoneHourOperator::Operation(input); - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::TIMEZONE_MINUTE); - if (part_data) { - part_data[idx] = TimezoneMinuteOperator::Operation(input); - } - return; - } -} - -template <> -void DatePart::StructOperator::Operation(bigint_vec &bigint_values, double_vec &double_values, const timestamp_t &input, - const idx_t idx, const part_mask_t mask) { - D_ASSERT(Timestamp::IsFinite(input)); - date_t d; - dtime_t t; - Timestamp::Convert(input, d, t); - - // Both define epoch, and the correct value is the sum. - // So mask it out and compute it separately. - Operation(bigint_values, double_values, d, idx, mask & ~UnsafeNumericCast(EPOCH)); - Operation(bigint_values, double_values, t, idx, mask & ~UnsafeNumericCast(EPOCH)); - - if (mask & EPOCH) { - auto part_data = HasPartValue(double_values, DatePartSpecifier::EPOCH); - if (part_data) { - part_data[idx] = EpochOperator::Operation(input); - } - } - - if (mask & JD) { - auto part_data = HasPartValue(double_values, DatePartSpecifier::JULIAN_DAY); - if (part_data) { - part_data[idx] = JulianDayOperator::Operation(input); - } - } -} - -template <> -void DatePart::StructOperator::Operation(bigint_vec &bigint_values, double_vec &double_values, const interval_t &input, - const idx_t idx, const part_mask_t mask) { - int64_t *part_data; - if (mask & YMD) { - const auto mm = input.months % Interval::MONTHS_PER_YEAR; - part_data = HasPartValue(bigint_values, DatePartSpecifier::YEAR); - if (part_data) { - part_data[idx] = input.months / Interval::MONTHS_PER_YEAR; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::MONTH); - if (part_data) { - part_data[idx] = mm; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::DAY); - if (part_data) { - part_data[idx] = input.days; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::DECADE); - if (part_data) { - part_data[idx] = input.months / Interval::MONTHS_PER_DECADE; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::CENTURY); - if (part_data) { - part_data[idx] = input.months / Interval::MONTHS_PER_CENTURY; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::MILLENNIUM); - if (part_data) { - part_data[idx] = input.months / Interval::MONTHS_PER_MILLENIUM; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::QUARTER); - if (part_data) { - part_data[idx] = mm / Interval::MONTHS_PER_QUARTER + 1; - } - } - - if (mask & TIME) { - const auto micros = MicrosecondsOperator::Operation(input); - part_data = HasPartValue(bigint_values, DatePartSpecifier::MICROSECONDS); - if (part_data) { - part_data[idx] = micros; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::MILLISECONDS); - if (part_data) { - part_data[idx] = micros / Interval::MICROS_PER_MSEC; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::SECOND); - if (part_data) { - part_data[idx] = micros / Interval::MICROS_PER_SEC; - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::MINUTE); - if (part_data) { - part_data[idx] = MinutesOperator::Operation(input); - } - part_data = HasPartValue(bigint_values, DatePartSpecifier::HOUR); - if (part_data) { - part_data[idx] = HoursOperator::Operation(input); - } - } - - if (mask & EPOCH) { - auto part_data = HasPartValue(double_values, DatePartSpecifier::EPOCH); - if (part_data) { - part_data[idx] = EpochOperator::Operation(input); - } - } -} - -template -static int64_t ExtractElement(DatePartSpecifier type, T element) { - switch (type) { - case DatePartSpecifier::YEAR: - return DatePart::YearOperator::template Operation(element); - case DatePartSpecifier::MONTH: - return DatePart::MonthOperator::template Operation(element); - case DatePartSpecifier::DAY: - return DatePart::DayOperator::template Operation(element); - case DatePartSpecifier::DECADE: - return DatePart::DecadeOperator::template Operation(element); - case DatePartSpecifier::CENTURY: - return DatePart::CenturyOperator::template Operation(element); - case DatePartSpecifier::MILLENNIUM: - return DatePart::MillenniumOperator::template Operation(element); - case DatePartSpecifier::QUARTER: - return DatePart::QuarterOperator::template Operation(element); - case DatePartSpecifier::DOW: - return DatePart::DayOfWeekOperator::template Operation(element); - case DatePartSpecifier::ISODOW: - return DatePart::ISODayOfWeekOperator::template Operation(element); - case DatePartSpecifier::DOY: - return DatePart::DayOfYearOperator::template Operation(element); - case DatePartSpecifier::WEEK: - return DatePart::WeekOperator::template Operation(element); - case DatePartSpecifier::ISOYEAR: - return DatePart::ISOYearOperator::template Operation(element); - case DatePartSpecifier::YEARWEEK: - return DatePart::YearWeekOperator::template Operation(element); - case DatePartSpecifier::MICROSECONDS: - return DatePart::MicrosecondsOperator::template Operation(element); - case DatePartSpecifier::MILLISECONDS: - return DatePart::MillisecondsOperator::template Operation(element); - case DatePartSpecifier::SECOND: - return DatePart::SecondsOperator::template Operation(element); - case DatePartSpecifier::MINUTE: - return DatePart::MinutesOperator::template Operation(element); - case DatePartSpecifier::HOUR: - return DatePart::HoursOperator::template Operation(element); - case DatePartSpecifier::ERA: - return DatePart::EraOperator::template Operation(element); - case DatePartSpecifier::TIMEZONE: - return DatePart::TimezoneOperator::template Operation(element); - case DatePartSpecifier::TIMEZONE_HOUR: - return DatePart::TimezoneHourOperator::template Operation(element); - case DatePartSpecifier::TIMEZONE_MINUTE: - return DatePart::TimezoneMinuteOperator::template Operation(element); - default: - throw NotImplementedException("Specifier type not implemented for DATEPART"); - } -} - -template -static void DatePartFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 2); - auto &spec_arg = args.data[0]; - auto &date_arg = args.data[1]; - - BinaryExecutor::ExecuteWithNulls( - spec_arg, date_arg, result, args.size(), [&](string_t specifier, T date, ValidityMask &mask, idx_t idx) { - if (Value::IsFinite(date)) { - return ExtractElement(GetDatePartSpecifier(specifier.GetString()), date); - } else { - mask.SetInvalid(idx); - return int64_t(0); - } - }); -} - -static unique_ptr DatePartBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - // If we are only looking for Julian Days for timestamps, - // then return doubles. - if (arguments[0]->HasParameter() || !arguments[0]->IsFoldable()) { - return nullptr; - } - - Value part_value = ExpressionExecutor::EvaluateScalar(context, *arguments[0]); - const auto part_name = part_value.ToString(); - switch (GetDatePartSpecifier(part_name)) { - case DatePartSpecifier::JULIAN_DAY: - arguments.erase(arguments.begin()); - bound_function.arguments.erase(bound_function.arguments.begin()); - bound_function.name = "julian"; - bound_function.return_type = LogicalType::DOUBLE; - switch (arguments[0]->return_type.id()) { - case LogicalType::TIMESTAMP: - case LogicalType::TIMESTAMP_S: - case LogicalType::TIMESTAMP_MS: - case LogicalType::TIMESTAMP_NS: - bound_function.function = DatePart::UnaryFunction; - bound_function.statistics = DatePart::JulianDayOperator::template PropagateStatistics; - break; - case LogicalType::DATE: - bound_function.function = DatePart::UnaryFunction; - bound_function.statistics = DatePart::JulianDayOperator::template PropagateStatistics; - break; - default: - throw BinderException("%s can only take DATE or TIMESTAMP arguments", bound_function.name); - } - break; - case DatePartSpecifier::EPOCH: - arguments.erase(arguments.begin()); - bound_function.arguments.erase(bound_function.arguments.begin()); - bound_function.name = "epoch"; - bound_function.return_type = LogicalType::DOUBLE; - switch (arguments[0]->return_type.id()) { - case LogicalType::TIMESTAMP: - case LogicalType::TIMESTAMP_S: - case LogicalType::TIMESTAMP_MS: - case LogicalType::TIMESTAMP_NS: - bound_function.function = DatePart::UnaryFunction; - bound_function.statistics = DatePart::EpochOperator::template PropagateStatistics; - break; - case LogicalType::DATE: - bound_function.function = DatePart::UnaryFunction; - bound_function.statistics = DatePart::EpochOperator::template PropagateStatistics; - break; - case LogicalType::INTERVAL: - bound_function.function = DatePart::UnaryFunction; - bound_function.statistics = DatePart::EpochOperator::template PropagateStatistics; - break; - case LogicalType::TIME: - bound_function.function = DatePart::UnaryFunction; - bound_function.statistics = DatePart::EpochOperator::template PropagateStatistics; - break; - case LogicalType::TIME_TZ: - bound_function.function = DatePart::UnaryFunction; - bound_function.statistics = DatePart::EpochOperator::template PropagateStatistics; - break; - default: - throw BinderException("%s can only take temporal arguments", bound_function.name); - } - break; - default: - break; - } - - return nullptr; -} - -template -ScalarFunctionSet GetGenericDatePartFunction(scalar_function_t date_func, scalar_function_t ts_func, - scalar_function_t interval_func, function_statistics_t date_stats, - function_statistics_t ts_stats) { - ScalarFunctionSet operator_set; - operator_set.AddFunction(ScalarFunction({LogicalType::DATE}, LogicalType::BIGINT, std::move(date_func), nullptr, - nullptr, date_stats, DATE_CACHE)); - operator_set.AddFunction(ScalarFunction({LogicalType::TIMESTAMP}, LogicalType::BIGINT, std::move(ts_func), nullptr, - nullptr, ts_stats, DATE_CACHE)); - operator_set.AddFunction(ScalarFunction({LogicalType::INTERVAL}, LogicalType::BIGINT, std::move(interval_func))); - return operator_set; -} - -template -static ScalarFunctionSet GetDatePartFunction() { - return GetGenericDatePartFunction( - DatePart::UnaryFunction, DatePart::UnaryFunction, - ScalarFunction::UnaryFunction, OP::template PropagateStatistics, - OP::template PropagateStatistics); -} - -ScalarFunctionSet GetGenericTimePartFunction(const LogicalType &result_type, scalar_function_t date_func, - scalar_function_t ts_func, scalar_function_t interval_func, - scalar_function_t time_func, scalar_function_t timetz_func, - function_statistics_t date_stats, function_statistics_t ts_stats, - function_statistics_t time_stats, function_statistics_t timetz_stats) { - ScalarFunctionSet operator_set; - operator_set.AddFunction( - ScalarFunction({LogicalType::DATE}, result_type, std::move(date_func), nullptr, nullptr, date_stats)); - operator_set.AddFunction( - ScalarFunction({LogicalType::TIMESTAMP}, result_type, std::move(ts_func), nullptr, nullptr, ts_stats)); - operator_set.AddFunction(ScalarFunction({LogicalType::INTERVAL}, result_type, std::move(interval_func))); - operator_set.AddFunction( - ScalarFunction({LogicalType::TIME}, result_type, std::move(time_func), nullptr, nullptr, time_stats)); - operator_set.AddFunction( - ScalarFunction({LogicalType::TIME_TZ}, result_type, std::move(timetz_func), nullptr, nullptr, timetz_stats)); - return operator_set; -} - -template -static ScalarFunctionSet GetTimePartFunction(const LogicalType &result_type = LogicalType::BIGINT) { - return GetGenericTimePartFunction( - result_type, DatePart::UnaryFunction, DatePart::UnaryFunction, - ScalarFunction::UnaryFunction, ScalarFunction::UnaryFunction, - ScalarFunction::UnaryFunction, OP::template PropagateStatistics, - OP::template PropagateStatistics, OP::template PropagateStatistics, - OP::template PropagateStatistics); -} - -struct LastDayOperator { - template - static inline TR Operation(TA input) { - int32_t yyyy, mm, dd; - Date::Convert(input, yyyy, mm, dd); - yyyy += (mm / 12); - mm %= 12; - ++mm; - return Date::FromDate(yyyy, mm, 1) - 1; - } -}; - -template <> -date_t LastDayOperator::Operation(timestamp_t input) { - return LastDayOperator::Operation(Timestamp::GetDate(input)); -} - -struct MonthNameOperator { - template - static inline TR Operation(TA input) { - return Date::MONTH_NAMES[DatePart::MonthOperator::Operation(input) - 1]; - } -}; - -struct DayNameOperator { - template - static inline TR Operation(TA input) { - return Date::DAY_NAMES[DatePart::DayOfWeekOperator::Operation(input)]; - } -}; - -struct StructDatePart { - using part_codes_t = vector; - - struct BindData : public VariableReturnBindData { - part_codes_t part_codes; - - explicit BindData(const LogicalType &stype, const part_codes_t &part_codes_p) - : VariableReturnBindData(stype), part_codes(part_codes_p) { - } - - unique_ptr Copy() const override { - return make_uniq(stype, part_codes); - } - }; - - static unique_ptr Bind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - // collect names and deconflict, construct return type - if (arguments[0]->HasParameter()) { - throw ParameterNotResolvedException(); - } - if (!arguments[0]->IsFoldable()) { - throw BinderException("%s can only take constant lists of part names", bound_function.name); - } - - case_insensitive_set_t name_collision_set; - child_list_t struct_children; - part_codes_t part_codes; - - Value parts_list = ExpressionExecutor::EvaluateScalar(context, *arguments[0]); - if (parts_list.type().id() == LogicalTypeId::LIST) { - auto &list_children = ListValue::GetChildren(parts_list); - if (list_children.empty()) { - throw BinderException("%s requires non-empty lists of part names", bound_function.name); - } - for (const auto &part_value : list_children) { - if (part_value.IsNull()) { - throw BinderException("NULL struct entry name in %s", bound_function.name); - } - const auto part_name = part_value.ToString(); - const auto part_code = GetDateTypePartSpecifier(part_name, arguments[1]->return_type); - if (name_collision_set.find(part_name) != name_collision_set.end()) { - throw BinderException("Duplicate struct entry name \"%s\" in %s", part_name, bound_function.name); - } - name_collision_set.insert(part_name); - part_codes.emplace_back(part_code); - const auto part_type = IsBigintDatepart(part_code) ? LogicalType::BIGINT : LogicalType::DOUBLE; - struct_children.emplace_back(make_pair(part_name, part_type)); - } - } else { - throw BinderException("%s can only take constant lists of part names", bound_function.name); - } - - Function::EraseArgument(bound_function, arguments, 0); - bound_function.return_type = LogicalType::STRUCT(struct_children); - return make_uniq(bound_function.return_type, part_codes); - } - - template - static void Function(DataChunk &args, ExpressionState &state, Vector &result) { - auto &func_expr = state.expr.Cast(); - auto &info = func_expr.bind_info->Cast(); - D_ASSERT(args.ColumnCount() == 1); - - const auto count = args.size(); - Vector &input = args.data[0]; - - // Type counts - const auto BIGINT_COUNT = size_t(DatePartSpecifier::BEGIN_DOUBLE) - size_t(DatePartSpecifier::BEGIN_BIGINT); - const auto DOUBLE_COUNT = size_t(DatePartSpecifier::BEGIN_INVALID) - size_t(DatePartSpecifier::BEGIN_DOUBLE); - DatePart::StructOperator::bigint_vec bigint_values(BIGINT_COUNT, nullptr); - DatePart::StructOperator::double_vec double_values(DOUBLE_COUNT, nullptr); - const auto part_mask = DatePart::StructOperator::GetMask(info.part_codes); - - auto &child_entries = StructVector::GetEntries(result); - - // The first computer of a part "owns" it - // and other requestors just reference the owner - vector owners(int(DatePartSpecifier::JULIAN_DAY) + 1, child_entries.size()); - for (size_t col = 0; col < child_entries.size(); ++col) { - const auto part_index = size_t(info.part_codes[col]); - if (owners[part_index] == child_entries.size()) { - owners[part_index] = col; - } - } - - if (input.GetVectorType() == VectorType::CONSTANT_VECTOR) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - - if (ConstantVector::IsNull(input)) { - ConstantVector::SetNull(result, true); - } else { - ConstantVector::SetNull(result, false); - for (size_t col = 0; col < child_entries.size(); ++col) { - auto &child_entry = child_entries[col]; - ConstantVector::SetNull(*child_entry, false); - const auto part_index = size_t(info.part_codes[col]); - if (owners[part_index] == col) { - if (IsBigintDatepart(info.part_codes[col])) { - bigint_values[part_index - size_t(DatePartSpecifier::BEGIN_BIGINT)] = - ConstantVector::GetData(*child_entry); - } else { - double_values[part_index - size_t(DatePartSpecifier::BEGIN_DOUBLE)] = - ConstantVector::GetData(*child_entry); - } - } - } - auto tdata = ConstantVector::GetData(input); - if (Value::IsFinite(tdata[0])) { - DatePart::StructOperator::Operation(bigint_values, double_values, tdata[0], 0, part_mask); - } else { - for (auto &child_entry : child_entries) { - ConstantVector::SetNull(*child_entry, true); - } - } - } - } else { - UnifiedVectorFormat rdata; - input.ToUnifiedFormat(count, rdata); - - const auto &arg_valid = rdata.validity; - auto tdata = UnifiedVectorFormat::GetData(rdata); - - // Start with a valid flat vector - result.SetVectorType(VectorType::FLAT_VECTOR); - auto &res_valid = FlatVector::Validity(result); - if (res_valid.GetData()) { - res_valid.SetAllValid(count); - } - - // Start with valid children - for (size_t col = 0; col < child_entries.size(); ++col) { - auto &child_entry = child_entries[col]; - child_entry->SetVectorType(VectorType::FLAT_VECTOR); - auto &child_validity = FlatVector::Validity(*child_entry); - if (child_validity.GetData()) { - child_validity.SetAllValid(count); - } - - // Pre-multiplex - const auto part_index = size_t(info.part_codes[col]); - if (owners[part_index] == col) { - if (IsBigintDatepart(info.part_codes[col])) { - bigint_values[part_index - size_t(DatePartSpecifier::BEGIN_BIGINT)] = - FlatVector::GetData(*child_entry); - } else { - double_values[part_index - size_t(DatePartSpecifier::BEGIN_DOUBLE)] = - FlatVector::GetData(*child_entry); - } - } - } - - for (idx_t i = 0; i < count; ++i) { - const auto idx = rdata.sel->get_index(i); - if (arg_valid.RowIsValid(idx)) { - if (Value::IsFinite(tdata[idx])) { - DatePart::StructOperator::Operation(bigint_values, double_values, tdata[idx], i, part_mask); - } else { - for (auto &child_entry : child_entries) { - FlatVector::Validity(*child_entry).SetInvalid(i); - } - } - } else { - res_valid.SetInvalid(i); - for (auto &child_entry : child_entries) { - FlatVector::Validity(*child_entry).SetInvalid(i); - } - } - } - } - - // Reference any duplicate parts - for (size_t col = 0; col < child_entries.size(); ++col) { - const auto part_index = size_t(info.part_codes[col]); - const auto owner = owners[part_index]; - if (owner != col) { - child_entries[col]->Reference(*child_entries[owner]); - } - } - - result.Verify(count); - } - - static void SerializeFunction(Serializer &serializer, const optional_ptr bind_data_p, - const ScalarFunction &function) { - D_ASSERT(bind_data_p); - auto &info = bind_data_p->Cast(); - serializer.WriteProperty(100, "stype", info.stype); - serializer.WriteProperty(101, "part_codes", info.part_codes); - } - - static unique_ptr DeserializeFunction(Deserializer &deserializer, ScalarFunction &bound_function) { - auto stype = deserializer.ReadProperty(100, "stype"); - auto part_codes = deserializer.ReadProperty>(101, "part_codes"); - return make_uniq(std::move(stype), std::move(part_codes)); - } - - template - static ScalarFunction GetFunction(const LogicalType &temporal_type) { - auto part_type = LogicalType::LIST(LogicalType::VARCHAR); - auto result_type = LogicalType::STRUCT({}); - ScalarFunction result({part_type, temporal_type}, result_type, Function, Bind); - result.serialize = SerializeFunction; - result.deserialize = DeserializeFunction; - return result; - } -}; -template -ScalarFunctionSet GetCachedDatepartFunction() { - return GetGenericDatePartFunction>( - DatePartCachedFunction, DatePartCachedFunction, - ScalarFunction::UnaryFunction, OP::template PropagateStatistics, - OP::template PropagateStatistics); -} - -ScalarFunctionSet YearFun::GetFunctions() { - return GetCachedDatepartFunction(); -} - -ScalarFunctionSet MonthFun::GetFunctions() { - return GetCachedDatepartFunction(); -} - -ScalarFunctionSet DayFun::GetFunctions() { - return GetCachedDatepartFunction(); -} - -ScalarFunctionSet DecadeFun::GetFunctions() { - return GetDatePartFunction(); -} - -ScalarFunctionSet CenturyFun::GetFunctions() { - return GetDatePartFunction(); -} - -ScalarFunctionSet MillenniumFun::GetFunctions() { - return GetDatePartFunction(); -} - -ScalarFunctionSet QuarterFun::GetFunctions() { - return GetDatePartFunction(); -} - -ScalarFunctionSet DayOfWeekFun::GetFunctions() { - return GetDatePartFunction(); -} - -ScalarFunctionSet ISODayOfWeekFun::GetFunctions() { - return GetDatePartFunction(); -} - -ScalarFunctionSet DayOfYearFun::GetFunctions() { - return GetDatePartFunction(); -} - -ScalarFunctionSet WeekFun::GetFunctions() { - return GetDatePartFunction(); -} - -ScalarFunctionSet ISOYearFun::GetFunctions() { - return GetDatePartFunction(); -} - -ScalarFunctionSet EraFun::GetFunctions() { - return GetDatePartFunction(); -} - -ScalarFunctionSet TimezoneFun::GetFunctions() { - auto operator_set = GetDatePartFunction(); - - // PG also defines timezone(INTERVAL, TIME_TZ) => TIME_TZ - operator_set.AddFunction( - ScalarFunction({LogicalType::INTERVAL, LogicalType::TIME_TZ}, LogicalType::TIME_TZ, - DatePart::TimezoneOperator::BinaryFunction)); - - return operator_set; -} - -ScalarFunctionSet TimezoneHourFun::GetFunctions() { - return GetDatePartFunction(); -} - -ScalarFunctionSet TimezoneMinuteFun::GetFunctions() { - return GetDatePartFunction(); -} - -ScalarFunctionSet EpochFun::GetFunctions() { - return GetTimePartFunction(LogicalType::DOUBLE); -} - -ScalarFunctionSet EpochNsFun::GetFunctions() { - using OP = DatePart::EpochNanosecondsOperator; - auto operator_set = GetTimePartFunction(); - - // TIMESTAMP WITH TIME ZONE has the same representation as TIMESTAMP so no need to defer to ICU - auto tstz_func = DatePart::UnaryFunction; - auto tstz_stats = OP::template PropagateStatistics; - operator_set.AddFunction( - ScalarFunction({LogicalType::TIMESTAMP_TZ}, LogicalType::BIGINT, tstz_func, nullptr, nullptr, tstz_stats)); - return operator_set; -} - -ScalarFunctionSet EpochUsFun::GetFunctions() { - using OP = DatePart::EpochMicrosecondsOperator; - auto operator_set = GetTimePartFunction(); - - // TIMESTAMP WITH TIME ZONE has the same representation as TIMESTAMP so no need to defer to ICU - auto tstz_func = DatePart::UnaryFunction; - auto tstz_stats = OP::template PropagateStatistics; - operator_set.AddFunction( - ScalarFunction({LogicalType::TIMESTAMP_TZ}, LogicalType::BIGINT, tstz_func, nullptr, nullptr, tstz_stats)); - return operator_set; -} - -ScalarFunctionSet EpochMsFun::GetFunctions() { - using OP = DatePart::EpochMillisOperator; - auto operator_set = GetTimePartFunction(); - - // TIMESTAMP WITH TIME ZONE has the same representation as TIMESTAMP so no need to defer to ICU - auto tstz_func = DatePart::UnaryFunction; - auto tstz_stats = OP::template PropagateStatistics; - operator_set.AddFunction( - ScalarFunction({LogicalType::TIMESTAMP_TZ}, LogicalType::BIGINT, tstz_func, nullptr, nullptr, tstz_stats)); - - // Legacy inverse BIGINT => TIMESTAMP - operator_set.AddFunction( - ScalarFunction({LogicalType::BIGINT}, LogicalType::TIMESTAMP, DatePart::EpochMillisOperator::Inverse)); - - return operator_set; -} - -ScalarFunctionSet NanosecondsFun::GetFunctions() { - using OP = DatePart::NanosecondsOperator; - using TR = int64_t; - const LogicalType &result_type = LogicalType::BIGINT; - auto operator_set = GetTimePartFunction(); - - auto ns_func = DatePart::UnaryFunction; - auto ns_stats = OP::template PropagateStatistics; - operator_set.AddFunction( - ScalarFunction({LogicalType::TIMESTAMP_NS}, result_type, ns_func, nullptr, nullptr, ns_stats)); - - // TIMESTAMP WITH TIME ZONE has the same representation as TIMESTAMP so no need to defer to ICU - auto tstz_func = DatePart::UnaryFunction; - auto tstz_stats = OP::template PropagateStatistics; - operator_set.AddFunction( - ScalarFunction({LogicalType::TIMESTAMP_TZ}, LogicalType::BIGINT, tstz_func, nullptr, nullptr, tstz_stats)); - - return operator_set; -} - -ScalarFunctionSet MicrosecondsFun::GetFunctions() { - return GetTimePartFunction(); -} - -ScalarFunctionSet MillisecondsFun::GetFunctions() { - return GetTimePartFunction(); -} - -ScalarFunctionSet SecondsFun::GetFunctions() { - return GetTimePartFunction(); -} - -ScalarFunctionSet MinutesFun::GetFunctions() { - return GetTimePartFunction(); -} - -ScalarFunctionSet HoursFun::GetFunctions() { - return GetTimePartFunction(); -} - -ScalarFunctionSet YearWeekFun::GetFunctions() { - return GetDatePartFunction(); -} - -ScalarFunctionSet DayOfMonthFun::GetFunctions() { - return GetDatePartFunction(); -} - -ScalarFunctionSet WeekDayFun::GetFunctions() { - return GetDatePartFunction(); -} - -ScalarFunctionSet WeekOfYearFun::GetFunctions() { - return GetDatePartFunction(); -} - -ScalarFunctionSet LastDayFun::GetFunctions() { - ScalarFunctionSet last_day; - last_day.AddFunction(ScalarFunction({LogicalType::DATE}, LogicalType::DATE, - DatePart::UnaryFunction)); - last_day.AddFunction(ScalarFunction({LogicalType::TIMESTAMP}, LogicalType::DATE, - DatePart::UnaryFunction)); - return last_day; -} - -ScalarFunctionSet MonthNameFun::GetFunctions() { - ScalarFunctionSet monthname; - monthname.AddFunction(ScalarFunction({LogicalType::DATE}, LogicalType::VARCHAR, - DatePart::UnaryFunction)); - monthname.AddFunction(ScalarFunction({LogicalType::TIMESTAMP}, LogicalType::VARCHAR, - DatePart::UnaryFunction)); - return monthname; -} - -ScalarFunctionSet DayNameFun::GetFunctions() { - ScalarFunctionSet dayname; - dayname.AddFunction(ScalarFunction({LogicalType::DATE}, LogicalType::VARCHAR, - DatePart::UnaryFunction)); - dayname.AddFunction(ScalarFunction({LogicalType::TIMESTAMP}, LogicalType::VARCHAR, - DatePart::UnaryFunction)); - return dayname; -} - -ScalarFunctionSet JulianDayFun::GetFunctions() { - using OP = DatePart::JulianDayOperator; - - ScalarFunctionSet operator_set; - auto date_func = DatePart::UnaryFunction; - auto date_stats = OP::template PropagateStatistics; - operator_set.AddFunction( - ScalarFunction({LogicalType::DATE}, LogicalType::DOUBLE, date_func, nullptr, nullptr, date_stats)); - auto ts_func = DatePart::UnaryFunction; - auto ts_stats = OP::template PropagateStatistics; - operator_set.AddFunction( - ScalarFunction({LogicalType::TIMESTAMP}, LogicalType::DOUBLE, ts_func, nullptr, nullptr, ts_stats)); - - return operator_set; -} - -ScalarFunctionSet DatePartFun::GetFunctions() { - ScalarFunctionSet date_part; - date_part.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::DATE}, LogicalType::BIGINT, - DatePartFunction, DatePartBind)); - date_part.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::TIMESTAMP}, LogicalType::BIGINT, - DatePartFunction, DatePartBind)); - date_part.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::TIME}, LogicalType::BIGINT, - DatePartFunction, DatePartBind)); - date_part.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::INTERVAL}, LogicalType::BIGINT, - DatePartFunction, DatePartBind)); - date_part.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::TIME_TZ}, LogicalType::BIGINT, - DatePartFunction, DatePartBind)); - - // struct variants - date_part.AddFunction(StructDatePart::GetFunction(LogicalType::DATE)); - date_part.AddFunction(StructDatePart::GetFunction(LogicalType::TIMESTAMP)); - date_part.AddFunction(StructDatePart::GetFunction(LogicalType::TIME)); - date_part.AddFunction(StructDatePart::GetFunction(LogicalType::INTERVAL)); - date_part.AddFunction(StructDatePart::GetFunction(LogicalType::TIME_TZ)); - - return date_part; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/date/date_sub.cpp b/src/duckdb/src/core_functions/scalar/date/date_sub.cpp deleted file mode 100644 index 6d4c4e249..000000000 --- a/src/duckdb/src/core_functions/scalar/date/date_sub.cpp +++ /dev/null @@ -1,454 +0,0 @@ -#include "duckdb/core_functions/scalar/date_functions.hpp" -#include "duckdb/common/enums/date_part_specifier.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/operator/subtract.hpp" -#include "duckdb/common/types/date.hpp" -#include "duckdb/common/types/interval.hpp" -#include "duckdb/common/types/time.hpp" -#include "duckdb/common/types/timestamp.hpp" -#include "duckdb/common/vector_operations/ternary_executor.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/string_util.hpp" - -namespace duckdb { - -struct DateSub { - static int64_t SubtractMicros(timestamp_t startdate, timestamp_t enddate) { - const auto start = Timestamp::GetEpochMicroSeconds(startdate); - const auto end = Timestamp::GetEpochMicroSeconds(enddate); - return SubtractOperatorOverflowCheck::Operation(end, start); - } - - template - static inline void BinaryExecute(Vector &left, Vector &right, Vector &result, idx_t count) { - BinaryExecutor::ExecuteWithNulls( - left, right, result, count, [&](TA startdate, TB enddate, ValidityMask &mask, idx_t idx) { - if (Value::IsFinite(startdate) && Value::IsFinite(enddate)) { - return OP::template Operation(startdate, enddate); - } else { - mask.SetInvalid(idx); - return TR(); - } - }); - } - - struct MonthOperator { - template - static inline TR Operation(TA start_ts, TB end_ts) { - - if (start_ts > end_ts) { - return -MonthOperator::Operation(end_ts, start_ts); - } - // The number of complete months depends on whether end_ts is on the last day of the month. - date_t end_date; - dtime_t end_time; - Timestamp::Convert(end_ts, end_date, end_time); - - int32_t yyyy, mm, dd; - Date::Convert(end_date, yyyy, mm, dd); - const auto end_days = Date::MonthDays(yyyy, mm); - if (end_days == dd) { - // Now check whether the start day is after the end day - date_t start_date; - dtime_t start_time; - Timestamp::Convert(start_ts, start_date, start_time); - Date::Convert(start_date, yyyy, mm, dd); - if (dd > end_days || (dd == end_days && start_time < end_time)) { - // Move back to the same time on the last day of the (shorter) end month - start_date = Date::FromDate(yyyy, mm, end_days); - start_ts = Timestamp::FromDatetime(start_date, start_time); - } - } - - // Our interval difference will now give the correct result. - // Note that PG gives different interval subtraction results, - // so if we change this we will have to reimplement. - return Interval::GetAge(end_ts, start_ts).months; - } - }; - - struct QuarterOperator { - template - static inline TR Operation(TA start_ts, TB end_ts) { - return MonthOperator::Operation(start_ts, end_ts) / Interval::MONTHS_PER_QUARTER; - } - }; - - struct YearOperator { - template - static inline TR Operation(TA start_ts, TB end_ts) { - return MonthOperator::Operation(start_ts, end_ts) / Interval::MONTHS_PER_YEAR; - } - }; - - struct DecadeOperator { - template - static inline TR Operation(TA start_ts, TB end_ts) { - return MonthOperator::Operation(start_ts, end_ts) / Interval::MONTHS_PER_DECADE; - } - }; - - struct CenturyOperator { - template - static inline TR Operation(TA start_ts, TB end_ts) { - return MonthOperator::Operation(start_ts, end_ts) / Interval::MONTHS_PER_CENTURY; - } - }; - - struct MilleniumOperator { - template - static inline TR Operation(TA start_ts, TB end_ts) { - return MonthOperator::Operation(start_ts, end_ts) / Interval::MONTHS_PER_MILLENIUM; - } - }; - - struct DayOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return SubtractMicros(startdate, enddate) / Interval::MICROS_PER_DAY; - } - }; - - struct WeekOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return SubtractMicros(startdate, enddate) / Interval::MICROS_PER_WEEK; - } - }; - - struct MicrosecondsOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return SubtractMicros(startdate, enddate); - } - }; - - struct MillisecondsOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return SubtractMicros(startdate, enddate) / Interval::MICROS_PER_MSEC; - } - }; - - struct SecondsOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return SubtractMicros(startdate, enddate) / Interval::MICROS_PER_SEC; - } - }; - - struct MinutesOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return SubtractMicros(startdate, enddate) / Interval::MICROS_PER_MINUTE; - } - }; - - struct HoursOperator { - template - static inline TR Operation(TA startdate, TB enddate) { - return SubtractMicros(startdate, enddate) / Interval::MICROS_PER_HOUR; - } - }; -}; - -// DATE specialisations -template <> -int64_t DateSub::YearOperator::Operation(date_t startdate, date_t enddate) { - dtime_t t0(0); - return YearOperator::Operation(Timestamp::FromDatetime(startdate, t0), - Timestamp::FromDatetime(enddate, t0)); -} - -template <> -int64_t DateSub::MonthOperator::Operation(date_t startdate, date_t enddate) { - dtime_t t0(0); - return MonthOperator::Operation(Timestamp::FromDatetime(startdate, t0), - Timestamp::FromDatetime(enddate, t0)); -} - -template <> -int64_t DateSub::DayOperator::Operation(date_t startdate, date_t enddate) { - dtime_t t0(0); - return DayOperator::Operation(Timestamp::FromDatetime(startdate, t0), - Timestamp::FromDatetime(enddate, t0)); -} - -template <> -int64_t DateSub::DecadeOperator::Operation(date_t startdate, date_t enddate) { - dtime_t t0(0); - return DecadeOperator::Operation(Timestamp::FromDatetime(startdate, t0), - Timestamp::FromDatetime(enddate, t0)); -} - -template <> -int64_t DateSub::CenturyOperator::Operation(date_t startdate, date_t enddate) { - dtime_t t0(0); - return CenturyOperator::Operation(Timestamp::FromDatetime(startdate, t0), - Timestamp::FromDatetime(enddate, t0)); -} - -template <> -int64_t DateSub::MilleniumOperator::Operation(date_t startdate, date_t enddate) { - dtime_t t0(0); - return MilleniumOperator::Operation(Timestamp::FromDatetime(startdate, t0), - Timestamp::FromDatetime(enddate, t0)); -} - -template <> -int64_t DateSub::QuarterOperator::Operation(date_t startdate, date_t enddate) { - dtime_t t0(0); - return QuarterOperator::Operation(Timestamp::FromDatetime(startdate, t0), - Timestamp::FromDatetime(enddate, t0)); -} - -template <> -int64_t DateSub::WeekOperator::Operation(date_t startdate, date_t enddate) { - dtime_t t0(0); - return WeekOperator::Operation(Timestamp::FromDatetime(startdate, t0), - Timestamp::FromDatetime(enddate, t0)); -} - -template <> -int64_t DateSub::MicrosecondsOperator::Operation(date_t startdate, date_t enddate) { - dtime_t t0(0); - return MicrosecondsOperator::Operation(Timestamp::FromDatetime(startdate, t0), - Timestamp::FromDatetime(enddate, t0)); -} - -template <> -int64_t DateSub::MillisecondsOperator::Operation(date_t startdate, date_t enddate) { - dtime_t t0(0); - return MillisecondsOperator::Operation(Timestamp::FromDatetime(startdate, t0), - Timestamp::FromDatetime(enddate, t0)); -} - -template <> -int64_t DateSub::SecondsOperator::Operation(date_t startdate, date_t enddate) { - dtime_t t0(0); - return SecondsOperator::Operation(Timestamp::FromDatetime(startdate, t0), - Timestamp::FromDatetime(enddate, t0)); -} - -template <> -int64_t DateSub::MinutesOperator::Operation(date_t startdate, date_t enddate) { - dtime_t t0(0); - return MinutesOperator::Operation(Timestamp::FromDatetime(startdate, t0), - Timestamp::FromDatetime(enddate, t0)); -} - -template <> -int64_t DateSub::HoursOperator::Operation(date_t startdate, date_t enddate) { - dtime_t t0(0); - return HoursOperator::Operation(Timestamp::FromDatetime(startdate, t0), - Timestamp::FromDatetime(enddate, t0)); -} - -// TIME specialisations -template <> -int64_t DateSub::YearOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"year\" not recognized"); -} - -template <> -int64_t DateSub::MonthOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"month\" not recognized"); -} - -template <> -int64_t DateSub::DayOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"day\" not recognized"); -} - -template <> -int64_t DateSub::DecadeOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"decade\" not recognized"); -} - -template <> -int64_t DateSub::CenturyOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"century\" not recognized"); -} - -template <> -int64_t DateSub::MilleniumOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"millennium\" not recognized"); -} - -template <> -int64_t DateSub::QuarterOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"quarter\" not recognized"); -} - -template <> -int64_t DateSub::WeekOperator::Operation(dtime_t startdate, dtime_t enddate) { - throw NotImplementedException("\"time\" units \"week\" not recognized"); -} - -template <> -int64_t DateSub::MicrosecondsOperator::Operation(dtime_t startdate, dtime_t enddate) { - return enddate.micros - startdate.micros; -} - -template <> -int64_t DateSub::MillisecondsOperator::Operation(dtime_t startdate, dtime_t enddate) { - return (enddate.micros - startdate.micros) / Interval::MICROS_PER_MSEC; -} - -template <> -int64_t DateSub::SecondsOperator::Operation(dtime_t startdate, dtime_t enddate) { - return (enddate.micros - startdate.micros) / Interval::MICROS_PER_SEC; -} - -template <> -int64_t DateSub::MinutesOperator::Operation(dtime_t startdate, dtime_t enddate) { - return (enddate.micros - startdate.micros) / Interval::MICROS_PER_MINUTE; -} - -template <> -int64_t DateSub::HoursOperator::Operation(dtime_t startdate, dtime_t enddate) { - return (enddate.micros - startdate.micros) / Interval::MICROS_PER_HOUR; -} - -template -static int64_t SubtractDateParts(DatePartSpecifier type, TA startdate, TB enddate) { - switch (type) { - case DatePartSpecifier::YEAR: - case DatePartSpecifier::ISOYEAR: - return DateSub::YearOperator::template Operation(startdate, enddate); - case DatePartSpecifier::MONTH: - return DateSub::MonthOperator::template Operation(startdate, enddate); - case DatePartSpecifier::DAY: - case DatePartSpecifier::DOW: - case DatePartSpecifier::ISODOW: - case DatePartSpecifier::DOY: - case DatePartSpecifier::JULIAN_DAY: - return DateSub::DayOperator::template Operation(startdate, enddate); - case DatePartSpecifier::DECADE: - return DateSub::DecadeOperator::template Operation(startdate, enddate); - case DatePartSpecifier::CENTURY: - return DateSub::CenturyOperator::template Operation(startdate, enddate); - case DatePartSpecifier::MILLENNIUM: - return DateSub::MilleniumOperator::template Operation(startdate, enddate); - case DatePartSpecifier::QUARTER: - return DateSub::QuarterOperator::template Operation(startdate, enddate); - case DatePartSpecifier::WEEK: - case DatePartSpecifier::YEARWEEK: - return DateSub::WeekOperator::template Operation(startdate, enddate); - case DatePartSpecifier::MICROSECONDS: - return DateSub::MicrosecondsOperator::template Operation(startdate, enddate); - case DatePartSpecifier::MILLISECONDS: - return DateSub::MillisecondsOperator::template Operation(startdate, enddate); - case DatePartSpecifier::SECOND: - case DatePartSpecifier::EPOCH: - return DateSub::SecondsOperator::template Operation(startdate, enddate); - case DatePartSpecifier::MINUTE: - return DateSub::MinutesOperator::template Operation(startdate, enddate); - case DatePartSpecifier::HOUR: - return DateSub::HoursOperator::template Operation(startdate, enddate); - default: - throw NotImplementedException("Specifier type not implemented for DATESUB"); - } -} - -struct DateSubTernaryOperator { - template - static inline TR Operation(TS part, TA startdate, TB enddate, ValidityMask &mask, idx_t idx) { - if (Value::IsFinite(startdate) && Value::IsFinite(enddate)) { - return SubtractDateParts(GetDatePartSpecifier(part.GetString()), startdate, enddate); - } else { - mask.SetInvalid(idx); - return TR(); - } - } -}; - -template -static void DateSubBinaryExecutor(DatePartSpecifier type, Vector &left, Vector &right, Vector &result, idx_t count) { - switch (type) { - case DatePartSpecifier::YEAR: - case DatePartSpecifier::ISOYEAR: - DateSub::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::MONTH: - DateSub::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::DAY: - case DatePartSpecifier::DOW: - case DatePartSpecifier::ISODOW: - case DatePartSpecifier::DOY: - case DatePartSpecifier::JULIAN_DAY: - DateSub::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::DECADE: - DateSub::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::CENTURY: - DateSub::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::MILLENNIUM: - DateSub::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::QUARTER: - DateSub::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::WEEK: - case DatePartSpecifier::YEARWEEK: - DateSub::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::MICROSECONDS: - DateSub::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::MILLISECONDS: - DateSub::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::SECOND: - case DatePartSpecifier::EPOCH: - DateSub::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::MINUTE: - DateSub::BinaryExecute(left, right, result, count); - break; - case DatePartSpecifier::HOUR: - DateSub::BinaryExecute(left, right, result, count); - break; - default: - throw NotImplementedException("Specifier type not implemented for DATESUB"); - } -} - -template -static void DateSubFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 3); - auto &part_arg = args.data[0]; - auto &start_arg = args.data[1]; - auto &end_arg = args.data[2]; - - if (part_arg.GetVectorType() == VectorType::CONSTANT_VECTOR) { - // Common case of constant part. - if (ConstantVector::IsNull(part_arg)) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(result, true); - } else { - const auto type = GetDatePartSpecifier(ConstantVector::GetData(part_arg)->GetString()); - DateSubBinaryExecutor(type, start_arg, end_arg, result, args.size()); - } - } else { - TernaryExecutor::ExecuteWithNulls( - part_arg, start_arg, end_arg, result, args.size(), - DateSubTernaryOperator::Operation); - } -} - -ScalarFunctionSet DateSubFun::GetFunctions() { - ScalarFunctionSet date_sub("date_sub"); - date_sub.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::DATE, LogicalType::DATE}, - LogicalType::BIGINT, DateSubFunction)); - date_sub.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::TIMESTAMP, LogicalType::TIMESTAMP}, - LogicalType::BIGINT, DateSubFunction)); - date_sub.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::TIME, LogicalType::TIME}, - LogicalType::BIGINT, DateSubFunction)); - return date_sub; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/date/date_trunc.cpp b/src/duckdb/src/core_functions/scalar/date/date_trunc.cpp deleted file mode 100644 index 6e5bcc700..000000000 --- a/src/duckdb/src/core_functions/scalar/date/date_trunc.cpp +++ /dev/null @@ -1,734 +0,0 @@ -#include "duckdb/core_functions/scalar/date_functions.hpp" -#include "duckdb/common/enums/date_part_specifier.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/operator/cast_operators.hpp" -#include "duckdb/common/types/date.hpp" -#include "duckdb/common/types/time.hpp" -#include "duckdb/common/types/timestamp.hpp" -#include "duckdb/common/types/value.hpp" -#include "duckdb/execution/expression_executor.hpp" - -namespace duckdb { - -struct DateTrunc { - template - static inline TR UnaryFunction(TA input) { - if (Value::IsFinite(input)) { - return OP::template Operation(input); - } else { - return Cast::template Operation(input); - } - } - - template - static inline void UnaryExecute(Vector &left, Vector &result, idx_t count) { - UnaryExecutor::Execute(left, result, count, UnaryFunction); - } - - struct MillenniumOperator { - template - static inline TR Operation(TA input) { - return Date::FromDate((Date::ExtractYear(input) / 1000) * 1000, 1, 1); - } - }; - - struct CenturyOperator { - template - static inline TR Operation(TA input) { - return Date::FromDate((Date::ExtractYear(input) / 100) * 100, 1, 1); - } - }; - - struct DecadeOperator { - template - static inline TR Operation(TA input) { - return Date::FromDate((Date::ExtractYear(input) / 10) * 10, 1, 1); - } - }; - - struct YearOperator { - template - static inline TR Operation(TA input) { - return Date::FromDate(Date::ExtractYear(input), 1, 1); - } - }; - - struct QuarterOperator { - template - static inline TR Operation(TA input) { - int32_t yyyy, mm, dd; - Date::Convert(input, yyyy, mm, dd); - mm = 1 + (((mm - 1) / 3) * 3); - return Date::FromDate(yyyy, mm, 1); - } - }; - - struct MonthOperator { - template - static inline TR Operation(TA input) { - return Date::FromDate(Date::ExtractYear(input), Date::ExtractMonth(input), 1); - } - }; - - struct WeekOperator { - template - static inline TR Operation(TA input) { - return Date::GetMondayOfCurrentWeek(input); - } - }; - - struct ISOYearOperator { - template - static inline TR Operation(TA input) { - date_t date = Date::GetMondayOfCurrentWeek(input); - date.days -= (Date::ExtractISOWeekNumber(date) - 1) * Interval::DAYS_PER_WEEK; - - return date; - } - }; - - struct DayOperator { - template - static inline TR Operation(TA input) { - return input; - } - }; - - struct HourOperator { - template - static inline TR Operation(TA input) { - int32_t hour, min, sec, micros; - date_t date; - dtime_t time; - Timestamp::Convert(input, date, time); - Time::Convert(time, hour, min, sec, micros); - return Timestamp::FromDatetime(date, Time::FromTime(hour, 0, 0, 0)); - } - }; - - struct MinuteOperator { - template - static inline TR Operation(TA input) { - int32_t hour, min, sec, micros; - date_t date; - dtime_t time; - Timestamp::Convert(input, date, time); - Time::Convert(time, hour, min, sec, micros); - return Timestamp::FromDatetime(date, Time::FromTime(hour, min, 0, 0)); - } - }; - - struct SecondOperator { - template - static inline TR Operation(TA input) { - int32_t hour, min, sec, micros; - date_t date; - dtime_t time; - Timestamp::Convert(input, date, time); - Time::Convert(time, hour, min, sec, micros); - return Timestamp::FromDatetime(date, Time::FromTime(hour, min, sec, 0)); - } - }; - - struct MillisecondOperator { - template - static inline TR Operation(TA input) { - int32_t hour, min, sec, micros; - date_t date; - dtime_t time; - Timestamp::Convert(input, date, time); - Time::Convert(time, hour, min, sec, micros); - micros -= UnsafeNumericCast(micros % Interval::MICROS_PER_MSEC); - return Timestamp::FromDatetime(date, Time::FromTime(hour, min, sec, micros)); - } - }; - - struct MicrosecondOperator { - template - static inline TR Operation(TA input) { - return input; - } - }; -}; - -// DATE specialisations -template <> -date_t DateTrunc::MillenniumOperator::Operation(timestamp_t input) { - return MillenniumOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -timestamp_t DateTrunc::MillenniumOperator::Operation(date_t input) { - return Timestamp::FromDatetime(MillenniumOperator::Operation(input), dtime_t(0)); -} - -template <> -timestamp_t DateTrunc::MillenniumOperator::Operation(timestamp_t input) { - return MillenniumOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -date_t DateTrunc::CenturyOperator::Operation(timestamp_t input) { - return CenturyOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -timestamp_t DateTrunc::CenturyOperator::Operation(date_t input) { - return Timestamp::FromDatetime(CenturyOperator::Operation(input), dtime_t(0)); -} - -template <> -timestamp_t DateTrunc::CenturyOperator::Operation(timestamp_t input) { - return CenturyOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -date_t DateTrunc::DecadeOperator::Operation(timestamp_t input) { - return DecadeOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -timestamp_t DateTrunc::DecadeOperator::Operation(date_t input) { - return Timestamp::FromDatetime(DecadeOperator::Operation(input), dtime_t(0)); -} - -template <> -timestamp_t DateTrunc::DecadeOperator::Operation(timestamp_t input) { - return DecadeOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -date_t DateTrunc::YearOperator::Operation(timestamp_t input) { - return YearOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -timestamp_t DateTrunc::YearOperator::Operation(date_t input) { - return Timestamp::FromDatetime(YearOperator::Operation(input), dtime_t(0)); -} - -template <> -timestamp_t DateTrunc::YearOperator::Operation(timestamp_t input) { - return YearOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -date_t DateTrunc::QuarterOperator::Operation(timestamp_t input) { - return QuarterOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -timestamp_t DateTrunc::QuarterOperator::Operation(date_t input) { - return Timestamp::FromDatetime(QuarterOperator::Operation(input), dtime_t(0)); -} - -template <> -timestamp_t DateTrunc::QuarterOperator::Operation(timestamp_t input) { - return QuarterOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -date_t DateTrunc::MonthOperator::Operation(timestamp_t input) { - return MonthOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -timestamp_t DateTrunc::MonthOperator::Operation(date_t input) { - return Timestamp::FromDatetime(MonthOperator::Operation(input), dtime_t(0)); -} - -template <> -timestamp_t DateTrunc::MonthOperator::Operation(timestamp_t input) { - return MonthOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -date_t DateTrunc::WeekOperator::Operation(timestamp_t input) { - return WeekOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -timestamp_t DateTrunc::WeekOperator::Operation(date_t input) { - return Timestamp::FromDatetime(WeekOperator::Operation(input), dtime_t(0)); -} - -template <> -timestamp_t DateTrunc::WeekOperator::Operation(timestamp_t input) { - return WeekOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -date_t DateTrunc::ISOYearOperator::Operation(timestamp_t input) { - return ISOYearOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -timestamp_t DateTrunc::ISOYearOperator::Operation(date_t input) { - return Timestamp::FromDatetime(ISOYearOperator::Operation(input), dtime_t(0)); -} - -template <> -timestamp_t DateTrunc::ISOYearOperator::Operation(timestamp_t input) { - return ISOYearOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -date_t DateTrunc::DayOperator::Operation(timestamp_t input) { - return DayOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -timestamp_t DateTrunc::DayOperator::Operation(date_t input) { - return Timestamp::FromDatetime(DayOperator::Operation(input), dtime_t(0)); -} - -template <> -timestamp_t DateTrunc::DayOperator::Operation(timestamp_t input) { - return DayOperator::Operation(Timestamp::GetDate(input)); -} - -template <> -date_t DateTrunc::HourOperator::Operation(date_t input) { - return DayOperator::Operation(input); -} - -template <> -timestamp_t DateTrunc::HourOperator::Operation(date_t input) { - return DayOperator::Operation(input); -} - -template <> -date_t DateTrunc::HourOperator::Operation(timestamp_t input) { - return Timestamp::GetDate(HourOperator::Operation(input)); -} - -template <> -date_t DateTrunc::MinuteOperator::Operation(date_t input) { - return DayOperator::Operation(input); -} - -template <> -timestamp_t DateTrunc::MinuteOperator::Operation(date_t input) { - return DayOperator::Operation(input); -} - -template <> -date_t DateTrunc::MinuteOperator::Operation(timestamp_t input) { - return Timestamp::GetDate(HourOperator::Operation(input)); -} - -template <> -date_t DateTrunc::SecondOperator::Operation(date_t input) { - return DayOperator::Operation(input); -} - -template <> -timestamp_t DateTrunc::SecondOperator::Operation(date_t input) { - return DayOperator::Operation(input); -} - -template <> -date_t DateTrunc::SecondOperator::Operation(timestamp_t input) { - return Timestamp::GetDate(DayOperator::Operation(input)); -} - -template <> -date_t DateTrunc::MillisecondOperator::Operation(date_t input) { - return DayOperator::Operation(input); -} - -template <> -timestamp_t DateTrunc::MillisecondOperator::Operation(date_t input) { - return DayOperator::Operation(input); -} - -template <> -date_t DateTrunc::MillisecondOperator::Operation(timestamp_t input) { - return Timestamp::GetDate(MillisecondOperator::Operation(input)); -} - -template <> -date_t DateTrunc::MicrosecondOperator::Operation(date_t input) { - return DayOperator::Operation(input); -} - -template <> -timestamp_t DateTrunc::MicrosecondOperator::Operation(date_t input) { - return DayOperator::Operation(input); -} - -template <> -date_t DateTrunc::MicrosecondOperator::Operation(timestamp_t input) { - return Timestamp::GetDate(MicrosecondOperator::Operation(input)); -} - -// INTERVAL specialisations -template <> -interval_t DateTrunc::MillenniumOperator::Operation(interval_t input) { - input.days = 0; - input.micros = 0; - input.months = (input.months / Interval::MONTHS_PER_MILLENIUM) * Interval::MONTHS_PER_MILLENIUM; - return input; -} - -template <> -interval_t DateTrunc::CenturyOperator::Operation(interval_t input) { - input.days = 0; - input.micros = 0; - input.months = (input.months / Interval::MONTHS_PER_CENTURY) * Interval::MONTHS_PER_CENTURY; - return input; -} - -template <> -interval_t DateTrunc::DecadeOperator::Operation(interval_t input) { - input.days = 0; - input.micros = 0; - input.months = (input.months / Interval::MONTHS_PER_DECADE) * Interval::MONTHS_PER_DECADE; - return input; -} - -template <> -interval_t DateTrunc::YearOperator::Operation(interval_t input) { - input.days = 0; - input.micros = 0; - input.months = (input.months / Interval::MONTHS_PER_YEAR) * Interval::MONTHS_PER_YEAR; - return input; -} - -template <> -interval_t DateTrunc::QuarterOperator::Operation(interval_t input) { - input.days = 0; - input.micros = 0; - input.months = (input.months / Interval::MONTHS_PER_QUARTER) * Interval::MONTHS_PER_QUARTER; - return input; -} - -template <> -interval_t DateTrunc::MonthOperator::Operation(interval_t input) { - input.days = 0; - input.micros = 0; - return input; -} - -template <> -interval_t DateTrunc::WeekOperator::Operation(interval_t input) { - input.micros = 0; - input.days = (input.days / Interval::DAYS_PER_WEEK) * Interval::DAYS_PER_WEEK; - return input; -} - -template <> -interval_t DateTrunc::ISOYearOperator::Operation(interval_t input) { - return YearOperator::Operation(input); -} - -template <> -interval_t DateTrunc::DayOperator::Operation(interval_t input) { - input.micros = 0; - return input; -} - -template <> -interval_t DateTrunc::HourOperator::Operation(interval_t input) { - input.micros = (input.micros / Interval::MICROS_PER_HOUR) * Interval::MICROS_PER_HOUR; - return input; -} - -template <> -interval_t DateTrunc::MinuteOperator::Operation(interval_t input) { - input.micros = (input.micros / Interval::MICROS_PER_MINUTE) * Interval::MICROS_PER_MINUTE; - return input; -} - -template <> -interval_t DateTrunc::SecondOperator::Operation(interval_t input) { - input.micros = (input.micros / Interval::MICROS_PER_SEC) * Interval::MICROS_PER_SEC; - return input; -} - -template <> -interval_t DateTrunc::MillisecondOperator::Operation(interval_t input) { - input.micros = (input.micros / Interval::MICROS_PER_MSEC) * Interval::MICROS_PER_MSEC; - return input; -} - -template <> -interval_t DateTrunc::MicrosecondOperator::Operation(interval_t input) { - return input; -} - -template -static TR TruncateElement(DatePartSpecifier type, TA element) { - if (!Value::IsFinite(element)) { - return Cast::template Operation(element); - } - - switch (type) { - case DatePartSpecifier::MILLENNIUM: - return DateTrunc::MillenniumOperator::Operation(element); - case DatePartSpecifier::CENTURY: - return DateTrunc::CenturyOperator::Operation(element); - case DatePartSpecifier::DECADE: - return DateTrunc::DecadeOperator::Operation(element); - case DatePartSpecifier::YEAR: - return DateTrunc::YearOperator::Operation(element); - case DatePartSpecifier::QUARTER: - return DateTrunc::QuarterOperator::Operation(element); - case DatePartSpecifier::MONTH: - return DateTrunc::MonthOperator::Operation(element); - case DatePartSpecifier::WEEK: - case DatePartSpecifier::YEARWEEK: - return DateTrunc::WeekOperator::Operation(element); - case DatePartSpecifier::ISOYEAR: - return DateTrunc::ISOYearOperator::Operation(element); - case DatePartSpecifier::DAY: - case DatePartSpecifier::DOW: - case DatePartSpecifier::ISODOW: - case DatePartSpecifier::DOY: - case DatePartSpecifier::JULIAN_DAY: - return DateTrunc::DayOperator::Operation(element); - case DatePartSpecifier::HOUR: - return DateTrunc::HourOperator::Operation(element); - case DatePartSpecifier::MINUTE: - return DateTrunc::MinuteOperator::Operation(element); - case DatePartSpecifier::SECOND: - case DatePartSpecifier::EPOCH: - return DateTrunc::SecondOperator::Operation(element); - case DatePartSpecifier::MILLISECONDS: - return DateTrunc::MillisecondOperator::Operation(element); - case DatePartSpecifier::MICROSECONDS: - return DateTrunc::MicrosecondOperator::Operation(element); - default: - throw NotImplementedException("Specifier type not implemented for DATETRUNC"); - } -} - -struct DateTruncBinaryOperator { - template - static inline TR Operation(TA specifier, TB date) { - return TruncateElement(GetDatePartSpecifier(specifier.GetString()), date); - } -}; - -template -static void DateTruncUnaryExecutor(DatePartSpecifier type, Vector &left, Vector &result, idx_t count) { - switch (type) { - case DatePartSpecifier::MILLENNIUM: - DateTrunc::UnaryExecute(left, result, count); - break; - case DatePartSpecifier::CENTURY: - DateTrunc::UnaryExecute(left, result, count); - break; - case DatePartSpecifier::DECADE: - DateTrunc::UnaryExecute(left, result, count); - break; - case DatePartSpecifier::YEAR: - DateTrunc::UnaryExecute(left, result, count); - break; - case DatePartSpecifier::QUARTER: - DateTrunc::UnaryExecute(left, result, count); - break; - case DatePartSpecifier::MONTH: - DateTrunc::UnaryExecute(left, result, count); - break; - case DatePartSpecifier::WEEK: - case DatePartSpecifier::YEARWEEK: - DateTrunc::UnaryExecute(left, result, count); - break; - case DatePartSpecifier::ISOYEAR: - DateTrunc::UnaryExecute(left, result, count); - break; - case DatePartSpecifier::DAY: - case DatePartSpecifier::DOW: - case DatePartSpecifier::ISODOW: - case DatePartSpecifier::DOY: - case DatePartSpecifier::JULIAN_DAY: - DateTrunc::UnaryExecute(left, result, count); - break; - case DatePartSpecifier::HOUR: - DateTrunc::UnaryExecute(left, result, count); - break; - case DatePartSpecifier::MINUTE: - DateTrunc::UnaryExecute(left, result, count); - break; - case DatePartSpecifier::SECOND: - case DatePartSpecifier::EPOCH: - DateTrunc::UnaryExecute(left, result, count); - break; - case DatePartSpecifier::MILLISECONDS: - DateTrunc::UnaryExecute(left, result, count); - break; - case DatePartSpecifier::MICROSECONDS: - DateTrunc::UnaryExecute(left, result, count); - break; - default: - throw NotImplementedException("Specifier type not implemented for DATETRUNC"); - } -} - -template -static void DateTruncFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 2); - auto &part_arg = args.data[0]; - auto &date_arg = args.data[1]; - - if (part_arg.GetVectorType() == VectorType::CONSTANT_VECTOR) { - // Common case of constant part. - if (ConstantVector::IsNull(part_arg)) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(result, true); - } else { - const auto type = GetDatePartSpecifier(ConstantVector::GetData(part_arg)->GetString()); - DateTruncUnaryExecutor(type, date_arg, result, args.size()); - } - } else { - BinaryExecutor::ExecuteStandard(part_arg, date_arg, result, - args.size()); - } -} - -template -static unique_ptr DateTruncStatistics(vector &child_stats) { - // we can only propagate date stats if the child has stats - auto &nstats = child_stats[1]; - if (!NumericStats::HasMinMax(nstats)) { - return nullptr; - } - // run the operator on both the min and the max, this gives us the [min, max] bound - auto min = NumericStats::GetMin(nstats); - auto max = NumericStats::GetMax(nstats); - if (min > max) { - return nullptr; - } - - // Infinite values are unmodified - auto min_part = DateTrunc::UnaryFunction(min); - auto max_part = DateTrunc::UnaryFunction(max); - - auto min_value = Value::CreateValue(min_part); - auto max_value = Value::CreateValue(max_part); - auto result = NumericStats::CreateEmpty(min_value.type()); - NumericStats::SetMin(result, min_value); - NumericStats::SetMax(result, max_value); - result.CopyValidity(child_stats[0]); - return result.ToUnique(); -} - -template -static unique_ptr PropagateDateTruncStatistics(ClientContext &context, FunctionStatisticsInput &input) { - return DateTruncStatistics(input.child_stats); -} - -template -static function_statistics_t DateTruncStats(DatePartSpecifier type) { - switch (type) { - case DatePartSpecifier::MILLENNIUM: - return PropagateDateTruncStatistics; - case DatePartSpecifier::CENTURY: - return PropagateDateTruncStatistics; - case DatePartSpecifier::DECADE: - return PropagateDateTruncStatistics; - case DatePartSpecifier::YEAR: - return PropagateDateTruncStatistics; - case DatePartSpecifier::QUARTER: - return PropagateDateTruncStatistics; - case DatePartSpecifier::MONTH: - return PropagateDateTruncStatistics; - case DatePartSpecifier::WEEK: - case DatePartSpecifier::YEARWEEK: - return PropagateDateTruncStatistics; - case DatePartSpecifier::ISOYEAR: - return PropagateDateTruncStatistics; - case DatePartSpecifier::DAY: - case DatePartSpecifier::DOW: - case DatePartSpecifier::ISODOW: - case DatePartSpecifier::DOY: - case DatePartSpecifier::JULIAN_DAY: - return PropagateDateTruncStatistics; - case DatePartSpecifier::HOUR: - return PropagateDateTruncStatistics; - case DatePartSpecifier::MINUTE: - return PropagateDateTruncStatistics; - case DatePartSpecifier::SECOND: - case DatePartSpecifier::EPOCH: - return PropagateDateTruncStatistics; - case DatePartSpecifier::MILLISECONDS: - return PropagateDateTruncStatistics; - case DatePartSpecifier::MICROSECONDS: - return PropagateDateTruncStatistics; - default: - throw NotImplementedException("Specifier type not implemented for DATETRUNC statistics"); - } -} - -static unique_ptr DateTruncBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - if (!arguments[0]->IsFoldable()) { - return nullptr; - } - - // Rebind to return a date if we are truncating that far - Value part_value = ExpressionExecutor::EvaluateScalar(context, *arguments[0]); - if (part_value.IsNull()) { - return nullptr; - } - const auto part_name = part_value.ToString(); - const auto part_code = GetDatePartSpecifier(part_name); - switch (part_code) { - case DatePartSpecifier::MILLENNIUM: - case DatePartSpecifier::CENTURY: - case DatePartSpecifier::DECADE: - case DatePartSpecifier::YEAR: - case DatePartSpecifier::QUARTER: - case DatePartSpecifier::MONTH: - case DatePartSpecifier::WEEK: - case DatePartSpecifier::YEARWEEK: - case DatePartSpecifier::ISOYEAR: - case DatePartSpecifier::DAY: - case DatePartSpecifier::DOW: - case DatePartSpecifier::ISODOW: - case DatePartSpecifier::DOY: - case DatePartSpecifier::JULIAN_DAY: - switch (bound_function.arguments[1].id()) { - case LogicalType::TIMESTAMP: - bound_function.function = DateTruncFunction; - bound_function.statistics = DateTruncStats(part_code); - break; - case LogicalType::DATE: - bound_function.function = DateTruncFunction; - bound_function.statistics = DateTruncStats(part_code); - break; - default: - throw NotImplementedException("Temporal argument type for DATETRUNC"); - } - bound_function.return_type = LogicalType::DATE; - break; - default: - switch (bound_function.arguments[1].id()) { - case LogicalType::TIMESTAMP: - bound_function.statistics = DateTruncStats(part_code); - break; - case LogicalType::DATE: - bound_function.statistics = DateTruncStats(part_code); - break; - default: - throw NotImplementedException("Temporal argument type for DATETRUNC"); - } - break; - } - - return nullptr; -} - -ScalarFunctionSet DateTruncFun::GetFunctions() { - ScalarFunctionSet date_trunc("date_trunc"); - date_trunc.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::TIMESTAMP}, LogicalType::TIMESTAMP, - DateTruncFunction, DateTruncBind)); - date_trunc.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::DATE}, LogicalType::TIMESTAMP, - DateTruncFunction, DateTruncBind)); - date_trunc.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::INTERVAL}, LogicalType::INTERVAL, - DateTruncFunction)); - return date_trunc; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/date/epoch.cpp b/src/duckdb/src/core_functions/scalar/date/epoch.cpp deleted file mode 100644 index 0944335de..000000000 --- a/src/duckdb/src/core_functions/scalar/date/epoch.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "duckdb/core_functions/scalar/date_functions.hpp" - -#include "duckdb/common/operator/cast_operators.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/vector_operations/unary_executor.hpp" - -namespace duckdb { - -struct EpochSecOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE sec) { - int64_t result; - if (!TryCast::Operation(sec * Interval::MICROS_PER_SEC, result)) { - throw ConversionException("Could not convert epoch seconds to TIMESTAMP WITH TIME ZONE"); - } - return timestamp_t(result); - } -}; - -static void EpochSecFunction(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() == 1); - - UnaryExecutor::Execute(input.data[0], result, input.size()); -} - -ScalarFunction ToTimestampFun::GetFunction() { - // to_timestamp is an alias from Postgres that converts the time in seconds to a timestamp - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::TIMESTAMP_TZ, EpochSecFunction); -} - -struct TimeTZSortKeyOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input) { - return input.sort_key(); - } -}; - -static void TimeTZSortKeyFunction(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() == 1); - - UnaryExecutor::Execute(input.data[0], result, input.size()); -} - -ScalarFunction TimeTZSortKeyFun::GetFunction() { - return ScalarFunction({LogicalType::TIME_TZ}, LogicalType::UBIGINT, TimeTZSortKeyFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/date/make_date.cpp b/src/duckdb/src/core_functions/scalar/date/make_date.cpp deleted file mode 100644 index 1ef81e376..000000000 --- a/src/duckdb/src/core_functions/scalar/date/make_date.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include "duckdb/core_functions/scalar/date_functions.hpp" -#include "duckdb/common/operator/cast_operators.hpp" -#include "duckdb/common/types/date.hpp" -#include "duckdb/common/types/time.hpp" -#include "duckdb/common/types/timestamp.hpp" -#include "duckdb/common/vector_operations/ternary_executor.hpp" -#include "duckdb/common/vector_operations/senary_executor.hpp" -#include "duckdb/common/exception/conversion_exception.hpp" - -#include - -namespace duckdb { - -struct MakeDateOperator { - template - static RESULT_TYPE Operation(YYYY yyyy, MM mm, DD dd) { - return Date::FromDate(Cast::Operation(yyyy), Cast::Operation(mm), - Cast::Operation(dd)); - } -}; - -template -static void ExecuteMakeDate(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() == 3); - auto &yyyy = input.data[0]; - auto &mm = input.data[1]; - auto &dd = input.data[2]; - - TernaryExecutor::Execute(yyyy, mm, dd, result, input.size(), - MakeDateOperator::Operation); -} - -template -static date_t FromDateCast(T year, T month, T day) { - date_t result; - if (!Date::TryFromDate(Cast::Operation(year), Cast::Operation(month), - Cast::Operation(day), result)) { - throw ConversionException("Date out of range: %d-%d-%d", year, month, day); - } - return result; -} - -template -static void ExecuteStructMakeDate(DataChunk &input, ExpressionState &state, Vector &result) { - // this should be guaranteed by the binder - D_ASSERT(input.ColumnCount() == 1); - auto &vec = input.data[0]; - - auto &children = StructVector::GetEntries(vec); - D_ASSERT(children.size() == 3); - auto &yyyy = *children[0]; - auto &mm = *children[1]; - auto &dd = *children[2]; - - TernaryExecutor::Execute(yyyy, mm, dd, result, input.size(), FromDateCast); -} - -struct MakeTimeOperator { - template - static RESULT_TYPE Operation(HH hh, MM mm, SS ss) { - - auto hh_32 = Cast::Operation(hh); - auto mm_32 = Cast::Operation(mm); - // Have to check this separately because safe casting of DOUBLE => INT32 can round. - int32_t ss_32 = 0; - if (ss < 0 || ss > Interval::SECS_PER_MINUTE) { - ss_32 = Cast::Operation(ss); - } else { - ss_32 = LossyNumericCast(ss); - } - auto micros = LossyNumericCast(std::round((ss - ss_32) * Interval::MICROS_PER_SEC)); - - if (!Time::IsValidTime(hh_32, mm_32, ss_32, micros)) { - throw ConversionException("Time out of range: %d:%d:%d.%d", hh_32, mm_32, ss_32, micros); - } - return Time::FromTime(hh_32, mm_32, ss_32, micros); - } -}; - -template -static void ExecuteMakeTime(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() == 3); - auto &yyyy = input.data[0]; - auto &mm = input.data[1]; - auto &dd = input.data[2]; - - TernaryExecutor::Execute(yyyy, mm, dd, result, input.size(), - MakeTimeOperator::Operation); -} - -struct MakeTimestampOperator { - template - static RESULT_TYPE Operation(YYYY yyyy, MM mm, DD dd, HR hr, MN mn, SS ss) { - const auto d = MakeDateOperator::Operation(yyyy, mm, dd); - const auto t = MakeTimeOperator::Operation(hr, mn, ss); - return Timestamp::FromDatetime(d, t); - } - - template - static RESULT_TYPE Operation(T micros) { - return timestamp_t(micros); - } -}; - -template -static void ExecuteMakeTimestamp(DataChunk &input, ExpressionState &state, Vector &result) { - if (input.ColumnCount() == 1) { - auto func = MakeTimestampOperator::Operation; - UnaryExecutor::Execute(input.data[0], result, input.size(), func); - return; - } - - D_ASSERT(input.ColumnCount() == 6); - - auto func = MakeTimestampOperator::Operation; - SenaryExecutor::Execute(input, result, func); -} - -ScalarFunctionSet MakeDateFun::GetFunctions() { - ScalarFunctionSet make_date("make_date"); - make_date.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT, LogicalType::BIGINT}, - LogicalType::DATE, ExecuteMakeDate)); - - child_list_t make_date_children { - {"year", LogicalType::BIGINT}, {"month", LogicalType::BIGINT}, {"day", LogicalType::BIGINT}}; - make_date.AddFunction( - ScalarFunction({LogicalType::STRUCT(make_date_children)}, LogicalType::DATE, ExecuteStructMakeDate)); - return make_date; -} - -ScalarFunction MakeTimeFun::GetFunction() { - return ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT, LogicalType::DOUBLE}, LogicalType::TIME, - ExecuteMakeTime); -} - -ScalarFunctionSet MakeTimestampFun::GetFunctions() { - ScalarFunctionSet operator_set("make_timestamp"); - operator_set.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT, LogicalType::BIGINT, - LogicalType::BIGINT, LogicalType::BIGINT, LogicalType::DOUBLE}, - LogicalType::TIMESTAMP, ExecuteMakeTimestamp)); - operator_set.AddFunction( - ScalarFunction({LogicalType::BIGINT}, LogicalType::TIMESTAMP, ExecuteMakeTimestamp)); - return operator_set; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/date/time_bucket.cpp b/src/duckdb/src/core_functions/scalar/date/time_bucket.cpp deleted file mode 100644 index 31ae5f539..000000000 --- a/src/duckdb/src/core_functions/scalar/date/time_bucket.cpp +++ /dev/null @@ -1,370 +0,0 @@ -#include "duckdb/common/exception.hpp" -#include "duckdb/common/limits.hpp" -#include "duckdb/common/operator/cast_operators.hpp" -#include "duckdb/common/operator/subtract.hpp" -#include "duckdb/common/types/date.hpp" -#include "duckdb/common/types/interval.hpp" -#include "duckdb/common/types/timestamp.hpp" -#include "duckdb/common/types/value.hpp" -#include "duckdb/common/vector_operations/binary_executor.hpp" -#include "duckdb/common/vector_operations/ternary_executor.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/core_functions/scalar/date_functions.hpp" - -namespace duckdb { - -struct TimeBucket { - - // Use 2000-01-03 00:00:00 (Monday) as origin when bucket_width is days, hours, ... for TimescaleDB compatibility - // There are 10959 days between 1970-01-01 and 2000-01-03 - constexpr static const int64_t DEFAULT_ORIGIN_MICROS = 10959 * Interval::MICROS_PER_DAY; - // Use 2000-01-01 as origin when bucket_width is months, years, ... for TimescaleDB compatibility - // There are 360 months between 1970-01-01 and 2000-01-01 - constexpr static const int32_t DEFAULT_ORIGIN_MONTHS = 360; - - enum struct BucketWidthType : uint8_t { CONVERTIBLE_TO_MICROS, CONVERTIBLE_TO_MONTHS, UNCLASSIFIED }; - - static inline BucketWidthType ClassifyBucketWidth(const interval_t bucket_width) { - if (bucket_width.months == 0 && Interval::GetMicro(bucket_width) > 0) { - return BucketWidthType::CONVERTIBLE_TO_MICROS; - } else if (bucket_width.months > 0 && bucket_width.days == 0 && bucket_width.micros == 0) { - return BucketWidthType::CONVERTIBLE_TO_MONTHS; - } else { - return BucketWidthType::UNCLASSIFIED; - } - } - - static inline BucketWidthType ClassifyBucketWidthErrorThrow(const interval_t bucket_width) { - if (bucket_width.months == 0) { - int64_t bucket_width_micros = Interval::GetMicro(bucket_width); - if (bucket_width_micros <= 0) { - throw NotImplementedException("Period must be greater than 0"); - } - return BucketWidthType::CONVERTIBLE_TO_MICROS; - } else if (bucket_width.months != 0 && bucket_width.days == 0 && bucket_width.micros == 0) { - if (bucket_width.months < 0) { - throw NotImplementedException("Period must be greater than 0"); - } - return BucketWidthType::CONVERTIBLE_TO_MONTHS; - } else { - throw NotImplementedException("Month intervals cannot have day or time component"); - } - } - - template - static inline int32_t EpochMonths(T ts) { - date_t ts_date = Cast::template Operation(ts); - return (Date::ExtractYear(ts_date) - 1970) * 12 + Date::ExtractMonth(ts_date) - 1; - } - - static inline timestamp_t WidthConvertibleToMicrosCommon(int64_t bucket_width_micros, int64_t ts_micros, - int64_t origin_micros) { - origin_micros %= bucket_width_micros; - ts_micros = SubtractOperatorOverflowCheck::Operation(ts_micros, origin_micros); - - int64_t result_micros = (ts_micros / bucket_width_micros) * bucket_width_micros; - if (ts_micros < 0 && ts_micros % bucket_width_micros != 0) { - result_micros = - SubtractOperatorOverflowCheck::Operation(result_micros, bucket_width_micros); - } - result_micros += origin_micros; - - return Timestamp::FromEpochMicroSeconds(result_micros); - } - - static inline date_t WidthConvertibleToMonthsCommon(int32_t bucket_width_months, int32_t ts_months, - int32_t origin_months) { - origin_months %= bucket_width_months; - ts_months = SubtractOperatorOverflowCheck::Operation(ts_months, origin_months); - - int32_t result_months = (ts_months / bucket_width_months) * bucket_width_months; - if (ts_months < 0 && ts_months % bucket_width_months != 0) { - result_months = - SubtractOperatorOverflowCheck::Operation(result_months, bucket_width_months); - } - result_months += origin_months; - - int32_t year = - (result_months < 0 && result_months % 12 != 0) ? 1970 + result_months / 12 - 1 : 1970 + result_months / 12; - int32_t month = - (result_months < 0 && result_months % 12 != 0) ? result_months % 12 + 13 : result_months % 12 + 1; - - return Date::FromDate(year, month, 1); - } - - struct WidthConvertibleToMicrosBinaryOperator { - template - static inline TR Operation(TA bucket_width, TB ts) { - if (!Value::IsFinite(ts)) { - return Cast::template Operation(ts); - } - int64_t bucket_width_micros = Interval::GetMicro(bucket_width); - int64_t ts_micros = Timestamp::GetEpochMicroSeconds(Cast::template Operation(ts)); - return Cast::template Operation( - WidthConvertibleToMicrosCommon(bucket_width_micros, ts_micros, DEFAULT_ORIGIN_MICROS)); - } - }; - - struct WidthConvertibleToMonthsBinaryOperator { - template - static inline TR Operation(TA bucket_width, TB ts) { - if (!Value::IsFinite(ts)) { - return Cast::template Operation(ts); - } - int32_t ts_months = EpochMonths(ts); - return Cast::template Operation( - WidthConvertibleToMonthsCommon(bucket_width.months, ts_months, DEFAULT_ORIGIN_MONTHS)); - } - }; - - struct BinaryOperator { - template - static inline TR Operation(TA bucket_width, TB ts) { - BucketWidthType bucket_width_type = ClassifyBucketWidthErrorThrow(bucket_width); - switch (bucket_width_type) { - case BucketWidthType::CONVERTIBLE_TO_MICROS: - return WidthConvertibleToMicrosBinaryOperator::Operation(bucket_width, ts); - case BucketWidthType::CONVERTIBLE_TO_MONTHS: - return WidthConvertibleToMonthsBinaryOperator::Operation(bucket_width, ts); - default: - throw NotImplementedException("Bucket type not implemented for TIME_BUCKET"); - } - } - }; - - struct OffsetWidthConvertibleToMicrosTernaryOperator { - template - static inline TR Operation(TA bucket_width, TB ts, TC offset) { - if (!Value::IsFinite(ts)) { - return Cast::template Operation(ts); - } - int64_t bucket_width_micros = Interval::GetMicro(bucket_width); - int64_t ts_micros = Timestamp::GetEpochMicroSeconds( - Interval::Add(Cast::template Operation(ts), Interval::Invert(offset))); - return Cast::template Operation(Interval::Add( - WidthConvertibleToMicrosCommon(bucket_width_micros, ts_micros, DEFAULT_ORIGIN_MICROS), offset)); - } - }; - - struct OffsetWidthConvertibleToMonthsTernaryOperator { - template - static inline TR Operation(TA bucket_width, TB ts, TC offset) { - if (!Value::IsFinite(ts)) { - return Cast::template Operation(ts); - } - int32_t ts_months = EpochMonths(Interval::Add(ts, Interval::Invert(offset))); - return Interval::Add(Cast::template Operation(WidthConvertibleToMonthsCommon( - bucket_width.months, ts_months, DEFAULT_ORIGIN_MONTHS)), - offset); - } - }; - - struct OffsetTernaryOperator { - template - static inline TR Operation(TA bucket_width, TB ts, TC offset) { - BucketWidthType bucket_width_type = ClassifyBucketWidthErrorThrow(bucket_width); - switch (bucket_width_type) { - case BucketWidthType::CONVERTIBLE_TO_MICROS: - return OffsetWidthConvertibleToMicrosTernaryOperator::Operation(bucket_width, ts, - offset); - case BucketWidthType::CONVERTIBLE_TO_MONTHS: - return OffsetWidthConvertibleToMonthsTernaryOperator::Operation(bucket_width, ts, - offset); - default: - throw NotImplementedException("Bucket type not implemented for TIME_BUCKET"); - } - } - }; - - struct OriginWidthConvertibleToMicrosTernaryOperator { - template - static inline TR Operation(TA bucket_width, TB ts, TC origin) { - if (!Value::IsFinite(ts)) { - return Cast::template Operation(ts); - } - int64_t bucket_width_micros = Interval::GetMicro(bucket_width); - int64_t ts_micros = Timestamp::GetEpochMicroSeconds(Cast::template Operation(ts)); - int64_t origin_micros = Timestamp::GetEpochMicroSeconds(Cast::template Operation(origin)); - return Cast::template Operation( - WidthConvertibleToMicrosCommon(bucket_width_micros, ts_micros, origin_micros)); - } - }; - - struct OriginWidthConvertibleToMonthsTernaryOperator { - template - static inline TR Operation(TA bucket_width, TB ts, TC origin) { - if (!Value::IsFinite(ts)) { - return Cast::template Operation(ts); - } - int32_t ts_months = EpochMonths(ts); - int32_t origin_months = EpochMonths(origin); - return Cast::template Operation( - WidthConvertibleToMonthsCommon(bucket_width.months, ts_months, origin_months)); - } - }; - - struct OriginTernaryOperator { - template - static inline TR Operation(TA bucket_width, TB ts, TC origin, ValidityMask &mask, idx_t idx) { - if (!Value::IsFinite(origin)) { - mask.SetInvalid(idx); - return TR(); - } - BucketWidthType bucket_width_type = ClassifyBucketWidthErrorThrow(bucket_width); - switch (bucket_width_type) { - case BucketWidthType::CONVERTIBLE_TO_MICROS: - return OriginWidthConvertibleToMicrosTernaryOperator::Operation(bucket_width, ts, - origin); - case BucketWidthType::CONVERTIBLE_TO_MONTHS: - return OriginWidthConvertibleToMonthsTernaryOperator::Operation(bucket_width, ts, - origin); - default: - throw NotImplementedException("Bucket type not implemented for TIME_BUCKET"); - } - } - }; -}; - -template -static void TimeBucketFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 2); - - auto &bucket_width_arg = args.data[0]; - auto &ts_arg = args.data[1]; - - if (bucket_width_arg.GetVectorType() == VectorType::CONSTANT_VECTOR) { - if (ConstantVector::IsNull(bucket_width_arg)) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(result, true); - } else { - interval_t bucket_width = *ConstantVector::GetData(bucket_width_arg); - TimeBucket::BucketWidthType bucket_width_type = TimeBucket::ClassifyBucketWidth(bucket_width); - switch (bucket_width_type) { - case TimeBucket::BucketWidthType::CONVERTIBLE_TO_MICROS: - BinaryExecutor::Execute( - bucket_width_arg, ts_arg, result, args.size(), - TimeBucket::WidthConvertibleToMicrosBinaryOperator::Operation); - break; - case TimeBucket::BucketWidthType::CONVERTIBLE_TO_MONTHS: - BinaryExecutor::Execute( - bucket_width_arg, ts_arg, result, args.size(), - TimeBucket::WidthConvertibleToMonthsBinaryOperator::Operation); - break; - case TimeBucket::BucketWidthType::UNCLASSIFIED: - BinaryExecutor::Execute(bucket_width_arg, ts_arg, result, args.size(), - TimeBucket::BinaryOperator::Operation); - break; - default: - throw NotImplementedException("Bucket type not implemented for TIME_BUCKET"); - } - } - } else { - BinaryExecutor::Execute(bucket_width_arg, ts_arg, result, args.size(), - TimeBucket::BinaryOperator::Operation); - } -} - -template -static void TimeBucketOffsetFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 3); - - auto &bucket_width_arg = args.data[0]; - auto &ts_arg = args.data[1]; - auto &offset_arg = args.data[2]; - - if (bucket_width_arg.GetVectorType() == VectorType::CONSTANT_VECTOR) { - if (ConstantVector::IsNull(bucket_width_arg)) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(result, true); - } else { - interval_t bucket_width = *ConstantVector::GetData(bucket_width_arg); - TimeBucket::BucketWidthType bucket_width_type = TimeBucket::ClassifyBucketWidth(bucket_width); - switch (bucket_width_type) { - case TimeBucket::BucketWidthType::CONVERTIBLE_TO_MICROS: - TernaryExecutor::Execute( - bucket_width_arg, ts_arg, offset_arg, result, args.size(), - TimeBucket::OffsetWidthConvertibleToMicrosTernaryOperator::Operation); - break; - case TimeBucket::BucketWidthType::CONVERTIBLE_TO_MONTHS: - TernaryExecutor::Execute( - bucket_width_arg, ts_arg, offset_arg, result, args.size(), - TimeBucket::OffsetWidthConvertibleToMonthsTernaryOperator::Operation); - break; - case TimeBucket::BucketWidthType::UNCLASSIFIED: - TernaryExecutor::Execute( - bucket_width_arg, ts_arg, offset_arg, result, args.size(), - TimeBucket::OffsetTernaryOperator::Operation); - break; - default: - throw NotImplementedException("Bucket type not implemented for TIME_BUCKET"); - } - } - } else { - TernaryExecutor::Execute( - bucket_width_arg, ts_arg, offset_arg, result, args.size(), - TimeBucket::OffsetTernaryOperator::Operation); - } -} - -template -static void TimeBucketOriginFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 3); - - auto &bucket_width_arg = args.data[0]; - auto &ts_arg = args.data[1]; - auto &origin_arg = args.data[2]; - - if (bucket_width_arg.GetVectorType() == VectorType::CONSTANT_VECTOR && - origin_arg.GetVectorType() == VectorType::CONSTANT_VECTOR) { - if (ConstantVector::IsNull(bucket_width_arg) || ConstantVector::IsNull(origin_arg) || - !Value::IsFinite(*ConstantVector::GetData(origin_arg))) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(result, true); - } else { - interval_t bucket_width = *ConstantVector::GetData(bucket_width_arg); - TimeBucket::BucketWidthType bucket_width_type = TimeBucket::ClassifyBucketWidth(bucket_width); - switch (bucket_width_type) { - case TimeBucket::BucketWidthType::CONVERTIBLE_TO_MICROS: - TernaryExecutor::Execute( - bucket_width_arg, ts_arg, origin_arg, result, args.size(), - TimeBucket::OriginWidthConvertibleToMicrosTernaryOperator::Operation); - break; - case TimeBucket::BucketWidthType::CONVERTIBLE_TO_MONTHS: - TernaryExecutor::Execute( - bucket_width_arg, ts_arg, origin_arg, result, args.size(), - TimeBucket::OriginWidthConvertibleToMonthsTernaryOperator::Operation); - break; - case TimeBucket::BucketWidthType::UNCLASSIFIED: - TernaryExecutor::ExecuteWithNulls( - bucket_width_arg, ts_arg, origin_arg, result, args.size(), - TimeBucket::OriginTernaryOperator::Operation); - break; - default: - throw NotImplementedException("Bucket type not implemented for TIME_BUCKET"); - } - } - } else { - TernaryExecutor::ExecuteWithNulls( - bucket_width_arg, ts_arg, origin_arg, result, args.size(), - TimeBucket::OriginTernaryOperator::Operation); - } -} - -ScalarFunctionSet TimeBucketFun::GetFunctions() { - ScalarFunctionSet time_bucket; - time_bucket.AddFunction( - ScalarFunction({LogicalType::INTERVAL, LogicalType::DATE}, LogicalType::DATE, TimeBucketFunction)); - time_bucket.AddFunction(ScalarFunction({LogicalType::INTERVAL, LogicalType::TIMESTAMP}, LogicalType::TIMESTAMP, - TimeBucketFunction)); - time_bucket.AddFunction(ScalarFunction({LogicalType::INTERVAL, LogicalType::DATE, LogicalType::INTERVAL}, - LogicalType::DATE, TimeBucketOffsetFunction)); - time_bucket.AddFunction(ScalarFunction({LogicalType::INTERVAL, LogicalType::TIMESTAMP, LogicalType::INTERVAL}, - LogicalType::TIMESTAMP, TimeBucketOffsetFunction)); - time_bucket.AddFunction(ScalarFunction({LogicalType::INTERVAL, LogicalType::DATE, LogicalType::DATE}, - LogicalType::DATE, TimeBucketOriginFunction)); - time_bucket.AddFunction(ScalarFunction({LogicalType::INTERVAL, LogicalType::TIMESTAMP, LogicalType::TIMESTAMP}, - LogicalType::TIMESTAMP, TimeBucketOriginFunction)); - return time_bucket; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/date/to_interval.cpp b/src/duckdb/src/core_functions/scalar/date/to_interval.cpp deleted file mode 100644 index e16111f8e..000000000 --- a/src/duckdb/src/core_functions/scalar/date/to_interval.cpp +++ /dev/null @@ -1,232 +0,0 @@ -#include "duckdb/core_functions/scalar/date_functions.hpp" -#include "duckdb/common/types/interval.hpp" -#include "duckdb/common/operator/cast_operators.hpp" -#include "duckdb/common/operator/multiply.hpp" -#include "duckdb/core_functions/to_interval.hpp" - -namespace duckdb { - -template <> -bool TryMultiplyOperator::Operation(double left, int64_t right, int64_t &result) { - return TryCast::Operation(left * double(right), result); -} - -struct ToMillenniaOperator { - template - static inline TR Operation(TA input) { - interval_t result; - result.days = 0; - result.micros = 0; - if (!TryMultiplyOperator::Operation(input, Interval::MONTHS_PER_MILLENIUM, - result.months)) { - throw OutOfRangeException("Interval value %s millennia out of range", NumericHelper::ToString(input)); - } - return result; - } -}; - -struct ToCenturiesOperator { - template - static inline TR Operation(TA input) { - interval_t result; - result.days = 0; - result.micros = 0; - if (!TryMultiplyOperator::Operation(input, Interval::MONTHS_PER_CENTURY, result.months)) { - throw OutOfRangeException("Interval value %s centuries out of range", NumericHelper::ToString(input)); - } - return result; - } -}; - -struct ToDecadesOperator { - template - static inline TR Operation(TA input) { - interval_t result; - result.days = 0; - result.micros = 0; - if (!TryMultiplyOperator::Operation(input, Interval::MONTHS_PER_DECADE, result.months)) { - throw OutOfRangeException("Interval value %s decades out of range", NumericHelper::ToString(input)); - } - return result; - } -}; - -struct ToYearsOperator { - template - static inline TR Operation(TA input) { - interval_t result; - result.days = 0; - result.micros = 0; - if (!TryMultiplyOperator::Operation(input, Interval::MONTHS_PER_YEAR, - result.months)) { - throw OutOfRangeException("Interval value %d years out of range", input); - } - return result; - } -}; - -struct ToQuartersOperator { - template - static inline TR Operation(TA input) { - interval_t result; - if (!TryMultiplyOperator::Operation(input, Interval::MONTHS_PER_QUARTER, - result.months)) { - throw OutOfRangeException("Interval value %d quarters out of range", input); - } - result.days = 0; - result.micros = 0; - return result; - } -}; - -struct ToMonthsOperator { - template - static inline TR Operation(TA input) { - interval_t result; - result.months = input; - result.days = 0; - result.micros = 0; - return result; - } -}; - -struct ToWeeksOperator { - template - static inline TR Operation(TA input) { - interval_t result; - result.months = 0; - if (!TryMultiplyOperator::Operation(input, Interval::DAYS_PER_WEEK, result.days)) { - throw OutOfRangeException("Interval value %d weeks out of range", input); - } - result.micros = 0; - return result; - } -}; - -struct ToDaysOperator { - template - static inline TR Operation(TA input) { - interval_t result; - result.months = 0; - result.days = input; - result.micros = 0; - return result; - } -}; - -struct ToHoursOperator { - template - static inline TR Operation(TA input) { - interval_t result; - result.months = 0; - result.days = 0; - if (!TryMultiplyOperator::Operation(input, Interval::MICROS_PER_HOUR, result.micros)) { - throw OutOfRangeException("Interval value %s hours out of range", NumericHelper::ToString(input)); - } - return result; - } -}; - -struct ToMinutesOperator { - template - static inline TR Operation(TA input) { - interval_t result; - result.months = 0; - result.days = 0; - if (!TryMultiplyOperator::Operation(input, Interval::MICROS_PER_MINUTE, result.micros)) { - throw OutOfRangeException("Interval value %s minutes out of range", NumericHelper::ToString(input)); - } - return result; - } -}; - -struct ToMilliSecondsOperator { - template - static inline TR Operation(TA input) { - interval_t result; - result.months = 0; - result.days = 0; - if (!TryMultiplyOperator::Operation(input, Interval::MICROS_PER_MSEC, result.micros)) { - throw OutOfRangeException("Interval value %s milliseconds out of range", NumericHelper::ToString(input)); - } - return result; - } -}; - -struct ToMicroSecondsOperator { - template - static inline TR Operation(TA input) { - interval_t result; - result.months = 0; - result.days = 0; - result.micros = input; - return result; - } -}; - -ScalarFunction ToMillenniaFun::GetFunction() { - return ScalarFunction({LogicalType::INTEGER}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); -} - -ScalarFunction ToCenturiesFun::GetFunction() { - return ScalarFunction({LogicalType::INTEGER}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); -} - -ScalarFunction ToDecadesFun::GetFunction() { - return ScalarFunction({LogicalType::INTEGER}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); -} - -ScalarFunction ToYearsFun::GetFunction() { - return ScalarFunction({LogicalType::INTEGER}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); -} - -ScalarFunction ToQuartersFun::GetFunction() { - return ScalarFunction({LogicalType::INTEGER}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); -} - -ScalarFunction ToMonthsFun::GetFunction() { - return ScalarFunction({LogicalType::INTEGER}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); -} - -ScalarFunction ToWeeksFun::GetFunction() { - return ScalarFunction({LogicalType::INTEGER}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); -} - -ScalarFunction ToDaysFun::GetFunction() { - return ScalarFunction({LogicalType::INTEGER}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); -} - -ScalarFunction ToHoursFun::GetFunction() { - return ScalarFunction({LogicalType::BIGINT}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); -} - -ScalarFunction ToMinutesFun::GetFunction() { - return ScalarFunction({LogicalType::BIGINT}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); -} - -ScalarFunction ToSecondsFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); -} - -ScalarFunction ToMillisecondsFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); -} - -ScalarFunction ToMicrosecondsFun::GetFunction() { - return ScalarFunction({LogicalType::BIGINT}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/debug/vector_type.cpp b/src/duckdb/src/core_functions/scalar/debug/vector_type.cpp deleted file mode 100644 index 625273cde..000000000 --- a/src/duckdb/src/core_functions/scalar/debug/vector_type.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "duckdb/core_functions/scalar/debug_functions.hpp" - -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/enum_util.hpp" - -namespace duckdb { - -static void VectorTypeFunction(DataChunk &input, ExpressionState &state, Vector &result) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - auto data = ConstantVector::GetData(result); - data[0] = StringVector::AddString(result, EnumUtil::ToString(input.data[0].GetVectorType())); -} - -ScalarFunction VectorTypeFun::GetFunction() { - auto vector_type_fun = ScalarFunction("vector_type", // name of the function - {LogicalType::ANY}, // argument list - LogicalType::VARCHAR, // return type - VectorTypeFunction); - vector_type_fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return vector_type_fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/enum/enum_functions.cpp b/src/duckdb/src/core_functions/scalar/enum/enum_functions.cpp deleted file mode 100644 index ddf07c3d1..000000000 --- a/src/duckdb/src/core_functions/scalar/enum/enum_functions.cpp +++ /dev/null @@ -1,169 +0,0 @@ -#include "duckdb/core_functions/scalar/enum_functions.hpp" - -namespace duckdb { - -static void EnumFirstFunction(DataChunk &input, ExpressionState &state, Vector &result) { - auto types = input.GetTypes(); - D_ASSERT(types.size() == 1); - auto &enum_vector = EnumType::GetValuesInsertOrder(types[0]); - auto val = Value(enum_vector.GetValue(0)); - result.Reference(val); -} - -static void EnumLastFunction(DataChunk &input, ExpressionState &state, Vector &result) { - auto types = input.GetTypes(); - D_ASSERT(types.size() == 1); - auto enum_size = EnumType::GetSize(types[0]); - auto &enum_vector = EnumType::GetValuesInsertOrder(types[0]); - auto val = Value(enum_vector.GetValue(enum_size - 1)); - result.Reference(val); -} - -static void EnumRangeFunction(DataChunk &input, ExpressionState &state, Vector &result) { - auto types = input.GetTypes(); - D_ASSERT(types.size() == 1); - auto enum_size = EnumType::GetSize(types[0]); - auto &enum_vector = EnumType::GetValuesInsertOrder(types[0]); - vector enum_values; - for (idx_t i = 0; i < enum_size; i++) { - enum_values.emplace_back(enum_vector.GetValue(i)); - } - auto val = Value::LIST(LogicalType::VARCHAR, enum_values); - result.Reference(val); -} - -static void EnumRangeBoundaryFunction(DataChunk &input, ExpressionState &state, Vector &result) { - auto types = input.GetTypes(); - D_ASSERT(types.size() == 2); - idx_t start, end; - auto first_param = input.GetValue(0, 0); - auto second_param = input.GetValue(1, 0); - - auto &enum_vector = - first_param.IsNull() ? EnumType::GetValuesInsertOrder(types[1]) : EnumType::GetValuesInsertOrder(types[0]); - - if (first_param.IsNull()) { - start = 0; - } else { - start = first_param.GetValue(); - } - if (second_param.IsNull()) { - end = EnumType::GetSize(types[0]); - } else { - end = second_param.GetValue() + 1; - } - vector enum_values; - for (idx_t i = start; i < end; i++) { - enum_values.emplace_back(enum_vector.GetValue(i)); - } - Value val; - if (enum_values.empty()) { - val = Value::EMPTYLIST(LogicalType::VARCHAR); - } else { - val = Value::LIST(enum_values); - } - result.Reference(val); -} - -static void EnumCodeFunction(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.GetTypes().size() == 1); - result.Reinterpret(input.data[0]); -} - -static void CheckEnumParameter(const Expression &expr) { - if (expr.HasParameter()) { - throw ParameterNotResolvedException(); - } -} - -unique_ptr BindEnumFunction(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - CheckEnumParameter(*arguments[0]); - if (arguments[0]->return_type.id() != LogicalTypeId::ENUM) { - throw BinderException("This function needs an ENUM as an argument"); - } - return nullptr; -} - -unique_ptr BindEnumCodeFunction(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - CheckEnumParameter(*arguments[0]); - if (arguments[0]->return_type.id() != LogicalTypeId::ENUM) { - throw BinderException("This function needs an ENUM as an argument"); - } - - auto phy_type = EnumType::GetPhysicalType(arguments[0]->return_type); - switch (phy_type) { - case PhysicalType::UINT8: - bound_function.return_type = LogicalType(LogicalTypeId::UTINYINT); - break; - case PhysicalType::UINT16: - bound_function.return_type = LogicalType(LogicalTypeId::USMALLINT); - break; - case PhysicalType::UINT32: - bound_function.return_type = LogicalType(LogicalTypeId::UINTEGER); - break; - case PhysicalType::UINT64: - bound_function.return_type = LogicalType(LogicalTypeId::UBIGINT); - break; - default: - throw InternalException("Unsupported Enum Internal Type"); - } - - return nullptr; -} - -unique_ptr BindEnumRangeBoundaryFunction(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - CheckEnumParameter(*arguments[0]); - CheckEnumParameter(*arguments[1]); - if (arguments[0]->return_type.id() != LogicalTypeId::ENUM && arguments[0]->return_type != LogicalType::SQLNULL) { - throw BinderException("This function needs an ENUM as an argument"); - } - if (arguments[1]->return_type.id() != LogicalTypeId::ENUM && arguments[1]->return_type != LogicalType::SQLNULL) { - throw BinderException("This function needs an ENUM as an argument"); - } - if (arguments[0]->return_type == LogicalType::SQLNULL && arguments[1]->return_type == LogicalType::SQLNULL) { - throw BinderException("This function needs an ENUM as an argument"); - } - if (arguments[0]->return_type.id() == LogicalTypeId::ENUM && - arguments[1]->return_type.id() == LogicalTypeId::ENUM && - arguments[0]->return_type != arguments[1]->return_type) { - throw BinderException("The parameters need to link to ONLY one enum OR be NULL "); - } - return nullptr; -} - -ScalarFunction EnumFirstFun::GetFunction() { - auto fun = ScalarFunction({LogicalType::ANY}, LogicalType::VARCHAR, EnumFirstFunction, BindEnumFunction); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return fun; -} - -ScalarFunction EnumLastFun::GetFunction() { - auto fun = ScalarFunction({LogicalType::ANY}, LogicalType::VARCHAR, EnumLastFunction, BindEnumFunction); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return fun; -} - -ScalarFunction EnumCodeFun::GetFunction() { - auto fun = ScalarFunction({LogicalType::ANY}, LogicalType::ANY, EnumCodeFunction, BindEnumCodeFunction); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return fun; -} - -ScalarFunction EnumRangeFun::GetFunction() { - auto fun = ScalarFunction({LogicalType::ANY}, LogicalType::LIST(LogicalType::VARCHAR), EnumRangeFunction, - BindEnumFunction); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return fun; -} - -ScalarFunction EnumRangeBoundaryFun::GetFunction() { - auto fun = ScalarFunction({LogicalType::ANY, LogicalType::ANY}, LogicalType::LIST(LogicalType::VARCHAR), - EnumRangeBoundaryFunction, BindEnumRangeBoundaryFunction); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/generic/alias.cpp b/src/duckdb/src/core_functions/scalar/generic/alias.cpp deleted file mode 100644 index e7065ba5b..000000000 --- a/src/duckdb/src/core_functions/scalar/generic/alias.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "duckdb/core_functions/scalar/generic_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" - -namespace duckdb { - -static void AliasFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &func_expr = state.expr.Cast(); - Value v(state.expr.alias.empty() ? func_expr.children[0]->GetName() : state.expr.alias); - result.Reference(v); -} - -ScalarFunction AliasFun::GetFunction() { - auto fun = ScalarFunction({LogicalType::ANY}, LogicalType::VARCHAR, AliasFunction); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/generic/can_implicitly_cast.cpp b/src/duckdb/src/core_functions/scalar/generic/can_implicitly_cast.cpp deleted file mode 100644 index 37b25d489..000000000 --- a/src/duckdb/src/core_functions/scalar/generic/can_implicitly_cast.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "duckdb/core_functions/scalar/generic_functions.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/function/cast/cast_function_set.hpp" -#include "duckdb/function/cast_rules.hpp" - -namespace duckdb { - -bool CanCastImplicitly(ClientContext &context, const LogicalType &source, const LogicalType &target) { - return CastFunctionSet::Get(context).ImplicitCastCost(source, target) >= 0; -} - -static void CanCastImplicitlyFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &context = state.GetContext(); - bool can_cast_implicitly = CanCastImplicitly(context, args.data[0].GetType(), args.data[1].GetType()); - auto v = Value::BOOLEAN(can_cast_implicitly); - result.Reference(v); -} - -unique_ptr BindCanCastImplicitlyExpression(FunctionBindExpressionInput &input) { - auto &source_type = input.function.children[0]->return_type; - auto &target_type = input.function.children[1]->return_type; - if (source_type.id() == LogicalTypeId::UNKNOWN || source_type.id() == LogicalTypeId::SQLNULL || - target_type.id() == LogicalTypeId::UNKNOWN || target_type.id() == LogicalTypeId::SQLNULL) { - // parameter - unknown return type - return nullptr; - } - // emit a constant expression - return make_uniq( - Value::BOOLEAN(CanCastImplicitly(input.context, source_type, target_type))); -} - -ScalarFunction CanCastImplicitlyFun::GetFunction() { - auto fun = ScalarFunction({LogicalType::ANY, LogicalType::ANY}, LogicalType::BOOLEAN, CanCastImplicitlyFunction); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - fun.bind_expression = BindCanCastImplicitlyExpression; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/generic/current_setting.cpp b/src/duckdb/src/core_functions/scalar/generic/current_setting.cpp deleted file mode 100644 index 43bbdcfbe..000000000 --- a/src/duckdb/src/core_functions/scalar/generic/current_setting.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "duckdb/core_functions/scalar/generic_functions.hpp" - -#include "duckdb/main/database.hpp" -#include "duckdb/main/client_context.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/catalog/catalog.hpp" -namespace duckdb { - -struct CurrentSettingBindData : public FunctionData { - explicit CurrentSettingBindData(Value value_p) : value(std::move(value_p)) { - } - - Value value; - -public: - unique_ptr Copy() const override { - return make_uniq(value); - } - - bool Equals(const FunctionData &other_p) const override { - auto &other = other_p.Cast(); - return Value::NotDistinctFrom(value, other.value); - } -}; - -static void CurrentSettingFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &func_expr = state.expr.Cast(); - auto &info = func_expr.bind_info->Cast(); - result.Reference(info.value); -} - -unique_ptr CurrentSettingBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - - auto &key_child = arguments[0]; - if (key_child->return_type.id() == LogicalTypeId::UNKNOWN) { - throw ParameterNotResolvedException(); - } - if (key_child->return_type.id() != LogicalTypeId::VARCHAR || - key_child->return_type.id() != LogicalTypeId::VARCHAR || !key_child->IsFoldable()) { - throw ParserException("Key name for current_setting needs to be a constant string"); - } - Value key_val = ExpressionExecutor::EvaluateScalar(context, *key_child); - D_ASSERT(key_val.type().id() == LogicalTypeId::VARCHAR); - if (key_val.IsNull() || StringValue::Get(key_val).empty()) { - throw ParserException("Key name for current_setting needs to be neither NULL nor empty"); - } - - auto key = StringUtil::Lower(StringValue::Get(key_val)); - Value val; - if (!context.TryGetCurrentSetting(key, val)) { - Catalog::AutoloadExtensionByConfigName(context, key); - // If autoloader didn't throw, the config is now available - context.TryGetCurrentSetting(key, val); - } - - bound_function.return_type = val.type(); - return make_uniq(val); -} - -ScalarFunction CurrentSettingFun::GetFunction() { - auto fun = ScalarFunction({LogicalType::VARCHAR}, LogicalType::ANY, CurrentSettingFunction, CurrentSettingBind); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/generic/hash.cpp b/src/duckdb/src/core_functions/scalar/generic/hash.cpp deleted file mode 100644 index b99e97049..000000000 --- a/src/duckdb/src/core_functions/scalar/generic/hash.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "duckdb/core_functions/scalar/generic_functions.hpp" - -namespace duckdb { - -static void HashFunction(DataChunk &args, ExpressionState &state, Vector &result) { - args.Hash(result); - if (args.AllConstant()) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } -} - -ScalarFunction HashFun::GetFunction() { - auto hash_fun = ScalarFunction({LogicalType::ANY}, LogicalType::HASH, HashFunction); - hash_fun.varargs = LogicalType::ANY; - hash_fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return hash_fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/generic/least.cpp b/src/duckdb/src/core_functions/scalar/generic/least.cpp deleted file mode 100644 index d91b49392..000000000 --- a/src/duckdb/src/core_functions/scalar/generic/least.cpp +++ /dev/null @@ -1,239 +0,0 @@ -#include "duckdb/common/operator/comparison_operators.hpp" -#include "duckdb/core_functions/scalar/generic_functions.hpp" -#include "duckdb/core_functions/create_sort_key.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" - -namespace duckdb { - -template -struct LeastOperator { - template - static T Operation(T left, T right) { - return OP::Operation(left, right) ? left : right; - } -}; - -struct LeastGreatestSortKeyState : public FunctionLocalState { - explicit LeastGreatestSortKeyState(idx_t column_count) - : intermediate(LogicalType::BLOB), modifiers(OrderType::ASCENDING, OrderByNullType::NULLS_LAST) { - vector types; - // initialize sort key chunk - for (idx_t i = 0; i < column_count; i++) { - types.push_back(LogicalType::BLOB); - } - sort_keys.Initialize(Allocator::DefaultAllocator(), types); - } - - DataChunk sort_keys; - Vector intermediate; - OrderModifiers modifiers; -}; - -unique_ptr LeastGreatestSortKeyInit(ExpressionState &state, const BoundFunctionExpression &expr, - FunctionData *bind_data) { - return make_uniq(expr.children.size()); -} - -template -struct StandardLeastGreatest { - static constexpr bool IS_STRING = STRING; - - static DataChunk &Prepare(DataChunk &args, ExpressionState &) { - return args; - } - - static Vector &TargetVector(Vector &result, ExpressionState &) { - return result; - } - - static void FinalizeResult(idx_t rows, bool result_has_value[], Vector &result, ExpressionState &) { - auto &result_mask = FlatVector::Validity(result); - for (idx_t i = 0; i < rows; i++) { - if (!result_has_value[i]) { - result_mask.SetInvalid(i); - } - } - } -}; - -struct SortKeyLeastGreatest { - static constexpr bool IS_STRING = false; - - static DataChunk &Prepare(DataChunk &args, ExpressionState &state) { - auto &lstate = ExecuteFunctionState::GetFunctionState(state)->Cast(); - lstate.sort_keys.Reset(); - for (idx_t c_idx = 0; c_idx < args.ColumnCount(); c_idx++) { - CreateSortKeyHelpers::CreateSortKey(args.data[c_idx], args.size(), lstate.modifiers, - lstate.sort_keys.data[c_idx]); - } - lstate.sort_keys.SetCardinality(args.size()); - return lstate.sort_keys; - } - - static Vector &TargetVector(Vector &result, ExpressionState &state) { - auto &lstate = ExecuteFunctionState::GetFunctionState(state)->Cast(); - return lstate.intermediate; - } - - static void FinalizeResult(idx_t rows, bool result_has_value[], Vector &result, ExpressionState &state) { - auto &lstate = ExecuteFunctionState::GetFunctionState(state)->Cast(); - auto result_keys = FlatVector::GetData(lstate.intermediate); - auto &result_mask = FlatVector::Validity(result); - for (idx_t i = 0; i < rows; i++) { - if (!result_has_value[i]) { - result_mask.SetInvalid(i); - } else { - CreateSortKeyHelpers::DecodeSortKey(result_keys[i], result, i, lstate.modifiers); - } - } - } -}; - -template > -static void LeastGreatestFunction(DataChunk &args, ExpressionState &state, Vector &result) { - if (args.ColumnCount() == 1) { - // single input: nop - result.Reference(args.data[0]); - return; - } - auto &input = BASE_OP::Prepare(args, state); - auto &result_vector = BASE_OP::TargetVector(result, state); - - auto result_type = VectorType::CONSTANT_VECTOR; - for (idx_t col_idx = 0; col_idx < input.ColumnCount(); col_idx++) { - if (args.data[col_idx].GetVectorType() != VectorType::CONSTANT_VECTOR) { - // non-constant input: result is not a constant vector - result_type = VectorType::FLAT_VECTOR; - } - if (BASE_OP::IS_STRING) { - // for string vectors we add a reference to the heap of the children - StringVector::AddHeapReference(result_vector, input.data[col_idx]); - } - } - - auto result_data = FlatVector::GetData(result_vector); - bool result_has_value[STANDARD_VECTOR_SIZE] {false}; - // perform the operation column-by-column - for (idx_t col_idx = 0; col_idx < input.ColumnCount(); col_idx++) { - if (input.data[col_idx].GetVectorType() == VectorType::CONSTANT_VECTOR && - ConstantVector::IsNull(input.data[col_idx])) { - // ignore null vector - continue; - } - - UnifiedVectorFormat vdata; - input.data[col_idx].ToUnifiedFormat(input.size(), vdata); - - auto input_data = UnifiedVectorFormat::GetData(vdata); - if (!vdata.validity.AllValid()) { - // potential new null entries: have to check the null mask - for (idx_t i = 0; i < input.size(); i++) { - auto vindex = vdata.sel->get_index(i); - if (vdata.validity.RowIsValid(vindex)) { - // not a null entry: perform the operation and add to new set - auto ivalue = input_data[vindex]; - if (!result_has_value[i] || OP::template Operation(ivalue, result_data[i])) { - result_has_value[i] = true; - result_data[i] = ivalue; - } - } - } - } else { - // no new null entries: only need to perform the operation - for (idx_t i = 0; i < input.size(); i++) { - auto vindex = vdata.sel->get_index(i); - - auto ivalue = input_data[vindex]; - if (!result_has_value[i] || OP::template Operation(ivalue, result_data[i])) { - result_has_value[i] = true; - result_data[i] = ivalue; - } - } - } - } - BASE_OP::FinalizeResult(input.size(), result_has_value, result, state); - result.SetVectorType(result_type); -} - -template -unique_ptr BindLeastGreatest(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - LogicalType child_type = ExpressionBinder::GetExpressionReturnType(*arguments[0]); - for (idx_t i = 1; i < arguments.size(); i++) { - auto arg_type = ExpressionBinder::GetExpressionReturnType(*arguments[i]); - if (!LogicalType::TryGetMaxLogicalType(context, child_type, arg_type, child_type)) { - throw BinderException(arguments[i]->query_location, - "Cannot combine types of %s and %s - an explicit cast is required", - child_type.ToString(), arg_type.ToString()); - } - } - switch (child_type.id()) { - case LogicalTypeId::UNKNOWN: - throw ParameterNotResolvedException(); - case LogicalTypeId::INTEGER_LITERAL: - child_type = IntegerLiteral::GetType(child_type); - break; - case LogicalTypeId::STRING_LITERAL: - child_type = LogicalType::VARCHAR; - break; - default: - break; - } - switch (child_type.InternalType()) { - case PhysicalType::BOOL: - case PhysicalType::INT8: - bound_function.function = LeastGreatestFunction; - break; - case PhysicalType::INT16: - bound_function.function = LeastGreatestFunction; - break; - case PhysicalType::INT32: - bound_function.function = LeastGreatestFunction; - break; - case PhysicalType::INT64: - bound_function.function = LeastGreatestFunction; - break; - case PhysicalType::INT128: - bound_function.function = LeastGreatestFunction; - break; - case PhysicalType::DOUBLE: - bound_function.function = LeastGreatestFunction; - break; - case PhysicalType::VARCHAR: - bound_function.function = LeastGreatestFunction>; - break; - default: - // fallback with sort keys - bound_function.function = LeastGreatestFunction; - bound_function.init_local_state = LeastGreatestSortKeyInit; - break; - } - bound_function.arguments[0] = child_type; - bound_function.varargs = child_type; - bound_function.return_type = child_type; - return nullptr; -} - -template -ScalarFunction GetLeastGreatestFunction() { - return ScalarFunction({LogicalType::ANY}, LogicalType::ANY, nullptr, BindLeastGreatest, nullptr, nullptr, - nullptr, LogicalType::ANY, FunctionStability::CONSISTENT, - FunctionNullHandling::SPECIAL_HANDLING); -} - -template -static ScalarFunctionSet GetLeastGreatestFunctions() { - ScalarFunctionSet fun_set; - fun_set.AddFunction(GetLeastGreatestFunction()); - return fun_set; -} - -ScalarFunctionSet LeastFun::GetFunctions() { - return GetLeastGreatestFunctions(); -} - -ScalarFunctionSet GreatestFun::GetFunctions() { - return GetLeastGreatestFunctions(); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/generic/stats.cpp b/src/duckdb/src/core_functions/scalar/generic/stats.cpp deleted file mode 100644 index f547ca78d..000000000 --- a/src/duckdb/src/core_functions/scalar/generic/stats.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "duckdb/core_functions/scalar/generic_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" - -namespace duckdb { - -struct StatsBindData : public FunctionData { - explicit StatsBindData(string stats_p = string()) : stats(std::move(stats_p)) { - } - - string stats; - -public: - unique_ptr Copy() const override { - return make_uniq(stats); - } - - bool Equals(const FunctionData &other_p) const override { - auto &other = other_p.Cast(); - return stats == other.stats; - } -}; - -static void StatsFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &func_expr = state.expr.Cast(); - auto &info = func_expr.bind_info->Cast(); - if (info.stats.empty()) { - info.stats = "No statistics"; - } - Value v(info.stats); - result.Reference(v); -} - -unique_ptr StatsBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - return make_uniq(); -} - -static unique_ptr StatsPropagateStats(ClientContext &context, FunctionStatisticsInput &input) { - auto &child_stats = input.child_stats; - auto &bind_data = input.bind_data; - auto &info = bind_data->Cast(); - info.stats = child_stats[0].ToString(); - return nullptr; -} - -ScalarFunction StatsFun::GetFunction() { - ScalarFunction stats({LogicalType::ANY}, LogicalType::VARCHAR, StatsFunction, StatsBind, nullptr, - StatsPropagateStats); - stats.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - stats.stability = FunctionStability::VOLATILE; - return stats; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/generic/system_functions.cpp b/src/duckdb/src/core_functions/scalar/generic/system_functions.cpp deleted file mode 100644 index 97fb3fbdf..000000000 --- a/src/duckdb/src/core_functions/scalar/generic/system_functions.cpp +++ /dev/null @@ -1,148 +0,0 @@ -#include "duckdb/catalog/catalog_search_path.hpp" -#include "duckdb/core_functions/scalar/generic_functions.hpp" -#include "duckdb/main/database.hpp" -#include "duckdb/main/client_context.hpp" -#include "duckdb/main/client_data.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp" -#include "duckdb/transaction/duck_transaction.hpp" -#include "duckdb/main/database_manager.hpp" -#include "duckdb/execution/expression_executor.hpp" - -namespace duckdb { - -// current_query -static void CurrentQueryFunction(DataChunk &input, ExpressionState &state, Vector &result) { - Value val(state.GetContext().GetCurrentQuery()); - result.Reference(val); -} - -// current_schema -static void CurrentSchemaFunction(DataChunk &input, ExpressionState &state, Vector &result) { - Value val(ClientData::Get(state.GetContext()).catalog_search_path->GetDefault().schema); - result.Reference(val); -} - -// current_database -static void CurrentDatabaseFunction(DataChunk &input, ExpressionState &state, Vector &result) { - Value val(DatabaseManager::GetDefaultDatabase(state.GetContext())); - result.Reference(val); -} - -struct CurrentSchemasBindData : public FunctionData { - explicit CurrentSchemasBindData(Value result_value) : result(std::move(result_value)) { - } - - Value result; - -public: - unique_ptr Copy() const override { - return make_uniq(result); - } - bool Equals(const FunctionData &other_p) const override { - auto &other = other_p.Cast(); - return Value::NotDistinctFrom(result, other.result); - } -}; - -static unique_ptr CurrentSchemasBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - if (arguments[0]->return_type.id() != LogicalTypeId::BOOLEAN) { - throw BinderException("current_schemas requires a boolean input"); - } - if (!arguments[0]->IsFoldable()) { - throw NotImplementedException("current_schemas requires a constant input"); - } - Value schema_value = ExpressionExecutor::EvaluateScalar(context, *arguments[0]); - Value result_val; - if (schema_value.IsNull()) { - // null - result_val = Value(LogicalType::LIST(LogicalType::VARCHAR)); - } else { - auto implicit_schemas = BooleanValue::Get(schema_value); - vector schema_list; - auto &catalog_search_path = ClientData::Get(context).catalog_search_path; - auto &search_path = implicit_schemas ? catalog_search_path->Get() : catalog_search_path->GetSetPaths(); - std::transform(search_path.begin(), search_path.end(), std::back_inserter(schema_list), - [](const CatalogSearchEntry &s) -> Value { return Value(s.schema); }); - result_val = Value::LIST(LogicalType::VARCHAR, schema_list); - } - return make_uniq(std::move(result_val)); -} - -// current_schemas -static void CurrentSchemasFunction(DataChunk &input, ExpressionState &state, Vector &result) { - auto &func_expr = state.expr.Cast(); - auto &info = func_expr.bind_info->Cast(); - result.Reference(info.result); -} - -// in_search_path -static void InSearchPathFunction(DataChunk &input, ExpressionState &state, Vector &result) { - auto &context = state.GetContext(); - auto &search_path = ClientData::Get(context).catalog_search_path; - BinaryExecutor::Execute( - input.data[0], input.data[1], result, input.size(), [&](string_t db_name, string_t schema_name) { - return search_path->SchemaInSearchPath(context, db_name.GetString(), schema_name.GetString()); - }); -} - -// txid_current -static void TransactionIdCurrent(DataChunk &input, ExpressionState &state, Vector &result) { - auto &context = state.GetContext(); - auto &catalog = Catalog::GetCatalog(context, DatabaseManager::GetDefaultDatabase(context)); - auto &transaction = DuckTransaction::Get(context, catalog); - auto val = Value::UBIGINT(transaction.start_time); - result.Reference(val); -} - -// version -static void VersionFunction(DataChunk &input, ExpressionState &state, Vector &result) { - auto val = Value(DuckDB::LibraryVersion()); - result.Reference(val); -} - -ScalarFunction CurrentQueryFun::GetFunction() { - ScalarFunction current_query({}, LogicalType::VARCHAR, CurrentQueryFunction); - current_query.stability = FunctionStability::VOLATILE; - return current_query; -} - -ScalarFunction CurrentSchemaFun::GetFunction() { - ScalarFunction current_schema({}, LogicalType::VARCHAR, CurrentSchemaFunction); - current_schema.stability = FunctionStability::CONSISTENT_WITHIN_QUERY; - return current_schema; -} - -ScalarFunction CurrentDatabaseFun::GetFunction() { - ScalarFunction current_database({}, LogicalType::VARCHAR, CurrentDatabaseFunction); - current_database.stability = FunctionStability::CONSISTENT_WITHIN_QUERY; - return current_database; -} - -ScalarFunction CurrentSchemasFun::GetFunction() { - auto varchar_list_type = LogicalType::LIST(LogicalType::VARCHAR); - ScalarFunction current_schemas({LogicalType::BOOLEAN}, varchar_list_type, CurrentSchemasFunction, - CurrentSchemasBind); - current_schemas.stability = FunctionStability::CONSISTENT_WITHIN_QUERY; - return current_schemas; -} - -ScalarFunction InSearchPathFun::GetFunction() { - ScalarFunction in_search_path({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, - InSearchPathFunction); - in_search_path.stability = FunctionStability::CONSISTENT_WITHIN_QUERY; - return in_search_path; -} - -ScalarFunction CurrentTransactionIdFun::GetFunction() { - ScalarFunction txid_current({}, LogicalType::UBIGINT, TransactionIdCurrent); - txid_current.stability = FunctionStability::CONSISTENT_WITHIN_QUERY; - return txid_current; -} - -ScalarFunction VersionFun::GetFunction() { - return ScalarFunction({}, LogicalType::VARCHAR, VersionFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/generic/typeof.cpp b/src/duckdb/src/core_functions/scalar/generic/typeof.cpp deleted file mode 100644 index b74a0cef5..000000000 --- a/src/duckdb/src/core_functions/scalar/generic/typeof.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "duckdb/core_functions/scalar/generic_functions.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" - -namespace duckdb { - -static 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.function.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.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - fun.bind_expression = BindTypeOfFunctionExpression; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/list/array_slice.cpp b/src/duckdb/src/core_functions/scalar/list/array_slice.cpp deleted file mode 100644 index 3cc0960d9..000000000 --- a/src/duckdb/src/core_functions/scalar/list/array_slice.cpp +++ /dev/null @@ -1,455 +0,0 @@ -#include "duckdb/core_functions/scalar/list_functions.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/common/swap.hpp" -#include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/function/scalar/string_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" -#include "duckdb/planner/expression/bound_cast_expression.hpp" - -namespace duckdb { - -struct ListSliceBindData : public FunctionData { - ListSliceBindData(const LogicalType &return_type_p, bool begin_is_empty_p, bool end_is_empty_p) - : return_type(return_type_p), begin_is_empty(begin_is_empty_p), end_is_empty(end_is_empty_p) { - } - ~ListSliceBindData() override; - - LogicalType return_type; - - bool begin_is_empty; - bool end_is_empty; - -public: - bool Equals(const FunctionData &other_p) const override; - unique_ptr Copy() const override; -}; - -ListSliceBindData::~ListSliceBindData() { -} - -bool ListSliceBindData::Equals(const FunctionData &other_p) const { - auto &other = other_p.Cast(); - return return_type == other.return_type && begin_is_empty == other.begin_is_empty && - end_is_empty == other.end_is_empty; -} - -unique_ptr ListSliceBindData::Copy() const { - return make_uniq(return_type, begin_is_empty, end_is_empty); -} - -template -static idx_t CalculateSliceLength(idx_t begin, idx_t end, INDEX_TYPE step, bool svalid) { - if (step < 0) { - step = AbsValue(step); - } - if (step == 0 && svalid) { - throw InvalidInputException("Slice step cannot be zero"); - } - if (step == 1) { - return NumericCast(end - begin); - } else if (static_cast(step) >= (end - begin)) { - return 1; - } - if ((end - begin) % UnsafeNumericCast(step) != 0) { - return (end - begin) / UnsafeNumericCast(step) + 1; - } - return (end - begin) / UnsafeNumericCast(step); -} - -template -INDEX_TYPE ValueLength(const INPUT_TYPE &value) { - return 0; -} - -template <> -int64_t ValueLength(const list_entry_t &value) { - return UnsafeNumericCast(value.length); -} - -template <> -int64_t ValueLength(const string_t &value) { - return LengthFun::Length(value); -} - -template -static void ClampIndex(INDEX_TYPE &index, const INPUT_TYPE &value, const INDEX_TYPE length, bool is_min) { - if (index < 0) { - index = (!is_min) ? index + 1 : index; - index = length + index; - return; - } else if (index > length) { - index = length; - } - return; -} - -template -static bool ClampSlice(const INPUT_TYPE &value, INDEX_TYPE &begin, INDEX_TYPE &end) { - // Clamp offsets - begin = (begin != 0 && begin != (INDEX_TYPE)NumericLimits::Minimum()) ? begin - 1 : begin; - - bool is_min = false; - if (begin == (INDEX_TYPE)NumericLimits::Minimum()) { - begin++; - is_min = true; - } - - const auto length = ValueLength(value); - if (begin < 0 && -begin > length && end < 0 && end < -length) { - begin = 0; - end = 0; - return true; - } - if (begin < 0 && -begin > length) { - begin = 0; - } - ClampIndex(begin, value, length, is_min); - ClampIndex(end, value, length, false); - end = MaxValue(begin, end); - - return true; -} - -template -INPUT_TYPE SliceValue(Vector &result, INPUT_TYPE input, INDEX_TYPE begin, INDEX_TYPE end) { - return input; -} - -template <> -list_entry_t SliceValue(Vector &result, list_entry_t input, int64_t begin, int64_t end) { - input.offset = UnsafeNumericCast(UnsafeNumericCast(input.offset) + begin); - input.length = UnsafeNumericCast(end - begin); - return input; -} - -template <> -string_t SliceValue(Vector &result, string_t input, int64_t begin, int64_t end) { - // one-based - zero has strange semantics - return SubstringFun::SubstringUnicode(result, input, begin + 1, end - begin); -} - -template -INPUT_TYPE SliceValueWithSteps(Vector &result, SelectionVector &sel, INPUT_TYPE input, INDEX_TYPE begin, INDEX_TYPE end, - INDEX_TYPE step, idx_t &sel_idx) { - return input; -} - -template <> -list_entry_t SliceValueWithSteps(Vector &result, SelectionVector &sel, list_entry_t input, int64_t begin, int64_t end, - int64_t step, idx_t &sel_idx) { - if (end - begin == 0) { - input.length = 0; - input.offset = sel_idx; - return input; - } - input.length = CalculateSliceLength(UnsafeNumericCast(begin), UnsafeNumericCast(end), step, true); - idx_t child_idx = input.offset + UnsafeNumericCast(begin); - if (step < 0) { - child_idx = input.offset + UnsafeNumericCast(end) - 1; - } - input.offset = sel_idx; - for (idx_t i = 0; i < input.length; i++) { - sel.set_index(sel_idx, child_idx); - child_idx += static_cast(step); // intentional overflow?? - sel_idx++; - } - return input; -} - -template -static void ExecuteConstantSlice(Vector &result, Vector &str_vector, Vector &begin_vector, Vector &end_vector, - optional_ptr step_vector, const idx_t count, SelectionVector &sel, - idx_t &sel_idx, optional_ptr result_child_vector, bool begin_is_empty, - bool end_is_empty) { - - // check all this nullness early - auto str_valid = !ConstantVector::IsNull(str_vector); - auto begin_valid = !ConstantVector::IsNull(begin_vector); - auto end_valid = !ConstantVector::IsNull(end_vector); - auto step_valid = step_vector && !ConstantVector::IsNull(*step_vector); - - if (!str_valid || !begin_valid || !end_valid || (step_vector && !step_valid)) { - ConstantVector::SetNull(result, true); - return; - } - - auto result_data = ConstantVector::GetData(result); - auto str_data = ConstantVector::GetData(str_vector); - auto begin_data = ConstantVector::GetData(begin_vector); - auto end_data = ConstantVector::GetData(end_vector); - auto step_data = step_vector ? ConstantVector::GetData(*step_vector) : nullptr; - - auto str = str_data[0]; - auto begin = begin_is_empty ? 0 : begin_data[0]; - auto end = end_is_empty ? ValueLength(str) : end_data[0]; - auto step = step_data ? step_data[0] : 1; - - if (step < 0) { - swap(begin, end); - begin = end_is_empty ? 0 : begin; - end = begin_is_empty ? ValueLength(str) : end; - } - - // Clamp offsets - bool clamp_result = false; - if (step_valid || step == 1) { - clamp_result = ClampSlice(str, begin, end); - } - - idx_t sel_length = 0; - bool sel_valid = false; - if (step_valid && step != 1 && end - begin > 0) { - sel_length = - CalculateSliceLength(UnsafeNumericCast(begin), UnsafeNumericCast(end), step, step_valid); - sel.Initialize(sel_length); - sel_valid = true; - } - - // Try to slice - if (!clamp_result) { - ConstantVector::SetNull(result, true); - } else if (step == 1) { - result_data[0] = SliceValue(result, str, begin, end); - } else { - result_data[0] = SliceValueWithSteps(result, sel, str, begin, end, step, sel_idx); - } - - if (sel_valid) { - result_child_vector->Slice(sel, sel_length); - result_child_vector->Flatten(sel_length); - ListVector::SetListSize(result, sel_length); - } -} - -template -static void ExecuteFlatSlice(Vector &result, Vector &list_vector, Vector &begin_vector, Vector &end_vector, - optional_ptr step_vector, const idx_t count, SelectionVector &sel, idx_t &sel_idx, - optional_ptr result_child_vector, bool begin_is_empty, bool end_is_empty) { - UnifiedVectorFormat list_data, begin_data, end_data, step_data; - idx_t sel_length = 0; - - list_vector.ToUnifiedFormat(count, list_data); - begin_vector.ToUnifiedFormat(count, begin_data); - end_vector.ToUnifiedFormat(count, end_data); - if (step_vector) { - step_vector->ToUnifiedFormat(count, step_data); - sel.Initialize(ListVector::GetListSize(list_vector)); - } - - auto result_data = FlatVector::GetData(result); - auto &result_mask = FlatVector::Validity(result); - - for (idx_t i = 0; i < count; ++i) { - auto list_idx = list_data.sel->get_index(i); - auto begin_idx = begin_data.sel->get_index(i); - auto end_idx = end_data.sel->get_index(i); - auto step_idx = step_vector ? step_data.sel->get_index(i) : 0; - - auto list_valid = list_data.validity.RowIsValid(list_idx); - auto begin_valid = begin_data.validity.RowIsValid(begin_idx); - auto end_valid = end_data.validity.RowIsValid(end_idx); - auto step_valid = step_vector && step_data.validity.RowIsValid(step_idx); - - if (!list_valid || !begin_valid || !end_valid || (step_vector && !step_valid)) { - result_mask.SetInvalid(i); - continue; - } - - auto sliced = reinterpret_cast(list_data.data)[list_idx]; - auto begin = begin_is_empty ? 0 : reinterpret_cast(begin_data.data)[begin_idx]; - auto end = end_is_empty ? ValueLength(sliced) - : reinterpret_cast(end_data.data)[end_idx]; - auto step = step_vector ? reinterpret_cast(step_data.data)[step_idx] : 1; - - if (step < 0) { - swap(begin, end); - begin = end_is_empty ? 0 : begin; - end = begin_is_empty ? ValueLength(sliced) : end; - } - - bool clamp_result = false; - if (step_valid || step == 1) { - clamp_result = ClampSlice(sliced, begin, end); - } - - idx_t length = 0; - if (end - begin > 0) { - length = - CalculateSliceLength(UnsafeNumericCast(begin), UnsafeNumericCast(end), step, step_valid); - } - sel_length += length; - - if (!clamp_result) { - result_mask.SetInvalid(i); - } else if (!step_vector) { - result_data[i] = SliceValue(result, sliced, begin, end); - } else { - result_data[i] = - SliceValueWithSteps(result, sel, sliced, begin, end, step, sel_idx); - } - } - if (step_vector) { - SelectionVector new_sel(sel_length); - for (idx_t i = 0; i < sel_length; ++i) { - new_sel.set_index(i, sel.get_index(i)); - } - result_child_vector->Slice(new_sel, sel_length); - result_child_vector->Flatten(sel_length); - ListVector::SetListSize(result, sel_length); - } -} - -template -static void ExecuteSlice(Vector &result, Vector &list_or_str_vector, Vector &begin_vector, Vector &end_vector, - optional_ptr step_vector, const idx_t count, bool begin_is_empty, bool end_is_empty) { - optional_ptr result_child_vector; - if (step_vector) { - result_child_vector = &ListVector::GetEntry(result); - } - - SelectionVector sel; - idx_t sel_idx = 0; - - if (result.GetVectorType() == VectorType::CONSTANT_VECTOR) { - ExecuteConstantSlice(result, list_or_str_vector, begin_vector, end_vector, step_vector, - count, sel, sel_idx, result_child_vector, begin_is_empty, - end_is_empty); - } else { - ExecuteFlatSlice(result, list_or_str_vector, begin_vector, end_vector, step_vector, - count, sel, sel_idx, result_child_vector, begin_is_empty, - end_is_empty); - } - result.Verify(count); -} - -static void ArraySliceFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 3 || args.ColumnCount() == 4); - D_ASSERT(args.data.size() == 3 || args.data.size() == 4); - auto count = args.size(); - - Vector &list_or_str_vector = result; - // this ensures that we do not change the input chunk - VectorOperations::Copy(args.data[0], list_or_str_vector, count, 0, 0); - - if (list_or_str_vector.GetType().id() == LogicalTypeId::SQLNULL) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(result, true); - return; - } - - Vector &begin_vector = args.data[1]; - Vector &end_vector = args.data[2]; - - optional_ptr step_vector; - if (args.ColumnCount() == 4) { - step_vector = &args.data[3]; - } - - auto &func_expr = state.expr.Cast(); - auto &info = func_expr.bind_info->Cast(); - auto begin_is_empty = info.begin_is_empty; - auto end_is_empty = info.end_is_empty; - - result.SetVectorType(args.AllConstant() ? VectorType::CONSTANT_VECTOR : VectorType::FLAT_VECTOR); - switch (result.GetType().id()) { - case LogicalTypeId::LIST: { - // Share the value dictionary as we are just going to slice it - if (list_or_str_vector.GetVectorType() != VectorType::FLAT_VECTOR && - list_or_str_vector.GetVectorType() != VectorType::CONSTANT_VECTOR) { - list_or_str_vector.Flatten(count); - } - ExecuteSlice(result, list_or_str_vector, begin_vector, end_vector, step_vector, count, - begin_is_empty, end_is_empty); - break; - } - case LogicalTypeId::VARCHAR: { - ExecuteSlice(result, list_or_str_vector, begin_vector, end_vector, step_vector, count, - begin_is_empty, end_is_empty); - break; - } - default: - throw NotImplementedException("Specifier type not implemented"); - } -} - -static bool CheckIfParamIsEmpty(duckdb::unique_ptr ¶m) { - bool is_empty = false; - if (param->return_type.id() == LogicalTypeId::LIST) { - auto empty_list = make_uniq(Value::LIST(LogicalType::INTEGER, vector())); - is_empty = param->Equals(*empty_list); - if (!is_empty) { - // if the param is not empty, the user has entered a list instead of a BIGINT - throw BinderException("The upper and lower bounds of the slice must be a BIGINT"); - } - } - return is_empty; -} - -static unique_ptr ArraySliceBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - D_ASSERT(arguments.size() == 3 || arguments.size() == 4); - D_ASSERT(bound_function.arguments.size() == 3 || bound_function.arguments.size() == 4); - - switch (arguments[0]->return_type.id()) { - case LogicalTypeId::ARRAY: { - // Cast to list - auto child_type = ArrayType::GetChildType(arguments[0]->return_type); - auto target_type = LogicalType::LIST(child_type); - arguments[0] = BoundCastExpression::AddCastToType(context, std::move(arguments[0]), target_type); - bound_function.return_type = arguments[0]->return_type; - } break; - case LogicalTypeId::LIST: - // The result is the same type - bound_function.return_type = arguments[0]->return_type; - break; - case LogicalTypeId::VARCHAR: - // string slice returns a string - if (bound_function.arguments.size() == 4) { - throw NotImplementedException( - "Slice with steps has not been implemented for string types, you can consider rewriting your query as " - "follows:\n SELECT array_to_string((str_split(string, '')[begin:end:step], '');"); - } - bound_function.return_type = arguments[0]->return_type; - for (idx_t i = 1; i < 3; i++) { - if (arguments[i]->return_type.id() != LogicalTypeId::LIST) { - bound_function.arguments[i] = LogicalType::BIGINT; - } - } - break; - case LogicalTypeId::SQLNULL: - case LogicalTypeId::UNKNOWN: - bound_function.arguments[0] = LogicalTypeId::UNKNOWN; - bound_function.return_type = LogicalType::SQLNULL; - break; - default: - throw BinderException("ARRAY_SLICE can only operate on LISTs and VARCHARs"); - } - - bool begin_is_empty = CheckIfParamIsEmpty(arguments[1]); - if (!begin_is_empty) { - bound_function.arguments[1] = LogicalType::BIGINT; - } - bool end_is_empty = CheckIfParamIsEmpty(arguments[2]); - if (!end_is_empty) { - bound_function.arguments[2] = LogicalType::BIGINT; - } - - return make_uniq(bound_function.return_type, begin_is_empty, end_is_empty); -} - -ScalarFunctionSet ListSliceFun::GetFunctions() { - // the arguments and return types are actually set in the binder function - ScalarFunction fun({LogicalType::ANY, LogicalType::ANY, LogicalType::ANY}, LogicalType::ANY, ArraySliceFunction, - ArraySliceBind); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - - ScalarFunctionSet set; - set.AddFunction(fun); - fun.arguments.push_back(LogicalType::BIGINT); - set.AddFunction(fun); - return set; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/list/flatten.cpp b/src/duckdb/src/core_functions/scalar/list/flatten.cpp deleted file mode 100644 index 4833dc7a5..000000000 --- a/src/duckdb/src/core_functions/scalar/list/flatten.cpp +++ /dev/null @@ -1,171 +0,0 @@ -#include "duckdb/core_functions/scalar/list_functions.hpp" -#include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/storage/statistics/list_stats.hpp" -#include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/planner/expression/bound_cast_expression.hpp" - -namespace duckdb { - -void ListFlattenFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 1); - - Vector &input = args.data[0]; - if (input.GetType().id() == LogicalTypeId::SQLNULL) { - result.Reference(input); - return; - } - - idx_t count = args.size(); - - // Prepare the result vector - result.SetVectorType(VectorType::FLAT_VECTOR); - // This holds the new offsets and lengths - auto result_entries = FlatVector::GetData(result); - auto &result_validity = FlatVector::Validity(result); - - // The outermost list in each row - UnifiedVectorFormat row_data; - input.ToUnifiedFormat(count, row_data); - auto row_entries = UnifiedVectorFormat::GetData(row_data); - - // The list elements in each row: [HERE, ...] - auto &row_lists = ListVector::GetEntry(input); - UnifiedVectorFormat row_lists_data; - idx_t total_row_lists = ListVector::GetListSize(input); - row_lists.ToUnifiedFormat(total_row_lists, row_lists_data); - auto row_lists_entries = UnifiedVectorFormat::GetData(row_lists_data); - - if (row_lists.GetType().id() == LogicalTypeId::SQLNULL) { - for (idx_t row_cnt = 0; row_cnt < count; row_cnt++) { - auto row_idx = row_data.sel->get_index(row_cnt); - if (!row_data.validity.RowIsValid(row_idx)) { - result_validity.SetInvalid(row_cnt); - continue; - } - result_entries[row_cnt].offset = 0; - result_entries[row_cnt].length = 0; - } - if (args.AllConstant()) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } - return; - } - - // The actual elements inside each row list: [[HERE, ...], []] - // This one becomes the child vector of the result. - auto &elem_vector = ListVector::GetEntry(row_lists); - - // We'll use this selection vector to slice the elem_vector. - idx_t child_elem_cnt = ListVector::GetListSize(row_lists); - SelectionVector sel(child_elem_cnt); - idx_t sel_idx = 0; - - // HERE, [[]], ... - for (idx_t row_cnt = 0; row_cnt < count; row_cnt++) { - auto row_idx = row_data.sel->get_index(row_cnt); - - if (!row_data.validity.RowIsValid(row_idx)) { - result_validity.SetInvalid(row_cnt); - continue; - } - - idx_t list_offset = sel_idx; - idx_t list_length = 0; - - // [HERE, [...], ...] - auto row_entry = row_entries[row_idx]; - for (idx_t row_lists_cnt = 0; row_lists_cnt < row_entry.length; row_lists_cnt++) { - auto row_lists_idx = row_lists_data.sel->get_index(row_entry.offset + row_lists_cnt); - - // Skip invalid lists - if (!row_lists_data.validity.RowIsValid(row_lists_idx)) { - continue; - } - - // [[HERE, ...], [.., ...]] - auto list_entry = row_lists_entries[row_lists_idx]; - list_length += list_entry.length; - - for (idx_t elem_cnt = 0; elem_cnt < list_entry.length; elem_cnt++) { - // offset of the element in the elem_vector. - idx_t offset = list_entry.offset + elem_cnt; - sel.set_index(sel_idx, offset); - sel_idx++; - } - } - - result_entries[row_cnt].offset = list_offset; - result_entries[row_cnt].length = list_length; - } - - ListVector::SetListSize(result, sel_idx); - - auto &result_child_vector = ListVector::GetEntry(result); - result_child_vector.Slice(elem_vector, sel, sel_idx); - result_child_vector.Flatten(sel_idx); - - if (args.AllConstant()) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } -} - -static unique_ptr ListFlattenBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - D_ASSERT(bound_function.arguments.size() == 1); - - if (arguments[0]->return_type.id() == LogicalTypeId::ARRAY) { - auto child_type = ArrayType::GetChildType(arguments[0]->return_type); - if (child_type.id() == LogicalTypeId::ARRAY) { - child_type = LogicalType::LIST(ArrayType::GetChildType(child_type)); - } - arguments[0] = - BoundCastExpression::AddCastToType(context, std::move(arguments[0]), LogicalType::LIST(child_type)); - } else if (arguments[0]->return_type.id() == LogicalTypeId::LIST) { - auto child_type = ListType::GetChildType(arguments[0]->return_type); - if (child_type.id() == LogicalTypeId::ARRAY) { - child_type = LogicalType::LIST(ArrayType::GetChildType(child_type)); - arguments[0] = - BoundCastExpression::AddCastToType(context, std::move(arguments[0]), LogicalType::LIST(child_type)); - } - } - - auto &input_type = arguments[0]->return_type; - bound_function.arguments[0] = input_type; - if (input_type.id() == LogicalTypeId::UNKNOWN) { - bound_function.arguments[0] = LogicalType(LogicalTypeId::UNKNOWN); - bound_function.return_type = LogicalType(LogicalTypeId::SQLNULL); - return nullptr; - } - D_ASSERT(input_type.id() == LogicalTypeId::LIST); - - auto child_type = ListType::GetChildType(input_type); - if (child_type.id() == LogicalType::SQLNULL) { - bound_function.return_type = input_type; - return make_uniq(bound_function.return_type); - } - if (child_type.id() == LogicalTypeId::UNKNOWN) { - bound_function.arguments[0] = LogicalType(LogicalTypeId::UNKNOWN); - bound_function.return_type = LogicalType(LogicalTypeId::SQLNULL); - return nullptr; - } - D_ASSERT(child_type.id() == LogicalTypeId::LIST); - - bound_function.return_type = child_type; - return make_uniq(bound_function.return_type); -} - -static unique_ptr ListFlattenStats(ClientContext &context, FunctionStatisticsInput &input) { - auto &child_stats = input.child_stats; - auto &list_child_stats = ListStats::GetChildStats(child_stats[0]); - auto child_copy = list_child_stats.Copy(); - child_copy.Set(StatsInfo::CAN_HAVE_NULL_VALUES); - return child_copy.ToUnique(); -} - -ScalarFunction ListFlattenFun::GetFunction() { - return ScalarFunction({LogicalType::LIST(LogicalType::LIST(LogicalType::ANY))}, LogicalType::LIST(LogicalType::ANY), - ListFlattenFunction, ListFlattenBind, nullptr, ListFlattenStats); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/list/list_aggregates.cpp b/src/duckdb/src/core_functions/scalar/list/list_aggregates.cpp deleted file mode 100644 index e423c1a78..000000000 --- a/src/duckdb/src/core_functions/scalar/list/list_aggregates.cpp +++ /dev/null @@ -1,530 +0,0 @@ -#include "duckdb/core_functions/scalar/list_functions.hpp" -#include "duckdb/core_functions/aggregate/nested_functions.hpp" -#include "duckdb/catalog/catalog.hpp" -#include "duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp" -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/planner/expression/bound_cast_expression.hpp" -#include "duckdb/planner/expression_binder.hpp" -#include "duckdb/function/function_binder.hpp" -#include "duckdb/core_functions/create_sort_key.hpp" -#include "duckdb/common/owning_string_map.hpp" - -namespace duckdb { - -// FIXME: use a local state for each thread to increase performance? -// FIXME: benchmark the use of simple_update against using update (if applicable) - -static unique_ptr ListAggregatesBindFailure(ScalarFunction &bound_function) { - bound_function.arguments[0] = LogicalType::SQLNULL; - bound_function.return_type = LogicalType::SQLNULL; - return make_uniq(LogicalType::SQLNULL); -} - -struct ListAggregatesBindData : public FunctionData { - ListAggregatesBindData(const LogicalType &stype_p, unique_ptr aggr_expr_p); - ~ListAggregatesBindData() override; - - LogicalType stype; - unique_ptr aggr_expr; - - unique_ptr Copy() const override { - return make_uniq(stype, aggr_expr->Copy()); - } - - bool Equals(const FunctionData &other_p) const override { - auto &other = other_p.Cast(); - return stype == other.stype && aggr_expr->Equals(*other.aggr_expr); - } - void Serialize(Serializer &serializer) const { - serializer.WriteProperty(1, "stype", stype); - serializer.WriteProperty(2, "aggr_expr", aggr_expr); - } - static unique_ptr Deserialize(Deserializer &deserializer) { - auto stype = deserializer.ReadProperty(1, "stype"); - auto aggr_expr = deserializer.ReadProperty>(2, "aggr_expr"); - auto result = make_uniq(std::move(stype), std::move(aggr_expr)); - return result; - } - - static void SerializeFunction(Serializer &serializer, const optional_ptr bind_data_p, - const ScalarFunction &function) { - auto bind_data = dynamic_cast(bind_data_p.get()); - serializer.WritePropertyWithDefault(100, "bind_data", bind_data, (const ListAggregatesBindData *)nullptr); - } - - static unique_ptr DeserializeFunction(Deserializer &deserializer, ScalarFunction &bound_function) { - auto result = deserializer.ReadPropertyWithExplicitDefault>( - 100, "bind_data", unique_ptr(nullptr)); - if (!result) { - return ListAggregatesBindFailure(bound_function); - } - return std::move(result); - } -}; - -ListAggregatesBindData::ListAggregatesBindData(const LogicalType &stype_p, unique_ptr aggr_expr_p) - : stype(stype_p), aggr_expr(std::move(aggr_expr_p)) { -} - -ListAggregatesBindData::~ListAggregatesBindData() { -} - -struct StateVector { - StateVector(idx_t count_p, unique_ptr aggr_expr_p) - : count(count_p), aggr_expr(std::move(aggr_expr_p)), state_vector(Vector(LogicalType::POINTER, count_p)) { - } - - ~StateVector() { // NOLINT - // destroy objects within the aggregate states - auto &aggr = aggr_expr->Cast(); - if (aggr.function.destructor) { - ArenaAllocator allocator(Allocator::DefaultAllocator()); - AggregateInputData aggr_input_data(aggr.bind_info.get(), allocator); - aggr.function.destructor(state_vector, aggr_input_data, count); - } - } - - idx_t count; - unique_ptr aggr_expr; - Vector state_vector; -}; - -struct FinalizeValueFunctor { - template - static void HistogramFinalize(T value, Vector &result, idx_t offset) { - FlatVector::GetData(result)[offset] = value; - } -}; - -struct FinalizeStringValueFunctor { - template - static void HistogramFinalize(T value, Vector &result, idx_t offset) { - FlatVector::GetData(result)[offset] = StringVector::AddStringOrBlob(result, value); - } -}; - -struct FinalizeGenericValueFunctor { - template - static void HistogramFinalize(T value, Vector &result, idx_t offset) { - CreateSortKeyHelpers::DecodeSortKey(value, result, offset, - OrderModifiers(OrderType::ASCENDING, OrderByNullType::NULLS_LAST)); - } -}; - -struct AggregateFunctor { - template > - static void ListExecuteFunction(Vector &result, Vector &state_vector, idx_t count) { - } -}; - -struct DistinctFunctor { - template > - static void ListExecuteFunction(Vector &result, Vector &state_vector, idx_t count) { - UnifiedVectorFormat sdata; - state_vector.ToUnifiedFormat(count, sdata); - auto states = UnifiedVectorFormat::GetData *>(sdata); - - auto old_len = ListVector::GetListSize(result); - idx_t new_entries = 0; - // figure out how much space we need - for (idx_t i = 0; i < count; i++) { - auto &state = *states[sdata.sel->get_index(i)]; - if (!state.hist) { - continue; - } - new_entries += state.hist->size(); - } - // reserve space in the list vector - ListVector::Reserve(result, old_len + new_entries); - auto &child_elements = ListVector::GetEntry(result); - auto list_entries = FlatVector::GetData(result); - - idx_t current_offset = old_len; - for (idx_t i = 0; i < count; i++) { - const auto rid = i; - auto &state = *states[sdata.sel->get_index(i)]; - auto &list_entry = list_entries[rid]; - list_entry.offset = current_offset; - if (!state.hist) { - list_entry.length = 0; - continue; - } - - for (auto &entry : *state.hist) { - OP::template HistogramFinalize(entry.first, child_elements, current_offset); - current_offset++; - } - list_entry.length = current_offset - list_entry.offset; - } - D_ASSERT(current_offset == old_len + new_entries); - ListVector::SetListSize(result, current_offset); - result.Verify(count); - } -}; - -struct UniqueFunctor { - template > - static void ListExecuteFunction(Vector &result, Vector &state_vector, idx_t count) { - UnifiedVectorFormat sdata; - state_vector.ToUnifiedFormat(count, sdata); - auto states = UnifiedVectorFormat::GetData *>(sdata); - - auto result_data = FlatVector::GetData(result); - for (idx_t i = 0; i < count; i++) { - - auto state = states[sdata.sel->get_index(i)]; - - if (!state->hist) { - result_data[i] = 0; - continue; - } - result_data[i] = state->hist->size(); - } - result.Verify(count); - } -}; - -template -static void ListAggregatesFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto count = args.size(); - Vector &lists = args.data[0]; - - // set the result vector - result.SetVectorType(VectorType::FLAT_VECTOR); - auto &result_validity = FlatVector::Validity(result); - - if (lists.GetType().id() == LogicalTypeId::SQLNULL) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(result, true); - return; - } - - // get the aggregate function - auto &func_expr = state.expr.Cast(); - auto &info = func_expr.bind_info->Cast(); - auto &aggr = info.aggr_expr->Cast(); - ArenaAllocator allocator(Allocator::DefaultAllocator()); - AggregateInputData aggr_input_data(aggr.bind_info.get(), allocator); - - D_ASSERT(aggr.function.update); - - auto lists_size = ListVector::GetListSize(lists); - auto &child_vector = ListVector::GetEntry(lists); - child_vector.Flatten(lists_size); - - UnifiedVectorFormat child_data; - child_vector.ToUnifiedFormat(lists_size, child_data); - - UnifiedVectorFormat lists_data; - lists.ToUnifiedFormat(count, lists_data); - auto list_entries = UnifiedVectorFormat::GetData(lists_data); - - // state_buffer holds the state for each list of this chunk - idx_t size = aggr.function.state_size(aggr.function); - auto state_buffer = make_unsafe_uniq_array_uninitialized(size * count); - - // state vector for initialize and finalize - StateVector state_vector(count, info.aggr_expr->Copy()); - auto states = FlatVector::GetData(state_vector.state_vector); - - // state vector of STANDARD_VECTOR_SIZE holds the pointers to the states - Vector state_vector_update = Vector(LogicalType::POINTER); - auto states_update = FlatVector::GetData(state_vector_update); - - // selection vector pointing to the data - SelectionVector sel_vector(STANDARD_VECTOR_SIZE); - idx_t states_idx = 0; - - for (idx_t i = 0; i < count; i++) { - - // initialize the state for this list - auto state_ptr = state_buffer.get() + size * i; - states[i] = state_ptr; - aggr.function.initialize(aggr.function, states[i]); - - auto lists_index = lists_data.sel->get_index(i); - const auto &list_entry = list_entries[lists_index]; - - // nothing to do for this list - if (!lists_data.validity.RowIsValid(lists_index)) { - result_validity.SetInvalid(i); - continue; - } - - // skip empty list - if (list_entry.length == 0) { - continue; - } - - for (idx_t child_idx = 0; child_idx < list_entry.length; child_idx++) { - // states vector is full, update - if (states_idx == STANDARD_VECTOR_SIZE) { - // update the aggregate state(s) - Vector slice(child_vector, sel_vector, states_idx); - aggr.function.update(&slice, aggr_input_data, 1, state_vector_update, states_idx); - - // reset values - states_idx = 0; - } - - auto source_idx = child_data.sel->get_index(list_entry.offset + child_idx); - sel_vector.set_index(states_idx, source_idx); - states_update[states_idx] = state_ptr; - states_idx++; - } - } - - // update the remaining elements of the last list(s) - if (states_idx != 0) { - Vector slice(child_vector, sel_vector, states_idx); - aggr.function.update(&slice, aggr_input_data, 1, state_vector_update, states_idx); - } - - if (IS_AGGR) { - // finalize all the aggregate states - aggr.function.finalize(state_vector.state_vector, aggr_input_data, result, count, 0); - - } else { - // finalize manually to use the map - D_ASSERT(aggr.function.arguments.size() == 1); - auto key_type = aggr.function.arguments[0]; - - switch (key_type.InternalType()) { - case PhysicalType::BOOL: - FUNCTION_FUNCTOR::template ListExecuteFunction( - result, state_vector.state_vector, count); - break; - case PhysicalType::UINT8: - FUNCTION_FUNCTOR::template ListExecuteFunction( - result, state_vector.state_vector, count); - break; - case PhysicalType::UINT16: - FUNCTION_FUNCTOR::template ListExecuteFunction( - result, state_vector.state_vector, count); - break; - case PhysicalType::UINT32: - FUNCTION_FUNCTOR::template ListExecuteFunction( - result, state_vector.state_vector, count); - break; - case PhysicalType::UINT64: - FUNCTION_FUNCTOR::template ListExecuteFunction( - result, state_vector.state_vector, count); - break; - case PhysicalType::INT8: - FUNCTION_FUNCTOR::template ListExecuteFunction( - result, state_vector.state_vector, count); - break; - case PhysicalType::INT16: - FUNCTION_FUNCTOR::template ListExecuteFunction( - result, state_vector.state_vector, count); - break; - case PhysicalType::INT32: - FUNCTION_FUNCTOR::template ListExecuteFunction( - result, state_vector.state_vector, count); - break; - case PhysicalType::INT64: - FUNCTION_FUNCTOR::template ListExecuteFunction( - result, state_vector.state_vector, count); - break; - case PhysicalType::FLOAT: - FUNCTION_FUNCTOR::template ListExecuteFunction( - result, state_vector.state_vector, count); - break; - case PhysicalType::DOUBLE: - FUNCTION_FUNCTOR::template ListExecuteFunction( - result, state_vector.state_vector, count); - break; - case PhysicalType::VARCHAR: - FUNCTION_FUNCTOR::template ListExecuteFunction>(result, state_vector.state_vector, - count); - break; - default: - FUNCTION_FUNCTOR::template ListExecuteFunction>(result, state_vector.state_vector, - count); - break; - } - } - - if (args.AllConstant()) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } -} - -static void ListAggregateFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() >= 2); - ListAggregatesFunction(args, state, result); -} - -static void ListDistinctFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 1); - ListAggregatesFunction(args, state, result); -} - -static void ListUniqueFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 1); - ListAggregatesFunction(args, state, result); -} - -template -static unique_ptr -ListAggregatesBindFunction(ClientContext &context, ScalarFunction &bound_function, const LogicalType &list_child_type, - AggregateFunction &aggr_function, vector> &arguments) { - - // create the child expression and its type - vector> children; - auto expr = make_uniq(Value(list_child_type)); - children.push_back(std::move(expr)); - // push any extra arguments into the list aggregate bind - if (arguments.size() > 2) { - for (idx_t i = 2; i < arguments.size(); i++) { - children.push_back(std::move(arguments[i])); - } - arguments.resize(2); - } - - FunctionBinder function_binder(context); - auto bound_aggr_function = function_binder.BindAggregateFunction(aggr_function, std::move(children)); - bound_function.arguments[0] = LogicalType::LIST(bound_aggr_function->function.arguments[0]); - - if (IS_AGGR) { - bound_function.return_type = bound_aggr_function->function.return_type; - } - // check if the aggregate function consumed all the extra input arguments - if (bound_aggr_function->children.size() > 1) { - throw InvalidInputException( - "Aggregate function %s is not supported for list_aggr: extra arguments were not removed during bind", - bound_aggr_function->ToString()); - } - - return make_uniq(bound_function.return_type, std::move(bound_aggr_function)); -} - -template -static unique_ptr ListAggregatesBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - - arguments[0] = BoundCastExpression::AddArrayCastToList(context, std::move(arguments[0])); - - if (arguments[0]->return_type.id() == LogicalTypeId::SQLNULL) { - return ListAggregatesBindFailure(bound_function); - } - - bool is_parameter = arguments[0]->return_type.id() == LogicalTypeId::UNKNOWN; - LogicalType child_type; - if (is_parameter) { - child_type = LogicalType::ANY; - } else if (arguments[0]->return_type.id() == LogicalTypeId::LIST || - arguments[0]->return_type.id() == LogicalTypeId::MAP) { - child_type = ListType::GetChildType(arguments[0]->return_type); - } else { - // Unreachable - throw InvalidInputException("First argument of list aggregate must be a list, map or array"); - } - - string function_name = "histogram"; - if (IS_AGGR) { // get the name of the aggregate function - if (!arguments[1]->IsFoldable()) { - throw InvalidInputException("Aggregate function name must be a constant"); - } - // get the function name - Value function_value = ExpressionExecutor::EvaluateScalar(context, *arguments[1]); - function_name = function_value.ToString(); - } - - // look up the aggregate function in the catalog - auto &func = Catalog::GetSystemCatalog(context).GetEntry(context, DEFAULT_SCHEMA, - function_name); - D_ASSERT(func.type == CatalogType::AGGREGATE_FUNCTION_ENTRY); - - if (is_parameter) { - bound_function.arguments[0] = LogicalTypeId::UNKNOWN; - bound_function.return_type = LogicalType::SQLNULL; - return nullptr; - } - - // find a matching aggregate function - ErrorData error; - vector types; - types.push_back(child_type); - // push any extra arguments into the type list - for (idx_t i = 2; i < arguments.size(); i++) { - types.push_back(arguments[i]->return_type); - } - - FunctionBinder function_binder(context); - auto best_function_idx = function_binder.BindFunction(func.name, func.functions, types, error); - if (!best_function_idx.IsValid()) { - throw BinderException("No matching aggregate function\n%s", error.Message()); - } - - // found a matching function, bind it as an aggregate - auto best_function = func.functions.GetFunctionByOffset(best_function_idx.GetIndex()); - if (IS_AGGR) { - return ListAggregatesBindFunction(context, bound_function, child_type, best_function, arguments); - } - - // create the unordered map histogram function - D_ASSERT(best_function.arguments.size() == 1); - auto aggr_function = HistogramFun::GetHistogramUnorderedMap(child_type); - return ListAggregatesBindFunction(context, bound_function, child_type, aggr_function, arguments); -} - -static unique_ptr ListAggregateBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - - // the list column and the name of the aggregate function - D_ASSERT(bound_function.arguments.size() >= 2); - D_ASSERT(arguments.size() >= 2); - - return ListAggregatesBind(context, bound_function, arguments); -} - -static unique_ptr ListDistinctBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - - D_ASSERT(bound_function.arguments.size() == 1); - D_ASSERT(arguments.size() == 1); - - arguments[0] = BoundCastExpression::AddArrayCastToList(context, std::move(arguments[0])); - bound_function.return_type = arguments[0]->return_type; - - return ListAggregatesBind<>(context, bound_function, arguments); -} - -static unique_ptr ListUniqueBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - - D_ASSERT(bound_function.arguments.size() == 1); - D_ASSERT(arguments.size() == 1); - bound_function.return_type = LogicalType::UBIGINT; - - return ListAggregatesBind<>(context, bound_function, arguments); -} - -ScalarFunction ListAggregateFun::GetFunction() { - auto result = ScalarFunction({LogicalType::LIST(LogicalType::ANY), LogicalType::VARCHAR}, LogicalType::ANY, - ListAggregateFunction, ListAggregateBind); - result.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - result.varargs = LogicalType::ANY; - result.serialize = ListAggregatesBindData::SerializeFunction; - result.deserialize = ListAggregatesBindData::DeserializeFunction; - return result; -} - -ScalarFunction ListDistinctFun::GetFunction() { - return ScalarFunction({LogicalType::LIST(LogicalType::ANY)}, LogicalType::LIST(LogicalType::ANY), - ListDistinctFunction, ListDistinctBind); -} - -ScalarFunction ListUniqueFun::GetFunction() { - return ScalarFunction({LogicalType::LIST(LogicalType::ANY)}, LogicalType::UBIGINT, ListUniqueFunction, - ListUniqueBind); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/list/list_distance.cpp b/src/duckdb/src/core_functions/scalar/list/list_distance.cpp deleted file mode 100644 index 23e19f871..000000000 --- a/src/duckdb/src/core_functions/scalar/list/list_distance.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#include "duckdb/core_functions/scalar/list_functions.hpp" -#include "duckdb/core_functions/array_kernels.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" - -namespace duckdb { - -//------------------------------------------------------------------------------ -// Generic "fold" function -//------------------------------------------------------------------------------ -// Given two lists of the same size, combine and reduce their elements into a -// single scalar value. - -template -static void ListGenericFold(DataChunk &args, ExpressionState &state, Vector &result) { - const auto &lstate = state.Cast(); - const auto &expr = lstate.expr.Cast(); - const auto &func_name = expr.function.name; - - auto count = args.size(); - - auto &lhs_vec = args.data[0]; - auto &rhs_vec = args.data[1]; - - const auto lhs_count = ListVector::GetListSize(lhs_vec); - const auto rhs_count = ListVector::GetListSize(rhs_vec); - - auto &lhs_child = ListVector::GetEntry(lhs_vec); - auto &rhs_child = ListVector::GetEntry(rhs_vec); - - lhs_child.Flatten(lhs_count); - rhs_child.Flatten(rhs_count); - - D_ASSERT(lhs_child.GetVectorType() == VectorType::FLAT_VECTOR); - D_ASSERT(rhs_child.GetVectorType() == VectorType::FLAT_VECTOR); - - if (!FlatVector::Validity(lhs_child).CheckAllValid(lhs_count)) { - throw InvalidInputException("%s: left argument can not contain NULL values", func_name); - } - - if (!FlatVector::Validity(rhs_child).CheckAllValid(rhs_count)) { - throw InvalidInputException("%s: right argument can not contain NULL values", func_name); - } - - auto lhs_data = FlatVector::GetData(lhs_child); - auto rhs_data = FlatVector::GetData(rhs_child); - - BinaryExecutor::ExecuteWithNulls( - lhs_vec, rhs_vec, result, count, - [&](const list_entry_t &left, const list_entry_t &right, ValidityMask &mask, idx_t row_idx) { - if (left.length != right.length) { - throw InvalidInputException( - "%s: list dimensions must be equal, got left length '%d' and right length '%d'", func_name, - left.length, right.length); - } - - if (!OP::ALLOW_EMPTY && left.length == 0) { - mask.SetInvalid(row_idx); - return TYPE(); - } - - return OP::Operation(lhs_data + left.offset, rhs_data + right.offset, left.length); - }); - - if (args.AllConstant()) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } -} - -//------------------------------------------------------------------------- -// Function Registration -//------------------------------------------------------------------------- - -template -static void AddListFoldFunction(ScalarFunctionSet &set, const LogicalType &type) { - const auto list = LogicalType::LIST(type); - if (type.id() == LogicalTypeId::FLOAT) { - set.AddFunction(ScalarFunction({list, list}, type, ListGenericFold)); - } else if (type.id() == LogicalTypeId::DOUBLE) { - set.AddFunction(ScalarFunction({list, list}, type, ListGenericFold)); - } else { - throw NotImplementedException("List function not implemented for type %s", type.ToString()); - } -} - -ScalarFunctionSet ListDistanceFun::GetFunctions() { - ScalarFunctionSet set("list_distance"); - for (auto &type : LogicalType::Real()) { - AddListFoldFunction(set, type); - } - return set; -} - -ScalarFunctionSet ListInnerProductFun::GetFunctions() { - ScalarFunctionSet set("list_inner_product"); - for (auto &type : LogicalType::Real()) { - AddListFoldFunction(set, type); - } - return set; -} - -ScalarFunctionSet ListNegativeInnerProductFun::GetFunctions() { - ScalarFunctionSet set("list_negative_inner_product"); - for (auto &type : LogicalType::Real()) { - AddListFoldFunction(set, type); - } - return set; -} - -ScalarFunctionSet ListCosineSimilarityFun::GetFunctions() { - ScalarFunctionSet set("list_cosine_similarity"); - for (auto &type : LogicalType::Real()) { - AddListFoldFunction(set, type); - } - return set; -} - -ScalarFunctionSet ListCosineDistanceFun::GetFunctions() { - ScalarFunctionSet set("list_cosine_distance"); - for (auto &type : LogicalType::Real()) { - AddListFoldFunction(set, type); - } - return set; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/list/list_filter.cpp b/src/duckdb/src/core_functions/scalar/list/list_filter.cpp deleted file mode 100644 index 9dbab0981..000000000 --- a/src/duckdb/src/core_functions/scalar/list/list_filter.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "duckdb/core_functions/scalar/list_functions.hpp" - -#include "duckdb/core_functions/lambda_functions.hpp" -#include "duckdb/planner/expression/bound_cast_expression.hpp" - -namespace duckdb { - -static unique_ptr ListFilterBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - - // the list column and the bound lambda expression - D_ASSERT(arguments.size() == 2); - if (arguments[1]->expression_class != ExpressionClass::BOUND_LAMBDA) { - throw BinderException("Invalid lambda expression!"); - } - - auto &bound_lambda_expr = arguments[1]->Cast(); - - // try to cast to boolean, if the return type of the lambda filter expression is not already boolean - if (bound_lambda_expr.lambda_expr->return_type != LogicalType::BOOLEAN) { - auto cast_lambda_expr = - BoundCastExpression::AddCastToType(context, std::move(bound_lambda_expr.lambda_expr), LogicalType::BOOLEAN); - bound_lambda_expr.lambda_expr = std::move(cast_lambda_expr); - } - - arguments[0] = BoundCastExpression::AddArrayCastToList(context, std::move(arguments[0])); - - bound_function.return_type = arguments[0]->return_type; - auto has_index = bound_lambda_expr.parameter_count == 2; - return LambdaFunctions::ListLambdaBind(context, bound_function, arguments, has_index); -} - -static LogicalType ListFilterBindLambda(const idx_t parameter_idx, const LogicalType &list_child_type) { - return LambdaFunctions::BindBinaryLambda(parameter_idx, list_child_type); -} - -ScalarFunction ListFilterFun::GetFunction() { - ScalarFunction fun({LogicalType::LIST(LogicalType::ANY), LogicalType::LAMBDA}, LogicalType::LIST(LogicalType::ANY), - LambdaFunctions::ListFilterFunction, ListFilterBind, nullptr, nullptr); - - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - fun.serialize = ListLambdaBindData::Serialize; - fun.deserialize = ListLambdaBindData::Deserialize; - fun.bind_lambda = ListFilterBindLambda; - - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/list/list_has_any_or_all.cpp b/src/duckdb/src/core_functions/scalar/list/list_has_any_or_all.cpp deleted file mode 100644 index 4a3e35090..000000000 --- a/src/duckdb/src/core_functions/scalar/list/list_has_any_or_all.cpp +++ /dev/null @@ -1,227 +0,0 @@ -#include "duckdb/core_functions/lambda_functions.hpp" -#include "duckdb/core_functions/scalar/list_functions.hpp" -#include "duckdb/core_functions/create_sort_key.hpp" -#include "duckdb/planner/expression/bound_cast_expression.hpp" -#include "duckdb/common/string_map_set.hpp" - -namespace duckdb { - -static unique_ptr ListHasAnyOrAllBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - - arguments[0] = BoundCastExpression::AddArrayCastToList(context, std::move(arguments[0])); - arguments[1] = BoundCastExpression::AddArrayCastToList(context, std::move(arguments[1])); - - const auto lhs_is_param = arguments[0]->HasParameter(); - const auto rhs_is_param = arguments[1]->HasParameter(); - - if (lhs_is_param && rhs_is_param) { - throw ParameterNotResolvedException(); - } - - const auto &lhs_list = arguments[0]->return_type; - const auto &rhs_list = arguments[1]->return_type; - - if (lhs_is_param) { - bound_function.arguments[0] = rhs_list; - bound_function.arguments[1] = rhs_list; - return nullptr; - } - if (rhs_is_param) { - bound_function.arguments[0] = lhs_list; - bound_function.arguments[1] = lhs_list; - return nullptr; - } - - bound_function.arguments[0] = lhs_list; - bound_function.arguments[1] = rhs_list; - - const auto &lhs_child = ListType::GetChildType(bound_function.arguments[0]); - const auto &rhs_child = ListType::GetChildType(bound_function.arguments[1]); - - if (lhs_child != LogicalType::SQLNULL && rhs_child != LogicalType::SQLNULL && lhs_child != rhs_child) { - LogicalType common_child; - if (!LogicalType::TryGetMaxLogicalType(context, lhs_child, rhs_child, common_child)) { - throw BinderException("'%s' cannot compare lists of different types: '%s' and '%s'", bound_function.name, - lhs_child.ToString(), rhs_child.ToString()); - } - bound_function.arguments[0] = LogicalType::LIST(common_child); - bound_function.arguments[1] = LogicalType::LIST(common_child); - } - - return nullptr; -} - -static void ListHasAnyFunction(DataChunk &args, ExpressionState &, Vector &result) { - - auto &l_vec = args.data[0]; - auto &r_vec = args.data[1]; - - if (ListType::GetChildType(l_vec.GetType()) == LogicalType::SQLNULL || - ListType::GetChildType(r_vec.GetType()) == LogicalType::SQLNULL) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::GetData(result)[0] = false; - return; - } - - const auto l_size = ListVector::GetListSize(l_vec); - const auto r_size = ListVector::GetListSize(r_vec); - - auto &l_child = ListVector::GetEntry(l_vec); - auto &r_child = ListVector::GetEntry(r_vec); - - // Setup unified formats for the list elements - UnifiedVectorFormat l_child_format; - UnifiedVectorFormat r_child_format; - - l_child.ToUnifiedFormat(l_size, l_child_format); - r_child.ToUnifiedFormat(r_size, r_child_format); - - // Create the sort keys for the list elements - Vector l_sortkey_vec(LogicalType::BLOB, l_size); - Vector r_sortkey_vec(LogicalType::BLOB, r_size); - - const OrderModifiers order_modifiers(OrderType::ASCENDING, OrderByNullType::NULLS_LAST); - - CreateSortKeyHelpers::CreateSortKey(l_child, l_size, order_modifiers, l_sortkey_vec); - CreateSortKeyHelpers::CreateSortKey(r_child, r_size, order_modifiers, r_sortkey_vec); - - const auto l_sortkey_ptr = FlatVector::GetData(l_sortkey_vec); - const auto r_sortkey_ptr = FlatVector::GetData(r_sortkey_vec); - - string_set_t set; - - BinaryExecutor::Execute( - l_vec, r_vec, result, args.size(), [&](const list_entry_t &l_list, const list_entry_t &r_list) { - // Short circuit if either list is empty - if (l_list.length == 0 || r_list.length == 0) { - return false; - } - - auto build_list = l_list; - auto probe_list = r_list; - - auto build_data = l_sortkey_ptr; - auto probe_data = r_sortkey_ptr; - - auto build_format = &l_child_format; - auto probe_format = &r_child_format; - - // Use the smaller list to build the set - if (r_list.length < l_list.length) { - - build_list = r_list; - probe_list = l_list; - - build_data = r_sortkey_ptr; - probe_data = l_sortkey_ptr; - - build_format = &r_child_format; - probe_format = &l_child_format; - } - - // Reset the set - set.clear(); - - // Build the set - for (auto idx = build_list.offset; idx < build_list.offset + build_list.length; idx++) { - const auto entry_idx = build_format->sel->get_index(idx); - if (build_format->validity.RowIsValid(entry_idx)) { - set.insert(build_data[entry_idx]); - } - } - // Probe the set - for (auto idx = probe_list.offset; idx < probe_list.offset + probe_list.length; idx++) { - const auto entry_idx = probe_format->sel->get_index(idx); - if (probe_format->validity.RowIsValid(entry_idx) && set.find(probe_data[entry_idx]) != set.end()) { - return true; - } - } - return false; - }); -} - -static void ListHasAllFunction(DataChunk &args, ExpressionState &state, Vector &result) { - - const auto &func_expr = state.expr.Cast(); - const auto swap = func_expr.function.name == "<@"; - - auto &l_vec = args.data[swap ? 1 : 0]; - auto &r_vec = args.data[swap ? 0 : 1]; - - if (ListType::GetChildType(l_vec.GetType()) == LogicalType::SQLNULL && - ListType::GetChildType(r_vec.GetType()) == LogicalType::SQLNULL) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::GetData(result)[0] = true; - return; - } - - const auto l_size = ListVector::GetListSize(l_vec); - const auto r_size = ListVector::GetListSize(r_vec); - - auto &l_child = ListVector::GetEntry(l_vec); - auto &r_child = ListVector::GetEntry(r_vec); - - // Setup unified formats for the list elements - UnifiedVectorFormat build_format; - UnifiedVectorFormat probe_format; - - l_child.ToUnifiedFormat(l_size, build_format); - r_child.ToUnifiedFormat(r_size, probe_format); - - // Create the sort keys for the list elements - Vector l_sortkey_vec(LogicalType::BLOB, l_size); - Vector r_sortkey_vec(LogicalType::BLOB, r_size); - - const OrderModifiers order_modifiers(OrderType::ASCENDING, OrderByNullType::NULLS_LAST); - - CreateSortKeyHelpers::CreateSortKey(l_child, l_size, order_modifiers, l_sortkey_vec); - CreateSortKeyHelpers::CreateSortKey(r_child, r_size, order_modifiers, r_sortkey_vec); - - const auto build_data = FlatVector::GetData(l_sortkey_vec); - const auto probe_data = FlatVector::GetData(r_sortkey_vec); - - string_set_t set; - - BinaryExecutor::Execute( - l_vec, r_vec, result, args.size(), [&](const list_entry_t &build_list, const list_entry_t &probe_list) { - // Short circuit if the probe list is empty - if (probe_list.length == 0) { - return true; - } - - // Reset the set - set.clear(); - - // Build the set - for (auto idx = build_list.offset; idx < build_list.offset + build_list.length; idx++) { - const auto entry_idx = build_format.sel->get_index(idx); - if (build_format.validity.RowIsValid(entry_idx)) { - set.insert(build_data[entry_idx]); - } - } - - // Probe the set - for (auto idx = probe_list.offset; idx < probe_list.offset + probe_list.length; idx++) { - const auto entry_idx = probe_format.sel->get_index(idx); - if (probe_format.validity.RowIsValid(entry_idx) && set.find(probe_data[entry_idx]) == set.end()) { - return false; - } - } - return true; - }); -} - -ScalarFunction ListHasAnyFun::GetFunction() { - ScalarFunction fun({LogicalType::LIST(LogicalType::ANY), LogicalType::LIST(LogicalType::ANY)}, LogicalType::BOOLEAN, - ListHasAnyFunction, ListHasAnyOrAllBind); - return fun; -} - -ScalarFunction ListHasAllFun::GetFunction() { - ScalarFunction fun({LogicalType::LIST(LogicalType::ANY), LogicalType::LIST(LogicalType::ANY)}, LogicalType::BOOLEAN, - ListHasAllFunction, ListHasAnyOrAllBind); - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/list/list_reduce.cpp b/src/duckdb/src/core_functions/scalar/list/list_reduce.cpp deleted file mode 100644 index a3b4e01d8..000000000 --- a/src/duckdb/src/core_functions/scalar/list/list_reduce.cpp +++ /dev/null @@ -1,232 +0,0 @@ -#include "duckdb/core_functions/scalar/list_functions.hpp" -#include "duckdb/core_functions/lambda_functions.hpp" -#include "duckdb/planner/expression/bound_cast_expression.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" - -namespace duckdb { - -struct ReduceExecuteInfo { - ReduceExecuteInfo(LambdaFunctions::LambdaInfo &info, ClientContext &context) - : left_slice(make_uniq(*info.child_vector)) { - SelectionVector left_vector(info.row_count); - active_rows.Resize(0, info.row_count); - active_rows.SetAllValid(info.row_count); - - left_sel.Initialize(info.row_count); - active_rows_sel.Initialize(info.row_count); - - idx_t reduced_row_idx = 0; - - for (idx_t original_row_idx = 0; original_row_idx < info.row_count; original_row_idx++) { - auto list_column_format_index = info.list_column_format.sel->get_index(original_row_idx); - if (info.list_column_format.validity.RowIsValid(list_column_format_index)) { - if (info.list_entries[list_column_format_index].length == 0) { - throw ParameterNotAllowedException("Cannot perform list_reduce on an empty input list"); - } - left_vector.set_index(reduced_row_idx, info.list_entries[list_column_format_index].offset); - reduced_row_idx++; - } else { - // Set the row as invalid and remove it from the active rows. - FlatVector::SetNull(info.result, original_row_idx, true); - active_rows.SetInvalid(original_row_idx); - } - } - left_slice->Slice(left_vector, reduced_row_idx); - - if (info.has_index) { - input_types.push_back(LogicalType::BIGINT); - } - input_types.push_back(left_slice->GetType()); - input_types.push_back(left_slice->GetType()); - for (auto &entry : info.column_infos) { - input_types.push_back(entry.vector.get().GetType()); - } - - expr_executor = make_uniq(context, *info.lambda_expr); - }; - ValidityMask active_rows; - unique_ptr left_slice; - unique_ptr expr_executor; - vector input_types; - - SelectionVector left_sel; - SelectionVector active_rows_sel; -}; - -static bool ExecuteReduce(idx_t loops, ReduceExecuteInfo &execute_info, LambdaFunctions::LambdaInfo &info, - DataChunk &result_chunk) { - idx_t original_row_idx = 0; - idx_t reduced_row_idx = 0; - idx_t valid_row_idx = 0; - - // create selection vectors for the left and right slice - auto data = execute_info.active_rows.GetData(); - - // reset right_sel each iteration to prevent referencing issues - SelectionVector right_sel; - right_sel.Initialize(info.row_count); - - idx_t bits_per_entry = sizeof(idx_t) * 8; - for (idx_t entry_idx = 0; original_row_idx < info.row_count; entry_idx++) { - if (data[entry_idx] == 0) { - original_row_idx += bits_per_entry; - continue; - } - - for (idx_t j = 0; entry_idx * bits_per_entry + j < info.row_count; j++) { - if (!execute_info.active_rows.RowIsValid(original_row_idx)) { - original_row_idx++; - continue; - } - auto list_column_format_index = info.list_column_format.sel->get_index(original_row_idx); - if (info.list_entries[list_column_format_index].length > loops + 1) { - right_sel.set_index(reduced_row_idx, info.list_entries[list_column_format_index].offset + loops + 1); - execute_info.left_sel.set_index(reduced_row_idx, valid_row_idx); - execute_info.active_rows_sel.set_index(reduced_row_idx, original_row_idx); - reduced_row_idx++; - - } else { - execute_info.active_rows.SetInvalid(original_row_idx); - auto val = execute_info.left_slice->GetValue(valid_row_idx); - info.result.SetValue(original_row_idx, val); - } - - original_row_idx++; - valid_row_idx++; - } - } - - if (reduced_row_idx == 0) { - return true; - } - - // create the index vector - Vector index_vector(Value::BIGINT(UnsafeNumericCast(loops + 1))); - - // slice the left and right slice - execute_info.left_slice->Slice(*execute_info.left_slice, execute_info.left_sel, reduced_row_idx); - Vector right_slice(*info.child_vector, right_sel, reduced_row_idx); - - // create the input chunk - DataChunk input_chunk; - input_chunk.InitializeEmpty(execute_info.input_types); - input_chunk.SetCardinality(reduced_row_idx); - - idx_t slice_offset = info.has_index ? 1 : 0; - if (info.has_index) { - input_chunk.data[0].Reference(index_vector); - } - input_chunk.data[slice_offset + 1].Reference(*execute_info.left_slice); - input_chunk.data[slice_offset].Reference(right_slice); - - // add the other columns - vector slices; - for (idx_t i = 0; i < info.column_infos.size(); i++) { - if (info.column_infos[i].vector.get().GetVectorType() == VectorType::CONSTANT_VECTOR) { - // only reference constant vectors - input_chunk.data[slice_offset + 2 + i].Reference(info.column_infos[i].vector); - } else { - // slice the other vectors - slices.emplace_back(info.column_infos[i].vector, execute_info.active_rows_sel, reduced_row_idx); - input_chunk.data[slice_offset + 2 + i].Reference(slices.back()); - } - } - - result_chunk.Reset(); - result_chunk.SetCardinality(reduced_row_idx); - execute_info.expr_executor->Execute(input_chunk, result_chunk); - - // We need to copy the result into left_slice to avoid data loss due to vector.Reference(...). - // Otherwise, we only keep the data of the previous iteration alive, not that of previous iterations. - execute_info.left_slice = make_uniq(result_chunk.data[0].GetType(), reduced_row_idx); - VectorOperations::Copy(result_chunk.data[0], *execute_info.left_slice, reduced_row_idx, 0, 0); - return false; -} - -void LambdaFunctions::ListReduceFunction(DataChunk &args, ExpressionState &state, Vector &result) { - // Initializes the left slice from the list entries, active rows, the expression executor and the input types - bool completed = false; - LambdaFunctions::LambdaInfo info(args, state, result, completed); - if (completed) { - return; - } - - ReduceExecuteInfo execute_info(info, state.GetContext()); - - // Since the left slice references the result chunk, we need to create two result chunks. - // This means there is always an empty result chunk for the next iteration, - // without the referenced chunk having to be reset until the current iteration is complete. - DataChunk odd_result_chunk; - odd_result_chunk.Initialize(Allocator::DefaultAllocator(), {info.lambda_expr->return_type}); - - DataChunk even_result_chunk; - even_result_chunk.Initialize(Allocator::DefaultAllocator(), {info.lambda_expr->return_type}); - - // Execute reduce until all rows are finished. - idx_t loops = 0; - bool end = false; - while (!end) { - auto &result_chunk = loops % 2 ? odd_result_chunk : even_result_chunk; - auto &spare_result_chunk = loops % 2 ? even_result_chunk : odd_result_chunk; - - end = ExecuteReduce(loops, execute_info, info, result_chunk); - spare_result_chunk.Reset(); - loops++; - } - - if (info.is_all_constant && !info.is_volatile) { - info.result.SetVectorType(VectorType::CONSTANT_VECTOR); - } -} - -static unique_ptr ListReduceBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - - // the list column and the bound lambda expression - D_ASSERT(arguments.size() == 2); - if (arguments[1]->expression_class != ExpressionClass::BOUND_LAMBDA) { - throw BinderException("Invalid lambda expression!"); - } - - arguments[0] = BoundCastExpression::AddArrayCastToList(context, std::move(arguments[0])); - - auto &bound_lambda_expr = arguments[1]->Cast(); - if (bound_lambda_expr.parameter_count < 2 || bound_lambda_expr.parameter_count > 3) { - throw BinderException("list_reduce expects a function with 2 or 3 arguments"); - } - auto has_index = bound_lambda_expr.parameter_count == 3; - - unique_ptr bind_data = LambdaFunctions::ListLambdaPrepareBind(arguments, context, bound_function); - if (bind_data) { - return bind_data; - } - - auto list_child_type = arguments[0]->return_type; - list_child_type = ListType::GetChildType(list_child_type); - - auto cast_lambda_expr = - BoundCastExpression::AddCastToType(context, std::move(bound_lambda_expr.lambda_expr), list_child_type, false); - if (!cast_lambda_expr) { - throw BinderException("Could not cast lambda expression to list child type"); - } - bound_function.return_type = cast_lambda_expr->return_type; - return make_uniq(bound_function.return_type, std::move(cast_lambda_expr), has_index); -} - -static LogicalType ListReduceBindLambda(const idx_t parameter_idx, const LogicalType &list_child_type) { - return LambdaFunctions::BindTernaryLambda(parameter_idx, list_child_type); -} - -ScalarFunction ListReduceFun::GetFunction() { - ScalarFunction fun({LogicalType::LIST(LogicalType::ANY), LogicalType::LAMBDA}, LogicalType::ANY, - LambdaFunctions::ListReduceFunction, ListReduceBind, nullptr, nullptr); - - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - fun.serialize = ListLambdaBindData::Serialize; - fun.deserialize = ListLambdaBindData::Deserialize; - fun.bind_lambda = ListReduceBindLambda; - - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/list/list_sort.cpp b/src/duckdb/src/core_functions/scalar/list/list_sort.cpp deleted file mode 100644 index 0fbe54ba9..000000000 --- a/src/duckdb/src/core_functions/scalar/list/list_sort.cpp +++ /dev/null @@ -1,416 +0,0 @@ -#include "duckdb/core_functions/scalar/list_functions.hpp" -#include "duckdb/common/enum_util.hpp" -#include "duckdb/common/numeric_utils.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/planner/expression/bound_cast_expression.hpp" -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/planner/expression/bound_reference_expression.hpp" -#include "duckdb/main/config.hpp" -#include "duckdb/common/sort/sort.hpp" - -namespace duckdb { - -struct ListSortBindData : public FunctionData { - ListSortBindData(OrderType order_type_p, OrderByNullType null_order_p, bool is_grade_up, - const LogicalType &return_type_p, const LogicalType &child_type_p, ClientContext &context_p); - ~ListSortBindData() override; - - OrderType order_type; - OrderByNullType null_order; - LogicalType return_type; - LogicalType child_type; - bool is_grade_up; - - vector types; - vector payload_types; - - ClientContext &context; - RowLayout payload_layout; - vector orders; - -public: - bool Equals(const FunctionData &other_p) const override; - unique_ptr Copy() const override; -}; - -ListSortBindData::ListSortBindData(OrderType order_type_p, OrderByNullType null_order_p, bool is_grade_up_p, - const LogicalType &return_type_p, const LogicalType &child_type_p, - ClientContext &context_p) - : order_type(order_type_p), null_order(null_order_p), return_type(return_type_p), child_type(child_type_p), - is_grade_up(is_grade_up_p), context(context_p) { - - // get the vector types - types.emplace_back(LogicalType::USMALLINT); - types.emplace_back(child_type); - D_ASSERT(types.size() == 2); - - // get the payload types - payload_types.emplace_back(LogicalType::UINTEGER); - D_ASSERT(payload_types.size() == 1); - - // initialize the payload layout - payload_layout.Initialize(payload_types); - - // get the BoundOrderByNode - auto idx_col_expr = make_uniq_base(LogicalType::USMALLINT, 0U); - auto lists_col_expr = make_uniq_base(child_type, 1U); - orders.emplace_back(OrderType::ASCENDING, OrderByNullType::ORDER_DEFAULT, std::move(idx_col_expr)); - orders.emplace_back(order_type, null_order, std::move(lists_col_expr)); -} - -unique_ptr ListSortBindData::Copy() const { - return make_uniq(order_type, null_order, is_grade_up, return_type, child_type, context); -} - -bool ListSortBindData::Equals(const FunctionData &other_p) const { - auto &other = other_p.Cast(); - return order_type == other.order_type && null_order == other.null_order && is_grade_up == other.is_grade_up; -} - -ListSortBindData::~ListSortBindData() { -} - -// create the key_chunk and the payload_chunk and sink them into the local_sort_state -void SinkDataChunk(Vector *child_vector, SelectionVector &sel, idx_t offset_lists_indices, vector &types, - vector &payload_types, Vector &payload_vector, LocalSortState &local_sort_state, - bool &data_to_sort, Vector &lists_indices) { - - // slice the child vector - Vector slice(*child_vector, sel, offset_lists_indices); - - // initialize and fill key_chunk - DataChunk key_chunk; - key_chunk.InitializeEmpty(types); - key_chunk.data[0].Reference(lists_indices); - key_chunk.data[1].Reference(slice); - key_chunk.SetCardinality(offset_lists_indices); - - // initialize and fill key_chunk and payload_chunk - DataChunk payload_chunk; - payload_chunk.InitializeEmpty(payload_types); - payload_chunk.data[0].Reference(payload_vector); - payload_chunk.SetCardinality(offset_lists_indices); - - key_chunk.Verify(); - payload_chunk.Verify(); - - // sink - key_chunk.Flatten(); - local_sort_state.SinkChunk(key_chunk, payload_chunk); - data_to_sort = true; -} - -static void ListSortFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() >= 1 && args.ColumnCount() <= 3); - auto count = args.size(); - Vector &input_lists = args.data[0]; - - result.SetVectorType(VectorType::FLAT_VECTOR); - auto &result_validity = FlatVector::Validity(result); - - if (input_lists.GetType().id() == LogicalTypeId::SQLNULL) { - result_validity.SetInvalid(0); - return; - } - - auto &func_expr = state.expr.Cast(); - auto &info = func_expr.bind_info->Cast(); - - // initialize the global and local sorting state - auto &buffer_manager = BufferManager::GetBufferManager(info.context); - GlobalSortState global_sort_state(buffer_manager, info.orders, info.payload_layout); - LocalSortState local_sort_state; - local_sort_state.Initialize(global_sort_state, buffer_manager); - - Vector sort_result_vec = info.is_grade_up ? Vector(input_lists.GetType()) : result; - - // this ensures that we do not change the order of the entries in the input chunk - VectorOperations::Copy(input_lists, sort_result_vec, count, 0, 0); - - // get the child vector - auto lists_size = ListVector::GetListSize(sort_result_vec); - auto &child_vector = ListVector::GetEntry(sort_result_vec); - - // get the lists data - UnifiedVectorFormat lists_data; - sort_result_vec.ToUnifiedFormat(count, lists_data); - auto list_entries = UnifiedVectorFormat::GetData(lists_data); - - // create the lists_indices vector, this contains an element for each list's entry, - // the element corresponds to the list's index, e.g. for [1, 2, 4], [5, 4] - // lists_indices contains [0, 0, 0, 1, 1] - Vector lists_indices(LogicalType::USMALLINT); - auto lists_indices_data = FlatVector::GetData(lists_indices); - - // create the payload_vector, this is just a vector containing incrementing integers - // this will later be used as the 'new' selection vector of the child_vector, after - // rearranging the payload according to the sorting order - Vector payload_vector(LogicalType::UINTEGER); - auto payload_vector_data = FlatVector::GetData(payload_vector); - - // selection vector pointing to the data of the child vector, - // used for slicing the child_vector correctly - SelectionVector sel(STANDARD_VECTOR_SIZE); - - idx_t offset_lists_indices = 0; - uint32_t incr_payload_count = 0; - bool data_to_sort = false; - - for (idx_t i = 0; i < count; i++) { - auto lists_index = lists_data.sel->get_index(i); - const auto &list_entry = list_entries[lists_index]; - - // nothing to do for this list - if (!lists_data.validity.RowIsValid(lists_index)) { - result_validity.SetInvalid(i); - continue; - } - - // empty list, no sorting required - if (list_entry.length == 0) { - continue; - } - - for (idx_t child_idx = 0; child_idx < list_entry.length; child_idx++) { - // lists_indices vector is full, sink - if (offset_lists_indices == STANDARD_VECTOR_SIZE) { - SinkDataChunk(&child_vector, sel, offset_lists_indices, info.types, info.payload_types, payload_vector, - local_sort_state, data_to_sort, lists_indices); - offset_lists_indices = 0; - } - - auto source_idx = list_entry.offset + child_idx; - sel.set_index(offset_lists_indices, source_idx); - lists_indices_data[offset_lists_indices] = UnsafeNumericCast(i); - payload_vector_data[offset_lists_indices] = NumericCast(source_idx); - offset_lists_indices++; - incr_payload_count++; - } - } - - if (offset_lists_indices != 0) { - SinkDataChunk(&child_vector, sel, offset_lists_indices, info.types, info.payload_types, payload_vector, - local_sort_state, data_to_sort, lists_indices); - } - - if (info.is_grade_up) { - ListVector::Reserve(result, lists_size); - ListVector::SetListSize(result, lists_size); - auto result_data = ListVector::GetData(result); - memcpy(result_data, list_entries, count * sizeof(list_entry_t)); - } - - if (data_to_sort) { - // add local state to global state, which sorts the data - global_sort_state.AddLocalState(local_sort_state); - global_sort_state.PrepareMergePhase(); - - // selection vector that is to be filled with the 'sorted' payload - SelectionVector sel_sorted(incr_payload_count); - idx_t sel_sorted_idx = 0; - - // scan the sorted row data - PayloadScanner scanner(*global_sort_state.sorted_blocks[0]->payload_data, global_sort_state); - for (;;) { - DataChunk result_chunk; - result_chunk.Initialize(Allocator::DefaultAllocator(), info.payload_types); - result_chunk.SetCardinality(0); - scanner.Scan(result_chunk); - if (result_chunk.size() == 0) { - break; - } - - // construct the selection vector with the new order from the result vectors - Vector result_vector(result_chunk.data[0]); - auto result_data = FlatVector::GetData(result_vector); - auto row_count = result_chunk.size(); - - for (idx_t i = 0; i < row_count; i++) { - sel_sorted.set_index(sel_sorted_idx, result_data[i]); - D_ASSERT(result_data[i] < lists_size); - sel_sorted_idx++; - } - } - - D_ASSERT(sel_sorted_idx == incr_payload_count); - if (info.is_grade_up) { - auto &result_entry = ListVector::GetEntry(result); - auto result_data = ListVector::GetData(result); - for (idx_t i = 0; i < count; i++) { - if (!result_validity.RowIsValid(i)) { - continue; - } - for (idx_t j = result_data[i].offset; j < result_data[i].offset + result_data[i].length; j++) { - auto b = sel_sorted.get_index(j) - result_data[i].offset; - result_entry.SetValue(j, Value::BIGINT(UnsafeNumericCast(b + 1))); - } - } - } else { - child_vector.Slice(sel_sorted, sel_sorted_idx); - child_vector.Flatten(sel_sorted_idx); - } - } - - if (args.AllConstant()) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } -} - -static unique_ptr ListSortBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments, OrderType &order, - OrderByNullType &null_order) { - - LogicalType child_type; - if (arguments[0]->return_type == LogicalTypeId::UNKNOWN) { - bound_function.arguments[0] = LogicalTypeId::UNKNOWN; - bound_function.return_type = LogicalType::SQLNULL; - child_type = bound_function.return_type; - return make_uniq(order, null_order, false, bound_function.return_type, child_type, context); - } - - arguments[0] = BoundCastExpression::AddArrayCastToList(context, std::move(arguments[0])); - child_type = ListType::GetChildType(arguments[0]->return_type); - - bound_function.arguments[0] = arguments[0]->return_type; - bound_function.return_type = arguments[0]->return_type; - - return make_uniq(order, null_order, false, bound_function.return_type, child_type, context); -} - -template -static T GetOrder(ClientContext &context, Expression &expr) { - if (!expr.IsFoldable()) { - throw InvalidInputException("Sorting order must be a constant"); - } - Value order_value = ExpressionExecutor::EvaluateScalar(context, expr); - auto order_name = StringUtil::Upper(order_value.ToString()); - return EnumUtil::FromString(order_name.c_str()); -} - -static unique_ptr ListGradeUpBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - - D_ASSERT(!arguments.empty() && arguments.size() <= 3); - auto order = OrderType::ORDER_DEFAULT; - auto null_order = OrderByNullType::ORDER_DEFAULT; - - // get the sorting order - if (arguments.size() >= 2) { - order = GetOrder(context, *arguments[1]); - } - // get the null sorting order - if (arguments.size() == 3) { - null_order = GetOrder(context, *arguments[2]); - } - auto &config = DBConfig::GetConfig(context); - order = config.ResolveOrder(order); - null_order = config.ResolveNullOrder(order, null_order); - - arguments[0] = BoundCastExpression::AddArrayCastToList(context, std::move(arguments[0])); - - bound_function.arguments[0] = arguments[0]->return_type; - bound_function.return_type = LogicalType::LIST(LogicalTypeId::BIGINT); - auto child_type = ListType::GetChildType(arguments[0]->return_type); - return make_uniq(order, null_order, true, bound_function.return_type, child_type, context); -} - -static unique_ptr ListNormalSortBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - D_ASSERT(!arguments.empty() && arguments.size() <= 3); - auto order = OrderType::ORDER_DEFAULT; - auto null_order = OrderByNullType::ORDER_DEFAULT; - - // get the sorting order - if (arguments.size() >= 2) { - order = GetOrder(context, *arguments[1]); - } - // get the null sorting order - if (arguments.size() == 3) { - null_order = GetOrder(context, *arguments[2]); - } - auto &config = DBConfig::GetConfig(context); - order = config.ResolveOrder(order); - null_order = config.ResolveNullOrder(order, null_order); - return ListSortBind(context, bound_function, arguments, order, null_order); -} - -static unique_ptr ListReverseSortBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - auto order = OrderType::ORDER_DEFAULT; - auto null_order = OrderByNullType::ORDER_DEFAULT; - - if (arguments.size() == 2) { - null_order = GetOrder(context, *arguments[1]); - } - auto &config = DBConfig::GetConfig(context); - order = config.ResolveOrder(order); - switch (order) { - case OrderType::ASCENDING: - order = OrderType::DESCENDING; - break; - case OrderType::DESCENDING: - order = OrderType::ASCENDING; - break; - default: - throw InternalException("Unexpected order type in list reverse sort"); - } - null_order = config.ResolveNullOrder(order, null_order); - return ListSortBind(context, bound_function, arguments, order, null_order); -} - -ScalarFunctionSet ListSortFun::GetFunctions() { - // one parameter: list - ScalarFunction sort({LogicalType::LIST(LogicalType::ANY)}, LogicalType::LIST(LogicalType::ANY), ListSortFunction, - ListNormalSortBind); - - // two parameters: list, order - ScalarFunction sort_order({LogicalType::LIST(LogicalType::ANY), LogicalType::VARCHAR}, - LogicalType::LIST(LogicalType::ANY), ListSortFunction, ListNormalSortBind); - - // three parameters: list, order, null order - ScalarFunction sort_orders({LogicalType::LIST(LogicalType::ANY), LogicalType::VARCHAR, LogicalType::VARCHAR}, - LogicalType::LIST(LogicalType::ANY), ListSortFunction, ListNormalSortBind); - - ScalarFunctionSet list_sort; - list_sort.AddFunction(sort); - list_sort.AddFunction(sort_order); - list_sort.AddFunction(sort_orders); - return list_sort; -} - -ScalarFunctionSet ListGradeUpFun::GetFunctions() { - // one parameter: list - ScalarFunction sort({LogicalType::LIST(LogicalType::ANY)}, LogicalType::LIST(LogicalType::ANY), ListSortFunction, - ListGradeUpBind); - - // two parameters: list, order - ScalarFunction sort_order({LogicalType::LIST(LogicalType::ANY), LogicalType::VARCHAR}, - LogicalType::LIST(LogicalType::ANY), ListSortFunction, ListGradeUpBind); - - // three parameters: list, order, null order - ScalarFunction sort_orders({LogicalType::LIST(LogicalType::ANY), LogicalType::VARCHAR, LogicalType::VARCHAR}, - LogicalType::LIST(LogicalType::ANY), ListSortFunction, ListGradeUpBind); - - ScalarFunctionSet list_grade_up; - list_grade_up.AddFunction(sort); - list_grade_up.AddFunction(sort_order); - list_grade_up.AddFunction(sort_orders); - return list_grade_up; -} - -ScalarFunctionSet ListReverseSortFun::GetFunctions() { - // one parameter: list - ScalarFunction sort_reverse({LogicalType::LIST(LogicalType::ANY)}, LogicalType::LIST(LogicalType::ANY), - ListSortFunction, ListReverseSortBind); - - // two parameters: list, null order - ScalarFunction sort_reverse_null_order({LogicalType::LIST(LogicalType::ANY), LogicalType::VARCHAR}, - LogicalType::LIST(LogicalType::ANY), ListSortFunction, ListReverseSortBind); - - ScalarFunctionSet list_reverse_sort; - list_reverse_sort.AddFunction(sort_reverse); - list_reverse_sort.AddFunction(sort_reverse_null_order); - return list_reverse_sort; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/list/list_transform.cpp b/src/duckdb/src/core_functions/scalar/list/list_transform.cpp deleted file mode 100644 index 01f10641e..000000000 --- a/src/duckdb/src/core_functions/scalar/list/list_transform.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "duckdb/core_functions/scalar/list_functions.hpp" - -#include "duckdb/core_functions/lambda_functions.hpp" -#include "duckdb/planner/expression/bound_cast_expression.hpp" - -namespace duckdb { - -static unique_ptr ListTransformBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - - // the list column and the bound lambda expression - D_ASSERT(arguments.size() == 2); - if (arguments[1]->expression_class != ExpressionClass::BOUND_LAMBDA) { - throw BinderException("Invalid lambda expression!"); - } - - arguments[0] = BoundCastExpression::AddArrayCastToList(context, std::move(arguments[0])); - - auto &bound_lambda_expr = arguments[1]->Cast(); - bound_function.return_type = LogicalType::LIST(bound_lambda_expr.lambda_expr->return_type); - auto has_index = bound_lambda_expr.parameter_count == 2; - return LambdaFunctions::ListLambdaBind(context, bound_function, arguments, has_index); -} - -static LogicalType ListTransformBindLambda(const idx_t parameter_idx, const LogicalType &list_child_type) { - return LambdaFunctions::BindBinaryLambda(parameter_idx, list_child_type); -} - -ScalarFunction ListTransformFun::GetFunction() { - ScalarFunction fun({LogicalType::LIST(LogicalType::ANY), LogicalType::LAMBDA}, LogicalType::LIST(LogicalType::ANY), - LambdaFunctions::ListTransformFunction, ListTransformBind, nullptr, nullptr); - - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - fun.serialize = ListLambdaBindData::Serialize; - fun.deserialize = ListLambdaBindData::Deserialize; - fun.bind_lambda = ListTransformBindLambda; - - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/list/list_value.cpp b/src/duckdb/src/core_functions/scalar/list/list_value.cpp deleted file mode 100644 index cc7a5df6f..000000000 --- a/src/duckdb/src/core_functions/scalar/list/list_value.cpp +++ /dev/null @@ -1,203 +0,0 @@ -#include "duckdb/core_functions/scalar/list_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/parser/expression/bound_expression.hpp" -#include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/common/pair.hpp" -#include "duckdb/storage/statistics/list_stats.hpp" -#include "duckdb/planner/expression_binder.hpp" -#include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/parser/query_error_context.hpp" - -namespace duckdb { - -struct ListValueAssign { - template - static T Assign(const T &input, Vector &result) { - return input; - } -}; - -struct ListValueStringAssign { - template - static T Assign(const T &input, Vector &result) { - return StringVector::AddStringOrBlob(result, input); - } -}; - -template -static void TemplatedListValueFunction(DataChunk &args, Vector &result) { - idx_t list_size = args.ColumnCount(); - ListVector::Reserve(result, args.size() * list_size); - auto result_data = FlatVector::GetData(result); - auto &list_child = ListVector::GetEntry(result); - auto child_data = FlatVector::GetData(list_child); - auto &child_validity = FlatVector::Validity(list_child); - - auto unified_format = args.ToUnifiedFormat(); - for (idx_t r = 0; r < args.size(); r++) { - for (idx_t c = 0; c < list_size; c++) { - auto input_idx = unified_format[c].sel->get_index(r); - auto result_idx = r * list_size + c; - auto input_data = UnifiedVectorFormat::GetData(unified_format[c]); - if (unified_format[c].validity.RowIsValid(input_idx)) { - child_data[result_idx] = OP::template Assign(input_data[input_idx], list_child); - } else { - child_validity.SetInvalid(result_idx); - } - } - result_data[r].offset = r * list_size; - result_data[r].length = list_size; - } - ListVector::SetListSize(result, args.size() * list_size); -} - -static void TemplatedListValueFunctionFallback(DataChunk &args, Vector &result) { - auto &child_type = ListType::GetChildType(result.GetType()); - auto result_data = FlatVector::GetData(result); - for (idx_t i = 0; i < args.size(); i++) { - result_data[i].offset = ListVector::GetListSize(result); - for (idx_t col_idx = 0; col_idx < args.ColumnCount(); col_idx++) { - auto val = args.GetValue(col_idx, i).DefaultCastAs(child_type); - ListVector::PushBack(result, val); - } - result_data[i].length = args.ColumnCount(); - } -} - -static void ListValueFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(result.GetType().id() == LogicalTypeId::LIST); - result.SetVectorType(VectorType::CONSTANT_VECTOR); - if (args.ColumnCount() == 0) { - // no columns - early out - result is a constant empty list - auto result_data = FlatVector::GetData(result); - result_data[0].length = 0; - result_data[0].offset = 0; - return; - } - for (idx_t i = 0; i < args.ColumnCount(); i++) { - if (args.data[i].GetVectorType() != VectorType::CONSTANT_VECTOR) { - result.SetVectorType(VectorType::FLAT_VECTOR); - } - } - auto &result_type = ListVector::GetEntry(result).GetType(); - switch (result_type.InternalType()) { - case PhysicalType::BOOL: - case PhysicalType::INT8: - TemplatedListValueFunction(args, result); - break; - case PhysicalType::INT16: - TemplatedListValueFunction(args, result); - break; - case PhysicalType::INT32: - TemplatedListValueFunction(args, result); - break; - case PhysicalType::INT64: - TemplatedListValueFunction(args, result); - break; - case PhysicalType::UINT8: - TemplatedListValueFunction(args, result); - break; - case PhysicalType::UINT16: - TemplatedListValueFunction(args, result); - break; - case PhysicalType::UINT32: - TemplatedListValueFunction(args, result); - break; - case PhysicalType::UINT64: - TemplatedListValueFunction(args, result); - break; - case PhysicalType::INT128: - TemplatedListValueFunction(args, result); - break; - case PhysicalType::UINT128: - TemplatedListValueFunction(args, result); - break; - case PhysicalType::FLOAT: - TemplatedListValueFunction(args, result); - break; - case PhysicalType::DOUBLE: - TemplatedListValueFunction(args, result); - break; - case PhysicalType::INTERVAL: - TemplatedListValueFunction(args, result); - break; - case PhysicalType::VARCHAR: - TemplatedListValueFunction(args, result); - break; - default: { - TemplatedListValueFunctionFallback(args, result); - break; - } - } -} - -template -static unique_ptr ListValueBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - // collect names and deconflict, construct return type - LogicalType child_type = - arguments.empty() ? LogicalType::SQLNULL : ExpressionBinder::GetExpressionReturnType(*arguments[0]); - for (idx_t i = 1; i < arguments.size(); i++) { - auto arg_type = ExpressionBinder::GetExpressionReturnType(*arguments[i]); - if (!LogicalType::TryGetMaxLogicalType(context, child_type, arg_type, child_type)) { - if (IS_UNPIVOT) { - string list_arguments = "Full list: "; - idx_t error_index = list_arguments.size(); - for (idx_t k = 0; k < arguments.size(); k++) { - if (k > 0) { - list_arguments += ", "; - } - if (k == i) { - error_index = list_arguments.size(); - } - list_arguments += arguments[k]->ToString() + " " + arguments[k]->return_type.ToString(); - } - auto error = - StringUtil::Format("Cannot unpivot columns of types %s and %s - an explicit cast is required", - child_type.ToString(), arg_type.ToString()); - throw BinderException(arguments[i]->query_location, - QueryErrorContext::Format(list_arguments, error, error_index, false)); - } else { - throw BinderException(arguments[i]->query_location, - "Cannot create a list of types %s and %s - an explicit cast is required", - child_type.ToString(), arg_type.ToString()); - } - } - } - child_type = LogicalType::NormalizeType(child_type); - - // this is more for completeness reasons - bound_function.varargs = child_type; - bound_function.return_type = LogicalType::LIST(child_type); - return make_uniq(bound_function.return_type); -} - -unique_ptr ListValueStats(ClientContext &context, FunctionStatisticsInput &input) { - auto &child_stats = input.child_stats; - auto &expr = input.expr; - auto list_stats = ListStats::CreateEmpty(expr.return_type); - auto &list_child_stats = ListStats::GetChildStats(list_stats); - for (idx_t i = 0; i < child_stats.size(); i++) { - list_child_stats.Merge(child_stats[i]); - } - return list_stats.ToUnique(); -} - -ScalarFunction ListValueFun::GetFunction() { - // the arguments and return types are actually set in the binder function - ScalarFunction fun("list_value", {}, LogicalTypeId::LIST, ListValueFunction, ListValueBind, nullptr, - ListValueStats); - fun.varargs = LogicalType::ANY; - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return fun; -} - -ScalarFunction UnpivotListFun::GetFunction() { - auto fun = ListValueFun::GetFunction(); - fun.name = "unpivot_list"; - fun.bind = ListValueBind; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/list/range.cpp b/src/duckdb/src/core_functions/scalar/list/range.cpp deleted file mode 100644 index d965eb30d..000000000 --- a/src/duckdb/src/core_functions/scalar/list/range.cpp +++ /dev/null @@ -1,275 +0,0 @@ -#include "duckdb/core_functions/scalar/list_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/common/types/vector.hpp" -#include "duckdb/common/types/timestamp.hpp" - -namespace duckdb { - -struct NumericRangeInfo { - using TYPE = int64_t; - using INCREMENT_TYPE = int64_t; - - static int64_t DefaultStart() { - return 0; - } - static int64_t DefaultIncrement() { - return 1; - } - - static uint64_t ListLength(int64_t start_value, int64_t end_value, int64_t increment_value, bool inclusive_bound) { - if (increment_value == 0) { - return 0; - } - if (start_value > end_value && increment_value > 0) { - return 0; - } - if (start_value < end_value && increment_value < 0) { - return 0; - } - hugeint_t total_diff = AbsValue(hugeint_t(end_value) - hugeint_t(start_value)); - hugeint_t increment = AbsValue(hugeint_t(increment_value)); - hugeint_t total_values = total_diff / increment; - if (total_diff % increment == 0) { - if (inclusive_bound) { - total_values += 1; - } - } else { - total_values += 1; - } - if (total_values > NumericLimits::Maximum()) { - throw InvalidInputException("Lists larger than 2^32 elements are not supported"); - } - return Hugeint::Cast(total_values); - } - - static void Increment(int64_t &input, int64_t increment) { - input += increment; - } -}; -struct TimestampRangeInfo { - using TYPE = timestamp_t; - using INCREMENT_TYPE = interval_t; - - static timestamp_t DefaultStart() { - throw InternalException("Default start not implemented for timestamp range"); - } - static interval_t DefaultIncrement() { - throw InternalException("Default increment not implemented for timestamp range"); - } - static uint64_t ListLength(timestamp_t start_value, timestamp_t end_value, interval_t increment_value, - bool inclusive_bound) { - bool is_positive = increment_value.months > 0 || increment_value.days > 0 || increment_value.micros > 0; - bool is_negative = increment_value.months < 0 || increment_value.days < 0 || increment_value.micros < 0; - if (!is_negative && !is_positive) { - // interval is 0: no result - return 0; - } - // We don't allow infinite bounds because they generate errors or infinite loops - if (!Timestamp::IsFinite(start_value) || !Timestamp::IsFinite(end_value)) { - throw InvalidInputException("Interval infinite bounds not supported"); - } - - if (is_negative && is_positive) { - // we don't allow a mix of - throw InvalidInputException("Interval with mix of negative/positive entries not supported"); - } - if (start_value > end_value && is_positive) { - return 0; - } - if (start_value < end_value && is_negative) { - return 0; - } - uint64_t total_values = 0; - if (is_negative) { - // negative interval, start_value is going down - while (inclusive_bound ? start_value >= end_value : start_value > end_value) { - start_value = Interval::Add(start_value, increment_value); - total_values++; - if (total_values > NumericLimits::Maximum()) { - throw InvalidInputException("Lists larger than 2^32 elements are not supported"); - } - } - } else { - // positive interval, start_value is going up - while (inclusive_bound ? start_value <= end_value : start_value < end_value) { - start_value = Interval::Add(start_value, increment_value); - total_values++; - if (total_values > NumericLimits::Maximum()) { - throw InvalidInputException("Lists larger than 2^32 elements are not supported"); - } - } - } - return total_values; - } - - static void Increment(timestamp_t &input, interval_t increment) { - input = Interval::Add(input, increment); - } -}; - -template -class RangeInfoStruct { -public: - explicit RangeInfoStruct(DataChunk &args_p) : args(args_p) { - switch (args.ColumnCount()) { - case 1: - args.data[0].ToUnifiedFormat(args.size(), vdata[0]); - break; - case 2: - args.data[0].ToUnifiedFormat(args.size(), vdata[0]); - args.data[1].ToUnifiedFormat(args.size(), vdata[1]); - break; - case 3: - args.data[0].ToUnifiedFormat(args.size(), vdata[0]); - args.data[1].ToUnifiedFormat(args.size(), vdata[1]); - args.data[2].ToUnifiedFormat(args.size(), vdata[2]); - break; - default: - throw InternalException("Unsupported number of parameters for range"); - } - } - - bool RowIsValid(idx_t row_idx) { - for (idx_t i = 0; i < args.ColumnCount(); i++) { - auto idx = vdata[i].sel->get_index(row_idx); - if (!vdata[i].validity.RowIsValid(idx)) { - return false; - } - } - return true; - } - - typename OP::TYPE StartListValue(idx_t row_idx) { - if (args.ColumnCount() == 1) { - return OP::DefaultStart(); - } else { - auto data = (typename OP::TYPE *)vdata[0].data; - auto idx = vdata[0].sel->get_index(row_idx); - return data[idx]; - } - } - - typename OP::TYPE EndListValue(idx_t row_idx) { - idx_t vdata_idx = args.ColumnCount() == 1 ? 0 : 1; - auto data = (typename OP::TYPE *)vdata[vdata_idx].data; - auto idx = vdata[vdata_idx].sel->get_index(row_idx); - return data[idx]; - } - - typename OP::INCREMENT_TYPE ListIncrementValue(idx_t row_idx) { - if (args.ColumnCount() < 3) { - return OP::DefaultIncrement(); - } else { - auto data = (typename OP::INCREMENT_TYPE *)vdata[2].data; - auto idx = vdata[2].sel->get_index(row_idx); - return data[idx]; - } - } - - void GetListValues(idx_t row_idx, typename OP::TYPE &start_value, typename OP::TYPE &end_value, - typename OP::INCREMENT_TYPE &increment_value) { - start_value = StartListValue(row_idx); - end_value = EndListValue(row_idx); - increment_value = ListIncrementValue(row_idx); - } - - uint64_t ListLength(idx_t row_idx) { - typename OP::TYPE start_value; - typename OP::TYPE end_value; - typename OP::INCREMENT_TYPE increment_value; - GetListValues(row_idx, start_value, end_value, increment_value); - return OP::ListLength(start_value, end_value, increment_value, INCLUSIVE_BOUND); - } - -private: - DataChunk &args; - UnifiedVectorFormat vdata[3]; -}; - -template -static void ListRangeFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(result.GetType().id() == LogicalTypeId::LIST); - - RangeInfoStruct info(args); - idx_t args_size = 1; - auto result_type = VectorType::CONSTANT_VECTOR; - for (idx_t i = 0; i < args.ColumnCount(); i++) { - if (args.data[i].GetVectorType() != VectorType::CONSTANT_VECTOR) { - args_size = args.size(); - result_type = VectorType::FLAT_VECTOR; - break; - } - } - auto list_data = FlatVector::GetData(result); - auto &result_validity = FlatVector::Validity(result); - uint64_t total_size = 0; - for (idx_t i = 0; i < args_size; i++) { - if (!info.RowIsValid(i)) { - result_validity.SetInvalid(i); - list_data[i].offset = total_size; - list_data[i].length = 0; - } else { - list_data[i].offset = total_size; - list_data[i].length = info.ListLength(i); - total_size += list_data[i].length; - } - } - - // now construct the child vector of the list - ListVector::Reserve(result, total_size); - auto range_data = FlatVector::GetData(ListVector::GetEntry(result)); - idx_t total_idx = 0; - for (idx_t i = 0; i < args_size; i++) { - typename OP::TYPE start_value = info.StartListValue(i); - typename OP::INCREMENT_TYPE increment = info.ListIncrementValue(i); - - typename OP::TYPE range_value = start_value; - for (idx_t range_idx = 0; range_idx < list_data[i].length; range_idx++) { - if (range_idx > 0) { - OP::Increment(range_value, increment); - } - range_data[total_idx++] = range_value; - } - } - - ListVector::SetListSize(result, total_size); - result.SetVectorType(result_type); - - result.Verify(args.size()); -} - -ScalarFunctionSet ListRangeFun::GetFunctions() { - // the arguments and return types are actually set in the binder function - ScalarFunctionSet range_set; - range_set.AddFunction(ScalarFunction({LogicalType::BIGINT}, LogicalType::LIST(LogicalType::BIGINT), - ListRangeFunction)); - range_set.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT}, - LogicalType::LIST(LogicalType::BIGINT), - ListRangeFunction)); - range_set.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT, LogicalType::BIGINT}, - LogicalType::LIST(LogicalType::BIGINT), - ListRangeFunction)); - range_set.AddFunction(ScalarFunction({LogicalType::TIMESTAMP, LogicalType::TIMESTAMP, LogicalType::INTERVAL}, - LogicalType::LIST(LogicalType::TIMESTAMP), - ListRangeFunction)); - return range_set; -} - -ScalarFunctionSet GenerateSeriesFun::GetFunctions() { - ScalarFunctionSet generate_series; - generate_series.AddFunction(ScalarFunction({LogicalType::BIGINT}, LogicalType::LIST(LogicalType::BIGINT), - ListRangeFunction)); - generate_series.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT}, - LogicalType::LIST(LogicalType::BIGINT), - ListRangeFunction)); - generate_series.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT, LogicalType::BIGINT}, - LogicalType::LIST(LogicalType::BIGINT), - ListRangeFunction)); - generate_series.AddFunction(ScalarFunction({LogicalType::TIMESTAMP, LogicalType::TIMESTAMP, LogicalType::INTERVAL}, - LogicalType::LIST(LogicalType::TIMESTAMP), - ListRangeFunction)); - return generate_series; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/map/cardinality.cpp b/src/duckdb/src/core_functions/scalar/map/cardinality.cpp deleted file mode 100644 index 8bf0dbd11..000000000 --- a/src/duckdb/src/core_functions/scalar/map/cardinality.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "duckdb/core_functions/scalar/map_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/parser/expression/bound_expression.hpp" -#include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/function/scalar/nested_functions.hpp" - -namespace duckdb { - -static void CardinalityFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &map = args.data[0]; - UnifiedVectorFormat map_data; - result.SetVectorType(VectorType::FLAT_VECTOR); - auto result_data = FlatVector::GetData(result); - auto &result_validity = FlatVector::Validity(result); - - map.ToUnifiedFormat(args.size(), map_data); - for (idx_t row = 0; row < args.size(); row++) { - auto list_entry = UnifiedVectorFormat::GetData(map_data)[map_data.sel->get_index(row)]; - result_data[row] = list_entry.length; - result_validity.Set(row, map_data.validity.RowIsValid(map_data.sel->get_index(row))); - } - - if (args.size() == 1) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } -} - -static unique_ptr CardinalityBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - if (arguments.size() != 1) { - throw BinderException("Cardinality must have exactly one arguments"); - } - - if (arguments[0]->return_type.id() != LogicalTypeId::MAP) { - throw BinderException("Cardinality can only operate on MAPs"); - } - - bound_function.return_type = LogicalType::UBIGINT; - return make_uniq(bound_function.return_type); -} - -ScalarFunction CardinalityFun::GetFunction() { - ScalarFunction fun({LogicalType::ANY}, LogicalType::UBIGINT, CardinalityFunction, CardinalityBind); - fun.varargs = LogicalType::ANY; - fun.null_handling = FunctionNullHandling::DEFAULT_NULL_HANDLING; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/map/map.cpp b/src/duckdb/src/core_functions/scalar/map/map.cpp deleted file mode 100644 index ab67475d1..000000000 --- a/src/duckdb/src/core_functions/scalar/map/map.cpp +++ /dev/null @@ -1,222 +0,0 @@ -#include "duckdb/core_functions/scalar/map_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/parser/expression/bound_expression.hpp" -#include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/common/pair.hpp" -#include "duckdb/common/types/value_map.hpp" -#include "duckdb/function/scalar/nested_functions.hpp" - -namespace duckdb { - -static void MapFunctionEmptyInput(Vector &result, const idx_t row_count) { - - // if no chunk is set in ExpressionExecutor::ExecuteExpression (args.data.empty(), e.g., - // in SELECT MAP()), then we always pass a row_count of 1 - result.SetVectorType(VectorType::CONSTANT_VECTOR); - ListVector::SetListSize(result, 0); - - auto result_data = ListVector::GetData(result); - result_data[0] = list_entry_t(); - result.Verify(row_count); -} - -static bool MapIsNull(DataChunk &chunk) { - if (chunk.data.empty()) { - return false; - } - D_ASSERT(chunk.data.size() == 2); - auto &keys = chunk.data[0]; - auto &values = chunk.data[1]; - - if (keys.GetType().id() == LogicalTypeId::SQLNULL) { - return true; - } - if (values.GetType().id() == LogicalTypeId::SQLNULL) { - return true; - } - return false; -} - -static void MapFunction(DataChunk &args, ExpressionState &, Vector &result) { - - // internal MAP representation - // - LIST-vector that contains STRUCTs as child entries - // - STRUCTs have exactly two fields, a key-field, and a value-field - // - key names are unique - D_ASSERT(result.GetType().id() == LogicalTypeId::MAP); - - if (MapIsNull(args)) { - auto &validity = FlatVector::Validity(result); - validity.SetInvalid(0); - result.SetVectorType(VectorType::CONSTANT_VECTOR); - return; - } - - auto row_count = args.size(); - - // early-out, if no data - if (args.data.empty()) { - return MapFunctionEmptyInput(result, row_count); - } - - auto &keys = args.data[0]; - auto &values = args.data[1]; - - // a LIST vector, where each row contains a LIST of KEYS - UnifiedVectorFormat keys_data; - keys.ToUnifiedFormat(row_count, keys_data); - auto keys_entries = UnifiedVectorFormat::GetData(keys_data); - - // the KEYs child vector - auto keys_child_vector = ListVector::GetEntry(keys); - UnifiedVectorFormat keys_child_data; - keys_child_vector.ToUnifiedFormat(ListVector::GetListSize(keys), keys_child_data); - - // a LIST vector, where each row contains a LIST of VALUES - UnifiedVectorFormat values_data; - values.ToUnifiedFormat(row_count, values_data); - auto values_entries = UnifiedVectorFormat::GetData(values_data); - - // the VALUEs child vector - auto values_child_vector = ListVector::GetEntry(values); - UnifiedVectorFormat values_child_data; - values_child_vector.ToUnifiedFormat(ListVector::GetListSize(values), values_child_data); - - // a LIST vector, where each row contains a MAP (LIST of STRUCTs) - UnifiedVectorFormat result_data; - result.ToUnifiedFormat(row_count, result_data); - auto result_entries = UnifiedVectorFormat::GetDataNoConst(result_data); - - auto &result_validity = FlatVector::Validity(result); - - // get the resulting size of the key/value child lists - idx_t result_child_size = 0; - for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { - auto keys_idx = keys_data.sel->get_index(row_idx); - auto values_idx = values_data.sel->get_index(row_idx); - if (!keys_data.validity.RowIsValid(keys_idx) || !values_data.validity.RowIsValid(values_idx)) { - continue; - } - auto keys_entry = keys_entries[keys_idx]; - result_child_size += keys_entry.length; - } - - // we need to slice potential non-flat vectors - SelectionVector sel_keys(result_child_size); - SelectionVector sel_values(result_child_size); - idx_t offset = 0; - - for (idx_t row_idx = 0; row_idx < row_count; row_idx++) { - - auto keys_idx = keys_data.sel->get_index(row_idx); - auto values_idx = values_data.sel->get_index(row_idx); - auto result_idx = result_data.sel->get_index(row_idx); - - // NULL MAP - if (!keys_data.validity.RowIsValid(keys_idx) || !values_data.validity.RowIsValid(values_idx)) { - result_validity.SetInvalid(row_idx); - continue; - } - - auto keys_entry = keys_entries[keys_idx]; - auto values_entry = values_entries[values_idx]; - - if (keys_entry.length != values_entry.length) { - MapVector::EvalMapInvalidReason(MapInvalidReason::NOT_ALIGNED); - } - - // set the selection vectors and perform a duplicate key check - value_set_t unique_keys; - for (idx_t child_idx = 0; child_idx < keys_entry.length; child_idx++) { - - auto key_idx = keys_child_data.sel->get_index(keys_entry.offset + child_idx); - auto value_idx = values_child_data.sel->get_index(values_entry.offset + child_idx); - - // NULL check - if (!keys_child_data.validity.RowIsValid(key_idx)) { - MapVector::EvalMapInvalidReason(MapInvalidReason::NULL_KEY); - } - - // unique check - auto value = keys_child_vector.GetValue(key_idx); - auto unique = unique_keys.insert(value).second; - if (!unique) { - MapVector::EvalMapInvalidReason(MapInvalidReason::DUPLICATE_KEY); - } - - // set selection vectors - sel_keys.set_index(offset + child_idx, key_idx); - sel_values.set_index(offset + child_idx, value_idx); - } - - // keys_entry and values_entry have the same length - result_entries[result_idx].length = keys_entry.length; - result_entries[result_idx].offset = offset; - offset += keys_entry.length; - } - D_ASSERT(offset == result_child_size); - - auto &result_key_vector = MapVector::GetKeys(result); - auto &result_value_vector = MapVector::GetValues(result); - - ListVector::SetListSize(result, offset); - result_key_vector.Slice(keys_child_vector, sel_keys, offset); - result_key_vector.Flatten(offset); - result_value_vector.Slice(values_child_vector, sel_values, offset); - result_value_vector.Flatten(offset); - - if (args.AllConstant()) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } - result.Verify(row_count); -} - -static unique_ptr MapBind(ClientContext &, ScalarFunction &bound_function, - vector> &arguments) { - - if (arguments.size() != 2 && !arguments.empty()) { - MapVector::EvalMapInvalidReason(MapInvalidReason::INVALID_PARAMS); - } - - bool is_null = false; - if (arguments.empty()) { - is_null = true; - } - if (!is_null) { - auto key_id = arguments[0]->return_type.id(); - auto value_id = arguments[1]->return_type.id(); - if (key_id == LogicalTypeId::SQLNULL || value_id == LogicalTypeId::SQLNULL) { - is_null = true; - } - } - - if (is_null) { - bound_function.return_type = LogicalType::MAP(LogicalTypeId::SQLNULL, LogicalTypeId::SQLNULL); - return make_uniq(bound_function.return_type); - } - - // bind a MAP with key-value pairs - D_ASSERT(arguments.size() == 2); - if (arguments[0]->return_type.id() != LogicalTypeId::LIST) { - MapVector::EvalMapInvalidReason(MapInvalidReason::INVALID_PARAMS); - } - if (arguments[1]->return_type.id() != LogicalTypeId::LIST) { - MapVector::EvalMapInvalidReason(MapInvalidReason::INVALID_PARAMS); - } - - auto key_type = ListType::GetChildType(arguments[0]->return_type); - auto value_type = ListType::GetChildType(arguments[1]->return_type); - - bound_function.return_type = LogicalType::MAP(key_type, value_type); - return make_uniq(bound_function.return_type); -} - -ScalarFunction MapFun::GetFunction() { - ScalarFunction fun({}, LogicalTypeId::MAP, MapFunction, MapBind); - fun.varargs = LogicalType::ANY; - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/map/map_concat.cpp b/src/duckdb/src/core_functions/scalar/map/map_concat.cpp deleted file mode 100644 index b3ffc1740..000000000 --- a/src/duckdb/src/core_functions/scalar/map/map_concat.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/parser/expression/bound_expression.hpp" -#include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/common/pair.hpp" -#include "duckdb/common/types.hpp" -#include "duckdb/common/unordered_map.hpp" -#include "duckdb/core_functions/scalar/map_functions.hpp" - -namespace duckdb { - -namespace { - -struct MapKeyIndexPair { - MapKeyIndexPair(idx_t map, idx_t key) : map_index(map), key_index(key) { - } - // The index of the map that this key comes from - idx_t map_index; - // The index within the maps key_list - idx_t key_index; -}; - -} // namespace - -vector GetListEntries(vector keys, vector values) { - D_ASSERT(keys.size() == values.size()); - vector entries; - for (idx_t i = 0; i < keys.size(); i++) { - child_list_t children; - children.emplace_back(make_pair("key", std::move(keys[i]))); - children.emplace_back(make_pair("value", std::move(values[i]))); - entries.push_back(Value::STRUCT(std::move(children))); - } - return entries; -} - -static void MapConcatFunction(DataChunk &args, ExpressionState &state, Vector &result) { - if (result.GetType().id() == LogicalTypeId::SQLNULL) { - // All inputs are NULL, just return NULL - auto &validity = FlatVector::Validity(result); - validity.SetInvalid(0); - result.SetVectorType(VectorType::CONSTANT_VECTOR); - return; - } - D_ASSERT(result.GetType().id() == LogicalTypeId::MAP); - auto count = args.size(); - - auto map_count = args.ColumnCount(); - vector map_formats(map_count); - for (idx_t i = 0; i < map_count; i++) { - auto &map = args.data[i]; - map.ToUnifiedFormat(count, map_formats[i]); - } - auto result_data = FlatVector::GetData(result); - - for (idx_t i = 0; i < count; i++) { - // Loop through all the maps per list - // we cant do better because all the entries of the child vector have to be contiguous - // so we cant start the next row before we have finished the one before it - auto &result_entry = result_data[i]; - vector index_to_map; - vector keys_list; - bool all_null = true; - for (idx_t map_idx = 0; map_idx < map_count; map_idx++) { - if (args.data[map_idx].GetType().id() == LogicalTypeId::SQLNULL) { - continue; - } - - auto &map_format = map_formats[map_idx]; - auto index = map_format.sel->get_index(i); - if (!map_format.validity.RowIsValid(index)) { - continue; - } - - all_null = false; - auto &keys = MapVector::GetKeys(args.data[map_idx]); - auto entry = UnifiedVectorFormat::GetData(map_format)[index]; - - // Update the list for this row - for (idx_t list_idx = 0; list_idx < entry.length; list_idx++) { - auto key_index = entry.offset + list_idx; - auto key = keys.GetValue(key_index); - auto entry = std::find(keys_list.begin(), keys_list.end(), key); - if (entry == keys_list.end()) { - // Result list does not contain this value yet - keys_list.push_back(key); - index_to_map.emplace_back(map_idx, key_index); - } else { - // Result list already contains this, update where to find the value at - auto distance = std::distance(keys_list.begin(), entry); - auto &mapping = *(index_to_map.begin() + distance); - mapping.key_index = key_index; - mapping.map_index = map_idx; - } - } - } - - result_entry.offset = ListVector::GetListSize(result); - result_entry.length = keys_list.size(); - if (all_null) { - D_ASSERT(keys_list.empty() && index_to_map.empty()); - FlatVector::SetNull(result, i, true); - continue; - } - - vector values_list; - D_ASSERT(keys_list.size() == index_to_map.size()); - // Get the values from the mapping - for (auto &mapping : index_to_map) { - auto &map = args.data[mapping.map_index]; - auto &values = MapVector::GetValues(map); - values_list.push_back(values.GetValue(mapping.key_index)); - } - D_ASSERT(values_list.size() == keys_list.size()); - auto list_entries = GetListEntries(std::move(keys_list), std::move(values_list)); - for (auto &list_entry : list_entries) { - ListVector::PushBack(result, list_entry); - } - } - - if (args.AllConstant()) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } - result.Verify(count); -} - -static bool IsEmptyMap(const LogicalType &map) { - D_ASSERT(map.id() == LogicalTypeId::MAP); - auto &key_type = MapType::KeyType(map); - auto &value_type = MapType::ValueType(map); - return key_type.id() == LogicalType::SQLNULL && value_type.id() == LogicalType::SQLNULL; -} - -static unique_ptr MapConcatBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - - auto arg_count = arguments.size(); - if (arg_count < 2) { - throw InvalidInputException("The provided amount of arguments is incorrect, please provide 2 or more maps"); - } - - if (arguments[0]->return_type.id() == LogicalTypeId::UNKNOWN) { - // Prepared statement - bound_function.arguments.emplace_back(LogicalTypeId::UNKNOWN); - bound_function.return_type = LogicalType(LogicalTypeId::SQLNULL); - return nullptr; - } - - LogicalType expected = LogicalType::SQLNULL; - - bool is_null = true; - // Check and verify that all the maps are of the same type - for (idx_t i = 0; i < arg_count; i++) { - auto &arg = arguments[i]; - auto &map = arg->return_type; - if (map.id() == LogicalTypeId::UNKNOWN) { - // Prepared statement - bound_function.arguments.emplace_back(LogicalTypeId::UNKNOWN); - bound_function.return_type = LogicalType(LogicalTypeId::SQLNULL); - return nullptr; - } - if (map.id() == LogicalTypeId::SQLNULL) { - // The maps are allowed to be NULL - continue; - } - if (map.id() != LogicalTypeId::MAP) { - throw InvalidInputException("MAP_CONCAT only takes map arguments"); - } - is_null = false; - if (IsEmptyMap(map)) { - // Map is allowed to be empty - continue; - } - - if (expected.id() == LogicalTypeId::SQLNULL) { - expected = map; - } else if (map != expected) { - throw InvalidInputException( - "'value' type of map differs between arguments, expected '%s', found '%s' instead", expected.ToString(), - map.ToString()); - } - } - - if (expected.id() == LogicalTypeId::SQLNULL && is_null == false) { - expected = LogicalType::MAP(LogicalType::SQLNULL, LogicalType::SQLNULL); - } - bound_function.return_type = expected; - return make_uniq(bound_function.return_type); -} - -ScalarFunction MapConcatFun::GetFunction() { - //! the arguments and return types are actually set in the binder function - ScalarFunction fun("map_concat", {}, LogicalTypeId::LIST, MapConcatFunction, MapConcatBind); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - fun.varargs = LogicalType::ANY; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/map/map_entries.cpp b/src/duckdb/src/core_functions/scalar/map/map_entries.cpp deleted file mode 100644 index 47e653993..000000000 --- a/src/duckdb/src/core_functions/scalar/map/map_entries.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "duckdb/core_functions/scalar/map_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/parser/expression/bound_expression.hpp" -#include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/common/pair.hpp" -#include "duckdb/function/scalar/nested_functions.hpp" - -namespace duckdb { - -// Reverse of map_from_entries -static void MapEntriesFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto count = args.size(); - - auto &map = args.data[0]; - if (map.GetType().id() == LogicalTypeId::SQLNULL) { - // Input is a constant NULL - result.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(result, true); - return; - } - - MapUtil::ReinterpretMap(result, map, count); - - if (args.AllConstant()) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } - result.Verify(count); -} - -static LogicalType CreateReturnType(const LogicalType &map) { - auto &key_type = MapType::KeyType(map); - auto &value_type = MapType::ValueType(map); - - child_list_t child_types; - child_types.push_back(make_pair("key", key_type)); - child_types.push_back(make_pair("value", value_type)); - - auto row_type = LogicalType::STRUCT(child_types); - return LogicalType::LIST(row_type); -} - -static unique_ptr MapEntriesBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - if (arguments.size() != 1) { - throw InvalidInputException("Too many arguments provided, only expecting a single map"); - } - auto &map = arguments[0]->return_type; - - if (map.id() == LogicalTypeId::UNKNOWN) { - // Prepared statement - bound_function.arguments.emplace_back(LogicalTypeId::UNKNOWN); - bound_function.return_type = LogicalType(LogicalTypeId::SQLNULL); - return nullptr; - } - - if (map.id() == LogicalTypeId::SQLNULL) { - // Input is NULL, output is STRUCT(NULL, NULL)[] - auto map_type = LogicalType::MAP(LogicalTypeId::SQLNULL, LogicalTypeId::SQLNULL); - bound_function.return_type = CreateReturnType(map_type); - return make_uniq(bound_function.return_type); - } - - if (map.id() != LogicalTypeId::MAP) { - throw InvalidInputException("The provided argument is not a map"); - } - bound_function.return_type = CreateReturnType(map); - return make_uniq(bound_function.return_type); -} - -ScalarFunction MapEntriesFun::GetFunction() { - //! the arguments and return types are actually set in the binder function - ScalarFunction fun({}, LogicalTypeId::LIST, MapEntriesFunction, MapEntriesBind); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - fun.varargs = LogicalType::ANY; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/map/map_extract.cpp b/src/duckdb/src/core_functions/scalar/map/map_extract.cpp deleted file mode 100644 index 79056cd0b..000000000 --- a/src/duckdb/src/core_functions/scalar/map/map_extract.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "duckdb/core_functions/scalar/map_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/parser/expression/bound_expression.hpp" -#include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/function/scalar/list/contains_or_position.hpp" -namespace duckdb { - -static unique_ptr MapExtractBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - if (arguments.size() != 2) { - throw BinderException("MAP_EXTRACT must have exactly two arguments"); - } - - auto &map_type = arguments[0]->return_type; - auto &input_type = arguments[1]->return_type; - - if (map_type.id() == LogicalTypeId::SQLNULL) { - bound_function.return_type = LogicalType::LIST(LogicalTypeId::SQLNULL); - return make_uniq(bound_function.return_type); - } - - if (map_type.id() != LogicalTypeId::MAP) { - throw BinderException("MAP_EXTRACT can only operate on MAPs"); - } - auto &value_type = MapType::ValueType(map_type); - - //! Here we have to construct the List Type that will be returned - bound_function.return_type = LogicalType::LIST(value_type); - auto key_type = MapType::KeyType(map_type); - if (key_type.id() != LogicalTypeId::SQLNULL && input_type.id() != LogicalTypeId::SQLNULL) { - bound_function.arguments[1] = MapType::KeyType(map_type); - } - return make_uniq(bound_function.return_type); -} - -static void MapExtractFunc(DataChunk &args, ExpressionState &state, Vector &result) { - const auto count = args.size(); - - auto &map_vec = args.data[0]; - auto &arg_vec = args.data[1]; - - const auto map_is_null = map_vec.GetType().id() == LogicalTypeId::SQLNULL; - const auto arg_is_null = arg_vec.GetType().id() == LogicalTypeId::SQLNULL; - - if (map_is_null || arg_is_null) { - // Short-circuit if either the map or the arg is NULL - ListVector::SetListSize(result, 0); - result.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::GetData(result)[0] = {0, 0}; - result.Verify(count); - return; - } - - auto &key_vec = MapVector::GetKeys(map_vec); - auto &val_vec = MapVector::GetValues(map_vec); - - // Collect the matching positions - Vector pos_vec(LogicalType::INTEGER, count); - ListSearchOp(map_vec, key_vec, arg_vec, pos_vec, args.size()); - - UnifiedVectorFormat val_format; - UnifiedVectorFormat pos_format; - UnifiedVectorFormat lst_format; - - val_vec.ToUnifiedFormat(ListVector::GetListSize(map_vec), val_format); - pos_vec.ToUnifiedFormat(count, pos_format); - map_vec.ToUnifiedFormat(count, lst_format); - - const auto pos_data = UnifiedVectorFormat::GetData(pos_format); - const auto inc_list_data = ListVector::GetData(map_vec); - const auto out_list_data = ListVector::GetData(result); - - idx_t offset = 0; - for (idx_t row_idx = 0; row_idx < count; row_idx++) { - auto lst_idx = lst_format.sel->get_index(row_idx); - if (!lst_format.validity.RowIsValid(lst_idx)) { - FlatVector::SetNull(result, row_idx, true); - continue; - } - - auto &inc_list = inc_list_data[lst_idx]; - auto &out_list = out_list_data[row_idx]; - - const auto pos_idx = pos_format.sel->get_index(row_idx); - if (!pos_format.validity.RowIsValid(pos_idx)) { - // We didnt find the key in the map, so return an empty list - out_list.offset = offset; - out_list.length = 0; - continue; - } - - // Compute the actual position of the value in the map value vector - const auto pos = inc_list.offset + UnsafeNumericCast(pos_data[pos_idx] - 1); - out_list.offset = offset; - out_list.length = 1; - ListVector::Append(result, val_vec, pos + 1, pos); - offset++; - } - - if (args.size() == 1) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } - - result.Verify(count); -} - -ScalarFunction MapExtractFun::GetFunction() { - ScalarFunction fun({LogicalType::ANY, LogicalType::ANY}, LogicalType::ANY, MapExtractFunc, MapExtractBind); - fun.varargs = LogicalType::ANY; - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/map/map_from_entries.cpp b/src/duckdb/src/core_functions/scalar/map/map_from_entries.cpp deleted file mode 100644 index fbaf1663d..000000000 --- a/src/duckdb/src/core_functions/scalar/map/map_from_entries.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "duckdb/core_functions/scalar/map_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/parser/expression/bound_expression.hpp" -#include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/function/scalar/nested_functions.hpp" - -namespace duckdb { - -static void MapFromEntriesFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto count = args.size(); - - MapUtil::ReinterpretMap(result, args.data[0], count); - MapVector::MapConversionVerify(result, count); - result.Verify(count); - - if (args.AllConstant()) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } -} - -static unique_ptr MapFromEntriesBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - if (arguments.size() != 1) { - throw InvalidInputException("The input argument must be a list of structs."); - } - auto &list = arguments[0]->return_type; - - if (list.id() == LogicalTypeId::UNKNOWN) { - bound_function.arguments.emplace_back(LogicalTypeId::UNKNOWN); - bound_function.return_type = LogicalType(LogicalTypeId::SQLNULL); - return nullptr; - } - - if (list.id() != LogicalTypeId::LIST) { - throw InvalidInputException("The provided argument is not a list of structs"); - } - auto &elem_type = ListType::GetChildType(list); - if (elem_type.id() != LogicalTypeId::STRUCT) { - throw InvalidInputException("The elements of the list must be structs"); - } - auto &children = StructType::GetChildTypes(elem_type); - if (children.size() != 2) { - throw InvalidInputException("The provided struct type should only contain 2 fields, a key and a value"); - } - - bound_function.return_type = LogicalType::MAP(elem_type); - return make_uniq(bound_function.return_type); -} - -ScalarFunction MapFromEntriesFun::GetFunction() { - //! the arguments and return types are actually set in the binder function - ScalarFunction fun({}, LogicalTypeId::MAP, MapFromEntriesFunction, MapFromEntriesBind); - fun.null_handling = FunctionNullHandling::DEFAULT_NULL_HANDLING; - fun.varargs = LogicalType::ANY; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/map/map_keys_values.cpp b/src/duckdb/src/core_functions/scalar/map/map_keys_values.cpp deleted file mode 100644 index c5578895d..000000000 --- a/src/duckdb/src/core_functions/scalar/map/map_keys_values.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "duckdb/core_functions/scalar/map_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/parser/expression/bound_expression.hpp" -#include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/common/pair.hpp" -#include "duckdb/function/scalar/nested_functions.hpp" - -namespace duckdb { - -static void MapKeyValueFunction(DataChunk &args, ExpressionState &state, Vector &result, - Vector &(*get_child_vector)(Vector &)) { - auto &map = args.data[0]; - - D_ASSERT(result.GetType().id() == LogicalTypeId::LIST); - if (map.GetType().id() == LogicalTypeId::SQLNULL) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(result, true); - return; - } - - auto count = args.size(); - D_ASSERT(map.GetType().id() == LogicalTypeId::MAP); - auto child = get_child_vector(map); - - auto &entries = ListVector::GetEntry(result); - entries.Reference(child); - - UnifiedVectorFormat map_data; - map.ToUnifiedFormat(count, map_data); - - D_ASSERT(result.GetVectorType() == VectorType::FLAT_VECTOR); - FlatVector::SetData(result, map_data.data); - FlatVector::SetValidity(result, map_data.validity); - auto list_size = ListVector::GetListSize(map); - ListVector::SetListSize(result, list_size); - if (map.GetVectorType() == VectorType::DICTIONARY_VECTOR) { - result.Slice(*map_data.sel, count); - } - if (args.AllConstant()) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } - result.Verify(count); -} - -static void MapKeysFunction(DataChunk &args, ExpressionState &state, Vector &result) { - MapKeyValueFunction(args, state, result, MapVector::GetKeys); -} - -static void MapValuesFunction(DataChunk &args, ExpressionState &state, Vector &result) { - MapKeyValueFunction(args, state, result, MapVector::GetValues); -} - -static unique_ptr MapKeyValueBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments, - const LogicalType &(*type_func)(const LogicalType &)) { - if (arguments.size() != 1) { - throw InvalidInputException("Too many arguments provided, only expecting a single map"); - } - auto &map = arguments[0]->return_type; - - if (map.id() == LogicalTypeId::UNKNOWN) { - // Prepared statement - bound_function.arguments.emplace_back(LogicalTypeId::UNKNOWN); - bound_function.return_type = LogicalType(LogicalTypeId::SQLNULL); - return nullptr; - } - - if (map.id() == LogicalTypeId::SQLNULL) { - // Input is NULL, output is NULL[] - bound_function.return_type = LogicalType::LIST(LogicalTypeId::SQLNULL); - return make_uniq(bound_function.return_type); - } - - if (map.id() != LogicalTypeId::MAP) { - throw InvalidInputException("The provided argument is not a map"); - } - - auto &type = type_func(map); - - bound_function.return_type = LogicalType::LIST(type); - return make_uniq(bound_function.return_type); -} - -static unique_ptr MapKeysBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - return MapKeyValueBind(context, bound_function, arguments, MapType::KeyType); -} - -static unique_ptr MapValuesBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - return MapKeyValueBind(context, bound_function, arguments, MapType::ValueType); -} - -ScalarFunction MapKeysFun::GetFunction() { - //! the arguments and return types are actually set in the binder function - ScalarFunction fun({}, LogicalTypeId::LIST, MapKeysFunction, MapKeysBind); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - fun.varargs = LogicalType::ANY; - return fun; -} - -ScalarFunction MapValuesFun::GetFunction() { - ScalarFunction fun({}, LogicalTypeId::LIST, MapValuesFunction, MapValuesBind); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - fun.varargs = LogicalType::ANY; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/math/numeric.cpp b/src/duckdb/src/core_functions/scalar/math/numeric.cpp deleted file mode 100644 index 1c47fbd95..000000000 --- a/src/duckdb/src/core_functions/scalar/math/numeric.cpp +++ /dev/null @@ -1,1423 +0,0 @@ -#include "duckdb/core_functions/scalar/math_functions.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/operator/abs.hpp" -#include "duckdb/common/operator/multiply.hpp" -#include "duckdb/common/types/hugeint.hpp" -#include "duckdb/common/types/cast_helpers.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/algorithm.hpp" -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/common/likely.hpp" -#include "duckdb/common/types/bit.hpp" -#include -#include - -namespace duckdb { - -template -static scalar_function_t GetScalarIntegerUnaryFunctionFixedReturn(const LogicalType &type) { - scalar_function_t function; - switch (type.id()) { - case LogicalTypeId::TINYINT: - function = &ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::SMALLINT: - function = &ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::INTEGER: - function = &ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::BIGINT: - function = &ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::HUGEINT: - function = &ScalarFunction::UnaryFunction; - break; - default: - throw NotImplementedException("Unimplemented type for GetScalarIntegerUnaryFunctionFixedReturn"); - } - return function; -} - -//===--------------------------------------------------------------------===// -// nextafter -//===--------------------------------------------------------------------===// -struct NextAfterOperator { - template - static inline TR Operation(TA base, TB exponent) { - throw NotImplementedException("Unimplemented type for NextAfter Function"); - } - - template - static inline double Operation(double input, double approximate_to) { - return nextafter(input, approximate_to); - } - template - static inline float Operation(float input, float approximate_to) { - return nextafterf(input, approximate_to); - } -}; - -ScalarFunctionSet NextAfterFun::GetFunctions() { - ScalarFunctionSet next_after_fun; - next_after_fun.AddFunction( - ScalarFunction({LogicalType::DOUBLE, LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::BinaryFunction)); - next_after_fun.AddFunction(ScalarFunction({LogicalType::FLOAT, LogicalType::FLOAT}, LogicalType::FLOAT, - ScalarFunction::BinaryFunction)); - return next_after_fun; -} - -//===--------------------------------------------------------------------===// -// abs -//===--------------------------------------------------------------------===// -static unique_ptr PropagateAbsStats(ClientContext &context, FunctionStatisticsInput &input) { - auto &child_stats = input.child_stats; - auto &expr = input.expr; - D_ASSERT(child_stats.size() == 1); - // can only propagate stats if the children have stats - auto &lstats = child_stats[0]; - Value new_min, new_max; - bool potential_overflow = true; - if (NumericStats::HasMinMax(lstats)) { - switch (expr.return_type.InternalType()) { - case PhysicalType::INT8: - potential_overflow = NumericStats::Min(lstats).GetValue() == NumericLimits::Minimum(); - break; - case PhysicalType::INT16: - potential_overflow = NumericStats::Min(lstats).GetValue() == NumericLimits::Minimum(); - break; - case PhysicalType::INT32: - potential_overflow = NumericStats::Min(lstats).GetValue() == NumericLimits::Minimum(); - break; - case PhysicalType::INT64: - potential_overflow = NumericStats::Min(lstats).GetValue() == NumericLimits::Minimum(); - break; - default: - return nullptr; - } - } - if (potential_overflow) { - new_min = Value(expr.return_type); - new_max = Value(expr.return_type); - } else { - // no potential overflow - - // compute stats - auto current_min = NumericStats::Min(lstats).GetValue(); - auto current_max = NumericStats::Max(lstats).GetValue(); - - int64_t min_val, max_val; - - if (current_min < 0 && current_max < 0) { - // if both min and max are below zero, then min=abs(cur_max) and max=abs(cur_min) - min_val = AbsValue(current_max); - max_val = AbsValue(current_min); - } else if (current_min < 0) { - D_ASSERT(current_max >= 0); - // if min is below zero and max is above 0, then min=0 and max=max(cur_max, abs(cur_min)) - min_val = 0; - max_val = MaxValue(AbsValue(current_min), current_max); - } else { - // if both current_min and current_max are > 0, then the abs is a no-op and can be removed entirely - *input.expr_ptr = std::move(input.expr.children[0]); - return child_stats[0].ToUnique(); - } - new_min = Value::Numeric(expr.return_type, min_val); - new_max = Value::Numeric(expr.return_type, max_val); - expr.function.function = ScalarFunction::GetScalarUnaryFunction(expr.return_type); - } - auto stats = NumericStats::CreateEmpty(expr.return_type); - NumericStats::SetMin(stats, new_min); - NumericStats::SetMax(stats, new_max); - stats.CopyValidity(lstats); - return stats.ToUnique(); -} - -template -unique_ptr DecimalUnaryOpBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - auto decimal_type = arguments[0]->return_type; - switch (decimal_type.InternalType()) { - case PhysicalType::INT16: - bound_function.function = ScalarFunction::GetScalarUnaryFunction(LogicalTypeId::SMALLINT); - break; - case PhysicalType::INT32: - bound_function.function = ScalarFunction::GetScalarUnaryFunction(LogicalTypeId::INTEGER); - break; - case PhysicalType::INT64: - bound_function.function = ScalarFunction::GetScalarUnaryFunction(LogicalTypeId::BIGINT); - break; - default: - bound_function.function = ScalarFunction::GetScalarUnaryFunction(LogicalTypeId::HUGEINT); - break; - } - bound_function.arguments[0] = decimal_type; - bound_function.return_type = decimal_type; - return nullptr; -} - -ScalarFunctionSet AbsOperatorFun::GetFunctions() { - ScalarFunctionSet abs; - for (auto &type : LogicalType::Numeric()) { - switch (type.id()) { - case LogicalTypeId::DECIMAL: - abs.AddFunction(ScalarFunction({type}, type, nullptr, DecimalUnaryOpBind)); - break; - case LogicalTypeId::TINYINT: - case LogicalTypeId::SMALLINT: - case LogicalTypeId::INTEGER: - case LogicalTypeId::BIGINT: - case LogicalTypeId::HUGEINT: { - ScalarFunction func({type}, type, ScalarFunction::GetScalarUnaryFunction(type)); - func.statistics = PropagateAbsStats; - abs.AddFunction(func); - break; - } - case LogicalTypeId::UTINYINT: - case LogicalTypeId::USMALLINT: - case LogicalTypeId::UINTEGER: - case LogicalTypeId::UBIGINT: - abs.AddFunction(ScalarFunction({type}, type, ScalarFunction::NopFunction)); - break; - default: - abs.AddFunction(ScalarFunction({type}, type, ScalarFunction::GetScalarUnaryFunction(type))); - break; - } - } - return abs; -} - -//===--------------------------------------------------------------------===// -// bit_count -//===--------------------------------------------------------------------===// -struct BitCntOperator { - template - static inline TR Operation(TA input) { - using TU = typename std::make_unsigned::type; - TR count = 0; - for (auto value = TU(input); value; ++count) { - value &= (value - 1); - } - return count; - } -}; - -struct HugeIntBitCntOperator { - template - static inline TR Operation(TA input) { - using TU = typename std::make_unsigned::type; - TR count = 0; - - for (auto value = TU(input.upper); value; ++count) { - value &= (value - 1); - } - for (auto value = TU(input.lower); value; ++count) { - value &= (value - 1); - } - return count; - } -}; - -struct BitStringBitCntOperator { - template - static inline TR Operation(TA input) { - TR count = Bit::BitCount(input); - return count; - } -}; - -ScalarFunctionSet BitCountFun::GetFunctions() { - ScalarFunctionSet functions; - functions.AddFunction(ScalarFunction({LogicalType::TINYINT}, LogicalType::TINYINT, - ScalarFunction::UnaryFunction)); - functions.AddFunction(ScalarFunction({LogicalType::SMALLINT}, LogicalType::TINYINT, - ScalarFunction::UnaryFunction)); - functions.AddFunction(ScalarFunction({LogicalType::INTEGER}, LogicalType::TINYINT, - ScalarFunction::UnaryFunction)); - functions.AddFunction(ScalarFunction({LogicalType::BIGINT}, LogicalType::TINYINT, - ScalarFunction::UnaryFunction)); - functions.AddFunction(ScalarFunction({LogicalType::HUGEINT}, LogicalType::TINYINT, - ScalarFunction::UnaryFunction)); - functions.AddFunction(ScalarFunction({LogicalType::BIT}, LogicalType::BIGINT, - ScalarFunction::UnaryFunction)); - return functions; -} - -//===--------------------------------------------------------------------===// -// sign -//===--------------------------------------------------------------------===// -struct SignOperator { - template - static TR Operation(TA input) { - if (input == TA(0)) { - return 0; - } else if (input > TA(0)) { - return 1; - } else { - return -1; - } - } -}; - -template <> -int8_t SignOperator::Operation(float input) { - if (input == 0 || Value::IsNan(input)) { - return 0; - } else if (input > 0) { - return 1; - } else { - return -1; - } -} - -template <> -int8_t SignOperator::Operation(double input) { - if (input == 0 || Value::IsNan(input)) { - return 0; - } else if (input > 0) { - return 1; - } else { - return -1; - } -} - -ScalarFunctionSet SignFun::GetFunctions() { - ScalarFunctionSet sign; - for (auto &type : LogicalType::Numeric()) { - if (type.id() == LogicalTypeId::DECIMAL) { - continue; - } else { - sign.AddFunction( - ScalarFunction({type}, LogicalType::TINYINT, - ScalarFunction::GetScalarUnaryFunctionFixedReturn(type))); - } - } - return sign; -} - -//===--------------------------------------------------------------------===// -// ceil -//===--------------------------------------------------------------------===// -struct CeilOperator { - template - static inline TR Operation(TA left) { - return std::ceil(left); - } -}; - -template -static void GenericRoundFunctionDecimal(DataChunk &input, ExpressionState &state, Vector &result) { - auto &func_expr = state.expr.Cast(); - OP::template Operation(input, DecimalType::GetScale(func_expr.children[0]->return_type), result); -} - -template -unique_ptr BindGenericRoundFunctionDecimal(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - // ceil essentially removes the scale - auto &decimal_type = arguments[0]->return_type; - auto scale = DecimalType::GetScale(decimal_type); - auto width = DecimalType::GetWidth(decimal_type); - if (scale == 0) { - bound_function.function = ScalarFunction::NopFunction; - } else { - switch (decimal_type.InternalType()) { - case PhysicalType::INT16: - bound_function.function = GenericRoundFunctionDecimal; - break; - case PhysicalType::INT32: - bound_function.function = GenericRoundFunctionDecimal; - break; - case PhysicalType::INT64: - bound_function.function = GenericRoundFunctionDecimal; - break; - default: - bound_function.function = GenericRoundFunctionDecimal; - break; - } - } - bound_function.arguments[0] = decimal_type; - bound_function.return_type = LogicalType::DECIMAL(width, 0); - return nullptr; -} - -struct CeilDecimalOperator { - template - static void Operation(DataChunk &input, uint8_t scale, Vector &result) { - T power_of_ten = UnsafeNumericCast(POWERS_OF_TEN_CLASS::POWERS_OF_TEN[scale]); - UnaryExecutor::Execute(input.data[0], result, input.size(), [&](T input) { - if (input <= 0) { - // below 0 we floor the number (e.g. -10.5 -> -10) - return UnsafeNumericCast(input / power_of_ten); - } else { - // above 0 we ceil the number - return UnsafeNumericCast(((input - 1) / power_of_ten) + 1); - } - }); - } -}; - -ScalarFunctionSet CeilFun::GetFunctions() { - ScalarFunctionSet ceil; - for (auto &type : LogicalType::Numeric()) { - scalar_function_t func = nullptr; - bind_scalar_function_t bind_func = nullptr; - if (type.IsIntegral()) { - // no ceil for integral numbers - continue; - } - switch (type.id()) { - case LogicalTypeId::FLOAT: - func = ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::DOUBLE: - func = ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::DECIMAL: - bind_func = BindGenericRoundFunctionDecimal; - break; - default: - throw InternalException("Unimplemented numeric type for function \"ceil\""); - } - ceil.AddFunction(ScalarFunction({type}, type, func, bind_func)); - } - return ceil; -} - -//===--------------------------------------------------------------------===// -// floor -//===--------------------------------------------------------------------===// -struct FloorOperator { - template - static inline TR Operation(TA left) { - return std::floor(left); - } -}; - -struct FloorDecimalOperator { - template - static void Operation(DataChunk &input, uint8_t scale, Vector &result) { - T power_of_ten = UnsafeNumericCast(POWERS_OF_TEN_CLASS::POWERS_OF_TEN[scale]); - UnaryExecutor::Execute(input.data[0], result, input.size(), [&](T input) { - if (input < 0) { - // below 0 we ceil the number (e.g. -10.5 -> -11) - return UnsafeNumericCast(((input + 1) / power_of_ten) - 1); - } else { - // above 0 we floor the number - return UnsafeNumericCast(input / power_of_ten); - } - }); - } -}; - -ScalarFunctionSet FloorFun::GetFunctions() { - ScalarFunctionSet floor; - for (auto &type : LogicalType::Numeric()) { - scalar_function_t func = nullptr; - bind_scalar_function_t bind_func = nullptr; - if (type.IsIntegral()) { - // no floor for integral numbers - continue; - } - switch (type.id()) { - case LogicalTypeId::FLOAT: - func = ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::DOUBLE: - func = ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::DECIMAL: - bind_func = BindGenericRoundFunctionDecimal; - break; - default: - throw InternalException("Unimplemented numeric type for function \"floor\""); - } - floor.AddFunction(ScalarFunction({type}, type, func, bind_func)); - } - return floor; -} - -//===--------------------------------------------------------------------===// -// trunc -//===--------------------------------------------------------------------===// -struct TruncOperator { - // Integer truncation is a NOP - template - static inline TR Operation(TA left) { - return std::trunc(left); - } -}; - -struct TruncDecimalOperator { - template - static void Operation(DataChunk &input, uint8_t scale, Vector &result) { - T power_of_ten = UnsafeNumericCast(POWERS_OF_TEN_CLASS::POWERS_OF_TEN[scale]); - UnaryExecutor::Execute(input.data[0], result, input.size(), [&](T input) { - // Always floor - return UnsafeNumericCast((input / power_of_ten)); - }); - } -}; - -ScalarFunctionSet TruncFun::GetFunctions() { - ScalarFunctionSet trunc; - for (auto &type : LogicalType::Numeric()) { - scalar_function_t func = nullptr; - bind_scalar_function_t bind_func = nullptr; - // Truncation of integers gets generated by some tools (e.g., Tableau/JDBC:Postgres) - switch (type.id()) { - case LogicalTypeId::FLOAT: - func = ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::DOUBLE: - func = ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::DECIMAL: - bind_func = BindGenericRoundFunctionDecimal; - break; - case LogicalTypeId::TINYINT: - case LogicalTypeId::SMALLINT: - case LogicalTypeId::INTEGER: - case LogicalTypeId::BIGINT: - case LogicalTypeId::HUGEINT: - case LogicalTypeId::UTINYINT: - case LogicalTypeId::USMALLINT: - case LogicalTypeId::UINTEGER: - case LogicalTypeId::UBIGINT: - case LogicalTypeId::UHUGEINT: - func = ScalarFunction::NopFunction; - break; - default: - throw InternalException("Unimplemented numeric type for function \"trunc\""); - } - trunc.AddFunction(ScalarFunction({type}, type, func, bind_func)); - } - return trunc; -} - -//===--------------------------------------------------------------------===// -// round -//===--------------------------------------------------------------------===// -struct RoundOperatorPrecision { - template - static inline TR Operation(TA input, TB precision) { - double rounded_value; - if (precision < 0) { - double modifier = std::pow(10, -TA(precision)); - rounded_value = (std::round(input / modifier)) * modifier; - if (std::isinf(rounded_value) || std::isnan(rounded_value)) { - return 0; - } - } else { - double modifier = std::pow(10, TA(precision)); - rounded_value = (std::round(input * modifier)) / modifier; - if (std::isinf(rounded_value) || std::isnan(rounded_value)) { - return input; - } - } - return LossyNumericCast(rounded_value); - } -}; - -struct RoundOperator { - template - static inline TR Operation(TA input) { - double rounded_value = round(input); - if (std::isinf(rounded_value) || std::isnan(rounded_value)) { - return input; - } - return LossyNumericCast(rounded_value); - } -}; - -struct RoundDecimalOperator { - template - static void Operation(DataChunk &input, uint8_t scale, Vector &result) { - T power_of_ten = UnsafeNumericCast(POWERS_OF_TEN_CLASS::POWERS_OF_TEN[scale]); - T addition = power_of_ten / 2; - // regular round rounds towards the nearest number - // in case of a tie we round away from zero - // i.e. -10.5 -> -11, 10.5 -> 11 - // we implement this by adding (positive) or subtracting (negative) 0.5 - // and then flooring the number - // e.g. 10.5 + 0.5 = 11, floor(11) = 11 - // 10.4 + 0.5 = 10.9, floor(10.9) = 10 - UnaryExecutor::Execute(input.data[0], result, input.size(), [&](T input) { - if (input < 0) { - input -= addition; - } else { - input += addition; - } - return UnsafeNumericCast(input / power_of_ten); - }); - } -}; - -struct RoundPrecisionFunctionData : public FunctionData { - explicit RoundPrecisionFunctionData(int32_t target_scale) : target_scale(target_scale) { - } - - int32_t target_scale; - - unique_ptr Copy() const override { - return make_uniq(target_scale); - } - - bool Equals(const FunctionData &other_p) const override { - auto &other = other_p.Cast(); - return target_scale == other.target_scale; - } -}; - -template -static void DecimalRoundNegativePrecisionFunction(DataChunk &input, ExpressionState &state, Vector &result) { - auto &func_expr = state.expr.Cast(); - auto &info = func_expr.bind_info->Cast(); - auto source_scale = DecimalType::GetScale(func_expr.children[0]->return_type); - auto width = DecimalType::GetWidth(func_expr.children[0]->return_type); - if (info.target_scale <= -int32_t(width - source_scale)) { - // scale too big for width - result.SetVectorType(VectorType::CONSTANT_VECTOR); - result.SetValue(0, Value::INTEGER(0)); - return; - } - T divide_power_of_ten = UnsafeNumericCast(POWERS_OF_TEN_CLASS::POWERS_OF_TEN[-info.target_scale + source_scale]); - T multiply_power_of_ten = UnsafeNumericCast(POWERS_OF_TEN_CLASS::POWERS_OF_TEN[-info.target_scale]); - T addition = divide_power_of_ten / 2; - - UnaryExecutor::Execute(input.data[0], result, input.size(), [&](T input) { - if (input < 0) { - input -= addition; - } else { - input += addition; - } - return UnsafeNumericCast(input / divide_power_of_ten * multiply_power_of_ten); - }); -} - -template -static void DecimalRoundPositivePrecisionFunction(DataChunk &input, ExpressionState &state, Vector &result) { - auto &func_expr = state.expr.Cast(); - auto &info = func_expr.bind_info->Cast(); - auto source_scale = DecimalType::GetScale(func_expr.children[0]->return_type); - T power_of_ten = UnsafeNumericCast(POWERS_OF_TEN_CLASS::POWERS_OF_TEN[source_scale - info.target_scale]); - T addition = power_of_ten / 2; - UnaryExecutor::Execute(input.data[0], result, input.size(), [&](T input) { - if (input < 0) { - input -= addition; - } else { - input += addition; - } - return UnsafeNumericCast(input / power_of_ten); - }); -} - -unique_ptr BindDecimalRoundPrecision(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - auto &decimal_type = arguments[0]->return_type; - if (arguments[1]->HasParameter()) { - throw ParameterNotResolvedException(); - } - if (!arguments[1]->IsFoldable()) { - throw NotImplementedException("ROUND(DECIMAL, INTEGER) with non-constant precision is not supported"); - } - Value val = ExpressionExecutor::EvaluateScalar(context, *arguments[1]).DefaultCastAs(LogicalType::INTEGER); - if (val.IsNull()) { - throw NotImplementedException("ROUND(DECIMAL, INTEGER) with non-constant precision is not supported"); - } - // our new precision becomes the round value - // e.g. ROUND(DECIMAL(18,3), 1) -> DECIMAL(18,1) - // but ONLY if the round value is positive - // if it is negative the scale becomes zero - // i.e. ROUND(DECIMAL(18,3), -1) -> DECIMAL(18,0) - int32_t round_value = IntegerValue::Get(val); - uint8_t target_scale; - auto width = DecimalType::GetWidth(decimal_type); - auto scale = DecimalType::GetScale(decimal_type); - if (round_value < 0) { - target_scale = 0; - switch (decimal_type.InternalType()) { - case PhysicalType::INT16: - bound_function.function = DecimalRoundNegativePrecisionFunction; - break; - case PhysicalType::INT32: - bound_function.function = DecimalRoundNegativePrecisionFunction; - break; - case PhysicalType::INT64: - bound_function.function = DecimalRoundNegativePrecisionFunction; - break; - default: - bound_function.function = DecimalRoundNegativePrecisionFunction; - break; - } - } else { - if (round_value >= (int32_t)scale) { - // if round_value is bigger than or equal to scale we do nothing - bound_function.function = ScalarFunction::NopFunction; - target_scale = scale; - } else { - target_scale = NumericCast(round_value); - switch (decimal_type.InternalType()) { - case PhysicalType::INT16: - bound_function.function = DecimalRoundPositivePrecisionFunction; - break; - case PhysicalType::INT32: - bound_function.function = DecimalRoundPositivePrecisionFunction; - break; - case PhysicalType::INT64: - bound_function.function = DecimalRoundPositivePrecisionFunction; - break; - default: - bound_function.function = DecimalRoundPositivePrecisionFunction; - break; - } - } - } - bound_function.arguments[0] = decimal_type; - bound_function.return_type = LogicalType::DECIMAL(width, target_scale); - return make_uniq(round_value); -} - -ScalarFunctionSet RoundFun::GetFunctions() { - ScalarFunctionSet round; - for (auto &type : LogicalType::Numeric()) { - scalar_function_t round_prec_func = nullptr; - scalar_function_t round_func = nullptr; - bind_scalar_function_t bind_func = nullptr; - bind_scalar_function_t bind_prec_func = nullptr; - if (type.IsIntegral()) { - // no round for integral numbers - continue; - } - switch (type.id()) { - case LogicalTypeId::FLOAT: - round_func = ScalarFunction::UnaryFunction; - round_prec_func = ScalarFunction::BinaryFunction; - break; - case LogicalTypeId::DOUBLE: - round_func = ScalarFunction::UnaryFunction; - round_prec_func = ScalarFunction::BinaryFunction; - break; - case LogicalTypeId::DECIMAL: - bind_func = BindGenericRoundFunctionDecimal; - bind_prec_func = BindDecimalRoundPrecision; - break; - default: - throw InternalException("Unimplemented numeric type for function \"floor\""); - } - round.AddFunction(ScalarFunction({type}, type, round_func, bind_func)); - round.AddFunction(ScalarFunction({type, LogicalType::INTEGER}, type, round_prec_func, bind_prec_func)); - } - return round; -} - -//===--------------------------------------------------------------------===// -// exp -//===--------------------------------------------------------------------===// -struct ExpOperator { - template - static inline TR Operation(TA left) { - return std::exp(left); - } -}; - -ScalarFunction ExpFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// pow -//===--------------------------------------------------------------------===// -struct PowOperator { - template - static inline TR Operation(TA base, TB exponent) { - return std::pow(base, exponent); - } -}; - -ScalarFunction PowOperatorFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE, LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::BinaryFunction); -} - -//===--------------------------------------------------------------------===// -// sqrt -//===--------------------------------------------------------------------===// -struct SqrtOperator { - template - static inline TR Operation(TA input) { - if (input < 0) { - throw OutOfRangeException("cannot take square root of a negative number"); - } - return std::sqrt(input); - } -}; - -ScalarFunction SqrtFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// cbrt -//===--------------------------------------------------------------------===// -struct CbRtOperator { - template - static inline TR Operation(TA left) { - return std::cbrt(left); - } -}; - -ScalarFunction CbrtFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// ln -//===--------------------------------------------------------------------===// - -struct LnOperator { - template - static inline TR Operation(TA input) { - if (input < 0) { - throw OutOfRangeException("cannot take logarithm of a negative number"); - } - if (input == 0) { - throw OutOfRangeException("cannot take logarithm of zero"); - } - return std::log(input); - } -}; - -ScalarFunction LnFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// log -//===--------------------------------------------------------------------===// -struct Log10Operator { - template - static inline TR Operation(TA input) { - if (input < 0) { - throw OutOfRangeException("cannot take logarithm of a negative number"); - } - if (input == 0) { - throw OutOfRangeException("cannot take logarithm of zero"); - } - return std::log10(input); - } -}; - -ScalarFunction Log10Fun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// log with base -//===--------------------------------------------------------------------===// -struct LogBaseOperator { - template - static inline TR Operation(TA b, TB x) { - auto divisor = Log10Operator::Operation(b); - if (divisor == 0) { - throw OutOfRangeException("divison by zero in based logarithm"); - } - return Log10Operator::Operation(x) / divisor; - } -}; - -ScalarFunctionSet LogFun::GetFunctions() { - ScalarFunctionSet funcs; - funcs.AddFunction(ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::DOUBLE, LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::BinaryFunction)); - return funcs; -} - -//===--------------------------------------------------------------------===// -// log2 -//===--------------------------------------------------------------------===// -struct Log2Operator { - template - static inline TR Operation(TA input) { - if (input < 0) { - throw OutOfRangeException("cannot take logarithm of a negative number"); - } - if (input == 0) { - throw OutOfRangeException("cannot take logarithm of zero"); - } - return std::log2(input); - } -}; - -ScalarFunction Log2Fun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// pi -//===--------------------------------------------------------------------===// -static void PiFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 0); - Value pi_value = Value::DOUBLE(PI); - result.Reference(pi_value); -} - -ScalarFunction PiFun::GetFunction() { - return ScalarFunction({}, LogicalType::DOUBLE, PiFunction); -} - -//===--------------------------------------------------------------------===// -// degrees -//===--------------------------------------------------------------------===// -struct DegreesOperator { - template - static inline TR Operation(TA left) { - return left * (180 / PI); - } -}; - -ScalarFunction DegreesFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// radians -//===--------------------------------------------------------------------===// -struct RadiansOperator { - template - static inline TR Operation(TA left) { - return left * (PI / 180); - } -}; - -ScalarFunction RadiansFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// isnan -//===--------------------------------------------------------------------===// -struct IsNanOperator { - template - static inline TR Operation(TA input) { - return Value::IsNan(input); - } -}; - -ScalarFunctionSet IsNanFun::GetFunctions() { - ScalarFunctionSet funcs; - funcs.AddFunction(ScalarFunction({LogicalType::FLOAT}, LogicalType::BOOLEAN, - ScalarFunction::UnaryFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::DOUBLE}, LogicalType::BOOLEAN, - ScalarFunction::UnaryFunction)); - return funcs; -} - -//===--------------------------------------------------------------------===// -// signbit -//===--------------------------------------------------------------------===// -struct SignBitOperator { - template - static inline TR Operation(TA input) { - return std::signbit(input); - } -}; - -ScalarFunctionSet SignBitFun::GetFunctions() { - ScalarFunctionSet funcs; - funcs.AddFunction(ScalarFunction({LogicalType::FLOAT}, LogicalType::BOOLEAN, - ScalarFunction::UnaryFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::DOUBLE}, LogicalType::BOOLEAN, - ScalarFunction::UnaryFunction)); - return funcs; -} - -//===--------------------------------------------------------------------===// -// isinf -//===--------------------------------------------------------------------===// -struct IsInfiniteOperator { - template - static inline TR Operation(TA input) { - return !Value::IsNan(input) && !Value::IsFinite(input); - } -}; - -template <> -bool IsInfiniteOperator::Operation(date_t input) { - return !Value::IsFinite(input); -} - -template <> -bool IsInfiniteOperator::Operation(timestamp_t input) { - return !Value::IsFinite(input); -} - -ScalarFunctionSet IsInfiniteFun::GetFunctions() { - ScalarFunctionSet funcs("isinf"); - funcs.AddFunction(ScalarFunction({LogicalType::FLOAT}, LogicalType::BOOLEAN, - ScalarFunction::UnaryFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::DOUBLE}, LogicalType::BOOLEAN, - ScalarFunction::UnaryFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::DATE}, LogicalType::BOOLEAN, - ScalarFunction::UnaryFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::TIMESTAMP}, LogicalType::BOOLEAN, - ScalarFunction::UnaryFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::TIMESTAMP_TZ}, LogicalType::BOOLEAN, - ScalarFunction::UnaryFunction)); - return funcs; -} - -//===--------------------------------------------------------------------===// -// isfinite -//===--------------------------------------------------------------------===// -struct IsFiniteOperator { - template - static inline TR Operation(TA input) { - return Value::IsFinite(input); - } -}; - -ScalarFunctionSet IsFiniteFun::GetFunctions() { - ScalarFunctionSet funcs; - funcs.AddFunction(ScalarFunction({LogicalType::FLOAT}, LogicalType::BOOLEAN, - ScalarFunction::UnaryFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::DOUBLE}, LogicalType::BOOLEAN, - ScalarFunction::UnaryFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::DATE}, LogicalType::BOOLEAN, - ScalarFunction::UnaryFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::TIMESTAMP}, LogicalType::BOOLEAN, - ScalarFunction::UnaryFunction)); - funcs.AddFunction(ScalarFunction({LogicalType::TIMESTAMP_TZ}, LogicalType::BOOLEAN, - ScalarFunction::UnaryFunction)); - return funcs; -} - -//===--------------------------------------------------------------------===// -// sin -//===--------------------------------------------------------------------===// -template -struct NoInfiniteDoubleWrapper { - template - static RESULT_TYPE Operation(INPUT_TYPE input) { - if (DUCKDB_UNLIKELY(!Value::IsFinite(input))) { - if (Value::IsNan(input)) { - return input; - } - throw OutOfRangeException("input value %lf is out of range for numeric function", input); - } - return OP::template Operation(input); - } -}; - -struct SinOperator { - template - static inline TR Operation(TA input) { - return std::sin(input); - } -}; - -ScalarFunction SinFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction>); -} - -//===--------------------------------------------------------------------===// -// cos -//===--------------------------------------------------------------------===// -struct CosOperator { - template - static inline TR Operation(TA input) { - return (double)std::cos(input); - } -}; - -ScalarFunction CosFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction>); -} - -//===--------------------------------------------------------------------===// -// tan -//===--------------------------------------------------------------------===// -struct TanOperator { - template - static inline TR Operation(TA input) { - return (double)std::tan(input); - } -}; - -ScalarFunction TanFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction>); -} - -//===--------------------------------------------------------------------===// -// asin -//===--------------------------------------------------------------------===// -struct ASinOperator { - template - static inline TR Operation(TA input) { - if (input < -1 || input > 1) { - throw InvalidInputException("ASIN is undefined outside [-1,1]"); - } - return (double)std::asin(input); - } -}; - -ScalarFunction AsinFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction>); -} - -//===--------------------------------------------------------------------===// -// atan -//===--------------------------------------------------------------------===// -struct ATanOperator { - template - static inline TR Operation(TA input) { - return (double)std::atan(input); - } -}; - -ScalarFunction AtanFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// atan2 -//===--------------------------------------------------------------------===// -struct ATan2 { - template - static inline TR Operation(TA left, TB right) { - return (double)std::atan2(left, right); - } -}; - -ScalarFunction Atan2Fun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE, LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::BinaryFunction); -} - -//===--------------------------------------------------------------------===// -// acos -//===--------------------------------------------------------------------===// -struct ACos { - template - static inline TR Operation(TA input) { - if (input < -1 || input > 1) { - throw InvalidInputException("ACOS is undefined outside [-1,1]"); - } - return (double)std::acos(input); - } -}; - -ScalarFunction AcosFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction>); -} - -//===--------------------------------------------------------------------===// -// cosh -//===--------------------------------------------------------------------===// -struct CoshOperator { - template - static inline TR Operation(TA input) { - return (double)std::cosh(input); - } -}; - -ScalarFunction CoshFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// acosh -//===--------------------------------------------------------------------===// -struct AcoshOperator { - template - static inline TR Operation(TA input) { - return (double)std::acosh(input); - } -}; - -ScalarFunction AcoshFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// sinh -//===--------------------------------------------------------------------===// -struct SinhOperator { - template - static inline TR Operation(TA input) { - return (double)std::sinh(input); - } -}; - -ScalarFunction SinhFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// asinh -//===--------------------------------------------------------------------===// -struct AsinhOperator { - template - static inline TR Operation(TA input) { - return (double)std::asinh(input); - } -}; - -ScalarFunction AsinhFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// tanh -//===--------------------------------------------------------------------===// -struct TanhOperator { - template - static inline TR Operation(TA input) { - return (double)std::tanh(input); - } -}; - -ScalarFunction TanhFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// atanh -//===--------------------------------------------------------------------===// -struct AtanhOperator { - template - static inline TR Operation(TA input) { - if (input < -1 || input > 1) { - throw InvalidInputException("ATANH is undefined outside [-1,1]"); - } - if (input == -1 || input == 1) { - return INFINITY; - } - return (double)std::atanh(input); - } -}; - -ScalarFunction AtanhFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// cot -//===--------------------------------------------------------------------===// -template -struct NoInfiniteNoZeroDoubleWrapper { - template - static RESULT_TYPE Operation(INPUT_TYPE input) { - if (DUCKDB_UNLIKELY(!Value::IsFinite(input))) { - if (Value::IsNan(input)) { - return input; - } - throw OutOfRangeException("input value %lf is out of range for numeric function", input); - } - if (DUCKDB_UNLIKELY((double)input == 0.0 || (double)input == -0.0)) { - throw OutOfRangeException("input value %lf is out of range for numeric function cotangent", input); - } - return OP::template Operation(input); - } -}; - -struct CotOperator { - template - static inline TR Operation(TA input) { - return 1.0 / (double)std::tan(input); - } -}; - -ScalarFunction CotFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction>); -} - -//===--------------------------------------------------------------------===// -// gamma -//===--------------------------------------------------------------------===// -struct GammaOperator { - template - static inline TR Operation(TA input) { - if (input == 0) { - throw OutOfRangeException("cannot take gamma of zero"); - } - return std::tgamma(input); - } -}; - -ScalarFunction GammaFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// gamma -//===--------------------------------------------------------------------===// -struct LogGammaOperator { - template - static inline TR Operation(TA input) { - if (input == 0) { - throw OutOfRangeException("cannot take log gamma of zero"); - } - return std::lgamma(input); - } -}; - -ScalarFunction LogGammaFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// factorial(), ! -//===--------------------------------------------------------------------===// -struct FactorialOperator { - template - static inline TR Operation(TA left) { - TR ret = 1; - for (TA i = 2; i <= left; i++) { - if (!TryMultiplyOperator::Operation(ret, TR(i), ret)) { - throw OutOfRangeException("Value out of range"); - } - } - return ret; - } -}; - -ScalarFunction FactorialOperatorFun::GetFunction() { - return ScalarFunction({LogicalType::INTEGER}, LogicalType::HUGEINT, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// even -//===--------------------------------------------------------------------===// -struct EvenOperator { - template - static inline TR Operation(TA left) { - double value; - if (left >= 0) { - value = std::ceil(left); - } else { - value = std::ceil(-left); - value = -value; - } - if (std::floor(value / 2) * 2 != value) { - if (left >= 0) { - return value += 1; - } - return value -= 1; - } - return value; - } -}; - -ScalarFunction EvenFun::GetFunction() { - return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); -} - -//===--------------------------------------------------------------------===// -// gcd -//===--------------------------------------------------------------------===// - -// should be replaced with std::gcd in a newer C++ standard -template -TA GreatestCommonDivisor(TA left, TA right) { - TA a = left; - TA b = right; - - // This protects the following modulo operations from a corner case, - // where we would get a runtime error due to an integer overflow. - if ((left == NumericLimits::Minimum() && right == -1) || - (left == -1 && right == NumericLimits::Minimum())) { - return 1; - } - - while (true) { - if (a == 0) { - return TryAbsOperator::Operation(b); - } - b %= a; - - if (b == 0) { - return TryAbsOperator::Operation(a); - } - a %= b; - } -} - -struct GreatestCommonDivisorOperator { - template - static inline TR Operation(TA left, TB right) { - return GreatestCommonDivisor(left, right); - } -}; - -ScalarFunctionSet GreatestCommonDivisorFun::GetFunctions() { - ScalarFunctionSet funcs; - funcs.AddFunction( - ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT}, LogicalType::BIGINT, - ScalarFunction::BinaryFunction)); - funcs.AddFunction( - ScalarFunction({LogicalType::HUGEINT, LogicalType::HUGEINT}, LogicalType::HUGEINT, - ScalarFunction::BinaryFunction)); - return funcs; -} - -//===--------------------------------------------------------------------===// -// lcm -//===--------------------------------------------------------------------===// - -// should be replaced with std::lcm in a newer C++ standard -struct LeastCommonMultipleOperator { - template - static inline TR Operation(TA left, TB right) { - if (left == 0 || right == 0) { - return 0; - } - TR result; - if (!TryMultiplyOperator::Operation(left, right / GreatestCommonDivisor(left, right), result)) { - throw OutOfRangeException("lcm value is out of range"); - } - return TryAbsOperator::Operation(result); - } -}; - -ScalarFunctionSet LeastCommonMultipleFun::GetFunctions() { - ScalarFunctionSet funcs; - - funcs.AddFunction( - ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT}, LogicalType::BIGINT, - ScalarFunction::BinaryFunction)); - funcs.AddFunction( - ScalarFunction({LogicalType::HUGEINT, LogicalType::HUGEINT}, LogicalType::HUGEINT, - ScalarFunction::BinaryFunction)); - return funcs; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/operators/bitwise.cpp b/src/duckdb/src/core_functions/scalar/operators/bitwise.cpp deleted file mode 100644 index 6e9415aad..000000000 --- a/src/duckdb/src/core_functions/scalar/operators/bitwise.cpp +++ /dev/null @@ -1,312 +0,0 @@ -#include "duckdb/core_functions/scalar/operators_functions.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/types/cast_helpers.hpp" -#include "duckdb/common/types/bit.hpp" - -namespace duckdb { - -template -static scalar_function_t GetScalarIntegerUnaryFunction(const LogicalType &type) { - scalar_function_t function; - switch (type.id()) { - case LogicalTypeId::TINYINT: - function = &ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::SMALLINT: - function = &ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::INTEGER: - function = &ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::BIGINT: - function = &ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::UTINYINT: - function = &ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::USMALLINT: - function = &ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::UINTEGER: - function = &ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::UBIGINT: - function = &ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::HUGEINT: - function = &ScalarFunction::UnaryFunction; - break; - case LogicalTypeId::UHUGEINT: - function = &ScalarFunction::UnaryFunction; - break; - default: - throw NotImplementedException("Unimplemented type for GetScalarIntegerUnaryFunction"); - } - return function; -} - -template -static scalar_function_t GetScalarIntegerBinaryFunction(const LogicalType &type) { - scalar_function_t function; - switch (type.id()) { - case LogicalTypeId::TINYINT: - function = &ScalarFunction::BinaryFunction; - break; - case LogicalTypeId::SMALLINT: - function = &ScalarFunction::BinaryFunction; - break; - case LogicalTypeId::INTEGER: - function = &ScalarFunction::BinaryFunction; - break; - case LogicalTypeId::BIGINT: - function = &ScalarFunction::BinaryFunction; - break; - case LogicalTypeId::UTINYINT: - function = &ScalarFunction::BinaryFunction; - break; - case LogicalTypeId::USMALLINT: - function = &ScalarFunction::BinaryFunction; - break; - case LogicalTypeId::UINTEGER: - function = &ScalarFunction::BinaryFunction; - break; - case LogicalTypeId::UBIGINT: - function = &ScalarFunction::BinaryFunction; - break; - case LogicalTypeId::HUGEINT: - function = &ScalarFunction::BinaryFunction; - break; - case LogicalTypeId::UHUGEINT: - function = &ScalarFunction::BinaryFunction; - break; - default: - throw NotImplementedException("Unimplemented type for GetScalarIntegerBinaryFunction"); - } - return function; -} - -//===--------------------------------------------------------------------===// -// & [bitwise_and] -//===--------------------------------------------------------------------===// -struct BitwiseANDOperator { - template - static inline TR Operation(TA left, TB right) { - return left & right; - } -}; - -static void BitwiseANDOperation(DataChunk &args, ExpressionState &state, Vector &result) { - BinaryExecutor::Execute( - args.data[0], args.data[1], result, args.size(), [&](string_t rhs, string_t lhs) { - string_t target = StringVector::EmptyString(result, rhs.GetSize()); - - Bit::BitwiseAnd(rhs, lhs, target); - return target; - }); -} - -ScalarFunctionSet BitwiseAndFun::GetFunctions() { - ScalarFunctionSet functions; - for (auto &type : LogicalType::Integral()) { - functions.AddFunction( - ScalarFunction({type, type}, type, GetScalarIntegerBinaryFunction(type))); - } - functions.AddFunction(ScalarFunction({LogicalType::BIT, LogicalType::BIT}, LogicalType::BIT, BitwiseANDOperation)); - return functions; -} - -//===--------------------------------------------------------------------===// -// | [bitwise_or] -//===--------------------------------------------------------------------===// -struct BitwiseOROperator { - template - static inline TR Operation(TA left, TB right) { - return left | right; - } -}; - -static void BitwiseOROperation(DataChunk &args, ExpressionState &state, Vector &result) { - BinaryExecutor::Execute( - args.data[0], args.data[1], result, args.size(), [&](string_t rhs, string_t lhs) { - string_t target = StringVector::EmptyString(result, rhs.GetSize()); - - Bit::BitwiseOr(rhs, lhs, target); - return target; - }); -} - -ScalarFunctionSet BitwiseOrFun::GetFunctions() { - ScalarFunctionSet functions; - for (auto &type : LogicalType::Integral()) { - functions.AddFunction( - ScalarFunction({type, type}, type, GetScalarIntegerBinaryFunction(type))); - } - functions.AddFunction(ScalarFunction({LogicalType::BIT, LogicalType::BIT}, LogicalType::BIT, BitwiseOROperation)); - return functions; -} - -//===--------------------------------------------------------------------===// -// # [bitwise_xor] -//===--------------------------------------------------------------------===// -struct BitwiseXOROperator { - template - static inline TR Operation(TA left, TB right) { - return left ^ right; - } -}; - -static void BitwiseXOROperation(DataChunk &args, ExpressionState &state, Vector &result) { - BinaryExecutor::Execute( - args.data[0], args.data[1], result, args.size(), [&](string_t rhs, string_t lhs) { - string_t target = StringVector::EmptyString(result, rhs.GetSize()); - - Bit::BitwiseXor(rhs, lhs, target); - return target; - }); -} - -ScalarFunctionSet BitwiseXorFun::GetFunctions() { - ScalarFunctionSet functions; - for (auto &type : LogicalType::Integral()) { - functions.AddFunction( - ScalarFunction({type, type}, type, GetScalarIntegerBinaryFunction(type))); - } - functions.AddFunction(ScalarFunction({LogicalType::BIT, LogicalType::BIT}, LogicalType::BIT, BitwiseXOROperation)); - return functions; -} - -//===--------------------------------------------------------------------===// -// ~ [bitwise_not] -//===--------------------------------------------------------------------===// -struct BitwiseNotOperator { - template - static inline TR Operation(TA input) { - return ~input; - } -}; - -static void BitwiseNOTOperation(DataChunk &args, ExpressionState &state, Vector &result) { - UnaryExecutor::Execute(args.data[0], result, args.size(), [&](string_t input) { - string_t target = StringVector::EmptyString(result, input.GetSize()); - - Bit::BitwiseNot(input, target); - return target; - }); -} - -ScalarFunctionSet BitwiseNotFun::GetFunctions() { - ScalarFunctionSet functions; - for (auto &type : LogicalType::Integral()) { - functions.AddFunction(ScalarFunction({type}, type, GetScalarIntegerUnaryFunction(type))); - } - functions.AddFunction(ScalarFunction({LogicalType::BIT}, LogicalType::BIT, BitwiseNOTOperation)); - return functions; -} - -//===--------------------------------------------------------------------===// -// << [bitwise_left_shift] -//===--------------------------------------------------------------------===// -struct BitwiseShiftLeftOperator { - template - static inline TR Operation(TA input, TB shift) { - TA max_shift = TA(sizeof(TA) * 8) + (NumericLimits::IsSigned() ? 0 : 1); - if (input < 0) { - throw OutOfRangeException("Cannot left-shift negative number %s", NumericHelper::ToString(input)); - } - if (shift < 0) { - throw OutOfRangeException("Cannot left-shift by negative number %s", NumericHelper::ToString(shift)); - } - if (shift >= max_shift) { - if (input == 0) { - return 0; - } - throw OutOfRangeException("Left-shift value %s is out of range", NumericHelper::ToString(shift)); - } - if (shift == 0) { - return input; - } - TA max_value = UnsafeNumericCast((TA(1) << (max_shift - shift - 1))); - if (input >= max_value) { - throw OutOfRangeException("Overflow in left shift (%s << %s)", NumericHelper::ToString(input), - NumericHelper::ToString(shift)); - } - return UnsafeNumericCast(input << shift); - } -}; - -static void BitwiseShiftLeftOperation(DataChunk &args, ExpressionState &state, Vector &result) { - BinaryExecutor::Execute( - args.data[0], args.data[1], result, args.size(), [&](string_t input, int32_t shift) { - auto max_shift = UnsafeNumericCast(Bit::BitLength(input)); - if (shift == 0) { - return input; - } - if (shift < 0) { - throw OutOfRangeException("Cannot left-shift by negative number %s", NumericHelper::ToString(shift)); - } - string_t target = StringVector::EmptyString(result, input.GetSize()); - - if (shift >= max_shift) { - Bit::SetEmptyBitString(target, input); - return target; - } - Bit::LeftShift(input, UnsafeNumericCast(shift), target); - return target; - }); -} - -ScalarFunctionSet LeftShiftFun::GetFunctions() { - ScalarFunctionSet functions; - for (auto &type : LogicalType::Integral()) { - functions.AddFunction( - ScalarFunction({type, type}, type, GetScalarIntegerBinaryFunction(type))); - } - functions.AddFunction( - ScalarFunction({LogicalType::BIT, LogicalType::INTEGER}, LogicalType::BIT, BitwiseShiftLeftOperation)); - return functions; -} - -//===--------------------------------------------------------------------===// -// >> [bitwise_right_shift] -//===--------------------------------------------------------------------===// -template -bool RightShiftInRange(T shift) { - return shift >= 0 && shift < T(sizeof(T) * 8); -} - -struct BitwiseShiftRightOperator { - template - static inline TR Operation(TA input, TB shift) { - return RightShiftInRange(shift) ? input >> shift : 0; - } -}; - -static void BitwiseShiftRightOperation(DataChunk &args, ExpressionState &state, Vector &result) { - BinaryExecutor::Execute( - args.data[0], args.data[1], result, args.size(), [&](string_t input, int32_t shift) { - auto max_shift = UnsafeNumericCast(Bit::BitLength(input)); - if (shift == 0) { - return input; - } - string_t target = StringVector::EmptyString(result, input.GetSize()); - if (shift < 0 || shift >= max_shift) { - Bit::SetEmptyBitString(target, input); - return target; - } - Bit::RightShift(input, UnsafeNumericCast(shift), target); - return target; - }); -} - -ScalarFunctionSet RightShiftFun::GetFunctions() { - ScalarFunctionSet functions; - for (auto &type : LogicalType::Integral()) { - functions.AddFunction( - ScalarFunction({type, type}, type, GetScalarIntegerBinaryFunction(type))); - } - functions.AddFunction( - ScalarFunction({LogicalType::BIT, LogicalType::INTEGER}, LogicalType::BIT, BitwiseShiftRightOperation)); - return functions; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/random/random.cpp b/src/duckdb/src/core_functions/scalar/random/random.cpp deleted file mode 100644 index 02567a486..000000000 --- a/src/duckdb/src/core_functions/scalar/random/random.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "duckdb/core_functions/scalar/random_functions.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/main/client_context.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/random_engine.hpp" -#include "duckdb/common/types/uuid.hpp" - -namespace duckdb { - -struct RandomLocalState : public FunctionLocalState { - explicit RandomLocalState(uint32_t seed) : random_engine(seed) { - } - - RandomEngine random_engine; -}; - -static void RandomFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 0); - auto &lstate = ExecuteFunctionState::GetFunctionState(state)->Cast(); - - result.SetVectorType(VectorType::FLAT_VECTOR); - auto result_data = FlatVector::GetData(result); - for (idx_t i = 0; i < args.size(); i++) { - result_data[i] = lstate.random_engine.NextRandom(); - } -} - -static unique_ptr RandomInitLocalState(ExpressionState &state, const BoundFunctionExpression &expr, - FunctionData *bind_data) { - auto &random_engine = RandomEngine::Get(state.GetContext()); - lock_guard guard(random_engine.lock); - return make_uniq(random_engine.NextRandomInteger()); -} - -ScalarFunction RandomFun::GetFunction() { - ScalarFunction random("random", {}, LogicalType::DOUBLE, RandomFunction, nullptr, nullptr, nullptr, - RandomInitLocalState); - random.stability = FunctionStability::VOLATILE; - return random; -} - -static void GenerateUUIDFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 0); - auto &lstate = ExecuteFunctionState::GetFunctionState(state)->Cast(); - - result.SetVectorType(VectorType::FLAT_VECTOR); - auto result_data = FlatVector::GetData(result); - - for (idx_t i = 0; i < args.size(); i++) { - result_data[i] = UUID::GenerateRandomUUID(lstate.random_engine); - } -} - -ScalarFunction UUIDFun::GetFunction() { - ScalarFunction uuid_function({}, LogicalType::UUID, GenerateUUIDFunction, nullptr, nullptr, nullptr, - RandomInitLocalState); - // generate a random uuid - uuid_function.stability = FunctionStability::VOLATILE; - return uuid_function; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/random/setseed.cpp b/src/duckdb/src/core_functions/scalar/random/setseed.cpp deleted file mode 100644 index a4e1d01d8..000000000 --- a/src/duckdb/src/core_functions/scalar/random/setseed.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "duckdb/core_functions/scalar/random_functions.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/main/client_context.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/limits.hpp" -#include "duckdb/common/random_engine.hpp" - -namespace duckdb { - -struct SetseedBindData : public FunctionData { - //! The client context for the function call - ClientContext &context; - - explicit SetseedBindData(ClientContext &context) : context(context) { - } - - unique_ptr Copy() const override { - return make_uniq(context); - } - - bool Equals(const FunctionData &other_p) const override { - return true; - } -}; - -static void SetSeedFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &func_expr = state.expr.Cast(); - auto &info = func_expr.bind_info->Cast(); - auto &input = args.data[0]; - input.Flatten(args.size()); - - auto input_seeds = FlatVector::GetData(input); - uint32_t half_max = NumericLimits::Maximum() / 2; - - auto &random_engine = RandomEngine::Get(info.context); - for (idx_t i = 0; i < args.size(); i++) { - if (input_seeds[i] < -1.0 || input_seeds[i] > 1.0 || Value::IsNan(input_seeds[i])) { - throw InvalidInputException("SETSEED accepts seed values between -1.0 and 1.0, inclusive"); - } - auto norm_seed = LossyNumericCast((input_seeds[i] + 1.0) * half_max); - random_engine.SetSeed(norm_seed); - } - - result.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(result, true); -} - -unique_ptr SetSeedBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - return make_uniq(context); -} - -ScalarFunction SetseedFun::GetFunction() { - ScalarFunction setseed("setseed", {LogicalType::DOUBLE}, LogicalType::SQLNULL, SetSeedFunction, SetSeedBind); - setseed.stability = FunctionStability::VOLATILE; - return setseed; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/ascii.cpp b/src/duckdb/src/core_functions/scalar/string/ascii.cpp deleted file mode 100644 index 5f41338bb..000000000 --- a/src/duckdb/src/core_functions/scalar/string/ascii.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" -#include "utf8proc.hpp" -#include "utf8proc_wrapper.hpp" - -namespace duckdb { - -struct AsciiOperator { - template - static inline TR Operation(const TA &input) { - auto str = input.GetData(); - if (Utf8Proc::Analyze(str, input.GetSize()) == UnicodeType::ASCII) { - return str[0]; - } - int utf8_bytes = 4; - return Utf8Proc::UTF8ToCodepoint(str, utf8_bytes); - } -}; - -ScalarFunction ASCIIFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR}, LogicalType::INTEGER, - ScalarFunction::UnaryFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/bar.cpp b/src/duckdb/src/core_functions/scalar/string/bar.cpp deleted file mode 100644 index b571e7ac2..000000000 --- a/src/duckdb/src/core_functions/scalar/string/bar.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/operator/cast_operators.hpp" -#include "duckdb/common/types/string_type.hpp" -#include "duckdb/common/types/value.hpp" -#include "duckdb/common/types/vector.hpp" -#include "duckdb/common/unicode_bar.hpp" -#include "duckdb/common/vector_operations/generic_executor.hpp" - -namespace duckdb { - -static string_t BarScalarFunction(double x, double min, double max, double max_width, string &result) { - static const char *FULL_BLOCK = UnicodeBar::FullBlock(); - static const char *const *PARTIAL_BLOCKS = UnicodeBar::PartialBlocks(); - static const idx_t PARTIAL_BLOCKS_COUNT = UnicodeBar::PartialBlocksCount(); - - if (!Value::IsFinite(max_width)) { - throw OutOfRangeException("Max bar width must not be NaN or infinity"); - } - if (max_width < 1) { - throw OutOfRangeException("Max bar width must be >= 1"); - } - if (max_width > 1000) { - throw OutOfRangeException("Max bar width must be <= 1000"); - } - - double width; - - if (Value::IsNan(x) || Value::IsNan(min) || Value::IsNan(max) || x <= min) { - width = 0; - } else if (x >= max) { - width = max_width; - } else { - width = max_width * (x - min) / (max - min); - } - - if (!Value::IsFinite(width)) { - throw OutOfRangeException("Bar width must not be NaN or infinity"); - } - - result.clear(); - - auto width_as_int = LossyNumericCast(width * PARTIAL_BLOCKS_COUNT); - idx_t full_blocks_count = (width_as_int / PARTIAL_BLOCKS_COUNT); - for (idx_t i = 0; i < full_blocks_count; i++) { - result += FULL_BLOCK; - } - - idx_t remaining = width_as_int % PARTIAL_BLOCKS_COUNT; - - if (remaining) { - result += PARTIAL_BLOCKS[remaining]; - } - - const idx_t integer_max_width = (idx_t)max_width; - if (result.size() < integer_max_width) { - result += std::string(integer_max_width - result.size(), ' '); - } - - return string_t(result); -} - -static void BarFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 3 || args.ColumnCount() == 4); - auto &x_arg = args.data[0]; - auto &min_arg = args.data[1]; - auto &max_arg = args.data[2]; - string buffer; - - if (args.ColumnCount() == 3) { - GenericExecutor::ExecuteTernary, PrimitiveType, PrimitiveType, - PrimitiveType>( - x_arg, min_arg, max_arg, result, args.size(), - [&](PrimitiveType x, PrimitiveType min, PrimitiveType max) { - return StringVector::AddString(result, BarScalarFunction(x.val, min.val, max.val, 80, buffer)); - }); - } else { - auto &width_arg = args.data[3]; - GenericExecutor::ExecuteQuaternary, PrimitiveType, PrimitiveType, - PrimitiveType, PrimitiveType>( - x_arg, min_arg, max_arg, width_arg, result, args.size(), - [&](PrimitiveType x, PrimitiveType min, PrimitiveType max, - PrimitiveType width) { - return StringVector::AddString(result, BarScalarFunction(x.val, min.val, max.val, width.val, buffer)); - }); - } -} - -ScalarFunctionSet BarFun::GetFunctions() { - ScalarFunctionSet bar; - bar.AddFunction(ScalarFunction({LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE}, - LogicalType::VARCHAR, BarFunction)); - bar.AddFunction(ScalarFunction({LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::DOUBLE}, - LogicalType::VARCHAR, BarFunction)); - return bar; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/chr.cpp b/src/duckdb/src/core_functions/scalar/string/chr.cpp deleted file mode 100644 index 34f897eb6..000000000 --- a/src/duckdb/src/core_functions/scalar/string/chr.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" -#include "utf8proc.hpp" -#include "utf8proc_wrapper.hpp" - -namespace duckdb { - -struct ChrOperator { - static void GetCodepoint(int32_t input, char c[], int &utf8_bytes) { - if (input < 0 || !Utf8Proc::CodepointToUtf8(input, utf8_bytes, &c[0])) { - throw InvalidInputException("Invalid UTF8 Codepoint %d", input); - } - } - - template - static inline TR Operation(const TA &input) { - char c[5] = {'\0', '\0', '\0', '\0', '\0'}; - int utf8_bytes; - GetCodepoint(input, c, utf8_bytes); - return string_t(&c[0], UnsafeNumericCast(utf8_bytes)); - } -}; - -#ifdef DUCKDB_DEBUG_NO_INLINE -// the chr function depends on the data always being inlined (which is always possible, since it outputs max 4 bytes) -// to enable chr when string inlining is disabled we create a special function here -static void ChrFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &code_vec = args.data[0]; - - char c[5] = {'\0', '\0', '\0', '\0', '\0'}; - int utf8_bytes; - UnaryExecutor::Execute(code_vec, result, args.size(), [&](int32_t input) { - ChrOperator::GetCodepoint(input, c, utf8_bytes); - return StringVector::AddString(result, &c[0], UnsafeNumericCast(utf8_bytes)); - }); -} -#endif - -ScalarFunction ChrFun::GetFunction() { - return ScalarFunction("chr", {LogicalType::INTEGER}, LogicalType::VARCHAR, -#ifdef DUCKDB_DEBUG_NO_INLINE - ChrFunction -#else - ScalarFunction::UnaryFunction -#endif - ); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/damerau_levenshtein.cpp b/src/duckdb/src/core_functions/scalar/string/damerau_levenshtein.cpp deleted file mode 100644 index 20bb7dfcd..000000000 --- a/src/duckdb/src/core_functions/scalar/string/damerau_levenshtein.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" -#include "duckdb/common/map.hpp" -#include "duckdb/common/vector.hpp" - -namespace duckdb { - -// Using Lowrance-Wagner (LW) algorithm: https://doi.org/10.1145%2F321879.321880 -// Can't calculate as trivial modification to levenshtein algorithm -// as we need to potentially know about earlier in the string -static idx_t DamerauLevenshteinDistance(const string_t &source, const string_t &target) { - // costs associated with each type of edit, to aid readability - constexpr uint8_t COST_SUBSTITUTION = 1; - constexpr uint8_t COST_INSERTION = 1; - constexpr uint8_t COST_DELETION = 1; - constexpr uint8_t COST_TRANSPOSITION = 1; - const auto source_len = source.GetSize(); - const auto target_len = target.GetSize(); - - // If one string is empty, the distance equals the length of the other string - // either through target_len insertions - // or source_len deletions - if (source_len == 0) { - return target_len * COST_INSERTION; - } else if (target_len == 0) { - return source_len * COST_DELETION; - } - - const auto source_str = source.GetData(); - const auto target_str = target.GetData(); - - // larger than the largest possible value: - const auto inf = source_len * COST_DELETION + target_len * COST_INSERTION + 1; - // minimum edit distance from prefix of source string to prefix of target string - // same object as H in LW paper (with indices offset by 1) - vector> distance(source_len + 2, vector(target_len + 2, inf)); - // keeps track of the largest string indices of source string matching each character - // same as DA in LW paper - map largest_source_chr_matching; - - // initialise row/column corresponding to zero-length strings - // partial string -> empty requires a deletion for each character - for (idx_t source_idx = 0; source_idx <= source_len; source_idx++) { - distance[source_idx + 1][1] = source_idx * COST_DELETION; - } - // and empty -> partial string means simply inserting characters - for (idx_t target_idx = 1; target_idx <= target_len; target_idx++) { - distance[1][target_idx + 1] = target_idx * COST_INSERTION; - } - // loop through string indices - these are offset by 2 from distance indices - for (idx_t source_idx = 0; source_idx < source_len; source_idx++) { - // keeps track of the largest string indices of target string matching current source character - // same as DB in LW paper - idx_t largest_target_chr_matching; - largest_target_chr_matching = 0; - for (idx_t target_idx = 0; target_idx < target_len; target_idx++) { - // correspond to i1 and j1 in LW paper respectively - idx_t largest_source_chr_matching_target; - idx_t largest_target_chr_matching_source; - // cost associated to diagnanl shift in distance matrix - // corresponds to d in LW paper - uint8_t cost_diagonal_shift; - largest_source_chr_matching_target = largest_source_chr_matching[target_str[target_idx]]; - largest_target_chr_matching_source = largest_target_chr_matching; - // if characters match, diagonal move costs nothing and we update our largest target index - // otherwise move is substitution and costs as such - if (source_str[source_idx] == target_str[target_idx]) { - cost_diagonal_shift = 0; - largest_target_chr_matching = target_idx + 1; - } else { - cost_diagonal_shift = COST_SUBSTITUTION; - } - distance[source_idx + 2][target_idx + 2] = MinValue( - distance[source_idx + 1][target_idx + 1] + cost_diagonal_shift, - MinValue(distance[source_idx + 2][target_idx + 1] + COST_INSERTION, - MinValue(distance[source_idx + 1][target_idx + 2] + COST_DELETION, - distance[largest_source_chr_matching_target][largest_target_chr_matching_source] + - (source_idx - largest_source_chr_matching_target) * COST_DELETION + - COST_TRANSPOSITION + - (target_idx - largest_target_chr_matching_source) * COST_INSERTION))); - } - largest_source_chr_matching[source_str[source_idx]] = source_idx + 1; - } - return distance[source_len + 1][target_len + 1]; -} - -static int64_t DamerauLevenshteinScalarFunction(Vector &result, const string_t source, const string_t target) { - return (int64_t)DamerauLevenshteinDistance(source, target); -} - -static void DamerauLevenshteinFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &source_vec = args.data[0]; - auto &target_vec = args.data[1]; - - BinaryExecutor::Execute( - source_vec, target_vec, result, args.size(), - [&](string_t source, string_t target) { return DamerauLevenshteinScalarFunction(result, source, target); }); -} - -ScalarFunction DamerauLevenshteinFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BIGINT, - DamerauLevenshteinFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/format_bytes.cpp b/src/duckdb/src/core_functions/scalar/string/format_bytes.cpp deleted file mode 100644 index 7a5117997..000000000 --- a/src/duckdb/src/core_functions/scalar/string/format_bytes.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" -#include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/common/string_util.hpp" - -namespace duckdb { - -template -static void FormatBytesFunction(DataChunk &args, ExpressionState &state, Vector &result) { - UnaryExecutor::Execute(args.data[0], result, args.size(), [&](int64_t bytes) { - bool is_negative = bytes < 0; - idx_t unsigned_bytes; - if (bytes < 0) { - if (bytes == NumericLimits::Minimum()) { - unsigned_bytes = idx_t(NumericLimits::Maximum()) + 1; - } else { - unsigned_bytes = idx_t(-bytes); - } - } else { - unsigned_bytes = idx_t(bytes); - } - return StringVector::AddString(result, (is_negative ? "-" : "") + - StringUtil::BytesToHumanReadableString(unsigned_bytes, MULTIPLIER)); - }); -} - -ScalarFunction FormatBytesFun::GetFunction() { - return ScalarFunction({LogicalType::BIGINT}, LogicalType::VARCHAR, FormatBytesFunction<1024>); -} - -ScalarFunction FormatreadabledecimalsizeFun::GetFunction() { - return ScalarFunction({LogicalType::BIGINT}, LogicalType::VARCHAR, FormatBytesFunction<1000>); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/hamming.cpp b/src/duckdb/src/core_functions/scalar/string/hamming.cpp deleted file mode 100644 index 892430da3..000000000 --- a/src/duckdb/src/core_functions/scalar/string/hamming.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" - -#include -#include - -namespace duckdb { - -static int64_t MismatchesScalarFunction(Vector &result, const string_t str, string_t tgt) { - idx_t str_len = str.GetSize(); - idx_t tgt_len = tgt.GetSize(); - - if (str_len != tgt_len) { - throw InvalidInputException("Mismatch Function: Strings must be of equal length!"); - } - if (str_len < 1) { - throw InvalidInputException("Mismatch Function: Strings must be of length > 0!"); - } - - idx_t mismatches = 0; - auto str_str = str.GetData(); - auto tgt_str = tgt.GetData(); - - for (idx_t idx = 0; idx < str_len; ++idx) { - if (str_str[idx] != tgt_str[idx]) { - mismatches++; - } - } - return (int64_t)mismatches; -} - -static void MismatchesFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &str_vec = args.data[0]; - auto &tgt_vec = args.data[1]; - - BinaryExecutor::Execute( - str_vec, tgt_vec, result, args.size(), - [&](string_t str, string_t tgt) { return MismatchesScalarFunction(result, str, tgt); }); -} - -ScalarFunction HammingFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BIGINT, MismatchesFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/hex.cpp b/src/duckdb/src/core_functions/scalar/string/hex.cpp deleted file mode 100644 index 6f982f261..000000000 --- a/src/duckdb/src/core_functions/scalar/string/hex.cpp +++ /dev/null @@ -1,436 +0,0 @@ -#include "duckdb/common/bit_utils.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/numeric_utils.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/common/types/blob.hpp" -#include "duckdb/common/vector_operations/unary_executor.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/core_functions/scalar/string_functions.hpp" - -namespace duckdb { - -static void WriteHexBytes(uint64_t x, char *&output, idx_t buffer_size) { - idx_t offset = buffer_size * 4; - - for (; offset >= 4; offset -= 4) { - uint8_t byte = (x >> (offset - 4)) & 0x0F; - *output = Blob::HEX_TABLE[byte]; - output++; - } -} - -template -static void WriteHugeIntHexBytes(T x, char *&output, idx_t buffer_size) { - idx_t offset = buffer_size * 4; - auto upper = x.upper; - auto lower = x.lower; - - for (; offset >= 68; offset -= 4) { - uint8_t byte = (upper >> (offset - 68)) & 0x0F; - *output = Blob::HEX_TABLE[byte]; - output++; - } - - for (; offset >= 4; offset -= 4) { - uint8_t byte = (lower >> (offset - 4)) & 0x0F; - *output = Blob::HEX_TABLE[byte]; - output++; - } -} - -static void WriteBinBytes(uint64_t x, char *&output, idx_t buffer_size) { - idx_t offset = buffer_size; - for (; offset >= 1; offset -= 1) { - *output = NumericCast(((x >> (offset - 1)) & 0x01) + '0'); - output++; - } -} - -template -static void WriteHugeIntBinBytes(T x, char *&output, idx_t buffer_size) { - auto upper = x.upper; - auto lower = x.lower; - idx_t offset = buffer_size; - - for (; offset >= 65; offset -= 1) { - *output = ((upper >> (offset - 65)) & 0x01) + '0'; - output++; - } - - for (; offset >= 1; offset -= 1) { - *output = ((lower >> (offset - 1)) & 0x01) + '0'; - output++; - } -} - -struct HexStrOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - auto data = input.GetData(); - auto size = input.GetSize(); - - // Allocate empty space - auto target = StringVector::EmptyString(result, size * 2); - auto output = target.GetDataWriteable(); - - for (idx_t i = 0; i < size; ++i) { - *output = Blob::HEX_TABLE[(data[i] >> 4) & 0x0F]; - output++; - *output = Blob::HEX_TABLE[data[i] & 0x0F]; - output++; - } - - target.Finalize(); - return target; - } -}; - -struct HexIntegralOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - - auto num_leading_zero = CountZeros::Leading(static_cast(input)); - idx_t num_bits_to_check = 64 - num_leading_zero; - D_ASSERT(num_bits_to_check <= sizeof(INPUT_TYPE) * 8); - - idx_t buffer_size = (num_bits_to_check + 3) / 4; - - // Special case: All bits are zero - if (buffer_size == 0) { - auto target = StringVector::EmptyString(result, 1); - auto output = target.GetDataWriteable(); - *output = '0'; - target.Finalize(); - return target; - } - - D_ASSERT(buffer_size > 0); - auto target = StringVector::EmptyString(result, buffer_size); - auto output = target.GetDataWriteable(); - - WriteHexBytes(static_cast(input), output, buffer_size); - - target.Finalize(); - return target; - } -}; - -struct HexHugeIntOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - - idx_t num_leading_zero = CountZeros::Leading(UnsafeNumericCast(input)); - idx_t buffer_size = sizeof(INPUT_TYPE) * 2 - (num_leading_zero / 4); - - // Special case: All bits are zero - if (buffer_size == 0) { - auto target = StringVector::EmptyString(result, 1); - auto output = target.GetDataWriteable(); - *output = '0'; - target.Finalize(); - return target; - } - - D_ASSERT(buffer_size > 0); - auto target = StringVector::EmptyString(result, buffer_size); - auto output = target.GetDataWriteable(); - - WriteHugeIntHexBytes(input, output, buffer_size); - - target.Finalize(); - return target; - } -}; - -struct HexUhugeIntOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - - idx_t num_leading_zero = CountZeros::Leading(UnsafeNumericCast(input)); - idx_t buffer_size = sizeof(INPUT_TYPE) * 2 - (num_leading_zero / 4); - - // Special case: All bits are zero - if (buffer_size == 0) { - auto target = StringVector::EmptyString(result, 1); - auto output = target.GetDataWriteable(); - *output = '0'; - target.Finalize(); - return target; - } - - D_ASSERT(buffer_size > 0); - auto target = StringVector::EmptyString(result, buffer_size); - auto output = target.GetDataWriteable(); - - WriteHugeIntHexBytes(input, output, buffer_size); - - target.Finalize(); - return target; - } -}; - -template -static void ToHexFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 1); - auto &input = args.data[0]; - idx_t count = args.size(); - UnaryExecutor::ExecuteString(input, result, count); -} - -struct BinaryStrOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - auto data = input.GetData(); - auto size = input.GetSize(); - - // Allocate empty space - auto target = StringVector::EmptyString(result, size * 8); - auto output = target.GetDataWriteable(); - - for (idx_t i = 0; i < size; ++i) { - auto byte = static_cast(data[i]); - for (idx_t i = 8; i >= 1; --i) { - *output = ((byte >> (i - 1)) & 0x01) + '0'; - output++; - } - } - - target.Finalize(); - return target; - } -}; - -struct BinaryIntegralOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - - auto num_leading_zero = CountZeros::Leading(static_cast(input)); - idx_t num_bits_to_check = 64 - num_leading_zero; - D_ASSERT(num_bits_to_check <= sizeof(INPUT_TYPE) * 8); - - idx_t buffer_size = num_bits_to_check; - - // Special case: All bits are zero - if (buffer_size == 0) { - auto target = StringVector::EmptyString(result, 1); - auto output = target.GetDataWriteable(); - *output = '0'; - target.Finalize(); - return target; - } - - D_ASSERT(buffer_size > 0); - auto target = StringVector::EmptyString(result, buffer_size); - auto output = target.GetDataWriteable(); - - WriteBinBytes(static_cast(input), output, buffer_size); - - target.Finalize(); - return target; - } -}; - -struct BinaryHugeIntOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - auto num_leading_zero = CountZeros::Leading(UnsafeNumericCast(input)); - idx_t buffer_size = sizeof(INPUT_TYPE) * 8 - num_leading_zero; - - // Special case: All bits are zero - if (buffer_size == 0) { - auto target = StringVector::EmptyString(result, 1); - auto output = target.GetDataWriteable(); - *output = '0'; - target.Finalize(); - return target; - } - - auto target = StringVector::EmptyString(result, buffer_size); - auto output = target.GetDataWriteable(); - - WriteHugeIntBinBytes(input, output, buffer_size); - - target.Finalize(); - return target; - } -}; - -struct BinaryUhugeIntOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - auto num_leading_zero = CountZeros::Leading(UnsafeNumericCast(input)); - idx_t buffer_size = sizeof(INPUT_TYPE) * 8 - num_leading_zero; - - // Special case: All bits are zero - if (buffer_size == 0) { - auto target = StringVector::EmptyString(result, 1); - auto output = target.GetDataWriteable(); - *output = '0'; - target.Finalize(); - return target; - } - - auto target = StringVector::EmptyString(result, buffer_size); - auto output = target.GetDataWriteable(); - - WriteHugeIntBinBytes(input, output, buffer_size); - - target.Finalize(); - return target; - } -}; - -struct FromHexOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - auto data = input.GetData(); - auto size = input.GetSize(); - - if (size > NumericLimits::Maximum()) { - throw InvalidInputException("Hexadecimal input length larger than 2^32 are not supported"); - } - - D_ASSERT(size <= NumericLimits::Maximum()); - auto buffer_size = (size + 1) / 2; - - // Allocate empty space - auto target = StringVector::EmptyString(result, buffer_size); - auto output = target.GetDataWriteable(); - - // Treated as a single byte - idx_t i = 0; - if (size % 2 != 0) { - *output = static_cast(StringUtil::GetHexValue(data[i])); - i++; - output++; - } - - for (; i < size; i += 2) { - uint8_t major = StringUtil::GetHexValue(data[i]); - uint8_t minor = StringUtil::GetHexValue(data[i + 1]); - *output = static_cast((major << 4) | minor); - output++; - } - - target.Finalize(); - return target; - } -}; - -struct FromBinaryOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - auto data = input.GetData(); - auto size = input.GetSize(); - - if (size > NumericLimits::Maximum()) { - throw InvalidInputException("Binary input length larger than 2^32 are not supported"); - } - - D_ASSERT(size <= NumericLimits::Maximum()); - auto buffer_size = (size + 7) / 8; - - // Allocate empty space - auto target = StringVector::EmptyString(result, buffer_size); - auto output = target.GetDataWriteable(); - - // Treated as a single byte - idx_t i = 0; - if (size % 8 != 0) { - uint8_t byte = 0; - for (idx_t j = size % 8; j > 0; --j) { - byte |= StringUtil::GetBinaryValue(data[i]) << (j - 1); - i++; - } - *output = static_cast(byte); // binary eh - output++; - } - - while (i < size) { - uint8_t byte = 0; - for (idx_t j = 8; j > 0; --j) { - byte |= StringUtil::GetBinaryValue(data[i]) << (j - 1); - i++; - } - *output = static_cast(byte); - output++; - } - - target.Finalize(); - return target; - } -}; - -template -static void ToBinaryFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 1); - auto &input = args.data[0]; - idx_t count = args.size(); - UnaryExecutor::ExecuteString(input, result, count); -} - -static void FromBinaryFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 1); - D_ASSERT(args.data[0].GetType().InternalType() == PhysicalType::VARCHAR); - auto &input = args.data[0]; - idx_t count = args.size(); - - UnaryExecutor::ExecuteString(input, result, count); -} - -static void FromHexFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 1); - D_ASSERT(args.data[0].GetType().InternalType() == PhysicalType::VARCHAR); - auto &input = args.data[0]; - idx_t count = args.size(); - - UnaryExecutor::ExecuteString(input, result, count); -} - -ScalarFunctionSet HexFun::GetFunctions() { - ScalarFunctionSet to_hex; - to_hex.AddFunction( - ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, ToHexFunction)); - to_hex.AddFunction( - ScalarFunction({LogicalType::VARINT}, LogicalType::VARCHAR, ToHexFunction)); - to_hex.AddFunction( - ScalarFunction({LogicalType::BLOB}, LogicalType::VARCHAR, ToHexFunction)); - to_hex.AddFunction( - ScalarFunction({LogicalType::BIGINT}, LogicalType::VARCHAR, ToHexFunction)); - to_hex.AddFunction( - ScalarFunction({LogicalType::UBIGINT}, LogicalType::VARCHAR, ToHexFunction)); - to_hex.AddFunction( - ScalarFunction({LogicalType::HUGEINT}, LogicalType::VARCHAR, ToHexFunction)); - to_hex.AddFunction( - ScalarFunction({LogicalType::UHUGEINT}, LogicalType::VARCHAR, ToHexFunction)); - return to_hex; -} - -ScalarFunction UnhexFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR}, LogicalType::BLOB, FromHexFunction); -} - -ScalarFunctionSet BinFun::GetFunctions() { - ScalarFunctionSet to_binary; - - to_binary.AddFunction( - ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, ToBinaryFunction)); - to_binary.AddFunction( - ScalarFunction({LogicalType::VARINT}, LogicalType::VARCHAR, ToBinaryFunction)); - to_binary.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::VARCHAR, - ToBinaryFunction)); - to_binary.AddFunction( - ScalarFunction({LogicalType::BIGINT}, LogicalType::VARCHAR, ToBinaryFunction)); - to_binary.AddFunction(ScalarFunction({LogicalType::HUGEINT}, LogicalType::VARCHAR, - ToBinaryFunction)); - to_binary.AddFunction(ScalarFunction({LogicalType::UHUGEINT}, LogicalType::VARCHAR, - ToBinaryFunction)); - return to_binary; -} - -ScalarFunction UnbinFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR}, LogicalType::BLOB, FromBinaryFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/instr.cpp b/src/duckdb/src/core_functions/scalar/string/instr.cpp deleted file mode 100644 index 66608db60..000000000 --- a/src/duckdb/src/core_functions/scalar/string/instr.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" - -#include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/function/scalar/string_functions.hpp" -#include "utf8proc.hpp" - -namespace duckdb { - -struct InstrOperator { - template - static inline TR Operation(TA haystack, TB needle) { - int64_t string_position = 0; - - auto location = ContainsFun::Find(haystack, needle); - if (location != DConstants::INVALID_INDEX) { - auto len = (utf8proc_ssize_t)location; - auto str = reinterpret_cast(haystack.GetData()); - D_ASSERT(len <= (utf8proc_ssize_t)haystack.GetSize()); - for (++string_position; len > 0; ++string_position) { - utf8proc_int32_t codepoint; - auto bytes = utf8proc_iterate(str, len, &codepoint); - str += bytes; - len -= bytes; - } - } - return string_position; - } -}; - -struct InstrAsciiOperator { - template - static inline TR Operation(TA haystack, TB needle) { - auto location = ContainsFun::Find(haystack, needle); - return UnsafeNumericCast(location == DConstants::INVALID_INDEX ? 0U : location + 1U); - } -}; - -static unique_ptr InStrPropagateStats(ClientContext &context, FunctionStatisticsInput &input) { - auto &child_stats = input.child_stats; - auto &expr = input.expr; - D_ASSERT(child_stats.size() == 2); - // can only propagate stats if the children have stats - // for strpos, we only care if the FIRST string has unicode or not - if (!StringStats::CanContainUnicode(child_stats[0])) { - expr.function.function = ScalarFunction::BinaryFunction; - } - return nullptr; -} - -ScalarFunction InstrFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BIGINT, - ScalarFunction::BinaryFunction, nullptr, nullptr, - InStrPropagateStats); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/jaccard.cpp b/src/duckdb/src/core_functions/scalar/string/jaccard.cpp deleted file mode 100644 index e3f081b6a..000000000 --- a/src/duckdb/src/core_functions/scalar/string/jaccard.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "duckdb/common/map.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/core_functions/scalar/string_functions.hpp" - -#include -#include - -namespace duckdb { - -namespace { -constexpr size_t MAX_SIZE = std::numeric_limits::max() + 1; -} - -static inline std::bitset GetSet(const string_t &str) { - std::bitset array_set; - - idx_t str_len = str.GetSize(); - auto s = str.GetData(); - - for (idx_t pos = 0; pos < str_len; pos++) { - array_set.set(static_cast(s[pos])); - } - return array_set; -} - -static double JaccardSimilarity(const string_t &str, const string_t &txt) { - if (str.GetSize() < 1 || txt.GetSize() < 1) { - throw InvalidInputException("Jaccard Function: An argument too short!"); - } - std::bitset m_str, m_txt; - - m_str = GetSet(str); - m_txt = GetSet(txt); - - idx_t size_intersect = (m_str & m_txt).count(); - idx_t size_union = (m_str | m_txt).count(); - - return static_cast(size_intersect) / static_cast(size_union); -} - -static double JaccardScalarFunction(Vector &result, const string_t str, string_t tgt) { - return (double)JaccardSimilarity(str, tgt); -} - -static void JaccardFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &str_vec = args.data[0]; - auto &tgt_vec = args.data[1]; - - BinaryExecutor::Execute( - str_vec, tgt_vec, result, args.size(), - [&](string_t str, string_t tgt) { return JaccardScalarFunction(result, str, tgt); }); -} - -ScalarFunction JaccardFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::DOUBLE, JaccardFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/jaro_winkler.cpp b/src/duckdb/src/core_functions/scalar/string/jaro_winkler.cpp deleted file mode 100644 index 3c54b411f..000000000 --- a/src/duckdb/src/core_functions/scalar/string/jaro_winkler.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "jaro_winkler.hpp" - -#include "duckdb/core_functions/scalar/string_functions.hpp" - -namespace duckdb { - -static inline double JaroScalarFunction(const string_t &s1, const string_t &s2) { - auto s1_begin = s1.GetData(); - auto s2_begin = s2.GetData(); - return duckdb_jaro_winkler::jaro_similarity(s1_begin, s1_begin + s1.GetSize(), s2_begin, s2_begin + s2.GetSize()); -} - -static inline double JaroWinklerScalarFunction(const string_t &s1, const string_t &s2) { - auto s1_begin = s1.GetData(); - auto s2_begin = s2.GetData(); - return duckdb_jaro_winkler::jaro_winkler_similarity(s1_begin, s1_begin + s1.GetSize(), s2_begin, - s2_begin + s2.GetSize()); -} - -template -static void CachedFunction(Vector &constant, Vector &other, Vector &result, idx_t count) { - auto val = constant.GetValue(0); - if (val.IsNull()) { - auto &result_validity = FlatVector::Validity(result); - result_validity.SetAllInvalid(count); - return; - } - - auto str_val = StringValue::Get(val); - auto cached = CACHED_SIMILARITY(str_val); - UnaryExecutor::Execute(other, result, count, [&](const string_t &other_str) { - auto other_str_begin = other_str.GetData(); - return cached.similarity(other_str_begin, other_str_begin + other_str.GetSize()); - }); -} - -template > -static void TemplatedJaroWinklerFunction(DataChunk &args, Vector &result, SIMILARITY_FUNCTION fun) { - bool arg0_constant = args.data[0].GetVectorType() == VectorType::CONSTANT_VECTOR; - bool arg1_constant = args.data[1].GetVectorType() == VectorType::CONSTANT_VECTOR; - if (!(arg0_constant ^ arg1_constant)) { - // We can't optimize by caching one of the two strings - BinaryExecutor::Execute(args.data[0], args.data[1], result, args.size(), fun); - return; - } - - if (arg0_constant) { - CachedFunction(args.data[0], args.data[1], result, args.size()); - } else { - CachedFunction(args.data[1], args.data[0], result, args.size()); - } -} - -static void JaroFunction(DataChunk &args, ExpressionState &state, Vector &result) { - TemplatedJaroWinklerFunction>(args, result, JaroScalarFunction); -} - -static void JaroWinklerFunction(DataChunk &args, ExpressionState &state, Vector &result) { - TemplatedJaroWinklerFunction>(args, result, - JaroWinklerScalarFunction); -} - -ScalarFunction JaroSimilarityFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::DOUBLE, JaroFunction); -} - -ScalarFunction JaroWinklerSimilarityFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::DOUBLE, JaroWinklerFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/left_right.cpp b/src/duckdb/src/core_functions/scalar/string/left_right.cpp deleted file mode 100644 index 886559b62..000000000 --- a/src/duckdb/src/core_functions/scalar/string/left_right.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/limits.hpp" -#include "duckdb/function/scalar/string_functions.hpp" - -#include -#include - -namespace duckdb { - -struct LeftRightUnicode { - template - static inline TR Operation(TA input) { - return LengthFun::Length(input); - } - - static string_t Substring(Vector &result, string_t input, int64_t offset, int64_t length) { - return SubstringFun::SubstringUnicode(result, input, offset, length); - } -}; - -struct LeftRightGrapheme { - template - static inline TR Operation(TA input) { - return LengthFun::GraphemeCount(input); - } - - static string_t Substring(Vector &result, string_t input, int64_t offset, int64_t length) { - return SubstringFun::SubstringGrapheme(result, input, offset, length); - } -}; - -template -static string_t LeftScalarFunction(Vector &result, const string_t str, int64_t pos) { - if (pos >= 0) { - return OP::Substring(result, str, 1, pos); - } - - int64_t num_characters = OP::template Operation(str); - pos = MaxValue(0, num_characters + pos); - return OP::Substring(result, str, 1, pos); -} - -template -static void LeftFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &str_vec = args.data[0]; - auto &pos_vec = args.data[1]; - - BinaryExecutor::Execute( - str_vec, pos_vec, result, args.size(), - [&](string_t str, int64_t pos) { return LeftScalarFunction(result, str, pos); }); -} - -ScalarFunction LeftFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR, LogicalType::BIGINT}, LogicalType::VARCHAR, - LeftFunction); -} - -ScalarFunction LeftGraphemeFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR, LogicalType::BIGINT}, LogicalType::VARCHAR, - LeftFunction); -} - -template -static string_t RightScalarFunction(Vector &result, const string_t str, int64_t pos) { - int64_t num_characters = OP::template Operation(str); - if (pos >= 0) { - int64_t len = MinValue(num_characters, pos); - int64_t start = num_characters - len + 1; - return OP::Substring(result, str, start, len); - } - - int64_t len = 0; - if (pos != std::numeric_limits::min()) { - len = num_characters - MinValue(num_characters, -pos); - } - int64_t start = num_characters - len + 1; - return OP::Substring(result, str, start, len); -} - -template -static void RightFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &str_vec = args.data[0]; - auto &pos_vec = args.data[1]; - BinaryExecutor::Execute( - str_vec, pos_vec, result, args.size(), - [&](string_t str, int64_t pos) { return RightScalarFunction(result, str, pos); }); -} - -ScalarFunction RightFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR, LogicalType::BIGINT}, LogicalType::VARCHAR, - RightFunction); -} - -ScalarFunction RightGraphemeFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR, LogicalType::BIGINT}, LogicalType::VARCHAR, - RightFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/levenshtein.cpp b/src/duckdb/src/core_functions/scalar/string/levenshtein.cpp deleted file mode 100644 index 13731e385..000000000 --- a/src/duckdb/src/core_functions/scalar/string/levenshtein.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/string_util.hpp" - -#include -#include - -namespace duckdb { - -// See: https://www.kdnuggets.com/2020/10/optimizing-levenshtein-distance-measuring-text-similarity.html -// And: Iterative 2-row algorithm: https://en.wikipedia.org/wiki/Levenshtein_distance -// Note: A first implementation using the array algorithm version resulted in an error raised by duckdb -// (too muach memory usage) - -static idx_t LevenshteinDistance(const string_t &txt, const string_t &tgt) { - auto txt_len = txt.GetSize(); - auto tgt_len = tgt.GetSize(); - - // If one string is empty, the distance equals the length of the other string - if (txt_len == 0) { - return tgt_len; - } else if (tgt_len == 0) { - return txt_len; - } - - auto txt_str = txt.GetData(); - auto tgt_str = tgt.GetData(); - - // Create two working vectors - vector distances0(tgt_len + 1, 0); - vector distances1(tgt_len + 1, 0); - - idx_t cost_substitution = 0; - idx_t cost_insertion = 0; - idx_t cost_deletion = 0; - - // initialize distances0 vector - // edit distance for an empty txt string is just the number of characters to delete from tgt - for (idx_t pos_tgt = 0; pos_tgt <= tgt_len; pos_tgt++) { - distances0[pos_tgt] = pos_tgt; - } - - for (idx_t pos_txt = 0; pos_txt < txt_len; pos_txt++) { - // calculate distances1 (current raw distances) from the previous row - - distances1[0] = pos_txt + 1; - - for (idx_t pos_tgt = 0; pos_tgt < tgt_len; pos_tgt++) { - cost_deletion = distances0[pos_tgt + 1] + 1; - cost_insertion = distances1[pos_tgt] + 1; - cost_substitution = distances0[pos_tgt]; - - if (txt_str[pos_txt] != tgt_str[pos_tgt]) { - cost_substitution += 1; - } - - distances1[pos_tgt + 1] = MinValue(cost_deletion, MinValue(cost_substitution, cost_insertion)); - } - // copy distances1 (current row) to distances0 (previous row) for next iteration - // since data in distances1 is always invalidated, a swap without copy is more efficient - distances0 = distances1; - } - - return distances0[tgt_len]; -} - -static int64_t LevenshteinScalarFunction(Vector &result, const string_t str, string_t tgt) { - return (int64_t)LevenshteinDistance(str, tgt); -} - -static void LevenshteinFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &str_vec = args.data[0]; - auto &tgt_vec = args.data[1]; - - BinaryExecutor::Execute( - str_vec, tgt_vec, result, args.size(), - [&](string_t str, string_t tgt) { return LevenshteinScalarFunction(result, str, tgt); }); -} - -ScalarFunction LevenshteinFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BIGINT, LevenshteinFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/pad.cpp b/src/duckdb/src/core_functions/scalar/string/pad.cpp deleted file mode 100644 index 856544ea7..000000000 --- a/src/duckdb/src/core_functions/scalar/string/pad.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" - -#include "duckdb/common/algorithm.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/vector_operations/ternary_executor.hpp" -#include "duckdb/common/pair.hpp" - -#include "utf8proc.hpp" - -namespace duckdb { - -static pair PadCountChars(const idx_t len, const char *data, const idx_t size) { - // Count how much of str will fit in the output - auto str = reinterpret_cast(data); - idx_t nbytes = 0; - idx_t nchars = 0; - for (; nchars < len && nbytes < size; ++nchars) { - utf8proc_int32_t codepoint; - auto bytes = utf8proc_iterate(str + nbytes, UnsafeNumericCast(size - nbytes), &codepoint); - D_ASSERT(bytes > 0); - nbytes += UnsafeNumericCast(bytes); - } - - return pair(nbytes, nchars); -} - -static bool InsertPadding(const idx_t len, const string_t &pad, vector &result) { - // Copy the padding until the output is long enough - auto data = pad.GetData(); - auto size = pad.GetSize(); - - // Check whether we need data that we don't have - if (len > 0 && size == 0) { - return false; - } - - // Insert characters until we have all we need. - auto str = reinterpret_cast(data); - idx_t nbytes = 0; - for (idx_t nchars = 0; nchars < len; ++nchars) { - // If we are at the end of the pad, flush all of it and loop back - if (nbytes >= size) { - result.insert(result.end(), data, data + size); - nbytes = 0; - } - - // Write the next character - utf8proc_int32_t codepoint; - auto bytes = utf8proc_iterate(str + nbytes, UnsafeNumericCast(size - nbytes), &codepoint); - D_ASSERT(bytes > 0); - nbytes += UnsafeNumericCast(bytes); - } - - // Flush the remaining pad - result.insert(result.end(), data, data + nbytes); - - return true; -} - -static string_t LeftPadFunction(const string_t &str, const int32_t len, const string_t &pad, vector &result) { - // Reuse the buffer - result.clear(); - - // Get information about the base string - auto data_str = str.GetData(); - auto size_str = str.GetSize(); - - // Count how much of str will fit in the output - auto written = PadCountChars(UnsafeNumericCast(len), data_str, size_str); - - // Left pad by the number of characters still needed - if (!InsertPadding(UnsafeNumericCast(len) - written.second, pad, result)) { - throw InvalidInputException("Insufficient padding in LPAD."); - } - - // Append as much of the original string as fits - result.insert(result.end(), data_str, data_str + written.first); - - return string_t(result.data(), UnsafeNumericCast(result.size())); -} - -struct LeftPadOperator { - static inline string_t Operation(const string_t &str, const int32_t len, const string_t &pad, - vector &result) { - return LeftPadFunction(str, len, pad, result); - } -}; - -static string_t RightPadFunction(const string_t &str, const int32_t len, const string_t &pad, vector &result) { - // Reuse the buffer - result.clear(); - - // Get information about the base string - auto data_str = str.GetData(); - auto size_str = str.GetSize(); - - // Count how much of str will fit in the output - auto written = PadCountChars(UnsafeNumericCast(len), data_str, size_str); - - // Append as much of the original string as fits - result.insert(result.end(), data_str, data_str + written.first); - - // Right pad by the number of characters still needed - if (!InsertPadding(UnsafeNumericCast(len) - written.second, pad, result)) { - throw InvalidInputException("Insufficient padding in RPAD."); - }; - - return string_t(result.data(), UnsafeNumericCast(result.size())); -} - -struct RightPadOperator { - static inline string_t Operation(const string_t &str, const int32_t len, const string_t &pad, - vector &result) { - return RightPadFunction(str, len, pad, result); - } -}; - -template -static void PadFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &str_vector = args.data[0]; - auto &len_vector = args.data[1]; - auto &pad_vector = args.data[2]; - - vector buffer; - TernaryExecutor::Execute( - str_vector, len_vector, pad_vector, result, args.size(), [&](string_t str, int32_t len, string_t pad) { - len = MaxValue(len, 0); - return StringVector::AddString(result, OP::Operation(str, len, pad, buffer)); - }); -} - -ScalarFunction LpadFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR, LogicalType::INTEGER, LogicalType::VARCHAR}, LogicalType::VARCHAR, - PadFunction); -} - -ScalarFunction RpadFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR, LogicalType::INTEGER, LogicalType::VARCHAR}, LogicalType::VARCHAR, - PadFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/parse_path.cpp b/src/duckdb/src/core_functions/scalar/string/parse_path.cpp deleted file mode 100644 index cc304d512..000000000 --- a/src/duckdb/src/core_functions/scalar/string/parse_path.cpp +++ /dev/null @@ -1,348 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" -#include "duckdb/function/scalar/string_functions.hpp" -#include "duckdb/common/local_file_system.hpp" -#include - -namespace duckdb { - -static string GetSeparator(const string_t &input) { - string option = input.GetString(); - - // system's path separator - auto fs = FileSystem::CreateLocal(); - auto system_sep = fs->PathSeparator(option); - - string separator; - if (option == "system") { - separator = system_sep; - } else if (option == "forward_slash") { - separator = "/"; - } else if (option == "backslash") { - separator = "\\"; - } else { // both_slash (default) - separator = "/\\"; - } - return separator; -} - -struct SplitInput { - SplitInput(Vector &result_list, Vector &result_child, idx_t offset) - : result_list(result_list), result_child(result_child), offset(offset) { - } - - Vector &result_list; - Vector &result_child; - idx_t offset; - - void AddSplit(const char *split_data, idx_t split_size, idx_t list_idx) { - auto list_entry = offset + list_idx; - if (list_entry >= ListVector::GetListCapacity(result_list)) { - ListVector::SetListSize(result_list, offset + list_idx); - ListVector::Reserve(result_list, ListVector::GetListCapacity(result_list) * 2); - } - FlatVector::GetData(result_child)[list_entry] = - StringVector::AddString(result_child, split_data, split_size); - } -}; - -static bool IsIdxValid(const idx_t &i, const idx_t &sentence_size) { - if (i > sentence_size || i == DConstants::INVALID_INDEX) { - return false; - } - return true; -} - -static idx_t Find(const char *input_data, idx_t input_size, const string &sep_data) { - if (sep_data.empty()) { - return 0; - } - auto pos = ContainsFun::Find(const_uchar_ptr_cast(input_data), input_size, const_uchar_ptr_cast(&sep_data[0]), 1); - // both_slash option - if (sep_data.size() > 1) { - auto sec_pos = - ContainsFun::Find(const_uchar_ptr_cast(input_data), input_size, const_uchar_ptr_cast(&sep_data[1]), 1); - // choose the leftmost valid position - if (sec_pos != DConstants::INVALID_INDEX && (sec_pos < pos || pos == DConstants::INVALID_INDEX)) { - return sec_pos; - } - } - return pos; -} - -static idx_t FindLast(const char *data_ptr, idx_t input_size, const string &sep_data) { - idx_t start = 0; - while (input_size > 0) { - auto pos = Find(data_ptr, input_size, sep_data); - if (!IsIdxValid(pos, input_size)) { - break; - } - start += (pos + 1); - data_ptr += (pos + 1); - input_size -= (pos + 1); - } - if (start < 1) { - return DConstants::INVALID_INDEX; - } - return start - 1; -} - -static idx_t SplitPath(string_t input, const string &sep, SplitInput &state) { - auto input_data = input.GetData(); - auto input_size = input.GetSize(); - if (!input_size) { - return 0; - } - idx_t list_idx = 0; - while (input_size > 0) { - auto pos = Find(input_data, input_size, sep); - if (!IsIdxValid(pos, input_size)) { - break; - } - - D_ASSERT(input_size >= pos); - if (pos == 0) { - if (list_idx == 0) { // first character in path is separator - state.AddSplit(input_data, 1, list_idx); - list_idx++; - if (input_size == 1) { // special case: the only character in path is a separator - return list_idx; - } - } // else: separator is in the path - } else { - state.AddSplit(input_data, pos, list_idx); - list_idx++; - } - input_data += (pos + 1); - input_size -= (pos + 1); - } - if (input_size > 0) { - state.AddSplit(input_data, input_size, list_idx); - list_idx++; - } - return list_idx; -} - -static void ReadOptionalArgs(DataChunk &args, Vector &sep, Vector &trim, const bool &front_trim) { - switch (args.ColumnCount()) { - case 1: { - // use default values - break; - } - case 2: { - UnifiedVectorFormat sec_arg; - args.data[1].ToUnifiedFormat(args.size(), sec_arg); - if (sec_arg.validity.RowIsValid(0)) { // if not NULL - switch (args.data[1].GetType().id()) { - case LogicalTypeId::VARCHAR: { - sep.Reinterpret(args.data[1]); - break; - } - case LogicalTypeId::BOOLEAN: { // parse_path and parse_driname won't get in here - trim.Reinterpret(args.data[1]); - break; - } - default: - throw InvalidInputException("Invalid argument type"); - } - } - break; - } - case 3: { - if (!front_trim) { - // set trim_extension - UnifiedVectorFormat sec_arg; - args.data[1].ToUnifiedFormat(args.size(), sec_arg); - if (sec_arg.validity.RowIsValid(0)) { - trim.Reinterpret(args.data[1]); - } - UnifiedVectorFormat third_arg; - args.data[2].ToUnifiedFormat(args.size(), third_arg); - if (third_arg.validity.RowIsValid(0)) { - sep.Reinterpret(args.data[2]); - } - } else { - throw InvalidInputException("Invalid number of arguments"); - } - break; - } - default: - throw InvalidInputException("Invalid number of arguments"); - } -} - -template -static void TrimPathFunction(DataChunk &args, ExpressionState &state, Vector &result) { - // set default values - Vector &path = args.data[0]; - Vector separator(string_t("default")); - Vector trim_extension(Value::BOOLEAN(false)); - ReadOptionalArgs(args, separator, trim_extension, FRONT_TRIM); - - TernaryExecutor::Execute( - path, separator, trim_extension, result, args.size(), - [&](string_t &inputs, string_t input_sep, bool trim_extension) { - auto data = inputs.GetData(); - auto input_size = inputs.GetSize(); - auto sep = GetSeparator(input_sep.GetString()); - - // find the beginning idx and the size of the result string - idx_t begin = 0; - idx_t new_size = input_size; - if (FRONT_TRIM) { // left trim - auto pos = Find(data, input_size, sep); - if (pos == 0) { // path starts with separator - pos = 1; - } - new_size = (IsIdxValid(pos, input_size)) ? pos : 0; - } else { // right trim - auto idx_last_sep = FindLast(data, input_size, sep); - if (IsIdxValid(idx_last_sep, input_size)) { - begin = idx_last_sep + 1; - } - if (trim_extension) { - auto idx_extension_sep = FindLast(data, input_size, "."); - if (begin <= idx_extension_sep && IsIdxValid(idx_extension_sep, input_size)) { - new_size = idx_extension_sep; - } - } - } - // copy the trimmed string - D_ASSERT(begin <= new_size); - auto target = StringVector::EmptyString(result, new_size - begin); - auto output = target.GetDataWriteable(); - memcpy(output, data + begin, new_size - begin); - - target.Finalize(); - return target; - }); -} - -static void ParseDirpathFunction(DataChunk &args, ExpressionState &state, Vector &result) { - // set default values - Vector &path = args.data[0]; - Vector separator(string_t("default")); - Vector trim_extension(false); - ReadOptionalArgs(args, separator, trim_extension, true); - - BinaryExecutor::Execute( - path, separator, result, args.size(), [&](string_t input_path, string_t input_sep) { - auto path = input_path.GetData(); - auto path_size = input_path.GetSize(); - auto sep = GetSeparator(input_sep.GetString()); - - auto last_sep = FindLast(path, path_size, sep); - if (last_sep == 0 && path_size == 1) { - last_sep = 1; - } - idx_t new_size = (IsIdxValid(last_sep, path_size)) ? last_sep : 0; - - auto target = StringVector::EmptyString(result, new_size); - auto output = target.GetDataWriteable(); - memcpy(output, path, new_size); - target.Finalize(); - return StringVector::AddString(result, target); - }); -} - -static void ParsePathFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(args.ColumnCount() == 1 || args.ColumnCount() == 2); - UnifiedVectorFormat input_data; - args.data[0].ToUnifiedFormat(args.size(), input_data); - auto inputs = UnifiedVectorFormat::GetData(input_data); - - // set the separator - string input_sep = "default"; - if (args.ColumnCount() == 2) { - UnifiedVectorFormat sep_data; - args.data[1].ToUnifiedFormat(args.size(), sep_data); - if (sep_data.validity.RowIsValid(0)) { - input_sep = UnifiedVectorFormat::GetData(sep_data)->GetString(); - } - } - const string sep = GetSeparator(input_sep); - - D_ASSERT(result.GetType().id() == LogicalTypeId::LIST); - result.SetVectorType(VectorType::FLAT_VECTOR); - ListVector::SetListSize(result, 0); - - // set up the list entries - auto list_data = FlatVector::GetData(result); - auto &child_entry = ListVector::GetEntry(result); - auto &result_mask = FlatVector::Validity(result); - idx_t total_splits = 0; - for (idx_t i = 0; i < args.size(); i++) { - auto input_idx = input_data.sel->get_index(i); - if (!input_data.validity.RowIsValid(input_idx)) { - result_mask.SetInvalid(i); - continue; - } - SplitInput split_input(result, child_entry, total_splits); - auto list_length = SplitPath(inputs[input_idx], sep, split_input); - list_data[i].length = list_length; - list_data[i].offset = total_splits; - total_splits += list_length; - } - ListVector::SetListSize(result, total_splits); - D_ASSERT(ListVector::GetListSize(result) == total_splits); - - if (args.AllConstant()) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } -} - -ScalarFunctionSet ParseDirnameFun::GetFunctions() { - ScalarFunctionSet parse_dirname; - ScalarFunction func({LogicalType::VARCHAR}, LogicalType::VARCHAR, TrimPathFunction, nullptr, nullptr, nullptr, - nullptr, LogicalType::INVALID, FunctionStability::CONSISTENT, - FunctionNullHandling::SPECIAL_HANDLING); - parse_dirname.AddFunction(func); - // separator options - func.arguments.emplace_back(LogicalType::VARCHAR); - parse_dirname.AddFunction(func); - return parse_dirname; -} - -ScalarFunctionSet ParseDirpathFun::GetFunctions() { - ScalarFunctionSet parse_dirpath; - ScalarFunction func({LogicalType::VARCHAR}, LogicalType::VARCHAR, ParseDirpathFunction, nullptr, nullptr, nullptr, - nullptr, LogicalType::INVALID, FunctionStability::CONSISTENT, - FunctionNullHandling::SPECIAL_HANDLING); - parse_dirpath.AddFunction(func); - // separator options - func.arguments.emplace_back(LogicalType::VARCHAR); - parse_dirpath.AddFunction(func); - return parse_dirpath; -} - -ScalarFunctionSet ParseFilenameFun::GetFunctions() { - ScalarFunctionSet parse_filename; - parse_filename.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, TrimPathFunction, - nullptr, nullptr, nullptr, nullptr, LogicalType::INVALID, - FunctionStability::CONSISTENT, FunctionNullHandling::SPECIAL_HANDLING)); - parse_filename.AddFunction(ScalarFunction( - {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::VARCHAR, TrimPathFunction, nullptr, nullptr, - nullptr, nullptr, LogicalType::INVALID, FunctionStability::CONSISTENT, FunctionNullHandling::SPECIAL_HANDLING)); - parse_filename.AddFunction(ScalarFunction( - {LogicalType::VARCHAR, LogicalType::BOOLEAN}, LogicalType::VARCHAR, TrimPathFunction, nullptr, nullptr, - nullptr, nullptr, LogicalType::INVALID, FunctionStability::CONSISTENT, FunctionNullHandling::SPECIAL_HANDLING)); - parse_filename.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::BOOLEAN, LogicalType::VARCHAR}, - LogicalType::VARCHAR, TrimPathFunction, nullptr, nullptr, nullptr, - nullptr, LogicalType::INVALID, FunctionStability::CONSISTENT, - FunctionNullHandling::SPECIAL_HANDLING)); - return parse_filename; -} - -ScalarFunctionSet ParsePathFun::GetFunctions() { - auto varchar_list_type = LogicalType::LIST(LogicalType::VARCHAR); - ScalarFunctionSet parse_path; - ScalarFunction func({LogicalType::VARCHAR}, varchar_list_type, ParsePathFunction, nullptr, nullptr, nullptr, - nullptr, LogicalType::INVALID, FunctionStability::CONSISTENT, - FunctionNullHandling::SPECIAL_HANDLING); - parse_path.AddFunction(func); - // separator options - func.arguments.emplace_back(LogicalType::VARCHAR); - parse_path.AddFunction(func); - return parse_path; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/printf.cpp b/src/duckdb/src/core_functions/scalar/string/printf.cpp deleted file mode 100644 index 8b670b5ad..000000000 --- a/src/duckdb/src/core_functions/scalar/string/printf.cpp +++ /dev/null @@ -1,187 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/limits.hpp" -#include "fmt/format.h" -#include "fmt/printf.h" - -namespace duckdb { - -struct FMTPrintf { - template - static string OP(const char *format_str, vector> &format_args) { - return duckdb_fmt::vsprintf( - format_str, duckdb_fmt::basic_format_args(format_args.data(), static_cast(format_args.size()))); - } -}; - -struct FMTFormat { - template - static string OP(const char *format_str, vector> &format_args) { - return duckdb_fmt::vformat( - format_str, duckdb_fmt::basic_format_args(format_args.data(), static_cast(format_args.size()))); - } -}; - -unique_ptr BindPrintfFunction(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - for (idx_t i = 1; i < arguments.size(); i++) { - switch (arguments[i]->return_type.id()) { - case LogicalTypeId::BOOLEAN: - bound_function.arguments.emplace_back(LogicalType::BOOLEAN); - break; - case LogicalTypeId::TINYINT: - case LogicalTypeId::SMALLINT: - case LogicalTypeId::INTEGER: - case LogicalTypeId::BIGINT: - bound_function.arguments.emplace_back(LogicalType::BIGINT); - break; - case LogicalTypeId::UTINYINT: - case LogicalTypeId::USMALLINT: - case LogicalTypeId::UINTEGER: - case LogicalTypeId::UBIGINT: - bound_function.arguments.emplace_back(LogicalType::UBIGINT); - break; - case LogicalTypeId::FLOAT: - case LogicalTypeId::DOUBLE: - bound_function.arguments.emplace_back(LogicalType::DOUBLE); - break; - case LogicalTypeId::VARCHAR: - bound_function.arguments.push_back(LogicalType::VARCHAR); - break; - case LogicalTypeId::DECIMAL: - // decimal type: add cast to double - bound_function.arguments.emplace_back(LogicalType::DOUBLE); - break; - case LogicalTypeId::UNKNOWN: - // parameter: accept any input and rebind later - bound_function.arguments.emplace_back(LogicalType::ANY); - break; - default: - // all other types: add cast to string - bound_function.arguments.emplace_back(LogicalType::VARCHAR); - break; - } - } - return nullptr; -} - -template -static void PrintfFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &format_string = args.data[0]; - auto &result_validity = FlatVector::Validity(result); - result.SetVectorType(VectorType::CONSTANT_VECTOR); - result_validity.Initialize(args.size()); - for (idx_t i = 0; i < args.ColumnCount(); i++) { - switch (args.data[i].GetVectorType()) { - case VectorType::CONSTANT_VECTOR: - if (ConstantVector::IsNull(args.data[i])) { - // constant null! result is always NULL regardless of other input - result.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(result, true); - return; - } - break; - default: - // FLAT VECTOR, we can directly OR the nullmask - args.data[i].Flatten(args.size()); - result.SetVectorType(VectorType::FLAT_VECTOR); - result_validity.Combine(FlatVector::Validity(args.data[i]), args.size()); - break; - } - } - idx_t count = result.GetVectorType() == VectorType::CONSTANT_VECTOR ? 1 : args.size(); - - auto format_data = FlatVector::GetData(format_string); - auto result_data = FlatVector::GetData(result); - for (idx_t idx = 0; idx < count; idx++) { - if (result.GetVectorType() == VectorType::FLAT_VECTOR && FlatVector::IsNull(result, idx)) { - // this entry is NULL: skip it - continue; - } - - // first fetch the format string - auto fmt_idx = format_string.GetVectorType() == VectorType::CONSTANT_VECTOR ? 0 : idx; - auto format_string = format_data[fmt_idx].GetString(); - - // now gather all the format arguments - vector> format_args; - vector> string_args; - - for (idx_t col_idx = 1; col_idx < args.ColumnCount(); col_idx++) { - auto &col = args.data[col_idx]; - idx_t arg_idx = col.GetVectorType() == VectorType::CONSTANT_VECTOR ? 0 : idx; - switch (col.GetType().id()) { - case LogicalTypeId::BOOLEAN: { - auto arg_data = FlatVector::GetData(col); - format_args.emplace_back(duckdb_fmt::internal::make_arg(arg_data[arg_idx])); - break; - } - case LogicalTypeId::TINYINT: { - auto arg_data = FlatVector::GetData(col); - format_args.emplace_back(duckdb_fmt::internal::make_arg(arg_data[arg_idx])); - break; - } - case LogicalTypeId::SMALLINT: { - auto arg_data = FlatVector::GetData(col); - format_args.emplace_back(duckdb_fmt::internal::make_arg(arg_data[arg_idx])); - break; - } - case LogicalTypeId::INTEGER: { - auto arg_data = FlatVector::GetData(col); - format_args.emplace_back(duckdb_fmt::internal::make_arg(arg_data[arg_idx])); - break; - } - case LogicalTypeId::BIGINT: { - auto arg_data = FlatVector::GetData(col); - format_args.emplace_back(duckdb_fmt::internal::make_arg(arg_data[arg_idx])); - break; - } - case LogicalTypeId::UBIGINT: { - auto arg_data = FlatVector::GetData(col); - format_args.emplace_back(duckdb_fmt::internal::make_arg(arg_data[arg_idx])); - break; - } - case LogicalTypeId::FLOAT: { - auto arg_data = FlatVector::GetData(col); - format_args.emplace_back(duckdb_fmt::internal::make_arg(arg_data[arg_idx])); - break; - } - case LogicalTypeId::DOUBLE: { - auto arg_data = FlatVector::GetData(col); - format_args.emplace_back(duckdb_fmt::internal::make_arg(arg_data[arg_idx])); - break; - } - case LogicalTypeId::VARCHAR: { - auto arg_data = FlatVector::GetData(col); - auto string_view = - duckdb_fmt::basic_string_view(arg_data[arg_idx].GetData(), arg_data[arg_idx].GetSize()); - format_args.emplace_back(duckdb_fmt::internal::make_arg(string_view)); - break; - } - default: - throw InternalException("Unexpected type for printf format"); - } - } - // finally actually perform the format - string dynamic_result = FORMAT_FUN::template OP(format_string.c_str(), format_args); - result_data[idx] = StringVector::AddString(result, dynamic_result); - } -} - -ScalarFunction PrintfFun::GetFunction() { - // duckdb_fmt::printf_context, duckdb_fmt::vsprintf - ScalarFunction printf_fun({LogicalType::VARCHAR}, LogicalType::VARCHAR, - PrintfFunction, BindPrintfFunction); - printf_fun.varargs = LogicalType::ANY; - return printf_fun; -} - -ScalarFunction FormatFun::GetFunction() { - // duckdb_fmt::format_context, duckdb_fmt::vformat - ScalarFunction format_fun({LogicalType::VARCHAR}, LogicalType::VARCHAR, - PrintfFunction, BindPrintfFunction); - format_fun.varargs = LogicalType::ANY; - return format_fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/repeat.cpp b/src/duckdb/src/core_functions/scalar/string/repeat.cpp deleted file mode 100644 index 31318290f..000000000 --- a/src/duckdb/src/core_functions/scalar/string/repeat.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "duckdb/common/vector_operations/binary_executor.hpp" -#include "duckdb/core_functions/scalar/string_functions.hpp" -#include "duckdb/common/operator/multiply.hpp" - -namespace duckdb { - -static void RepeatFunction(DataChunk &args, ExpressionState &, Vector &result) { - auto &str_vector = args.data[0]; - auto &cnt_vector = args.data[1]; - - BinaryExecutor::Execute( - str_vector, cnt_vector, result, args.size(), [&](string_t str, int64_t cnt) { - auto input_str = str.GetData(); - auto size_str = str.GetSize(); - idx_t copy_count = cnt <= 0 || size_str == 0 ? 0 : UnsafeNumericCast(cnt); - - idx_t copy_size; - if (TryMultiplyOperator::Operation(size_str, copy_count, copy_size)) { - auto result_str = StringVector::EmptyString(result, copy_size); - auto result_data = result_str.GetDataWriteable(); - for (idx_t i = 0; i < copy_count; i++) { - memcpy(result_data + i * size_str, input_str, size_str); - } - result_str.Finalize(); - return result_str; - } else { - throw OutOfRangeException( - "Cannot create a string of size: '%d' * '%d', the maximum supported string size is: '%d'", size_str, - copy_count, string_t::MAX_STRING_SIZE); - } - }); -} - -unique_ptr RepeatBindFunction(ClientContext &, ScalarFunction &bound_function, - vector> &arguments) { - switch (arguments[0]->return_type.id()) { - case LogicalTypeId::UNKNOWN: - throw ParameterNotResolvedException(); - case LogicalTypeId::LIST: - break; - default: - throw NotImplementedException("repeat(list, count) requires a list as parameter"); - } - bound_function.arguments[0] = arguments[0]->return_type; - bound_function.return_type = arguments[0]->return_type; - return nullptr; -} - -static void RepeatListFunction(DataChunk &args, ExpressionState &, Vector &result) { - auto &list_vector = args.data[0]; - auto &cnt_vector = args.data[1]; - - auto &source_child = ListVector::GetEntry(list_vector); - auto &result_child = ListVector::GetEntry(result); - - idx_t current_size = ListVector::GetListSize(result); - BinaryExecutor::Execute( - list_vector, cnt_vector, result, args.size(), [&](list_entry_t list_input, int64_t cnt) { - idx_t copy_count = cnt <= 0 || list_input.length == 0 ? 0 : UnsafeNumericCast(cnt); - idx_t result_length = list_input.length * copy_count; - idx_t new_size = current_size + result_length; - ListVector::Reserve(result, new_size); - list_entry_t result_list; - result_list.offset = current_size; - result_list.length = result_length; - for (idx_t i = 0; i < copy_count; i++) { - // repeat the list contents "cnt" times - VectorOperations::Copy(source_child, result_child, list_input.offset + list_input.length, - list_input.offset, current_size); - current_size += list_input.length; - } - return result_list; - }); - ListVector::SetListSize(result, current_size); -} - -ScalarFunctionSet RepeatFun::GetFunctions() { - ScalarFunctionSet repeat; - for (const auto &type : {LogicalType::VARCHAR, LogicalType::BLOB}) { - repeat.AddFunction(ScalarFunction({type, LogicalType::BIGINT}, type, RepeatFunction)); - } - repeat.AddFunction(ScalarFunction({LogicalType::LIST(LogicalType::ANY), LogicalType::BIGINT}, - LogicalType::LIST(LogicalType::ANY), RepeatListFunction, RepeatBindFunction)); - return repeat; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/replace.cpp b/src/duckdb/src/core_functions/scalar/string/replace.cpp deleted file mode 100644 index a85d390f7..000000000 --- a/src/duckdb/src/core_functions/scalar/string/replace.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" - -#include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/vector_operations/ternary_executor.hpp" - -#include -#include -#include - -namespace duckdb { - -static idx_t NextNeedle(const char *input_haystack, idx_t size_haystack, const char *input_needle, - const idx_t size_needle) { - // Needle needs something to proceed - if (size_needle > 0) { - // Haystack should be bigger or equal size to the needle - for (idx_t string_position = 0; (size_haystack - string_position) >= size_needle; ++string_position) { - // Compare Needle to the Haystack - if ((memcmp(input_haystack + string_position, input_needle, size_needle) == 0)) { - return string_position; - } - } - } - // Did not find the needle - return size_haystack; -} - -static string_t ReplaceScalarFunction(const string_t &haystack, const string_t &needle, const string_t &thread, - vector &result) { - // Get information about the needle, the haystack and the "thread" - auto input_haystack = haystack.GetData(); - auto size_haystack = haystack.GetSize(); - - auto input_needle = needle.GetData(); - auto size_needle = needle.GetSize(); - - auto input_thread = thread.GetData(); - auto size_thread = thread.GetSize(); - - // Reuse the buffer - result.clear(); - - for (;;) { - // Append the non-matching characters - auto string_position = NextNeedle(input_haystack, size_haystack, input_needle, size_needle); - result.insert(result.end(), input_haystack, input_haystack + string_position); - input_haystack += string_position; - size_haystack -= string_position; - - // Stop when we have read the entire haystack - if (size_haystack == 0) { - break; - } - - // Replace the matching characters - result.insert(result.end(), input_thread, input_thread + size_thread); - input_haystack += size_needle; - size_haystack -= size_needle; - } - - return string_t(result.data(), UnsafeNumericCast(result.size())); -} - -static void ReplaceFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &haystack_vector = args.data[0]; - auto &needle_vector = args.data[1]; - auto &thread_vector = args.data[2]; - - vector buffer; - TernaryExecutor::Execute( - haystack_vector, needle_vector, thread_vector, result, args.size(), - [&](string_t input_string, string_t needle_string, string_t thread_string) { - return StringVector::AddString(result, - ReplaceScalarFunction(input_string, needle_string, thread_string, buffer)); - }); -} - -ScalarFunction ReplaceFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::VARCHAR, - ReplaceFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/reverse.cpp b/src/duckdb/src/core_functions/scalar/string/reverse.cpp deleted file mode 100644 index cef1441fa..000000000 --- a/src/duckdb/src/core_functions/scalar/string/reverse.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" - -#include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/vector_operations/unary_executor.hpp" -#include "utf8proc_wrapper.hpp" - -#include - -namespace duckdb { - -//! Fast ASCII string reverse, returns false if the input data is not ascii -static bool StrReverseASCII(const char *input, idx_t n, char *output) { - for (idx_t i = 0; i < n; i++) { - if (input[i] & 0x80) { - // non-ascii character - return false; - } - output[n - i - 1] = input[i]; - } - return true; -} - -//! Unicode string reverse using grapheme breakers -static void StrReverseUnicode(const char *input, idx_t n, char *output) { - for (auto cluster : Utf8Proc::GraphemeClusters(input, n)) { - memcpy(output + n - cluster.end, input + cluster.start, cluster.end - cluster.start); - } -} - -struct ReverseOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - auto input_data = input.GetData(); - auto input_length = input.GetSize(); - - auto target = StringVector::EmptyString(result, input_length); - auto target_data = target.GetDataWriteable(); - if (!StrReverseASCII(input_data, input_length, target_data)) { - StrReverseUnicode(input_data, input_length, target_data); - } - target.Finalize(); - return target; - } -}; - -static void ReverseFunction(DataChunk &args, ExpressionState &state, Vector &result) { - UnaryExecutor::ExecuteString(args.data[0], result, args.size()); -} - -ScalarFunction ReverseFun::GetFunction() { - return ScalarFunction("reverse", {LogicalType::VARCHAR}, LogicalType::VARCHAR, ReverseFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/starts_with.cpp b/src/duckdb/src/core_functions/scalar/string/starts_with.cpp deleted file mode 100644 index c4661b913..000000000 --- a/src/duckdb/src/core_functions/scalar/string/starts_with.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" - -#include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" - -namespace duckdb { - -static bool StartsWith(const unsigned char *haystack, idx_t haystack_size, const unsigned char *needle, - idx_t needle_size) { - D_ASSERT(needle_size > 0); - if (needle_size > haystack_size) { - // needle is bigger than haystack: haystack cannot start with needle - return false; - } - return memcmp(haystack, needle, needle_size) == 0; -} - -static bool StartsWith(const string_t &haystack_s, const string_t &needle_s) { - - auto haystack = const_uchar_ptr_cast(haystack_s.GetData()); - auto haystack_size = haystack_s.GetSize(); - auto needle = const_uchar_ptr_cast(needle_s.GetData()); - auto needle_size = needle_s.GetSize(); - if (needle_size == 0) { - // empty needle: always true - return true; - } - return StartsWith(haystack, haystack_size, needle, needle_size); -} - -struct StartsWithOperator { - template - static inline TR Operation(TA left, TB right) { - return StartsWith(left, right); - } -}; - -ScalarFunction StartsWithOperatorFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, - ScalarFunction::BinaryFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/to_base.cpp b/src/duckdb/src/core_functions/scalar/string/to_base.cpp deleted file mode 100644 index 963f4f562..000000000 --- a/src/duckdb/src/core_functions/scalar/string/to_base.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" - -namespace duckdb { - -static const char alphabet[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -static unique_ptr ToBaseBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - // If no min_length is specified, default to 0 - D_ASSERT(arguments.size() == 2 || arguments.size() == 3); - if (arguments.size() == 2) { - arguments.push_back(make_uniq_base(Value::INTEGER(0))); - } - return nullptr; -} - -static void ToBaseFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &input = args.data[0]; - auto &radix = args.data[1]; - auto &min_length = args.data[2]; - auto count = args.size(); - - TernaryExecutor::Execute( - input, radix, min_length, result, count, [&](int64_t input, int32_t radix, int32_t min_length) { - if (input < 0) { - throw InvalidInputException("'to_base' number must be greater than or equal to 0"); - } - if (radix < 2 || radix > 36) { - throw InvalidInputException("'to_base' radix must be between 2 and 36"); - } - if (min_length > 64 || min_length < 0) { - throw InvalidInputException("'to_base' min_length must be between 0 and 64"); - } - - char buf[64]; - char *end = buf + sizeof(buf); - char *ptr = end; - do { - *--ptr = alphabet[input % radix]; - input /= radix; - } while (input > 0); - - auto length = end - ptr; - while (length < min_length) { - *--ptr = '0'; - length++; - } - - return StringVector::AddString(result, ptr, UnsafeNumericCast(end - ptr)); - }); -} - -ScalarFunctionSet ToBaseFun::GetFunctions() { - ScalarFunctionSet set("to_base"); - - set.AddFunction( - ScalarFunction({LogicalType::BIGINT, LogicalType::INTEGER}, LogicalType::VARCHAR, ToBaseFunction, ToBaseBind)); - set.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::INTEGER, LogicalType::INTEGER}, - LogicalType::VARCHAR, ToBaseFunction, ToBaseBind)); - - return set; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/translate.cpp b/src/duckdb/src/core_functions/scalar/string/translate.cpp deleted file mode 100644 index c01ec2a25..000000000 --- a/src/duckdb/src/core_functions/scalar/string/translate.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" - -#include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/vector_operations/ternary_executor.hpp" -#include "utf8proc.hpp" -#include "utf8proc_wrapper.hpp" - -#include -#include -#include -#include - -namespace duckdb { - -static string_t TranslateScalarFunction(const string_t &haystack, const string_t &needle, const string_t &thread, - vector &result) { - // Get information about the haystack, the needle and the "thread" - auto input_haystack = haystack.GetData(); - auto size_haystack = haystack.GetSize(); - - auto input_needle = needle.GetData(); - auto size_needle = needle.GetSize(); - - auto input_thread = thread.GetData(); - auto size_thread = thread.GetSize(); - - // Reuse the buffer - result.clear(); - result.reserve(size_haystack); - - idx_t i = 0, j = 0; - int sz = 0, c_sz = 0; - - // Character to be replaced - unordered_map to_replace; - while (i < size_needle && j < size_thread) { - auto codepoint_needle = Utf8Proc::UTF8ToCodepoint(input_needle, sz); - input_needle += sz; - i += UnsafeNumericCast(sz); - auto codepoint_thread = Utf8Proc::UTF8ToCodepoint(input_thread, sz); - input_thread += sz; - j += UnsafeNumericCast(sz); - // Ignore unicode character that is existed in to_replace - if (to_replace.count(codepoint_needle) == 0) { - to_replace[codepoint_needle] = codepoint_thread; - } - } - - // Character to be deleted - unordered_set to_delete; - while (i < size_needle) { - auto codepoint_needle = Utf8Proc::UTF8ToCodepoint(input_needle, sz); - input_needle += sz; - i += UnsafeNumericCast(sz); - // Add unicode character that will be deleted - if (to_replace.count(codepoint_needle) == 0) { - to_delete.insert(codepoint_needle); - } - } - - char c[5] = {'\0', '\0', '\0', '\0', '\0'}; - for (i = 0; i < size_haystack; i += UnsafeNumericCast(sz)) { - auto codepoint_haystack = Utf8Proc::UTF8ToCodepoint(input_haystack, sz); - if (to_replace.count(codepoint_haystack) != 0) { - Utf8Proc::CodepointToUtf8(to_replace[codepoint_haystack], c_sz, c); - result.insert(result.end(), c, c + c_sz); - } else if (to_delete.count(codepoint_haystack) == 0) { - result.insert(result.end(), input_haystack, input_haystack + sz); - } - input_haystack += sz; - } - - return string_t(result.data(), UnsafeNumericCast(result.size())); -} - -static void TranslateFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &haystack_vector = args.data[0]; - auto &needle_vector = args.data[1]; - auto &thread_vector = args.data[2]; - - vector buffer; - TernaryExecutor::Execute( - haystack_vector, needle_vector, thread_vector, result, args.size(), - [&](string_t input_string, string_t needle_string, string_t thread_string) { - return StringVector::AddString(result, - TranslateScalarFunction(input_string, needle_string, thread_string, buffer)); - }); -} - -ScalarFunction TranslateFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::VARCHAR, - TranslateFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/trim.cpp b/src/duckdb/src/core_functions/scalar/string/trim.cpp deleted file mode 100644 index d89ebbaff..000000000 --- a/src/duckdb/src/core_functions/scalar/string/trim.cpp +++ /dev/null @@ -1,158 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" - -#include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/vector_operations/unary_executor.hpp" -#include "utf8proc.hpp" - -#include - -namespace duckdb { - -template -struct TrimOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - auto data = input.GetData(); - auto size = input.GetSize(); - - utf8proc_int32_t codepoint; - auto str = reinterpret_cast(data); - - // Find the first character that is not left trimmed - idx_t begin = 0; - if (LTRIM) { - while (begin < size) { - auto bytes = - utf8proc_iterate(str + begin, UnsafeNumericCast(size - begin), &codepoint); - D_ASSERT(bytes > 0); - if (utf8proc_category(codepoint) != UTF8PROC_CATEGORY_ZS) { - break; - } - begin += UnsafeNumericCast(bytes); - } - } - - // Find the last character that is not right trimmed - idx_t end; - if (RTRIM) { - end = begin; - for (auto next = begin; next < size;) { - auto bytes = utf8proc_iterate(str + next, UnsafeNumericCast(size - next), &codepoint); - D_ASSERT(bytes > 0); - next += UnsafeNumericCast(bytes); - if (utf8proc_category(codepoint) != UTF8PROC_CATEGORY_ZS) { - end = next; - } - } - } else { - end = size; - } - - // Copy the trimmed string - auto target = StringVector::EmptyString(result, end - begin); - auto output = target.GetDataWriteable(); - memcpy(output, data + begin, end - begin); - - target.Finalize(); - return target; - } -}; - -template -static void UnaryTrimFunction(DataChunk &args, ExpressionState &state, Vector &result) { - UnaryExecutor::ExecuteString>(args.data[0], result, args.size()); -} - -static void GetIgnoredCodepoints(string_t ignored, unordered_set &ignored_codepoints) { - auto dataptr = reinterpret_cast(ignored.GetData()); - auto size = ignored.GetSize(); - idx_t pos = 0; - while (pos < size) { - utf8proc_int32_t codepoint; - pos += UnsafeNumericCast( - utf8proc_iterate(dataptr + pos, UnsafeNumericCast(size - pos), &codepoint)); - ignored_codepoints.insert(codepoint); - } -} - -template -static void BinaryTrimFunction(DataChunk &input, ExpressionState &state, Vector &result) { - BinaryExecutor::Execute( - input.data[0], input.data[1], result, input.size(), [&](string_t input, string_t ignored) { - auto data = input.GetData(); - auto size = input.GetSize(); - - unordered_set ignored_codepoints; - GetIgnoredCodepoints(ignored, ignored_codepoints); - - utf8proc_int32_t codepoint; - auto str = reinterpret_cast(data); - - // Find the first character that is not left trimmed - idx_t begin = 0; - if (LTRIM) { - while (begin < size) { - auto bytes = - utf8proc_iterate(str + begin, UnsafeNumericCast(size - begin), &codepoint); - if (ignored_codepoints.find(codepoint) == ignored_codepoints.end()) { - break; - } - begin += UnsafeNumericCast(bytes); - } - } - - // Find the last character that is not right trimmed - idx_t end; - if (RTRIM) { - end = begin; - for (auto next = begin; next < size;) { - auto bytes = - utf8proc_iterate(str + next, UnsafeNumericCast(size - next), &codepoint); - D_ASSERT(bytes > 0); - next += UnsafeNumericCast(bytes); - if (ignored_codepoints.find(codepoint) == ignored_codepoints.end()) { - end = next; - } - } - } else { - end = size; - } - - // Copy the trimmed string - auto target = StringVector::EmptyString(result, end - begin); - auto output = target.GetDataWriteable(); - memcpy(output, data + begin, end - begin); - - target.Finalize(); - return target; - }); -} - -ScalarFunctionSet TrimFun::GetFunctions() { - ScalarFunctionSet trim; - trim.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, UnaryTrimFunction)); - - trim.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::VARCHAR, - BinaryTrimFunction)); - return trim; -} - -ScalarFunctionSet LtrimFun::GetFunctions() { - ScalarFunctionSet ltrim; - ltrim.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, UnaryTrimFunction)); - ltrim.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::VARCHAR, - BinaryTrimFunction)); - return ltrim; -} - -ScalarFunctionSet RtrimFun::GetFunctions() { - ScalarFunctionSet rtrim; - rtrim.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, UnaryTrimFunction)); - - rtrim.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::VARCHAR, - BinaryTrimFunction)); - return rtrim; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/unicode.cpp b/src/duckdb/src/core_functions/scalar/string/unicode.cpp deleted file mode 100644 index b62a129aa..000000000 --- a/src/duckdb/src/core_functions/scalar/string/unicode.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" - -#include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/vector_operations/unary_executor.hpp" -#include "utf8proc.hpp" - -#include - -namespace duckdb { - -struct UnicodeOperator { - template - static inline TR Operation(const TA &input) { - auto str = reinterpret_cast(input.GetData()); - auto len = input.GetSize(); - utf8proc_int32_t codepoint; - (void)utf8proc_iterate(str, UnsafeNumericCast(len), &codepoint); - return codepoint; - } -}; - -ScalarFunction UnicodeFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR}, LogicalType::INTEGER, - ScalarFunction::UnaryFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/url_encode.cpp b/src/duckdb/src/core_functions/scalar/string/url_encode.cpp deleted file mode 100644 index 51d49079c..000000000 --- a/src/duckdb/src/core_functions/scalar/string/url_encode.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "duckdb/common/vector_operations/unary_executor.hpp" -#include "duckdb/core_functions/scalar/string_functions.hpp" -#include "duckdb/common/string_util.hpp" - -namespace duckdb { - -struct URLEncodeOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - auto input_str = input.GetData(); - auto input_size = input.GetSize(); - idx_t result_length = StringUtil::URLEncodeSize(input_str, input_size); - auto result_str = StringVector::EmptyString(result, result_length); - StringUtil::URLEncodeBuffer(input_str, input_size, result_str.GetDataWriteable()); - result_str.Finalize(); - return result_str; - } -}; - -static void URLEncodeFunction(DataChunk &args, ExpressionState &state, Vector &result) { - UnaryExecutor::ExecuteString(args.data[0], result, args.size()); -} - -ScalarFunction UrlEncodeFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, URLEncodeFunction); -} - -struct URLDecodeOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - auto input_str = input.GetData(); - auto input_size = input.GetSize(); - idx_t result_length = StringUtil::URLDecodeSize(input_str, input_size); - auto result_str = StringVector::EmptyString(result, result_length); - StringUtil::URLDecodeBuffer(input_str, input_size, result_str.GetDataWriteable()); - result_str.Finalize(); - return result_str; - } -}; - -static void URLDecodeFunction(DataChunk &args, ExpressionState &state, Vector &result) { - UnaryExecutor::ExecuteString(args.data[0], result, args.size()); -} - -ScalarFunction UrlDecodeFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, URLDecodeFunction); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/struct/struct_insert.cpp b/src/duckdb/src/core_functions/scalar/struct/struct_insert.cpp deleted file mode 100644 index 6a44d12a7..000000000 --- a/src/duckdb/src/core_functions/scalar/struct/struct_insert.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "duckdb/core_functions/scalar/struct_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/parser/expression/bound_expression.hpp" -#include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/common/case_insensitive_map.hpp" -#include "duckdb/storage/statistics/struct_stats.hpp" -#include "duckdb/planner/expression_binder.hpp" - -namespace duckdb { - -static void StructInsertFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &starting_vec = args.data[0]; - - starting_vec.Verify(args.size()); - - auto &starting_child_entries = StructVector::GetEntries(starting_vec); - auto &result_child_entries = StructVector::GetEntries(result); - - // Assign the starting vector entries to the result vector - for (size_t i = 0; i < starting_child_entries.size(); i++) { - auto &starting_child = starting_child_entries[i]; - result_child_entries[i]->Reference(*starting_child); - } - - // Assign the new entries to the result vector - for (size_t i = 1; i < args.ColumnCount(); i++) { - result_child_entries[starting_child_entries.size() + i - 1]->Reference(args.data[i]); - } - - result.Verify(args.size()); - - if (args.AllConstant()) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } -} - -static unique_ptr StructInsertBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - case_insensitive_set_t name_collision_set; - - if (arguments.empty()) { - throw InvalidInputException("Missing required arguments for struct_insert function."); - } - - if (LogicalTypeId::STRUCT != arguments[0]->return_type.id()) { - throw InvalidInputException("The first argument to struct_insert must be a STRUCT"); - } - - if (arguments.size() < 2) { - throw InvalidInputException("Can't insert nothing into a struct"); - } - - child_list_t new_struct_children; - - auto &existing_struct_children = StructType::GetChildTypes(arguments[0]->return_type); - - for (size_t i = 0; i < existing_struct_children.size(); i++) { - auto &child = existing_struct_children[i]; - name_collision_set.insert(child.first); - new_struct_children.push_back(make_pair(child.first, child.second)); - } - - // Loop through the additional arguments (name/value pairs) - for (idx_t i = 1; i < arguments.size(); i++) { - auto &child = arguments[i]; - if (child->alias.empty() && bound_function.name == "struct_insert") { - throw BinderException("Need named argument for struct insert, e.g. STRUCT_PACK(a := b)"); - } - if (name_collision_set.find(child->alias) != name_collision_set.end()) { - throw BinderException("Duplicate struct entry name \"%s\"", child->alias); - } - name_collision_set.insert(child->alias); - new_struct_children.push_back(make_pair(child->alias, arguments[i]->return_type)); - } - - // this is more for completeness reasons - bound_function.return_type = LogicalType::STRUCT(new_struct_children); - return make_uniq(bound_function.return_type); -} - -unique_ptr StructInsertStats(ClientContext &context, FunctionStatisticsInput &input) { - auto &child_stats = input.child_stats; - auto &expr = input.expr; - auto new_struct_stats = StructStats::CreateUnknown(expr.return_type); - - auto existing_count = StructType::GetChildCount(child_stats[0].GetType()); - auto existing_stats = StructStats::GetChildStats(child_stats[0]); - for (idx_t i = 0; i < existing_count; i++) { - StructStats::SetChildStats(new_struct_stats, i, existing_stats[i]); - } - auto new_count = StructType::GetChildCount(expr.return_type); - auto offset = new_count - child_stats.size(); - for (idx_t i = 1; i < child_stats.size(); i++) { - StructStats::SetChildStats(new_struct_stats, offset + i, child_stats[i]); - } - return new_struct_stats.ToUnique(); -} - -ScalarFunction StructInsertFun::GetFunction() { - // the arguments and return types are actually set in the binder function - ScalarFunction fun({}, LogicalTypeId::STRUCT, StructInsertFunction, StructInsertBind, nullptr, StructInsertStats); - fun.varargs = LogicalType::ANY; - fun.serialize = VariableReturnBindData::Serialize; - fun.deserialize = VariableReturnBindData::Deserialize; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/union/union_extract.cpp b/src/duckdb/src/core_functions/scalar/union/union_extract.cpp deleted file mode 100644 index 8478ad0fd..000000000 --- a/src/duckdb/src/core_functions/scalar/union/union_extract.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "duckdb/core_functions/scalar/union_functions.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/planner/expression/bound_parameter_expression.hpp" - -namespace duckdb { - -struct UnionExtractBindData : public FunctionData { - UnionExtractBindData(string key, idx_t index, LogicalType type) - : key(std::move(key)), index(index), type(std::move(type)) { - } - - string key; - idx_t index; - LogicalType type; - -public: - unique_ptr Copy() const override { - return make_uniq(key, index, type); - } - bool Equals(const FunctionData &other_p) const override { - auto &other = other_p.Cast(); - return key == other.key && index == other.index && type == other.type; - } -}; - -static void UnionExtractFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &func_expr = state.expr.Cast(); - auto &info = func_expr.bind_info->Cast(); - - // this should be guaranteed by the binder - auto &vec = args.data[0]; - vec.Verify(args.size()); - - D_ASSERT(info.index < UnionType::GetMemberCount(vec.GetType())); - auto &member = UnionVector::GetMember(vec, info.index); - result.Reference(member); - result.Verify(args.size()); -} - -static unique_ptr UnionExtractBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - D_ASSERT(bound_function.arguments.size() == 2); - if (arguments[0]->return_type.id() == LogicalTypeId::UNKNOWN) { - throw ParameterNotResolvedException(); - } - if (arguments[0]->return_type.id() != LogicalTypeId::UNION) { - throw BinderException("union_extract can only take a union parameter"); - } - idx_t union_member_count = UnionType::GetMemberCount(arguments[0]->return_type); - if (union_member_count == 0) { - throw InternalException("Can't extract something from an empty union"); - } - bound_function.arguments[0] = arguments[0]->return_type; - - auto &key_child = arguments[1]; - if (key_child->HasParameter()) { - throw ParameterNotResolvedException(); - } - - if (key_child->return_type.id() != LogicalTypeId::VARCHAR || !key_child->IsFoldable()) { - throw BinderException("Key name for union_extract needs to be a constant string"); - } - Value key_val = ExpressionExecutor::EvaluateScalar(context, *key_child); - D_ASSERT(key_val.type().id() == LogicalTypeId::VARCHAR); - auto &key_str = StringValue::Get(key_val); - if (key_val.IsNull() || key_str.empty()) { - throw BinderException("Key name for union_extract needs to be neither NULL nor empty"); - } - string key = StringUtil::Lower(key_str); - - LogicalType return_type; - idx_t key_index = 0; - bool found_key = false; - - for (size_t i = 0; i < union_member_count; i++) { - auto &member_name = UnionType::GetMemberName(arguments[0]->return_type, i); - if (StringUtil::Lower(member_name) == key) { - found_key = true; - key_index = i; - return_type = UnionType::GetMemberType(arguments[0]->return_type, i); - break; - } - } - - if (!found_key) { - vector candidates; - candidates.reserve(union_member_count); - for (idx_t i = 0; i < union_member_count; i++) { - candidates.push_back(UnionType::GetMemberName(arguments[0]->return_type, i)); - } - auto closest_settings = StringUtil::TopNJaroWinkler(candidates, key); - auto message = StringUtil::CandidatesMessage(closest_settings, "Candidate Entries"); - throw BinderException("Could not find key \"%s\" in union\n%s", key, message); - } - - bound_function.return_type = return_type; - return make_uniq(key, key_index, return_type); -} - -ScalarFunction UnionExtractFun::GetFunction() { - // the arguments and return types are actually set in the binder function - return ScalarFunction({LogicalTypeId::UNION, LogicalType::VARCHAR}, LogicalType::ANY, UnionExtractFunction, - UnionExtractBind, nullptr, nullptr); -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/union/union_tag.cpp b/src/duckdb/src/core_functions/scalar/union/union_tag.cpp deleted file mode 100644 index 431df0ad2..000000000 --- a/src/duckdb/src/core_functions/scalar/union/union_tag.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "duckdb/core_functions/scalar/union_functions.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/planner/expression/bound_parameter_expression.hpp" - -namespace duckdb { - -static unique_ptr UnionTagBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - - if (arguments.empty()) { - throw BinderException("Missing required arguments for union_tag function."); - } - - if (LogicalTypeId::UNKNOWN == arguments[0]->return_type.id()) { - throw ParameterNotResolvedException(); - } - - if (LogicalTypeId::UNION != arguments[0]->return_type.id()) { - throw BinderException("First argument to union_tag function must be a union type."); - } - - if (arguments.size() > 1) { - throw BinderException("Too many arguments, union_tag takes at most one argument."); - } - - auto member_count = UnionType::GetMemberCount(arguments[0]->return_type); - if (member_count == 0) { - // this should never happen, empty unions are not allowed - throw InternalException("Can't get tags from an empty union"); - } - - bound_function.arguments[0] = arguments[0]->return_type; - - auto varchar_vector = Vector(LogicalType::VARCHAR, member_count); - for (idx_t i = 0; i < member_count; i++) { - auto str = string_t(UnionType::GetMemberName(arguments[0]->return_type, i)); - FlatVector::GetData(varchar_vector)[i] = - str.IsInlined() ? str : StringVector::AddString(varchar_vector, str); - } - auto enum_type = LogicalType::ENUM(varchar_vector, member_count); - bound_function.return_type = enum_type; - - return nullptr; -} - -static void UnionTagFunction(DataChunk &args, ExpressionState &state, Vector &result) { - D_ASSERT(result.GetType().id() == LogicalTypeId::ENUM); - result.Reinterpret(UnionVector::GetTags(args.data[0])); -} - -ScalarFunction UnionTagFun::GetFunction() { - return ScalarFunction({LogicalTypeId::UNION}, LogicalTypeId::ANY, UnionTagFunction, UnionTagBind, nullptr, - nullptr); // TODO: Statistics? -} - -} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/union/union_value.cpp b/src/duckdb/src/core_functions/scalar/union/union_value.cpp deleted file mode 100644 index 6ba7070a5..000000000 --- a/src/duckdb/src/core_functions/scalar/union/union_value.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "duckdb/core_functions/scalar/union_functions.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/planner/expression/bound_parameter_expression.hpp" - -namespace duckdb { - -struct UnionValueBindData : public FunctionData { - UnionValueBindData() { - } - -public: - unique_ptr Copy() const override { - return make_uniq(); - } - bool Equals(const FunctionData &other_p) const override { - return true; - } -}; - -static void UnionValueFunction(DataChunk &args, ExpressionState &state, Vector &result) { - // Assign the new entries to the result vector - UnionVector::GetMember(result, 0).Reference(args.data[0]); - - // Set the result tag vector to a constant value - auto &tag_vector = UnionVector::GetTags(result); - tag_vector.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::GetData(tag_vector)[0] = 0; - - if (args.AllConstant()) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } - - result.Verify(args.size()); -} - -static unique_ptr UnionValueBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - - if (arguments.size() != 1) { - throw BinderException("union_value takes exactly one argument"); - } - auto &child = arguments[0]; - - if (child->alias.empty()) { - throw BinderException("Need named argument for union tag, e.g. UNION_VALUE(a := b)"); - } - - child_list_t union_members; - - union_members.push_back(make_pair(child->alias, child->return_type)); - - bound_function.return_type = LogicalType::UNION(std::move(union_members)); - return make_uniq(bound_function.return_type); -} - -ScalarFunction UnionValueFun::GetFunction() { - ScalarFunction fun("union_value", {}, LogicalTypeId::UNION, UnionValueFunction, UnionValueBind, nullptr, nullptr); - fun.varargs = LogicalType::ANY; - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - fun.serialize = VariableReturnBindData::Serialize; - fun.deserialize = VariableReturnBindData::Deserialize; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/execution/aggregate_hashtable.cpp b/src/duckdb/src/execution/aggregate_hashtable.cpp index e09fd9b70..077d846cd 100644 --- a/src/duckdb/src/execution/aggregate_hashtable.cpp +++ b/src/duckdb/src/execution/aggregate_hashtable.cpp @@ -59,7 +59,8 @@ GroupedAggregateHashTable::GroupedAggregateHashTable(ClientContext &context, All } void GroupedAggregateHashTable::InitializePartitionedData() { - if (!partitioned_data || RadixPartitioning::RadixBits(partitioned_data->PartitionCount()) != radix_bits) { + if (!partitioned_data || + RadixPartitioning::RadixBitsOfPowerOfTwo(partitioned_data->PartitionCount()) != radix_bits) { D_ASSERT(!partitioned_data || partitioned_data->Count() == 0); partitioned_data = make_uniq(buffer_manager, layout, radix_bits, layout.ColumnCount() - 1); @@ -131,7 +132,11 @@ idx_t GroupedAggregateHashTable::Capacity() const { } idx_t GroupedAggregateHashTable::ResizeThreshold() const { - return LossyNumericCast(static_cast(Capacity()) / LOAD_FACTOR); + return ResizeThreshold(Capacity()); +} + +idx_t GroupedAggregateHashTable::ResizeThreshold(const idx_t capacity) { + return LossyNumericCast(static_cast(capacity) / LOAD_FACTOR); } idx_t GroupedAggregateHashTable::ApplyBitMask(hash_t hash) const { @@ -169,8 +174,8 @@ void GroupedAggregateHashTable::SetRadixBits(idx_t radix_bits_p) { void GroupedAggregateHashTable::Resize(idx_t size) { D_ASSERT(size >= STANDARD_VECTOR_SIZE); D_ASSERT(IsPowerOfTwo(size)); - if (size < capacity) { - throw InternalException("Cannot downsize a hash table!"); + if (Count() != 0 && size < capacity) { + throw InternalException("Cannot downsize a non-empty hash table!"); } capacity = size; diff --git a/src/duckdb/src/execution/expression_executor.cpp b/src/duckdb/src/execution/expression_executor.cpp index 458348bea..63a24f479 100644 --- a/src/duckdb/src/execution/expression_executor.cpp +++ b/src/duckdb/src/execution/expression_executor.cpp @@ -236,8 +236,10 @@ idx_t ExpressionExecutor::Select(const Expression &expr, ExpressionState *state, D_ASSERT(true_sel || false_sel); D_ASSERT(expr.return_type.id() == LogicalTypeId::BOOLEAN); switch (expr.expression_class) { +#ifndef DUCKDB_SMALLER_BINARY case ExpressionClass::BOUND_BETWEEN: return Select(expr.Cast(), state, sel, count, true_sel, false_sel); +#endif case ExpressionClass::BOUND_COMPARISON: return Select(expr.Cast(), state, sel, count, true_sel, false_sel); case ExpressionClass::BOUND_CONJUNCTION: diff --git a/src/duckdb/src/execution/expression_executor/execute_between.cpp b/src/duckdb/src/execution/expression_executor/execute_between.cpp index 95ff45070..341835136 100644 --- a/src/duckdb/src/execution/expression_executor/execute_between.cpp +++ b/src/duckdb/src/execution/expression_executor/execute_between.cpp @@ -7,6 +7,7 @@ namespace duckdb { +#ifndef DUCKDB_SMALLER_BINARY struct BothInclusiveBetweenOperator { template static inline bool Operation(T input, T lower, T upper) { @@ -85,6 +86,7 @@ static idx_t BetweenLoopTypeSwitch(Vector &input, Vector &lower, Vector &upper, throw InvalidTypeException(input.GetType(), "Invalid type for BETWEEN"); } } +#endif unique_ptr ExpressionExecutor::InitializeState(const BoundBetweenExpression &expr, ExpressionExecutorState &root) { @@ -131,6 +133,9 @@ void ExpressionExecutor::Execute(const BoundBetweenExpression &expr, ExpressionS idx_t ExpressionExecutor::Select(const BoundBetweenExpression &expr, ExpressionState *state, const SelectionVector *sel, idx_t count, SelectionVector *true_sel, SelectionVector *false_sel) { +#ifdef DUCKDB_SMALLER_BINARY + throw InternalException("ExpressionExecutor::Select not available with DUCKDB_SMALLER_BINARY"); +#else // resolve the children Vector input(state->intermediate_chunk.data[0]); Vector lower(state->intermediate_chunk.data[1]); @@ -152,6 +157,7 @@ idx_t ExpressionExecutor::Select(const BoundBetweenExpression &expr, ExpressionS } else { return BetweenLoopTypeSwitch(input, lower, upper, sel, count, true_sel, false_sel); } +#endif } } // namespace duckdb diff --git a/src/duckdb/src/execution/index/art/plan_art.cpp b/src/duckdb/src/execution/index/art/plan_art.cpp index 2acc56995..ce459b290 100644 --- a/src/duckdb/src/execution/index/art/plan_art.cpp +++ b/src/duckdb/src/execution/index/art/plan_art.cpp @@ -1,24 +1,18 @@ - +#include "duckdb/execution/index/art/art.hpp" +#include "duckdb/execution/operator/filter/physical_filter.hpp" #include "duckdb/execution/operator/order/physical_order.hpp" #include "duckdb/execution/operator/projection/physical_projection.hpp" -#include "duckdb/execution/operator/filter/physical_filter.hpp" #include "duckdb/execution/operator/schema/physical_create_art_index.hpp" - #include "duckdb/planner/expression/bound_operator_expression.hpp" #include "duckdb/planner/expression/bound_reference_expression.hpp" #include "duckdb/planner/operator/logical_create_index.hpp" -#include "duckdb/execution/index/art/art.hpp" - namespace duckdb { unique_ptr ART::CreatePlan(PlanIndexInput &input) { - // generate a physical plan for the parallel index creation which consists of the following operators - // table scan - projection (for expression execution) - filter (NOT NULL) - order (if applicable) - create index - auto &op = input.op; - auto &table_scan = input.table_scan; + // PROJECTION on indexed columns. vector new_column_types; vector> select_list; for (idx_t i = 0; i < op.expressions.size(); i++) { @@ -29,65 +23,66 @@ unique_ptr ART::CreatePlan(PlanIndexInput &input) { select_list.push_back(make_uniq(LogicalType::ROW_TYPE, op.info->scan_types.size() - 1)); auto projection = make_uniq(new_column_types, std::move(select_list), op.estimated_cardinality); - projection->children.push_back(std::move(table_scan)); + projection->children.push_back(std::move(input.table_scan)); - // filter operator for IS_NOT_NULL on each key column + // Optional NOT NULL filter. + unique_ptr prev_operator; + auto is_alter = op.alter_table_info != nullptr; + if (!is_alter) { + vector filter_types; + vector> filter_select_list; + auto not_null_type = ExpressionType::OPERATOR_IS_NOT_NULL; - vector filter_types; - vector> filter_select_list; + for (idx_t i = 0; i < new_column_types.size() - 1; i++) { + filter_types.push_back(new_column_types[i]); + auto is_not_null_expr = make_uniq(not_null_type, LogicalType::BOOLEAN); + auto bound_ref = make_uniq(new_column_types[i], i); + is_not_null_expr->children.push_back(std::move(bound_ref)); + filter_select_list.push_back(std::move(is_not_null_expr)); + } - for (idx_t i = 0; i < new_column_types.size() - 1; i++) { - filter_types.push_back(new_column_types[i]); - auto is_not_null_expr = - make_uniq(ExpressionType::OPERATOR_IS_NOT_NULL, LogicalType::BOOLEAN); - auto bound_ref = make_uniq(new_column_types[i], i); - is_not_null_expr->children.push_back(std::move(bound_ref)); - filter_select_list.push_back(std::move(is_not_null_expr)); - } + prev_operator = + make_uniq(std::move(filter_types), std::move(filter_select_list), op.estimated_cardinality); + prev_operator->types.emplace_back(LogicalType::ROW_TYPE); + prev_operator->children.push_back(std::move(projection)); - auto null_filter = - make_uniq(std::move(filter_types), std::move(filter_select_list), op.estimated_cardinality); - null_filter->types.emplace_back(LogicalType::ROW_TYPE); - null_filter->children.push_back(std::move(projection)); + } else { + prev_operator = std::move(projection); + } - // determine if we sort the data prior to index creation - // we don't sort, if either VARCHAR or compound key - auto perform_sorting = true; + // Determine whether to push an ORDER BY operator. + auto sort = true; if (op.unbound_expressions.size() > 1) { - perform_sorting = false; + sort = false; } else if (op.unbound_expressions[0]->return_type.InternalType() == PhysicalType::VARCHAR) { - perform_sorting = false; + sort = false; } - // actual physical create index operator - - auto physical_create_index = - make_uniq(op, op.table, op.info->column_ids, std::move(op.info), - std::move(op.unbound_expressions), op.estimated_cardinality, perform_sorting); - - if (perform_sorting) { - - // optional order operator - vector orders; - vector projections; - for (idx_t i = 0; i < new_column_types.size() - 1; i++) { - auto col_expr = make_uniq_base(new_column_types[i], i); - orders.emplace_back(OrderType::ASCENDING, OrderByNullType::NULLS_FIRST, std::move(col_expr)); - projections.emplace_back(i); - } - projections.emplace_back(new_column_types.size() - 1); - - auto physical_order = make_uniq(new_column_types, std::move(orders), std::move(projections), - op.estimated_cardinality); - physical_order->children.push_back(std::move(null_filter)); + // CREATE INDEX operator. + auto physical_create_index = make_uniq( + op, op.table, op.info->column_ids, std::move(op.info), std::move(op.unbound_expressions), + op.estimated_cardinality, sort, std::move(op.alter_table_info)); - physical_create_index->children.push_back(std::move(physical_order)); - } else { + if (!sort) { + physical_create_index->children.push_back(std::move(prev_operator)); + return std::move(physical_create_index); + } - // no ordering - physical_create_index->children.push_back(std::move(null_filter)); + // ORDER BY operator. + vector orders; + vector projections; + for (idx_t i = 0; i < new_column_types.size() - 1; i++) { + auto col_expr = make_uniq_base(new_column_types[i], i); + orders.emplace_back(OrderType::ASCENDING, OrderByNullType::NULLS_FIRST, std::move(col_expr)); + projections.emplace_back(i); } + projections.emplace_back(new_column_types.size() - 1); + + auto physical_order = + make_uniq(new_column_types, std::move(orders), std::move(projections), op.estimated_cardinality); + physical_order->children.push_back(std::move(prev_operator)); + physical_create_index->children.push_back(std::move(physical_order)); return std::move(physical_create_index); } diff --git a/src/duckdb/src/execution/join_hashtable.cpp b/src/duckdb/src/execution/join_hashtable.cpp index 095745c31..99f8129a5 100644 --- a/src/duckdb/src/execution/join_hashtable.cpp +++ b/src/duckdb/src/execution/join_hashtable.cpp @@ -1467,18 +1467,12 @@ bool JoinHashTable::PrepareExternalFinalize(const idx_t max_ht_size) { return true; } -static void CreateSpillChunk(DataChunk &spill_chunk, DataChunk &keys, DataChunk &payload, Vector &hashes) { +static void CreateSpillChunk(DataChunk &spill_chunk, DataChunk &payload, Vector &hashes) { + D_ASSERT(spill_chunk.ColumnCount() == payload.ColumnCount() + 1); spill_chunk.Reset(); - idx_t spill_col_idx = 0; - for (idx_t col_idx = 0; col_idx < keys.ColumnCount(); col_idx++) { - spill_chunk.data[col_idx].Reference(keys.data[col_idx]); - } - spill_col_idx += keys.ColumnCount(); - for (idx_t col_idx = 0; col_idx < payload.data.size(); col_idx++) { - spill_chunk.data[spill_col_idx + col_idx].Reference(payload.data[col_idx]); - } - spill_col_idx += payload.ColumnCount(); - spill_chunk.data[spill_col_idx].Reference(hashes); + spill_chunk.Reference(payload); + spill_chunk.data.back().Reference(hashes); + spill_chunk.SetCardinality(payload); } void JoinHashTable::ProbeAndSpill(ScanStructure &scan_structure, DataChunk &keys, TupleDataChunkState &key_state, @@ -1497,7 +1491,7 @@ void JoinHashTable::ProbeAndSpill(ScanStructure &scan_structure, DataChunk &keys radix_bits, partition_end, &true_sel, &false_sel); auto false_count = keys.size() - true_count; - CreateSpillChunk(spill_chunk, keys, payload, hashes); + CreateSpillChunk(spill_chunk, payload, hashes); // can't probe these values right now, append to spill spill_chunk.Slice(false_sel, false_count); diff --git a/src/duckdb/src/execution/operator/aggregate/physical_partitioned_aggregate.cpp b/src/duckdb/src/execution/operator/aggregate/physical_partitioned_aggregate.cpp new file mode 100644 index 000000000..32bf4ecc2 --- /dev/null +++ b/src/duckdb/src/execution/operator/aggregate/physical_partitioned_aggregate.cpp @@ -0,0 +1,226 @@ +#include "duckdb/execution/operator/aggregate/physical_partitioned_aggregate.hpp" +#include "duckdb/execution/operator/aggregate/ungrouped_aggregate_state.hpp" +#include "duckdb/common/types/value_map.hpp" + +namespace duckdb { + +PhysicalPartitionedAggregate::PhysicalPartitionedAggregate(ClientContext &context, vector types, + vector> aggregates_p, + vector> groups_p, + vector partitions_p, idx_t estimated_cardinality) + : PhysicalOperator(PhysicalOperatorType::PARTITIONED_AGGREGATE, std::move(types), estimated_cardinality), + partitions(std::move(partitions_p)), groups(std::move(groups_p)), aggregates(std::move(aggregates_p)) { +} + +OperatorPartitionInfo PhysicalPartitionedAggregate::RequiredPartitionInfo() const { + return OperatorPartitionInfo::PartitionColumns(partitions); +} +//===--------------------------------------------------------------------===// +// Global State +//===--------------------------------------------------------------------===// +class PartitionedAggregateLocalSinkState : public LocalSinkState { +public: + PartitionedAggregateLocalSinkState(const PhysicalPartitionedAggregate &op, const vector &child_types, + ExecutionContext &context) + : execute_state(context.client, op.aggregates, child_types) { + } + + //! The current partition + Value current_partition; + //! The local aggregate state for the current partition + unique_ptr state; + //! The ungrouped aggregate execute state + UngroupedAggregateExecuteState execute_state; +}; + +class PartitionedAggregateGlobalSinkState : public GlobalSinkState { +public: + PartitionedAggregateGlobalSinkState(const PhysicalPartitionedAggregate &op, ClientContext &context) + : op(op), aggregate_result(BufferAllocator::Get(context), op.types) { + } + + mutex lock; + const PhysicalPartitionedAggregate &op; + //! The per-partition aggregate states + value_map_t> aggregate_states; + //! Final aggregate result + ColumnDataCollection aggregate_result; + + GlobalUngroupedAggregateState &GetOrCreatePartition(ClientContext &context, const Value &partition) { + lock_guard l(lock); + // find the state that corresponds to this partition and combine + auto entry = aggregate_states.find(partition); + if (entry != aggregate_states.end()) { + return *entry->second; + } + // no state yet for this partition - allocate a new one + auto new_global_state = make_uniq(BufferAllocator::Get(context), op.aggregates); + auto &result = *new_global_state; + aggregate_states.insert(make_pair(partition, std::move(new_global_state))); + return result; + } + + void Combine(ClientContext &context, PartitionedAggregateLocalSinkState &lstate) { + if (!lstate.state) { + // no aggregate state + return; + } + auto &global_state = GetOrCreatePartition(context, lstate.current_partition); + global_state.Combine(*lstate.state); + // clear the local aggregate state + lstate.state.reset(); + } +}; + +unique_ptr PhysicalPartitionedAggregate::GetGlobalSinkState(ClientContext &context) const { + return make_uniq(*this, context); +} + +//===--------------------------------------------------------------------===// +// Local State +//===--------------------------------------------------------------------===// + +unique_ptr PhysicalPartitionedAggregate::GetLocalSinkState(ExecutionContext &context) const { + D_ASSERT(sink_state); + return make_uniq(*this, children[0]->GetTypes(), context); +} + +//===--------------------------------------------------------------------===// +// Sink +//===--------------------------------------------------------------------===// +SinkResultType PhysicalPartitionedAggregate::Sink(ExecutionContext &context, DataChunk &chunk, + OperatorSinkInput &input) const { + auto &gstate = input.global_state.Cast(); + auto &lstate = input.local_state.Cast(); + if (!lstate.state) { + // the local state is not yet initialized for this partition + // initialize the partition + child_list_t partition_values; + for (idx_t partition_idx = 0; partition_idx < groups.size(); partition_idx++) { + auto column_name = to_string(partition_idx); + auto &partition = input.local_state.partition_info.partition_data[partition_idx]; + D_ASSERT(Value::NotDistinctFrom(partition.min_val, partition.max_val)); + partition_values.emplace_back(make_pair(std::move(column_name), partition.min_val)); + } + lstate.current_partition = Value::STRUCT(std::move(partition_values)); + + // initialize the state + auto &global_aggregate_state = gstate.GetOrCreatePartition(context.client, lstate.current_partition); + lstate.state = make_uniq(global_aggregate_state); + } + + // perform the aggregation + lstate.execute_state.Sink(*lstate.state, chunk); + return SinkResultType::NEED_MORE_INPUT; +} + +//===--------------------------------------------------------------------===// +// Next Batch +//===--------------------------------------------------------------------===// +SinkNextBatchType PhysicalPartitionedAggregate::NextBatch(ExecutionContext &context, + OperatorSinkNextBatchInput &input) const { + // flush the local state + auto &gstate = input.global_state.Cast(); + auto &lstate = input.local_state.Cast(); + + // finalize and reset the current state (if any) + gstate.Combine(context.client, lstate); + return SinkNextBatchType::READY; +} + +//===--------------------------------------------------------------------===// +// Combine +//===--------------------------------------------------------------------===// +SinkCombineResultType PhysicalPartitionedAggregate::Combine(ExecutionContext &context, + OperatorSinkCombineInput &input) const { + auto &gstate = input.global_state.Cast(); + auto &lstate = input.local_state.Cast(); + gstate.Combine(context.client, lstate); + return SinkCombineResultType::FINISHED; +} + +//===--------------------------------------------------------------------===// +// Finalize +//===--------------------------------------------------------------------===// +SinkFinalizeType PhysicalPartitionedAggregate::Finalize(Pipeline &pipeline, Event &event, ClientContext &context, + OperatorSinkFinalizeInput &input) const { + auto &gstate = input.global_state.Cast(); + ColumnDataAppendState append_state; + gstate.aggregate_result.InitializeAppend(append_state); + // finalize each of the partitions and append to a ColumnDataCollection + DataChunk chunk; + chunk.Initialize(context, types); + for (auto &entry : gstate.aggregate_states) { + chunk.Reset(); + // reference the partitions + auto &partitions = StructValue::GetChildren(entry.first); + for (idx_t partition_idx = 0; partition_idx < partitions.size(); partition_idx++) { + chunk.data[partition_idx].Reference(partitions[partition_idx]); + } + // finalize the aggregates + entry.second->Finalize(chunk, partitions.size()); + + // append to the CDC + gstate.aggregate_result.Append(append_state, chunk); + } + return SinkFinalizeType::READY; +} + +//===--------------------------------------------------------------------===// +// Source +//===--------------------------------------------------------------------===// +class PartitionedAggregateGlobalSourceState : public GlobalSourceState { +public: + explicit PartitionedAggregateGlobalSourceState(PartitionedAggregateGlobalSinkState &gstate) { + gstate.aggregate_result.InitializeScan(scan_state); + } + + ColumnDataScanState scan_state; + + idx_t MaxThreads() override { + return 1; + } +}; + +unique_ptr PhysicalPartitionedAggregate::GetGlobalSourceState(ClientContext &context) const { + auto &gstate = sink_state->Cast(); + return make_uniq(gstate); +} + +SourceResultType PhysicalPartitionedAggregate::GetData(ExecutionContext &context, DataChunk &chunk, + OperatorSourceInput &input) const { + auto &gstate = sink_state->Cast(); + auto &gsource = input.global_state.Cast(); + gstate.aggregate_result.Scan(gsource.scan_state, chunk); + return chunk.size() == 0 ? SourceResultType::FINISHED : SourceResultType::HAVE_MORE_OUTPUT; +} + +//===--------------------------------------------------------------------===// +// ParamsToString +//===--------------------------------------------------------------------===// +InsertionOrderPreservingMap PhysicalPartitionedAggregate::ParamsToString() const { + InsertionOrderPreservingMap result; + string groups_info; + for (idx_t i = 0; i < groups.size(); i++) { + if (i > 0) { + groups_info += "\n"; + } + groups_info += groups[i]->GetName(); + } + result["Groups"] = groups_info; + string aggregate_info; + for (idx_t i = 0; i < aggregates.size(); i++) { + auto &aggregate = aggregates[i]->Cast(); + if (i > 0) { + aggregate_info += "\n"; + } + aggregate_info += aggregates[i]->GetName(); + if (aggregate.filter) { + aggregate_info += " Filter: " + aggregate.filter->GetName(); + } + } + result["Aggregates"] = aggregate_info; + return result; +} + +} // namespace duckdb diff --git a/src/duckdb/src/execution/operator/aggregate/physical_ungrouped_aggregate.cpp b/src/duckdb/src/execution/operator/aggregate/physical_ungrouped_aggregate.cpp index f44b2476c..0ec4bd2a3 100644 --- a/src/duckdb/src/execution/operator/aggregate/physical_ungrouped_aggregate.cpp +++ b/src/duckdb/src/execution/operator/aggregate/physical_ungrouped_aggregate.cpp @@ -142,6 +142,75 @@ void GlobalUngroupedAggregateState::CombineDistinct(LocalUngroupedAggregateState } } +//===--------------------------------------------------------------------===// +// Ungrouped Aggregate Execute State +//===--------------------------------------------------------------------===// +UngroupedAggregateExecuteState::UngroupedAggregateExecuteState(ClientContext &context, + const vector> &aggregates, + const vector &child_types) + : aggregates(aggregates), child_executor(context), aggregate_input_chunk(), filter_set() { + vector payload_types; + vector aggregate_objects; + auto &allocator = BufferAllocator::Get(context); + for (auto &aggregate : aggregates) { + D_ASSERT(aggregate->GetExpressionClass() == ExpressionClass::BOUND_AGGREGATE); + auto &aggr = aggregate->Cast(); + // initialize the payload chunk + for (auto &child : aggr.children) { + payload_types.push_back(child->return_type); + child_executor.AddExpression(*child); + } + aggregate_objects.emplace_back(&aggr); + } + if (!payload_types.empty()) { // for select count(*) from t; there is no payload at all + aggregate_input_chunk.Initialize(allocator, payload_types); + } + filter_set.Initialize(context, aggregate_objects, child_types); +} + +void UngroupedAggregateExecuteState::Reset() { + aggregate_input_chunk.Reset(); +} + +void UngroupedAggregateExecuteState::Sink(LocalUngroupedAggregateState &state, DataChunk &input) { + DataChunk &payload_chunk = aggregate_input_chunk; + + idx_t payload_idx = 0; + idx_t next_payload_idx = 0; + + for (idx_t aggr_idx = 0; aggr_idx < aggregates.size(); aggr_idx++) { + auto &aggregate = aggregates[aggr_idx]->Cast(); + + payload_idx = next_payload_idx; + next_payload_idx = payload_idx + aggregate.children.size(); + + if (aggregate.IsDistinct()) { + continue; + } + + idx_t payload_cnt = 0; + // resolve the filter (if any) + if (aggregate.filter) { + auto &filtered_data = filter_set.GetFilterData(aggr_idx); + auto count = filtered_data.ApplyFilter(input); + + child_executor.SetChunk(filtered_data.filtered_payload); + payload_chunk.SetCardinality(count); + } else { + child_executor.SetChunk(input); + payload_chunk.SetCardinality(input); + } + + // resolve the child expressions of the aggregate (if any) + for (idx_t i = 0; i < aggregate.children.size(); ++i) { + child_executor.ExecuteExpression(payload_idx + payload_cnt, payload_chunk.data[payload_idx + payload_cnt]); + payload_cnt++; + } + + state.Sink(payload_chunk, payload_idx, aggr_idx); + } +} + //===--------------------------------------------------------------------===// // Local State //===--------------------------------------------------------------------===// @@ -153,45 +222,19 @@ class UngroupedAggregateLocalSinkState : public LocalSinkState { public: UngroupedAggregateLocalSinkState(const PhysicalUngroupedAggregate &op, const vector &child_types, UngroupedAggregateGlobalSinkState &gstate_p, ExecutionContext &context) - : state(gstate_p.state), child_executor(context.client), aggregate_input_chunk(), filter_set() { + : state(gstate_p.state), execute_state(context.client, op.aggregates, child_types) { auto &gstate = gstate_p.Cast(); - - auto &allocator = BufferAllocator::Get(context.client); InitializeDistinctAggregates(op, gstate, context); - - vector payload_types; - vector aggregate_objects; - for (auto &aggregate : op.aggregates) { - D_ASSERT(aggregate->GetExpressionClass() == ExpressionClass::BOUND_AGGREGATE); - auto &aggr = aggregate->Cast(); - // initialize the payload chunk - for (auto &child : aggr.children) { - payload_types.push_back(child->return_type); - child_executor.AddExpression(*child); - } - aggregate_objects.emplace_back(&aggr); - } - if (!payload_types.empty()) { // for select count(*) from t; there is no payload at all - aggregate_input_chunk.Initialize(allocator, payload_types); - } - filter_set.Initialize(context.client, aggregate_objects, child_types); } //! The local aggregate state LocalUngroupedAggregateState state; - //! The executor - ExpressionExecutor child_executor; - //! The payload chunk, containing all the Vectors for the aggregates - DataChunk aggregate_input_chunk; - //! Aggregate filter data set - AggregateFilterDataSet filter_set; + //! The ungrouped aggregate execute state + UngroupedAggregateExecuteState execute_state; //! The local sink states of the distinct aggregates hash tables vector> radix_states; public: - void Reset() { - aggregate_input_chunk.Reset(); - } void InitializeDistinctAggregates(const PhysicalUngroupedAggregate &op, const UngroupedAggregateGlobalSinkState &gstate, ExecutionContext &context) { @@ -274,7 +317,7 @@ void PhysicalUngroupedAggregate::SinkDistinct(ExecutionContext &context, DataChu // And in our case, we need to filter the groups (the distinct aggr children) // Apply the filter before inserting into the hashtable - auto &filtered_data = sink.filter_set.GetFilterData(idx); + auto &filtered_data = sink.execute_state.filter_set.GetFilterData(idx); idx_t count = filtered_data.ApplyFilter(chunk); filtered_data.filtered_payload.SetCardinality(count); @@ -290,49 +333,13 @@ SinkResultType PhysicalUngroupedAggregate::Sink(ExecutionContext &context, DataC auto &sink = input.local_state.Cast(); // perform the aggregation inside the local state - sink.Reset(); + sink.execute_state.Reset(); if (distinct_data) { SinkDistinct(context, chunk, input); } - DataChunk &payload_chunk = sink.aggregate_input_chunk; - - idx_t payload_idx = 0; - idx_t next_payload_idx = 0; - - for (idx_t aggr_idx = 0; aggr_idx < aggregates.size(); aggr_idx++) { - auto &aggregate = aggregates[aggr_idx]->Cast(); - - payload_idx = next_payload_idx; - next_payload_idx = payload_idx + aggregate.children.size(); - - if (aggregate.IsDistinct()) { - continue; - } - - idx_t payload_cnt = 0; - // resolve the filter (if any) - if (aggregate.filter) { - auto &filtered_data = sink.filter_set.GetFilterData(aggr_idx); - auto count = filtered_data.ApplyFilter(chunk); - - sink.child_executor.SetChunk(filtered_data.filtered_payload); - payload_chunk.SetCardinality(count); - } else { - sink.child_executor.SetChunk(chunk); - payload_chunk.SetCardinality(chunk); - } - - // resolve the child expressions of the aggregate (if any) - for (idx_t i = 0; i < aggregate.children.size(); ++i) { - sink.child_executor.ExecuteExpression(payload_idx + payload_cnt, - payload_chunk.data[payload_idx + payload_cnt]); - payload_cnt++; - } - - sink.state.Sink(payload_chunk, payload_idx, aggr_idx); - } + sink.execute_state.Sink(sink.state, chunk); return SinkResultType::NEED_MORE_INPUT; } @@ -625,14 +632,14 @@ void VerifyNullHandling(DataChunk &chunk, UngroupedAggregateState &state, #endif } -void GlobalUngroupedAggregateState::Finalize(DataChunk &result) { +void GlobalUngroupedAggregateState::Finalize(DataChunk &result, idx_t column_offset) { result.SetCardinality(1); for (idx_t aggr_idx = 0; aggr_idx < state.aggregate_expressions.size(); aggr_idx++) { auto &aggregate = state.aggregate_expressions[aggr_idx]->Cast(); Vector state_vector(Value::POINTER(CastPointerToValue(state.aggregate_data[aggr_idx].get()))); AggregateInputData aggr_input_data(aggregate.bind_info.get(), allocator); - aggregate.function.finalize(state_vector, aggr_input_data, result.data[aggr_idx], 1, 0); + aggregate.function.finalize(state_vector, aggr_input_data, result.data[column_offset + aggr_idx], 1, 0); } } diff --git a/src/duckdb/src/execution/operator/aggregate/physical_window.cpp b/src/duckdb/src/execution/operator/aggregate/physical_window.cpp index e9bf471d7..dfdc7cae6 100644 --- a/src/duckdb/src/execution/operator/aggregate/physical_window.cpp +++ b/src/duckdb/src/execution/operator/aggregate/physical_window.cpp @@ -102,6 +102,8 @@ class WindowHashGroup { ValidityMask partition_mask; //! The order boundary mask OrderMasks order_masks; + //! The fully materialised data collection + unique_ptr collection; //! External paging bool external; // The processing stage for this group @@ -145,6 +147,8 @@ class WindowGlobalSinkState : public GlobalSinkState { unique_ptr global_partition; //! The execution functions Executors executors; + //! The shared expressions library + WindowSharedExpressions shared; }; class WindowPartitionGlobalSinkState : public PartitionGlobalSinkState { @@ -215,31 +219,31 @@ PhysicalWindow::PhysicalWindow(vector types, vector WindowExecutorFactory(BoundWindowExpression &wexpr, ClientContext &context, - WindowAggregationMode mode) { + WindowSharedExpressions &shared, WindowAggregationMode mode) { switch (wexpr.type) { case ExpressionType::WINDOW_AGGREGATE: - return make_uniq(wexpr, context, mode); + return make_uniq(wexpr, context, shared, mode); case ExpressionType::WINDOW_ROW_NUMBER: - return make_uniq(wexpr, context); + return make_uniq(wexpr, context, shared); case ExpressionType::WINDOW_RANK_DENSE: - return make_uniq(wexpr, context); + return make_uniq(wexpr, context, shared); case ExpressionType::WINDOW_RANK: - return make_uniq(wexpr, context); + return make_uniq(wexpr, context, shared); case ExpressionType::WINDOW_PERCENT_RANK: - return make_uniq(wexpr, context); + return make_uniq(wexpr, context, shared); case ExpressionType::WINDOW_CUME_DIST: - return make_uniq(wexpr, context); + return make_uniq(wexpr, context, shared); case ExpressionType::WINDOW_NTILE: - return make_uniq(wexpr, context); + return make_uniq(wexpr, context, shared); case ExpressionType::WINDOW_LEAD: case ExpressionType::WINDOW_LAG: - return make_uniq(wexpr, context); + return make_uniq(wexpr, context, shared); case ExpressionType::WINDOW_FIRST_VALUE: - return make_uniq(wexpr, context); + return make_uniq(wexpr, context, shared); case ExpressionType::WINDOW_LAST_VALUE: - return make_uniq(wexpr, context); + return make_uniq(wexpr, context, shared); case ExpressionType::WINDOW_NTH_VALUE: - return make_uniq(wexpr, context); + return make_uniq(wexpr, context, shared); break; default: throw InternalException("Window aggregate type %s", ExpressionTypeToString(wexpr.type)); @@ -256,7 +260,7 @@ WindowGlobalSinkState::WindowGlobalSinkState(const PhysicalWindow &op, ClientCon 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(); - auto wexec = WindowExecutorFactory(wexpr, context, mode); + auto wexec = WindowExecutorFactory(wexpr, context, shared, mode); executors.emplace_back(std::move(wexec)); } @@ -568,6 +572,15 @@ WindowHashGroup::WindowHashGroup(WindowGlobalSinkState &gstate, const idx_t hash if (rows) { blocks = rows->blocks.size(); } + + // Set up the collection for any fully materialised data + const auto &shared = WindowSharedExpressions::GetSortedExpressions(gstate.shared.coll_shared); + vector types; + for (auto &expr : shared) { + types.emplace_back(expr->return_type); + } + auto &buffer_manager = BufferManager::GetBufferManager(gstate.context); + collection = make_uniq(buffer_manager, count, types); } // Per-thread scan state @@ -606,6 +619,19 @@ class WindowLocalSourceState : public LocalSourceState { void Sink(); void Finalize(); void GetData(DataChunk &chunk); + + //! Storage and evaluation for the fully materialised data + unique_ptr builder; + ExpressionExecutor coll_exec; + DataChunk coll_chunk; + + //! Storage and evaluation for chunks used in the sink/build phase + ExpressionExecutor sink_exec; + DataChunk sink_chunk; + + //! Storage and evaluation for chunks used in the evaluate phase + ExpressionExecutor eval_exec; + DataChunk eval_chunk; }; WindowHashGroup::ExecutorGlobalStates &WindowHashGroup::Initialize(WindowGlobalSinkState &gsink) { @@ -660,8 +686,30 @@ void WindowLocalSourceState::Sink() { break; } + // Compute fully materialised expressions + if (coll_chunk.data.empty()) { + coll_chunk.SetCardinality(input_chunk); + } else { + coll_chunk.Reset(); + coll_exec.Execute(input_chunk, coll_chunk); + auto collection = window_hash_group->collection.get(); + if (!builder || &builder->collection != collection) { + builder = make_uniq(*collection); + } + + builder->Sink(coll_chunk, input_idx); + } + + // Compute sink expressions + if (sink_chunk.data.empty()) { + sink_chunk.SetCardinality(input_chunk); + } else { + sink_chunk.Reset(); + sink_exec.Execute(input_chunk, sink_chunk); + } + for (idx_t w = 0; w < executors.size(); ++w) { - executors[w]->Sink(input_chunk, input_idx, window_hash_group->count, *gestates[w], *local_states[w]); + executors[w]->Sink(sink_chunk, coll_chunk, input_idx, *gestates[w], *local_states[w]); } window_hash_group->sunk += input_chunk.size(); @@ -677,15 +725,20 @@ void WindowLocalSourceState::Finalize() { D_ASSERT(task); D_ASSERT(task->stage == WindowGroupStage::FINALIZE); + // First finalize the collection (so the executors can use it) + auto &gsink = gsource.gsink; + if (window_hash_group->collection) { + window_hash_group->collection->Combine(gsink.shared.coll_validity); + } + // Finalize all the executors. // Parallel finalisation is handled internally by the executor, // and should not return until all threads have completed work. - auto &gsink = gsource.gsink; const auto &executors = gsink.executors; auto &gestates = window_hash_group->gestates; auto &local_states = window_hash_group->thread_states.at(task->thread_idx); for (idx_t w = 0; w < executors.size(); ++w) { - executors[w]->Finalize(*gestates[w], *local_states[w]); + executors[w]->Finalize(*gestates[w], *local_states[w], window_hash_group->collection); } // Mark this range as done @@ -693,7 +746,9 @@ void WindowLocalSourceState::Finalize() { task->begin_idx = task->end_idx; } -WindowLocalSourceState::WindowLocalSourceState(WindowGlobalSourceState &gsource) : gsource(gsource), batch_index(0) { +WindowLocalSourceState::WindowLocalSourceState(WindowGlobalSourceState &gsource) + : gsource(gsource), batch_index(0), coll_exec(gsource.context), sink_exec(gsource.context), + eval_exec(gsource.context) { auto &gsink = gsource.gsink; auto &global_partition = *gsink.global_partition; @@ -706,6 +761,11 @@ WindowLocalSourceState::WindowLocalSourceState(WindowGlobalSourceState &gsource) } output_chunk.Initialize(global_partition.allocator, output_types); + auto &shared = gsink.shared; + shared.PrepareCollection(coll_exec, coll_chunk); + shared.PrepareSink(sink_exec, sink_chunk); + shared.PrepareEvaluate(eval_exec, eval_chunk); + ++gsource.locals; } @@ -819,7 +879,13 @@ void WindowLocalSourceState::GetData(DataChunk &result) { auto &gstate = *gestates[expr_idx]; auto &lstate = *local_states[expr_idx]; auto &result = output_chunk.data[expr_idx]; - executor.Evaluate(position, input_chunk, result, lstate, gstate); + if (eval_chunk.data.empty()) { + eval_chunk.SetCardinality(input_chunk); + } else { + eval_chunk.Reset(); + eval_exec.Execute(input_chunk, eval_chunk); + } + executor.Evaluate(position, eval_chunk, result, lstate, gstate); } output_chunk.SetCardinality(input_chunk); output_chunk.Verify(); @@ -856,7 +922,10 @@ unique_ptr PhysicalWindow::GetGlobalSourceState(ClientContext return make_uniq(context, gsink); } -bool PhysicalWindow::SupportsBatchIndex() const { +bool PhysicalWindow::SupportsPartitioning(const OperatorPartitionInfo &partition_info) const { + if (partition_info.RequiresPartitionColumns()) { + return false; + } // We can only preserve order for single partitioning // or work stealing causes out of order batch numbers auto &wexpr = select_list[order_idx]->Cast(); @@ -887,10 +956,14 @@ double PhysicalWindow::GetProgress(ClientContext &context, GlobalSourceState &gs return count ? (double(returned) / double(count)) : -1; } -idx_t PhysicalWindow::GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate_p, - LocalSourceState &lstate_p) const { +OperatorPartitionData PhysicalWindow::GetPartitionData(ExecutionContext &context, DataChunk &chunk, + GlobalSourceState &gstate_p, LocalSourceState &lstate_p, + const OperatorPartitionInfo &partition_info) const { + if (partition_info.RequiresPartitionColumns()) { + throw InternalException("PhysicalWindow::GetPartitionData: partition columns not supported"); + } auto &lstate = lstate_p.Cast(); - return lstate.batch_index; + return OperatorPartitionData(lstate.batch_index); } SourceResultType PhysicalWindow::GetData(ExecutionContext &context, DataChunk &chunk, diff --git a/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer_manager.cpp b/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer_manager.cpp index 064595f3c..d8be17df9 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer_manager.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer_manager.cpp @@ -148,4 +148,11 @@ string CSVBufferManager::GetFilePath() const { return file_path; } +bool CSVBufferManager::IsBlockUnloaded(idx_t block_idx) { + if (block_idx < cached_buffers.size()) { + return cached_buffers[block_idx]->IsUnloaded(); + } + return false; +} + } // namespace duckdb diff --git a/src/duckdb/src/execution/operator/csv_scanner/scanner/scanner_boundary.cpp b/src/duckdb/src/execution/operator/csv_scanner/scanner/scanner_boundary.cpp index 4ddd938bb..0a577d779 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/scanner/scanner_boundary.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/scanner/scanner_boundary.cpp @@ -106,4 +106,12 @@ void CSVIterator::SetStart(idx_t start) { boundary.buffer_pos = start; } +void CSVIterator::SetEnd(idx_t pos) { + boundary.end_pos = pos; +} + +idx_t CSVIterator::GetGlobalCurrentPos() { + return pos.buffer_pos + buffer_size * pos.buffer_idx; +} + } // namespace duckdb diff --git a/src/duckdb/src/execution/operator/csv_scanner/scanner/string_value_scanner.cpp b/src/duckdb/src/execution/operator/csv_scanner/scanner/string_value_scanner.cpp index 9662e849b..fa0983353 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/scanner/string_value_scanner.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/scanner/string_value_scanner.cpp @@ -840,11 +840,6 @@ bool StringValueResult::AddRow(StringValueResult &result, const idx_t buffer_pos } void StringValueResult::InvalidState(StringValueResult &result) { - bool force_error = !result.state_machine.options.ignore_errors.GetValue() && result.sniffing; - // Invalid unicode, we must error - if (force_error) { - result.HandleUnicodeError(result.cur_col_id, result.last_position); - } result.current_errors.Insert(UNTERMINATED_QUOTES, result.cur_col_id, result.chunk_col_id, result.last_position); } @@ -889,6 +884,7 @@ StringValueScanner::StringValueScanner(idx_t scanner_idx_p, const shared_ptrcontext.client_data->debug_set_max_line_length, csv_file_scan, lines_read, sniffing, buffer_manager->GetFilePath()) { + iterator.buffer_size = state_machine->options.buffer_size; } StringValueScanner::StringValueScanner(const shared_ptr &buffer_manager, @@ -900,6 +896,7 @@ StringValueScanner::StringValueScanner(const shared_ptr &buffe iterator.pos.buffer_pos, *error_handler, iterator, buffer_manager->context.client_data->debug_set_max_line_length, csv_file_scan, lines_read, sniffing, buffer_manager->GetFilePath()) { + iterator.buffer_size = state_machine->options.buffer_size; } unique_ptr StringValueScanner::GetCSVScanner(ClientContext &context, CSVReaderOptions &options) { @@ -1061,13 +1058,16 @@ void StringValueScanner::Flush(DataChunk &insert_chunk) { void StringValueScanner::Initialize() { states.Initialize(); + if (result.result_size != 1 && !(sniffing && state_machine->options.null_padding && !state_machine->options.dialect_options.skip_rows.IsSetByUser())) { SetStart(); + } else { + start_pos = iterator.GetGlobalCurrentPos(); } + result.last_position = {iterator.pos.buffer_idx, iterator.pos.buffer_pos, cur_buffer_handle->actual_size}; result.current_line_position.begin = result.last_position; - result.current_line_position.end = result.current_line_position.begin; } @@ -1197,10 +1197,10 @@ string_t StringValueScanner::RemoveEscape(const char *str_ptr, idx_t end, char e return removed_escapes; } -void StringValueScanner::ProcessOverbufferValue() { +void StringValueScanner::ProcessOverBufferValue() { // Process first string states.Initialize(); - string overbuffer_string; + string over_buffer_string; auto previous_buffer = previous_buffer_handle->Ptr(); if (result.last_position.buffer_pos == previous_buffer_handle->actual_size) { state_machine->Transition(states, previous_buffer[result.last_position.buffer_pos - 1]); @@ -1216,7 +1216,7 @@ void StringValueScanner::ProcessOverbufferValue() { break; } else { if (!result.comment) { - overbuffer_string += previous_buffer[i]; + over_buffer_string += previous_buffer[i]; } } if (states.IsQuoted()) { @@ -1233,7 +1233,7 @@ void StringValueScanner::ProcessOverbufferValue() { } j++; } - if (overbuffer_string.empty() && + if (over_buffer_string.empty() && state_machine->dialect_options.state_machine_options.new_line == NewLineIdentifier::CARRY_ON) { if (buffer_handle_ptr[iterator.pos.buffer_pos] == '\n') { iterator.pos.buffer_pos++; @@ -1253,7 +1253,7 @@ void StringValueScanner::ProcessOverbufferValue() { break; } else { if (!result.comment && !states.IsComment()) { - overbuffer_string += buffer_handle_ptr[iterator.pos.buffer_pos]; + over_buffer_string += buffer_handle_ptr[iterator.pos.buffer_pos]; } } if (states.IsQuoted()) { @@ -1280,16 +1280,16 @@ void StringValueScanner::ProcessOverbufferValue() { if (!skip_value) { string_t value; if (result.quoted) { - value = string_t(overbuffer_string.c_str() + result.quoted_position, - UnsafeNumericCast(overbuffer_string.size() - 1 - result.quoted_position)); + value = string_t(over_buffer_string.c_str() + result.quoted_position, + UnsafeNumericCast(over_buffer_string.size() - 1 - result.quoted_position)); if (result.escaped) { - const auto str_ptr = overbuffer_string.c_str() + result.quoted_position; - value = RemoveEscape(str_ptr, overbuffer_string.size() - 2, + const auto str_ptr = over_buffer_string.c_str() + result.quoted_position; + value = RemoveEscape(str_ptr, over_buffer_string.size() - 2, state_machine->dialect_options.state_machine_options.escape.GetValue(), result.parse_chunk.data[result.chunk_col_id]); } } else { - value = string_t(overbuffer_string.c_str(), UnsafeNumericCast(overbuffer_string.size())); + value = string_t(over_buffer_string.c_str(), UnsafeNumericCast(over_buffer_string.size())); } if (states.EmptyLine() && state_machine->dialect_options.num_cols == 1) { result.EmptyLine(result, iterator.pos.buffer_pos); @@ -1374,8 +1374,8 @@ bool StringValueScanner::MoveToNextBuffer() { iterator.pos.buffer_pos = 0; buffer_handle_ptr = cur_buffer_handle->Ptr(); - // Handle overbuffer value - ProcessOverbufferValue(); + // Handle over-buffer value + ProcessOverBufferValue(); result.buffer_ptr = buffer_handle_ptr; result.buffer_size = cur_buffer_handle->actual_size; return true; @@ -1408,38 +1408,86 @@ bool StringValueResult::PrintErrorLine() const { (state_machine.options.store_rejects.GetValue() || !state_machine.options.ignore_errors.GetValue()); } -void StringValueScanner::SkipUntilNewLine() { - // Now skip until next newline - if (state_machine->options.dialect_options.state_machine_options.new_line.GetValue() == - NewLineIdentifier::CARRY_ON) { - bool carriage_return = false; - bool not_carriage_return = false; - for (; iterator.pos.buffer_pos < cur_buffer_handle->actual_size; iterator.pos.buffer_pos++) { - if (buffer_handle_ptr[iterator.pos.buffer_pos] == '\r') { - carriage_return = true; - } else if (buffer_handle_ptr[iterator.pos.buffer_pos] != '\n') { - not_carriage_return = true; +bool StringValueScanner::FirstValueEndsOnQuote(CSVIterator iterator) const { + CSVStates current_state; + current_state.Initialize(CSVState::STANDARD); + const idx_t to_pos = iterator.GetEndPos(); + while (iterator.pos.buffer_pos < to_pos) { + state_machine->Transition(current_state, buffer_handle_ptr[iterator.pos.buffer_pos++]); + if ((current_state.IsState(CSVState::DELIMITER) || current_state.IsState(CSVState::CARRIAGE_RETURN) || + current_state.IsState(CSVState::RECORD_SEPARATOR))) { + return buffer_handle_ptr[iterator.pos.buffer_pos - 2] == + state_machine->dialect_options.state_machine_options.quote.GetValue(); + } + } + return false; +} + +bool StringValueScanner::SkipUntilState(CSVState initial_state, CSVState until_state, CSVIterator ¤t_iterator, + bool "ed) const { + CSVStates current_state; + current_state.Initialize(initial_state); + bool first_column = true; + const idx_t to_pos = current_iterator.GetEndPos(); + while (current_iterator.pos.buffer_pos < to_pos) { + state_machine->Transition(current_state, buffer_handle_ptr[current_iterator.pos.buffer_pos++]); + if (current_state.IsState(CSVState::STANDARD) || current_state.IsState(CSVState::STANDARD_NEWLINE)) { + while (current_iterator.pos.buffer_pos + 8 < to_pos) { + uint64_t value = Load( + reinterpret_cast(&buffer_handle_ptr[current_iterator.pos.buffer_pos])); + if (ContainsZeroByte((value ^ state_machine->transition_array.delimiter) & + (value ^ state_machine->transition_array.new_line) & + (value ^ state_machine->transition_array.carriage_return) & + (value ^ state_machine->transition_array.comment))) { + break; + } + current_iterator.pos.buffer_pos += 8; } - if (buffer_handle_ptr[iterator.pos.buffer_pos] == '\n') { - if (carriage_return || not_carriage_return) { - iterator.pos.buffer_pos++; - return; + while (state_machine->transition_array + .skip_standard[static_cast(buffer_handle_ptr[current_iterator.pos.buffer_pos])] && + current_iterator.pos.buffer_pos < to_pos - 1) { + current_iterator.pos.buffer_pos++; + } + } + if (current_state.IsState(CSVState::QUOTED)) { + while (current_iterator.pos.buffer_pos + 8 < to_pos) { + uint64_t value = Load( + reinterpret_cast(&buffer_handle_ptr[current_iterator.pos.buffer_pos])); + if (ContainsZeroByte((value ^ state_machine->transition_array.quote) & + (value ^ state_machine->transition_array.escape))) { + break; } + current_iterator.pos.buffer_pos += 8; + } + + while (state_machine->transition_array + .skip_quoted[static_cast(buffer_handle_ptr[current_iterator.pos.buffer_pos])] && + current_iterator.pos.buffer_pos < to_pos - 1) { + current_iterator.pos.buffer_pos++; } } - } else { - for (; iterator.pos.buffer_pos < cur_buffer_handle->actual_size; iterator.pos.buffer_pos++) { - if (buffer_handle_ptr[iterator.pos.buffer_pos] == '\n' || - buffer_handle_ptr[iterator.pos.buffer_pos] == '\r') { - iterator.pos.buffer_pos++; - return; + if ((current_state.IsState(CSVState::DELIMITER) || current_state.IsState(CSVState::CARRIAGE_RETURN) || + current_state.IsState(CSVState::RECORD_SEPARATOR)) && + first_column) { + if (buffer_handle_ptr[current_iterator.pos.buffer_pos - 1] == + state_machine->dialect_options.state_machine_options.quote.GetValue()) { + quoted = true; } } + if (current_state.WasState(CSVState::DELIMITER)) { + first_column = false; + } + if (current_state.IsState(until_state)) { + return true; + } + if (current_state.IsState(CSVState::INVALID)) { + return false; + } } + return false; } bool StringValueScanner::CanDirectlyCast(const LogicalType &type, bool icu_loaded) { - switch (type.id()) { case LogicalTypeId::TINYINT: case LogicalTypeId::SMALLINT: @@ -1467,60 +1515,103 @@ bool StringValueScanner::CanDirectlyCast(const LogicalType &type, bool icu_loade } } +bool StringValueScanner::IsRowValid(CSVIterator ¤t_iterator) const { + if (iterator.pos.buffer_pos == cur_buffer_handle->actual_size) { + return false; + } + constexpr idx_t result_size = 1; + auto scan_finder = + make_uniq(0U, buffer_manager, state_machine, make_shared_ptr(), + csv_file_scan, false, current_iterator, result_size); + auto &tuples = scan_finder->ParseChunk(); + current_iterator.pos = scan_finder->GetIteratorPosition(); + return (tuples.number_of_rows == 1 || tuples.first_line_is_comment) && tuples.borked_rows.empty() && + !tuples.current_errors.HasError(); + ; +} + +ValidRowInfo StringValueScanner::TryRow(CSVState state, idx_t start_pos, idx_t end_pos) const { + auto current_iterator = iterator; + current_iterator.SetStart(start_pos); + current_iterator.SetEnd(end_pos); + bool quoted = false; + if (SkipUntilState(state, CSVState::RECORD_SEPARATOR, current_iterator, quoted)) { + auto iterator_start = current_iterator; + idx_t current_pos = current_iterator.pos.buffer_pos; + current_iterator.SetEnd(iterator.GetEndPos()); + if (iterator.GetEndPos() == current_pos) { + return {false, current_pos, current_iterator.pos.buffer_idx, current_iterator.pos.buffer_pos, quoted}; + } + if (IsRowValid(current_iterator)) { + if (!quoted) { + quoted = FirstValueEndsOnQuote(iterator_start); + } + return {true, current_pos, current_iterator.pos.buffer_idx, current_iterator.pos.buffer_pos, quoted}; + } + } + return {false, current_iterator.pos.buffer_pos, current_iterator.pos.buffer_idx, current_iterator.pos.buffer_pos, + quoted}; +} + void StringValueScanner::SetStart() { + start_pos = iterator.GetGlobalCurrentPos(); if (iterator.first_one) { if (result.store_line_size) { result.error_handler.NewMaxLineSize(iterator.pos.buffer_pos); } return; } - // The result size of the data after skipping the row is one line - // We have to look for a new line that fits our schema - // 1. We walk until the next new line - bool line_found; - unique_ptr scan_finder; - do { - constexpr idx_t result_size = 1; - SkipUntilNewLine(); - if (state_machine->options.null_padding) { - // When Null Padding, we assume we start from the correct new-line - return; - } - scan_finder = - make_uniq(0U, buffer_manager, state_machine, make_shared_ptr(true), - csv_file_scan, false, iterator, result_size); - auto &tuples = scan_finder->ParseChunk(); - line_found = true; - if (tuples.number_of_rows != 1 || - (!tuples.borked_rows.empty() && !state_machine->options.ignore_errors.GetValue()) || - tuples.first_line_is_comment) { - line_found = false; - // If no tuples were parsed, this is not the correct start, we need to skip until the next new line - // Or if columns don't match, this is not the correct start, we need to skip until the next new line - if (scan_finder->previous_buffer_handle) { - if (scan_finder->iterator.pos.buffer_pos >= scan_finder->previous_buffer_handle->actual_size && - scan_finder->previous_buffer_handle->is_last_buffer) { - iterator.pos.buffer_idx = scan_finder->iterator.pos.buffer_idx; - iterator.pos.buffer_pos = scan_finder->iterator.pos.buffer_pos; - result.last_position = {iterator.pos.buffer_idx, iterator.pos.buffer_pos, result.buffer_size}; - iterator.done = scan_finder->iterator.done; - return; - } - } - if (iterator.pos.buffer_pos == cur_buffer_handle->actual_size || - scan_finder->iterator.GetBufferIdx() > iterator.GetBufferIdx()) { - // If things go terribly wrong, we never loop indefinitely. - iterator.pos.buffer_idx = scan_finder->iterator.pos.buffer_idx; - iterator.pos.buffer_pos = scan_finder->iterator.pos.buffer_pos; - result.last_position = {iterator.pos.buffer_idx, iterator.pos.buffer_pos, result.buffer_size}; - iterator.done = scan_finder->iterator.done; - return; + if (iterator.GetEndPos() > cur_buffer_handle->actual_size) { + iterator.SetEnd(cur_buffer_handle->actual_size); + } + // At this point we have 3 options: + // 1. We are at the start of a valid line + ValidRowInfo best_row = TryRow(CSVState::STANDARD_NEWLINE, iterator.pos.buffer_pos, iterator.GetEndPos()); + // 2. We are in the middle of a quoted value + if (state_machine->dialect_options.state_machine_options.quote.GetValue() != '\0') { + idx_t end_pos = iterator.GetEndPos(); + if (best_row.is_valid && best_row.end_buffer_idx == iterator.pos.buffer_idx) { + // If we got a valid row from the standard state, we limit our search up to that. + end_pos = best_row.end_pos; + } + auto quoted_row = TryRow(CSVState::QUOTED, iterator.pos.buffer_pos, end_pos); + if (quoted_row.is_valid && (!best_row.is_valid || best_row.last_state_quote)) { + best_row = quoted_row; + } + if (!best_row.is_valid && !quoted_row.is_valid && best_row.start_pos < quoted_row.start_pos) { + best_row = quoted_row; + } + } + // 3. We are in an escaped value + if (!best_row.is_valid && state_machine->dialect_options.state_machine_options.escape.GetValue() != '\0' && + state_machine->dialect_options.state_machine_options.quote.GetValue() != '\0') { + auto escape_row = TryRow(CSVState::ESCAPE, iterator.pos.buffer_pos, iterator.GetEndPos()); + if (escape_row.is_valid) { + best_row = escape_row; + } else { + if (best_row.start_pos < escape_row.start_pos) { + best_row = escape_row; } } - } while (!line_found); - iterator.pos.buffer_idx = scan_finder->result.current_line_position.begin.buffer_idx; - iterator.pos.buffer_pos = scan_finder->result.current_line_position.begin.buffer_pos; + } + if (!best_row.is_valid) { + bool is_this_the_end = + best_row.start_pos >= cur_buffer_handle->actual_size && cur_buffer_handle->is_last_buffer; + if (is_this_the_end) { + iterator.pos.buffer_pos = best_row.start_pos; + iterator.done = true; + } else { + bool mock; + SkipUntilState(CSVState::STANDARD_NEWLINE, CSVState::RECORD_SEPARATOR, iterator, mock); + } + } else { + iterator.pos.buffer_pos = best_row.start_pos; + iterator.done = iterator.pos.buffer_pos == cur_buffer_handle->actual_size; + } + // 4. We have an error, if we have an error, we let life go on, the scanner will either ignore it + // or throw. result.last_position = {iterator.pos.buffer_idx, iterator.pos.buffer_pos, result.buffer_size}; + start_pos = iterator.GetGlobalCurrentPos(); } void StringValueScanner::FinalizeChunkProcess() { @@ -1603,4 +1694,9 @@ void StringValueScanner::FinalizeChunkProcess() { } } } + +ValidatorLine StringValueScanner::GetValidationLine() { + return {start_pos, result.iterator.GetGlobalCurrentPos()}; +} + } // namespace duckdb diff --git a/src/duckdb/src/execution/operator/csv_scanner/sniffer/csv_sniffer.cpp b/src/duckdb/src/execution/operator/csv_scanner/sniffer/csv_sniffer.cpp index 950d74891..5f9e7216f 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/sniffer/csv_sniffer.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/sniffer/csv_sniffer.cpp @@ -181,10 +181,15 @@ SnifferResult CSVSniffer::AdaptiveSniff(const CSVSchema &file_schema) { } return min_sniff_res.ToSnifferResult(); } + SnifferResult CSVSniffer::SniffCSV(bool force_match) { buffer_manager->sniffing = true; // 1. Dialect Detection DetectDialect(); + if (buffer_manager->file_handle->compression_type != FileCompressionType::UNCOMPRESSED && + buffer_manager->IsBlockUnloaded(0)) { + buffer_manager->ResetBufferManager(); + } // 2. Type Detection DetectTypes(); // 3. Type Refinement diff --git a/src/duckdb/src/execution/operator/csv_scanner/sniffer/dialect_detection.cpp b/src/duckdb/src/execution/operator/csv_scanner/sniffer/dialect_detection.cpp index 43cef4fc9..c1f1fc9bf 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/sniffer/dialect_detection.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/sniffer/dialect_detection.cpp @@ -19,15 +19,15 @@ vector DialectCandidates::GetDefaultDelimiter() { } vector> DialectCandidates::GetDefaultQuote() { - return {{'\"'}, {'\"', '\''}, {'\0'}}; + return {{'\0'}, {'\"', '\''}, {'\"'}}; } vector DialectCandidates::GetDefaultQuoteRule() { - return {QuoteRule::QUOTES_RFC, QuoteRule::QUOTES_OTHER, QuoteRule::NO_QUOTES}; + return {QuoteRule::NO_QUOTES, QuoteRule::QUOTES_OTHER, QuoteRule::QUOTES_RFC}; } vector> DialectCandidates::GetDefaultEscape() { - return {{'\"', '\0', '\''}, {'\\'}, {'\0'}}; + return {{'\0'}, {'\\'}, {'\"', '\0', '\''}}; } vector DialectCandidates::GetDefaultComment() { @@ -334,24 +334,47 @@ void CSVSniffer::AnalyzeDialectCandidate(unique_ptr scanner, bool comments_are_acceptable = AreCommentsAcceptable( sniffed_column_counts, num_cols, options.dialect_options.state_machine_options.comment.IsSetByUser()); + bool quoted = scanner->ever_quoted && + sniffed_column_counts.state_machine.dialect_options.state_machine_options.quote.GetValue() != '\0'; + + // For our columns to match, we either don't have them manually set, or they match in value with the sniffed value + bool columns_match_set = num_cols == set_columns.Size() || + (num_cols == set_columns.Size() + 1 && sniffed_column_counts[0].last_value_always_empty) || + !set_columns.IsSet(); + // If rows are consistent and no invalid padding happens, this is the best suitable candidate if one of the // following is valid: // - There's a single column before. // - There are more values and no additional padding is required. // - There's more than one column and less padding is required. - if (rows_consistent && + if (columns_match_set && rows_consistent && (single_column_before || ((more_values || more_columns) && !require_more_padding) || - (more_than_one_column && require_less_padding)) && + (more_than_one_column && require_less_padding) || quoted) && !invalid_padding && comments_are_acceptable) { if (!candidates.empty() && set_columns.IsSet() && max_columns_found == set_columns.Size()) { // We have a candidate that fits our requirements better - return; + if (candidates.front()->ever_quoted || !scanner->ever_quoted) { + return; + } } auto &sniffing_state_machine = scanner->GetStateMachine(); - if (!candidates.empty() && candidates.front()->ever_quoted && !scanner->ever_quoted) { + if (!candidates.empty() && candidates.front()->ever_quoted) { // Give preference to quoted boys. - return; + if (!scanner->ever_quoted) { + return; + } else { + // Give preference to one that got escaped + if (!scanner->ever_escaped && candidates.front()->ever_escaped) { + return; + } + if (best_consistent_rows == consistent_rows) { + // If both have not been escaped, this might get solved later on. + sniffing_state_machine.dialect_options.num_cols = num_cols; + candidates.emplace_back(std::move(scanner)); + return; + } + } } if (max_columns_found == num_cols && ignored_rows > min_ignored_rows) { return; @@ -381,8 +404,8 @@ void CSVSniffer::AnalyzeDialectCandidate(unique_ptr scanner, // If there's more than one row and column, the start is good, rows are consistent, // no additional padding is required, and there is no invalid padding, and there is not yet a candidate // with the same quote, we add this state_machine as a suitable candidate. - if (more_than_one_row && more_than_one_column && start_good && rows_consistent && !require_more_padding && - !invalid_padding && num_cols == max_columns_found && comments_are_acceptable) { + if (columns_match_set && more_than_one_row && more_than_one_column && start_good && rows_consistent && + !require_more_padding && !invalid_padding && num_cols == max_columns_found && comments_are_acceptable) { auto &sniffing_state_machine = scanner->GetStateMachine(); bool same_quote_is_candidate = false; @@ -437,24 +460,31 @@ void CSVSniffer::RefineCandidates() { // Only one candidate nothing to refine or all candidates already checked return; } - vector> successful_candidates; - for (auto &cur_candidate : candidates) { - for (idx_t i = 1; i <= options.sample_size_chunks; i++) { + + for (idx_t i = 1; i <= options.sample_size_chunks; i++) { + vector> successful_candidates; + bool done = false; + for (auto &cur_candidate : candidates) { bool finished_file = cur_candidate->FinishedFile(); if (finished_file || i == options.sample_size_chunks) { // we finished the file or our chunk sample successfully successful_candidates.push_back(std::move(cur_candidate)); + done = true; break; } - if (!RefineCandidateNextChunk(*cur_candidate) || cur_candidate->GetResult().error) { - // This candidate failed, move to the next one + if ((!!RefineCandidateNextChunk(*cur_candidate) || cur_candidate->GetResult().error)) { + successful_candidates.push_back(std::move(cur_candidate)); break; } } + candidates = std::move(successful_candidates); + if (done) { + break; + } } // If we have multiple candidates with quotes set, we will give the preference to ones // that have actually quoted values, otherwise we will choose quotes = \0 - candidates.clear(); + vector> successful_candidates = std::move(candidates); if (!successful_candidates.empty()) { for (idx_t i = 0; i < successful_candidates.size(); i++) { unique_ptr cc_best_candidate = std::move(successful_candidates[i]); @@ -525,7 +555,7 @@ void CSVSniffer::DetectDialect() { // if no dialect candidate was found, we throw an exception if (candidates.empty()) { auto error = CSVError::SniffingError(options, dialect_candidates.Print()); - error_handler->Error(error); + error_handler->Error(error, true); } } } // namespace duckdb diff --git a/src/duckdb/src/execution/operator/csv_scanner/state_machine/csv_state_machine_cache.cpp b/src/duckdb/src/execution/operator/csv_scanner/state_machine/csv_state_machine_cache.cpp index 9c40809cb..e59c53dd3 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/state_machine/csv_state_machine_cache.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/state_machine/csv_state_machine_cache.cpp @@ -50,14 +50,20 @@ void CSVStateMachineCache::Insert(const CSVStateMachineOptions &state_machine_op // Now set values depending on configuration // 1) Standard/Invalid State - vector std_inv {static_cast(CSVState::STANDARD), static_cast(CSVState::INVALID)}; + vector std_inv {static_cast(CSVState::STANDARD), static_cast(CSVState::INVALID), + static_cast(CSVState::STANDARD_NEWLINE)}; for (auto &state : std_inv) { transition_array[delimiter][state] = CSVState::DELIMITER; - transition_array[static_cast('\n')][state] = CSVState::RECORD_SEPARATOR; if (new_line_id == NewLineIdentifier::CARRY_ON) { transition_array[static_cast('\r')][state] = CSVState::CARRIAGE_RETURN; + if (state == static_cast(CSVState::STANDARD_NEWLINE)) { + transition_array[static_cast('\n')][state] = CSVState::STANDARD; + } else { + transition_array[static_cast('\n')][state] = CSVState::RECORD_SEPARATOR; + } } else { transition_array[static_cast('\r')][state] = CSVState::RECORD_SEPARATOR; + transition_array[static_cast('\n')][state] = CSVState::RECORD_SEPARATOR; } if (comment != '\0') { transition_array[comment][state] = CSVState::COMMENT; @@ -138,9 +144,6 @@ void CSVStateMachineCache::Insert(const CSVStateMachineOptions &state_machine_op if (comment != '\0') { transition_array[comment][static_cast(CSVState::UNQUOTED)] = CSVState::COMMENT; } - // 7) Escaped State - transition_array[quote][static_cast(CSVState::ESCAPE)] = CSVState::QUOTED; - transition_array[escape][static_cast(CSVState::ESCAPE)] = CSVState::QUOTED; // 8) Not Set transition_array[delimiter][static_cast(CSVState::NOT_SET)] = CSVState::DELIMITER; diff --git a/src/duckdb/src/execution/operator/csv_scanner/table_function/global_csv_state.cpp b/src/duckdb/src/execution/operator/csv_scanner/table_function/global_csv_state.cpp index cefb13413..2685b93ff 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/table_function/global_csv_state.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/table_function/global_csv_state.cpp @@ -75,6 +75,12 @@ double CSVGlobalState::GetProgress(const ReadCSVData &bind_data_p) const { } unique_ptr CSVGlobalState::Next(optional_ptr previous_scanner) { + if (previous_scanner) { + // We have to insert information for validation + lock_guard parallel_lock(main_mutex); + validator.Insert(previous_scanner->csv_file_scan->file_idx, previous_scanner->scanner_idx, + previous_scanner->GetValidationLine()); + } if (single_threaded) { idx_t cur_idx; bool empty_file = false; @@ -183,7 +189,13 @@ void CSVGlobalState::DecrementThread() { D_ASSERT(running_threads > 0); running_threads--; if (running_threads == 0) { - for (auto &file : file_scans) { + bool ignore_or_store_errors = + bind_data.options.ignore_errors.GetValue() || bind_data.options.store_rejects.GetValue(); + if (!single_threaded && !ignore_or_store_errors) { + // If we are running multithreaded and not ignoring errors, we must run the validator + validator.Verify(); + } + for (const auto &file : file_scans) { file->error_handler->ErrorIfNeeded(); } FillRejectsTable(); diff --git a/src/duckdb/src/execution/operator/csv_scanner/util/csv_validator.cpp b/src/duckdb/src/execution/operator/csv_scanner/util/csv_validator.cpp new file mode 100644 index 000000000..1b8d3f348 --- /dev/null +++ b/src/duckdb/src/execution/operator/csv_scanner/util/csv_validator.cpp @@ -0,0 +1,63 @@ +#include "duckdb/execution/operator/csv_scanner/csv_validator.hpp" +#include + +namespace duckdb { + +void ThreadLines::Insert(idx_t thread_idx, ValidatorLine line_info) { + D_ASSERT(thread_lines.find(thread_idx) == thread_lines.end()); + thread_lines.insert({thread_idx, line_info}); +} + +string ThreadLines::Print() const { + string result; + for (auto &line : thread_lines) { + result += "{start_pos: " + std::to_string(line.second.start_pos) + + ", end_pos: " + std::to_string(line.second.end_pos) + "}"; + } + return result; +} + +void ThreadLines::Verify() const { + bool initialized = false; + idx_t last_end_pos = 0; + for (auto &line_info : thread_lines) { + if (!initialized) { + // First run, we just set the initialized to true + initialized = true; + } else { + if (line_info.second.start_pos == line_info.second.end_pos) { + last_end_pos = line_info.second.end_pos; + continue; + } + if (last_end_pos + error_margin < line_info.second.start_pos || + line_info.second.start_pos < last_end_pos - error_margin) { + std::ostringstream error; + error << "The Parallel CSV Reader currently does not support a full read on this file." << '\n'; + error << "To correctly parse this file, please run with the single threaded error (i.e., parallel = " + "false)" + << '\n'; + throw NotImplementedException(error.str()); + } + } + last_end_pos = line_info.second.end_pos; + } +} + +void CSVValidator::Insert(idx_t file_idx, idx_t thread_idx, ValidatorLine line_info) { + if (per_file_thread_lines.size() <= file_idx) { + per_file_thread_lines.resize(file_idx + 1); + } + per_file_thread_lines[file_idx].Insert(thread_idx, line_info); +} + +void CSVValidator::Verify() const { + for (auto &file : per_file_thread_lines) { + file.Verify(); + } +} + +string CSVValidator::Print(idx_t file_idx) const { + return per_file_thread_lines[file_idx].Print(); +} + +} // namespace duckdb diff --git a/src/duckdb/src/execution/operator/helper/physical_reservoir_sample.cpp b/src/duckdb/src/execution/operator/helper/physical_reservoir_sample.cpp index 869db44f6..32785a7ab 100644 --- a/src/duckdb/src/execution/operator/helper/physical_reservoir_sample.cpp +++ b/src/duckdb/src/execution/operator/helper/physical_reservoir_sample.cpp @@ -15,13 +15,14 @@ class SampleGlobalSinkState : public GlobalSinkState { if (percentage == 0) { return; } - sample = make_uniq(allocator, percentage, options.seed); + sample = make_uniq(allocator, percentage, + static_cast(options.seed.GetIndex())); } else { auto size = NumericCast(options.sample_size.GetValue()); if (size == 0) { return; } - sample = make_uniq(allocator, size, options.seed); + sample = make_uniq(allocator, size, static_cast(options.seed.GetIndex())); } } @@ -49,13 +50,15 @@ SinkResultType PhysicalReservoirSample::Sink(ExecutionContext &context, DataChun if (percentage == 0) { return SinkResultType::FINISHED; } - global_state.sample = make_uniq(allocator, percentage, options->seed); + global_state.sample = make_uniq(allocator, percentage, + static_cast(options->seed.GetIndex())); } else { idx_t num_samples = options->sample_size.GetValue(); if (num_samples == 0) { return SinkResultType::FINISHED; } - global_state.sample = make_uniq(allocator, num_samples, options->seed); + global_state.sample = + make_uniq(allocator, num_samples, static_cast(options->seed.GetIndex())); } } global_state.sample->AddToReservoir(chunk); diff --git a/src/duckdb/src/execution/operator/helper/physical_set.cpp b/src/duckdb/src/execution/operator/helper/physical_set.cpp index 4fe86880e..4a321a52e 100644 --- a/src/duckdb/src/execution/operator/helper/physical_set.cpp +++ b/src/duckdb/src/execution/operator/helper/physical_set.cpp @@ -48,7 +48,7 @@ SourceResultType PhysicalSet::GetData(ExecutionContext &context, DataChunk &chun } } - Value input_val = value.CastAs(context.client, option->parameter_type); + Value input_val = value.CastAs(context.client, DBConfig::ParseLogicalType(option->parameter_type)); switch (variable_scope) { case SetScope::GLOBAL: { if (!option->set_global) { diff --git a/src/duckdb/src/execution/operator/helper/physical_vacuum.cpp b/src/duckdb/src/execution/operator/helper/physical_vacuum.cpp index 186c15411..345745df8 100644 --- a/src/duckdb/src/execution/operator/helper/physical_vacuum.cpp +++ b/src/duckdb/src/execution/operator/helper/physical_vacuum.cpp @@ -15,7 +15,7 @@ PhysicalVacuum::PhysicalVacuum(unique_ptr info_p, optional_ptr table) { + explicit VacuumLocalSinkState(VacuumInfo &info, optional_ptr table) : hashes(LogicalType::HASH) { for (const auto &column_name : info.columns) { auto &column = table->GetColumn(column_name); if (DistinctStatistics::TypeIsSupported(column.GetType())) { @@ -27,6 +27,7 @@ class VacuumLocalSinkState : public LocalSinkState { }; vector> column_distinct_stats; + Vector hashes; }; unique_ptr PhysicalVacuum::GetLocalSinkState(ExecutionContext &context) const { @@ -62,7 +63,7 @@ SinkResultType PhysicalVacuum::Sink(ExecutionContext &context, DataChunk &chunk, if (!DistinctStatistics::TypeIsSupported(chunk.data[col_idx].GetType())) { continue; } - lstate.column_distinct_stats[col_idx]->Update(chunk.data[col_idx], chunk.size(), false); + lstate.column_distinct_stats[col_idx]->Update(chunk.data[col_idx], chunk.size(), lstate.hashes); } return SinkResultType::NEED_MORE_INPUT; diff --git a/src/duckdb/src/execution/operator/join/perfect_hash_join_executor.cpp b/src/duckdb/src/execution/operator/join/perfect_hash_join_executor.cpp index f5ced297d..a7c037d53 100644 --- a/src/duckdb/src/execution/operator/join/perfect_hash_join_executor.cpp +++ b/src/duckdb/src/execution/operator/join/perfect_hash_join_executor.cpp @@ -20,7 +20,7 @@ bool PerfectHashJoinExecutor::CanDoPerfectHashJoin() { bool PerfectHashJoinExecutor::BuildPerfectHashTable(LogicalType &key_type) { // First, allocate memory for each build column auto build_size = perfect_join_statistics.build_range + 1; - for (const auto &type : join.rhs_output_types) { + for (const auto &type : join.rhs_output_columns.col_types) { perfect_hash_table.emplace_back(type, build_size); } @@ -69,7 +69,7 @@ bool PerfectHashJoinExecutor::FullScanHashTable(LogicalType &key_type) { // Full scan the remaining build columns and fill the perfect hash table const auto build_size = perfect_join_statistics.build_range + 1; - for (idx_t i = 0; i < join.rhs_output_types.size(); i++) { + for (idx_t i = 0; i < join.rhs_output_columns.col_types.size(); i++) { auto &vector = perfect_hash_table[i]; const auto output_col_idx = ht.output_columns[i]; D_ASSERT(vector.GetType() == ht.layout.GetTypes()[output_col_idx]); @@ -166,7 +166,8 @@ unique_ptr PerfectHashJoinExecutor::GetOperatorState(ExecutionCon } OperatorResultType PerfectHashJoinExecutor::ProbePerfectHashTable(ExecutionContext &context, DataChunk &input, - DataChunk &result, OperatorState &state_p) { + DataChunk &lhs_output_columns, DataChunk &result, + OperatorState &state_p) { auto &state = state_p.Cast(); // keeps track of how many probe keys have a match idx_t probe_sel_count = 0; @@ -182,14 +183,14 @@ OperatorResultType PerfectHashJoinExecutor::ProbePerfectHashTable(ExecutionConte // If build is dense and probe is in build's domain, just reference probe if (perfect_join_statistics.is_build_dense && keys_count == probe_sel_count) { - result.Reference(input); + result.Reference(lhs_output_columns); } else { // otherwise, filter it out the values that do not match - result.Slice(input, state.probe_sel_vec, probe_sel_count, 0); + result.Slice(lhs_output_columns, state.probe_sel_vec, probe_sel_count, 0); } // on the build side, we need to fetch the data and build dictionary vectors with the sel_vec - for (idx_t i = 0; i < join.rhs_output_types.size(); i++) { - auto &result_vector = result.data[input.ColumnCount() + i]; + for (idx_t i = 0; i < join.rhs_output_columns.col_types.size(); i++) { + auto &result_vector = result.data[lhs_output_columns.ColumnCount() + i]; D_ASSERT(result_vector.GetType() == ht.layout.GetTypes()[ht.output_columns[i]]); auto &build_vec = perfect_hash_table[i]; result_vector.Reference(build_vec); diff --git a/src/duckdb/src/execution/operator/join/physical_blockwise_nl_join.cpp b/src/duckdb/src/execution/operator/join/physical_blockwise_nl_join.cpp index 1b6eb619d..deabb6f89 100644 --- a/src/duckdb/src/execution/operator/join/physical_blockwise_nl_join.cpp +++ b/src/duckdb/src/execution/operator/join/physical_blockwise_nl_join.cpp @@ -79,16 +79,28 @@ class BlockwiseNLJoinState : public CachingOperatorState { public: explicit BlockwiseNLJoinState(ExecutionContext &context, ColumnDataCollection &rhs, const PhysicalBlockwiseNLJoin &op) - : cross_product(rhs), left_outer(IsLeftOuterJoin(op.join_type)), match_sel(STANDARD_VECTOR_SIZE), + : op(op), cross_product(rhs), left_outer(IsLeftOuterJoin(op.join_type)), match_sel(STANDARD_VECTOR_SIZE), executor(context.client, *op.condition) { left_outer.Initialize(STANDARD_VECTOR_SIZE); + ResetMatches(); } + const PhysicalBlockwiseNLJoin &op; CrossProductExecutor cross_product; OuterJoinMarker left_outer; SelectionVector match_sel; ExpressionExecutor executor; DataChunk intermediate_chunk; + bool found_match[STANDARD_VECTOR_SIZE]; + + void ResetMatches() { + if (op.join_type != JoinType::SEMI && op.join_type != JoinType::ANTI) { + return; + } + for (idx_t i = 0; i < STANDARD_VECTOR_SIZE; i++) { + found_match[i] = false; + } + } }; unique_ptr PhysicalBlockwiseNLJoin::GetOperatorState(ExecutionContext &context) const { @@ -136,69 +148,66 @@ OperatorResultType PhysicalBlockwiseNLJoin::ExecuteInternal(ExecutionContext &co // now perform the actual join // we perform a cross product, then execute the expression directly on the cross product result idx_t result_count = 0; - bool found_match[STANDARD_VECTOR_SIZE] = {false}; - - do { - auto result = state.cross_product.Execute(input, *intermediate_chunk); - if (result == OperatorResultType::NEED_MORE_INPUT) { - // exhausted input, have to pull new LHS chunk - if (state.left_outer.Enabled()) { - // left join: before we move to the next chunk, see if we need to output any vectors that didn't - // have a match found - state.left_outer.ConstructLeftJoinResult(input, *intermediate_chunk); - state.left_outer.Reset(); - } - if (join_type == JoinType::SEMI) { - PhysicalJoin::ConstructSemiJoinResult(input, chunk, found_match); - } - if (join_type == JoinType::ANTI) { - PhysicalJoin::ConstructAntiJoinResult(input, chunk, found_match); - } + auto result = state.cross_product.Execute(input, *intermediate_chunk); + if (result == OperatorResultType::NEED_MORE_INPUT) { + // exhausted input, have to pull new LHS chunk + if (state.left_outer.Enabled()) { + // left join: before we move to the next chunk, see if we need to output any vectors that didn't + // have a match found + state.left_outer.ConstructLeftJoinResult(input, *intermediate_chunk); + state.left_outer.Reset(); + } - return OperatorResultType::NEED_MORE_INPUT; + if (join_type == JoinType::SEMI) { + PhysicalJoin::ConstructSemiJoinResult(input, chunk, state.found_match); + } + if (join_type == JoinType::ANTI) { + PhysicalJoin::ConstructAntiJoinResult(input, chunk, state.found_match); } + state.ResetMatches(); - // now perform the computation - result_count = state.executor.SelectExpression(*intermediate_chunk, state.match_sel); - - // handle anti and semi joins with different logic - if (result_count > 0) { - // found a match! - // handle anti semi join conditions first - if (join_type == JoinType::ANTI || join_type == JoinType::SEMI) { - if (state.cross_product.ScanLHS()) { - found_match[state.cross_product.PositionInChunk()] = true; - } else { - for (idx_t i = 0; i < result_count; i++) { - found_match[state.match_sel.get_index(i)] = true; - } - } - intermediate_chunk->Reset(); - // trick the loop to continue as semi and anti joins will never produce more output than - // the LHS cardinality - result_count = 0; + return OperatorResultType::NEED_MORE_INPUT; + } + + // now perform the computation + result_count = state.executor.SelectExpression(*intermediate_chunk, state.match_sel); + + // handle anti and semi joins with different logic + if (result_count > 0) { + // found a match! + // handle anti semi join conditions first + if (join_type == JoinType::ANTI || join_type == JoinType::SEMI) { + if (state.cross_product.ScanLHS()) { + state.found_match[state.cross_product.PositionInChunk()] = true; } else { - // check if the cross product is scanning the LHS or the RHS in its entirety - if (!state.cross_product.ScanLHS()) { - // set the match flags in the LHS - state.left_outer.SetMatches(state.match_sel, result_count); - // set the match flag in the RHS - gstate.right_outer.SetMatch(state.cross_product.ScanPosition() + - state.cross_product.PositionInChunk()); - } else { - // set the match flag in the LHS - state.left_outer.SetMatch(state.cross_product.PositionInChunk()); - // set the match flags in the RHS - gstate.right_outer.SetMatches(state.match_sel, result_count, state.cross_product.ScanPosition()); + for (idx_t i = 0; i < result_count; i++) { + state.found_match[state.match_sel.get_index(i)] = true; } - intermediate_chunk->Slice(state.match_sel, result_count); } - } else { - // no result: reset the chunk intermediate_chunk->Reset(); + // trick the loop to continue as semi and anti joins will never produce more output than + // the LHS cardinality + result_count = 0; + } else { + // check if the cross product is scanning the LHS or the RHS in its entirety + if (!state.cross_product.ScanLHS()) { + // set the match flags in the LHS + state.left_outer.SetMatches(state.match_sel, result_count); + // set the match flag in the RHS + gstate.right_outer.SetMatch(state.cross_product.ScanPosition() + state.cross_product.PositionInChunk()); + } else { + // set the match flag in the LHS + state.left_outer.SetMatch(state.cross_product.PositionInChunk()); + // set the match flags in the RHS + gstate.right_outer.SetMatches(state.match_sel, result_count, state.cross_product.ScanPosition()); + } + intermediate_chunk->Slice(state.match_sel, result_count); } - } while (result_count == 0); + } else { + // no result: reset the chunk + intermediate_chunk->Reset(); + } return OperatorResultType::HAVE_MORE_OUTPUT; } 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 3deb27b6d..2bcfc84d5 100644 --- a/src/duckdb/src/execution/operator/join/physical_hash_join.cpp +++ b/src/duckdb/src/execution/operator/join/physical_hash_join.cpp @@ -4,6 +4,7 @@ #include "duckdb/execution/expression_executor.hpp" #include "duckdb/execution/operator/aggregate/ungrouped_aggregate_state.hpp" #include "duckdb/function/aggregate/distributive_functions.hpp" +#include "duckdb/function/aggregate/distributive_function_utils.hpp" #include "duckdb/function/function_binder.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/main/query_profiler.hpp" @@ -31,7 +32,6 @@ PhysicalHashJoin::PhysicalHashJoin(LogicalOperator &op, unique_ptr pushdown_info_p) : PhysicalComparisonJoin(op, PhysicalOperatorType::HASH_JOIN, std::move(cond), join_type, estimated_cardinality), delim_types(std::move(delim_types)), perfect_join_statistics(std::move(perfect_join_stats)) { - D_ASSERT(left_projection_map.empty()); filter_pushdown = std::move(pushdown_info_p); @@ -48,6 +48,22 @@ PhysicalHashJoin::PhysicalHashJoin(LogicalOperator &op, unique_ptrGetTypes(); + + // Create a projection map for the LHS (if it was empty), for convenience + lhs_output_columns.col_idxs = left_projection_map; + if (lhs_output_columns.col_idxs.empty()) { + lhs_output_columns.col_idxs.reserve(lhs_input_types.size()); + for (idx_t i = 0; i < lhs_input_types.size(); i++) { + lhs_output_columns.col_idxs.emplace_back(i); + } + } + + for (auto &lhs_col : lhs_output_columns.col_idxs) { + auto &lhs_col_type = lhs_input_types[lhs_col]; + lhs_output_columns.col_types.push_back(lhs_col_type); + } + // For ANTI, SEMI and MARK join, we only need to store the keys, so for these the payload/RHS types are empty if (join_type == JoinType::ANTI || join_type == JoinType::SEMI || join_type == JoinType::MARK) { return; @@ -71,14 +87,14 @@ PhysicalHashJoin::PhysicalHashJoin(LogicalOperator &op, unique_ptrsecond); + rhs_output_columns.col_idxs.push_back(it->second); } - rhs_output_types.push_back(rhs_col_type); + rhs_output_columns.col_types.push_back(rhs_col_type); } } @@ -102,7 +118,9 @@ unique_ptr JoinFilterPushdownInfo::GetGlobalState(ClientC const PhysicalOperator &op) const { // clear any previously set filters // we can have previous filters for this operator in case of e.g. recursive CTEs - dynamic_filters->ClearFilters(op); + for (auto &info : probe_info) { + info.dynamic_filters->ClearFilters(op); + } auto result = make_uniq(); result->global_aggregate_state = make_uniq(BufferAllocator::Get(context), min_max_aggregates); @@ -121,11 +139,9 @@ class HashJoinGlobalSinkState : public GlobalSinkState { // For perfect hash join perfect_join_executor = make_uniq(op, *hash_table, op.perfect_join_statistics); // For external hash join - external = ClientConfig::GetConfig(context).force_external; + external = ClientConfig::GetConfig(context).GetSetting(context); // Set probe types - const auto &payload_types = op.children[0]->types; - probe_types.insert(probe_types.end(), op.condition_types.begin(), op.condition_types.end()); - probe_types.insert(probe_types.end(), payload_types.begin(), payload_types.end()); + probe_types = op.children[0]->types; probe_types.emplace_back(LogicalType::HASH); if (op.filter_pushdown) { @@ -189,8 +205,8 @@ class HashJoinLocalSinkState : public LocalSinkState { } join_keys.Initialize(allocator, op.condition_types); - if (!op.payload_types.empty()) { - payload_chunk.Initialize(allocator, op.payload_types); + if (!op.payload_columns.col_types.empty()) { + payload_chunk.Initialize(allocator, op.payload_columns.col_types); } hash_table = op.InitializeHashTable(context); @@ -218,7 +234,8 @@ class HashJoinLocalSinkState : public LocalSinkState { }; unique_ptr PhysicalHashJoin::InitializeHashTable(ClientContext &context) const { - auto result = make_uniq(context, conditions, payload_types, join_type, rhs_output_columns); + auto result = make_uniq(context, conditions, payload_columns.col_types, join_type, + rhs_output_columns.col_idxs); if (!delim_types.empty() && join_type == JoinType::MARK) { // correlated MARK join if (delim_types.size() + 1 == conditions.size()) { @@ -246,7 +263,7 @@ unique_ptr PhysicalHashJoin::InitializeHashTable(ClientContext &c delim_payload_types.push_back(aggr->return_type); info.correlated_aggregates.push_back(std::move(aggr)); - auto count_fun = CountFun::GetFunction(); + auto count_fun = CountFunctionBase::GetFunction(); vector> children; // this is a dummy but we need it to make the hash table understand whats going on children.push_back(make_uniq_base(count_fun.return_type, 0U)); @@ -278,11 +295,11 @@ unique_ptr PhysicalHashJoin::GetLocalSinkState(ExecutionContext void JoinFilterPushdownInfo::Sink(DataChunk &chunk, JoinFilterLocalState &lstate) const { // if we are pushing any filters into a probe-side, compute the min/max over the columns that we are pushing - for (idx_t pushdown_idx = 0; pushdown_idx < filters.size(); pushdown_idx++) { - auto &pushdown = filters[pushdown_idx]; + for (idx_t pushdown_idx = 0; pushdown_idx < join_condition.size(); pushdown_idx++) { + auto join_condition_idx = join_condition[pushdown_idx]; for (idx_t i = 0; i < 2; i++) { idx_t aggr_idx = pushdown_idx * 2 + i; - lstate.local_aggregate_state->Sink(chunk, pushdown.join_condition, aggr_idx); + lstate.local_aggregate_state->Sink(chunk, join_condition_idx, aggr_idx); } } } @@ -300,17 +317,13 @@ SinkResultType PhysicalHashJoin::Sink(ExecutionContext &context, DataChunk &chun // build the HT auto &ht = *lstate.hash_table; - if (payload_types.empty()) { + if (payload_columns.col_types.empty()) { // there are only keys: place an empty chunk in the payload lstate.payload_chunk.SetCardinality(chunk.size()); ht.Build(lstate.append_state, lstate.join_keys, lstate.payload_chunk); } else { // there are payload columns - lstate.payload_chunk.Reset(); - lstate.payload_chunk.SetCardinality(chunk); - for (idx_t i = 0; i < payload_column_idxs.size(); i++) { - lstate.payload_chunk.data[i].Reference(chunk.data[payload_column_idxs[i]]); - } + lstate.payload_chunk.ReferenceColumns(chunk, payload_columns.col_idxs); ht.Build(lstate.append_state, lstate.join_keys, lstate.payload_chunk); } @@ -426,18 +439,11 @@ class HashJoinFinalizeEvent : public BasePipelineEvent { make_uniq(shared_from_this(), context, sink, 0U, chunk_count, false, sink.op)); } else { // Parallel finalize - auto chunks_per_thread = MaxValue((chunk_count + num_threads - 1) / num_threads, 1); - - idx_t chunk_idx = 0; - for (idx_t thread_idx = 0; thread_idx < num_threads; thread_idx++) { - auto chunk_idx_from = chunk_idx; - auto chunk_idx_to = MinValue(chunk_idx_from + chunks_per_thread, chunk_count); - finalize_tasks.push_back(make_uniq(shared_from_this(), context, sink, - chunk_idx_from, chunk_idx_to, true, sink.op)); - chunk_idx = chunk_idx_to; - if (chunk_idx == chunk_count) { - break; - } + const idx_t chunks_per_task = context.config.verify_parallelism ? 1 : CHUNKS_PER_TASK; + for (idx_t chunk_idx = 0; chunk_idx < chunk_count; chunk_idx += chunks_per_task) { + auto chunk_idx_to = MinValue(chunk_idx + chunks_per_task, chunk_count); + finalize_tasks.push_back(make_uniq(shared_from_this(), context, sink, chunk_idx, + chunk_idx_to, true, sink.op)); } } SetTasks(std::move(finalize_tasks)); @@ -448,7 +454,8 @@ class HashJoinFinalizeEvent : public BasePipelineEvent { sink.hash_table->finalized = true; } - static constexpr const idx_t PARALLEL_CONSTRUCT_THRESHOLD = 1048576; + static constexpr idx_t PARALLEL_CONSTRUCT_THRESHOLD = 1048576; + static constexpr idx_t CHUNKS_PER_TASK = 64; }; void HashJoinGlobalSinkState::ScheduleFinalize(Pipeline &pipeline, Event &event) { @@ -572,34 +579,36 @@ void JoinFilterPushdownInfo::PushFilters(JoinFilterGlobalState &gstate, const Ph gstate.global_aggregate_state->Finalize(final_min_max); // create a filter for each of the aggregates - for (idx_t filter_idx = 0; filter_idx < filters.size(); filter_idx++) { - auto &filter = filters[filter_idx]; - auto filter_col_idx = filter.probe_column_index.column_index; - auto min_idx = filter_idx * 2; - auto max_idx = min_idx + 1; - - auto min_val = final_min_max.data[min_idx].GetValue(0); - auto max_val = final_min_max.data[max_idx].GetValue(0); - if (min_val.IsNull() || max_val.IsNull()) { - // min/max is NULL - // this can happen in case all values in the RHS column are NULL, but they are still pushed into the hash - // table e.g. because they are part of a RIGHT join - continue; - } - if (Value::NotDistinctFrom(min_val, max_val)) { - // min = max - generate an equality filter - auto constant_filter = make_uniq(ExpressionType::COMPARE_EQUAL, std::move(min_val)); - dynamic_filters->PushFilter(op, filter_col_idx, std::move(constant_filter)); - } else { - // min != max - generate a range filter - auto greater_equals = - make_uniq(ExpressionType::COMPARE_GREATERTHANOREQUALTO, std::move(min_val)); - dynamic_filters->PushFilter(op, filter_col_idx, std::move(greater_equals)); - auto less_equals = make_uniq(ExpressionType::COMPARE_LESSTHANOREQUALTO, std::move(max_val)); - dynamic_filters->PushFilter(op, filter_col_idx, std::move(less_equals)); + for (idx_t filter_idx = 0; filter_idx < join_condition.size(); filter_idx++) { + for (auto &info : probe_info) { + auto filter_col_idx = info.columns[filter_idx].probe_column_index.column_index; + auto min_idx = filter_idx * 2; + auto max_idx = min_idx + 1; + + auto min_val = final_min_max.data[min_idx].GetValue(0); + auto max_val = final_min_max.data[max_idx].GetValue(0); + if (min_val.IsNull() || max_val.IsNull()) { + // min/max is NULL + // this can happen in case all values in the RHS column are NULL, but they are still pushed into the + // hash table e.g. because they are part of a RIGHT join + continue; + } + if (Value::NotDistinctFrom(min_val, max_val)) { + // min = max - generate an equality filter + auto constant_filter = make_uniq(ExpressionType::COMPARE_EQUAL, std::move(min_val)); + info.dynamic_filters->PushFilter(op, filter_col_idx, std::move(constant_filter)); + } else { + // min != max - generate a range filter + auto greater_equals = + make_uniq(ExpressionType::COMPARE_GREATERTHANOREQUALTO, std::move(min_val)); + info.dynamic_filters->PushFilter(op, filter_col_idx, std::move(greater_equals)); + auto less_equals = + make_uniq(ExpressionType::COMPARE_LESSTHANOREQUALTO, std::move(max_val)); + info.dynamic_filters->PushFilter(op, filter_col_idx, std::move(less_equals)); + } + // not null filter + info.dynamic_filters->PushFilter(op, filter_col_idx, make_uniq()); } - // not null filter - dynamic_filters->PushFilter(op, filter_col_idx, make_uniq()); } } @@ -677,8 +686,9 @@ class HashJoinOperatorState : public CachingOperatorState { : probe_executor(context), scan_structure(*sink.hash_table, join_key_state) { } - DataChunk join_keys; + DataChunk lhs_join_keys; TupleDataChunkState join_key_state; + DataChunk lhs_output; ExpressionExecutor probe_executor; JoinHashTable::ScanStructure scan_structure; @@ -699,10 +709,13 @@ unique_ptr PhysicalHashJoin::GetOperatorState(ExecutionContext &c auto &allocator = BufferAllocator::Get(context.client); auto &sink = sink_state->Cast(); auto state = make_uniq(context.client, sink); + state->lhs_join_keys.Initialize(allocator, condition_types); + if (!lhs_output_columns.col_types.empty()) { + state->lhs_output.Initialize(allocator, lhs_output_columns.col_types); + } if (sink.perfect_join_executor) { state->perfect_hash_join_state = sink.perfect_join_executor->GetOperatorState(context); } else { - state->join_keys.Initialize(allocator, condition_types); for (auto &cond : conditions) { state->probe_executor.AddExpression(*cond.left); } @@ -723,17 +736,23 @@ OperatorResultType PhysicalHashJoin::ExecuteInternal(ExecutionContext &context, D_ASSERT(sink.finalized); D_ASSERT(!sink.scanned_data); + if (state.scan_structure.is_null || sink.perfect_join_executor) { + // place the lhs projected columns in the chunk + state.lhs_output.ReferenceColumns(input, lhs_output_columns.col_idxs); + } + if (sink.hash_table->Count() == 0) { if (EmptyResultIfRHSIsEmpty()) { return OperatorResultType::FINISHED; } - ConstructEmptyJoinResult(sink.hash_table->join_type, sink.hash_table->has_null, input, chunk); + ConstructEmptyJoinResult(sink.hash_table->join_type, sink.hash_table->has_null, state.lhs_output, chunk); return OperatorResultType::NEED_MORE_INPUT; } if (sink.perfect_join_executor) { D_ASSERT(!sink.external); - return sink.perfect_join_executor->ProbePerfectHashTable(context, input, chunk, *state.perfect_hash_join_state); + return sink.perfect_join_executor->ProbePerfectHashTable(context, input, state.lhs_output, chunk, + *state.perfect_hash_join_state); } if (sink.external && !state.initialized) { @@ -747,19 +766,19 @@ OperatorResultType PhysicalHashJoin::ExecuteInternal(ExecutionContext &context, if (state.scan_structure.is_null) { // probe the HT, start by resolving the join keys for the left chunk - state.join_keys.Reset(); - state.probe_executor.Execute(input, state.join_keys); + state.lhs_join_keys.Reset(); + state.probe_executor.Execute(input, state.lhs_join_keys); // perform the actual probe if (sink.external) { - sink.hash_table->ProbeAndSpill(state.scan_structure, state.join_keys, state.join_key_state, + sink.hash_table->ProbeAndSpill(state.scan_structure, state.lhs_join_keys, state.join_key_state, state.probe_state, input, *sink.probe_spill, state.spill_state, state.spill_chunk); } else { - sink.hash_table->Probe(state.scan_structure, state.join_keys, state.join_key_state, state.probe_state); + sink.hash_table->Probe(state.scan_structure, state.lhs_join_keys, state.join_key_state, state.probe_state); } } - state.scan_structure.Next(state.join_keys, input, chunk); + state.scan_structure.Next(state.lhs_join_keys, state.lhs_output, chunk); if (state.scan_structure.PointersExhausted() && chunk.size() == 0) { state.scan_structure.is_null = true; @@ -860,14 +879,12 @@ class HashJoinLocalSourceState : public LocalSourceState { //! Local scan state for probe spill ColumnDataConsumerScanState probe_local_scan; //! Chunks for holding the scanned probe collection - DataChunk probe_chunk; - DataChunk join_keys; - DataChunk payload; + DataChunk lhs_probe_chunk; + DataChunk lhs_join_keys; + DataChunk lhs_output; TupleDataChunkState join_key_state; + ExpressionExecutor lhs_join_key_executor; - //! Column indices to easily reference the join keys/payload columns in probe_chunk - vector join_key_indices; - vector payload_indices; //! Scan structure for the external probe JoinHashTable::ScanStructure scan_structure; JoinHashTable::ProbeState probe_state; @@ -1044,23 +1061,18 @@ bool HashJoinGlobalSourceState::AssignTask(HashJoinGlobalSinkState &sink, HashJo HashJoinLocalSourceState::HashJoinLocalSourceState(const PhysicalHashJoin &op, const HashJoinGlobalSinkState &sink, Allocator &allocator) - : local_stage(HashJoinSourceStage::INIT), addresses(LogicalType::POINTER), + : local_stage(HashJoinSourceStage::INIT), addresses(LogicalType::POINTER), lhs_join_key_executor(sink.context), scan_structure(*sink.hash_table, join_key_state) { auto &chunk_state = probe_local_scan.current_chunk_state; chunk_state.properties = ColumnDataScanProperties::ALLOW_ZERO_COPY; - probe_chunk.Initialize(allocator, sink.probe_types); - join_keys.Initialize(allocator, op.condition_types); - payload.Initialize(allocator, op.children[0]->types); + lhs_probe_chunk.Initialize(allocator, sink.probe_types); + lhs_join_keys.Initialize(allocator, op.condition_types); + lhs_output.Initialize(allocator, op.lhs_output_columns.col_types); TupleDataCollection::InitializeChunkState(join_key_state, op.condition_types); - // Store the indices of the columns to reference them easily - idx_t col_idx = 0; - for (; col_idx < op.condition_types.size(); col_idx++) { - join_key_indices.push_back(col_idx); - } - for (; col_idx < sink.probe_types.size() - 1; col_idx++) { - payload_indices.push_back(col_idx); + for (auto &cond : op.conditions) { + lhs_join_key_executor.AddExpression(*cond.left); } } @@ -1111,7 +1123,7 @@ void HashJoinLocalSourceState::ExternalProbe(HashJoinGlobalSinkState &sink, Hash if (!scan_structure.is_null) { // Still have elements remaining (i.e. we got >STANDARD_VECTOR_SIZE elements in the previous probe) - scan_structure.Next(join_keys, payload, chunk); + scan_structure.Next(lhs_join_keys, lhs_output, chunk); if (chunk.size() != 0 || !scan_structure.PointersExhausted()) { return; } @@ -1128,22 +1140,23 @@ void HashJoinLocalSourceState::ExternalProbe(HashJoinGlobalSinkState &sink, Hash } // Scan input chunk for next probe - sink.probe_spill->consumer->ScanChunk(probe_local_scan, probe_chunk); + sink.probe_spill->consumer->ScanChunk(probe_local_scan, lhs_probe_chunk); // Get the probe chunk columns/hashes - join_keys.ReferenceColumns(probe_chunk, join_key_indices); - payload.ReferenceColumns(probe_chunk, payload_indices); - auto precomputed_hashes = &probe_chunk.data.back(); + lhs_join_keys.Reset(); + lhs_join_key_executor.Execute(lhs_probe_chunk, lhs_join_keys); + lhs_output.ReferenceColumns(lhs_probe_chunk, sink.op.lhs_output_columns.col_idxs); + auto precomputed_hashes = &lhs_probe_chunk.data.back(); if (sink.hash_table->Count() == 0 && !gstate.op.EmptyResultIfRHSIsEmpty()) { - gstate.op.ConstructEmptyJoinResult(sink.hash_table->join_type, sink.hash_table->has_null, payload, chunk); + gstate.op.ConstructEmptyJoinResult(sink.hash_table->join_type, sink.hash_table->has_null, lhs_output, chunk); empty_ht_probe_in_progress = true; return; } // Perform the probe - sink.hash_table->Probe(scan_structure, join_keys, join_key_state, probe_state, precomputed_hashes); - scan_structure.Next(join_keys, payload, chunk); + sink.hash_table->Probe(scan_structure, lhs_join_keys, join_key_state, probe_state, precomputed_hashes); + scan_structure.Next(lhs_join_keys, lhs_output, chunk); } void HashJoinLocalSourceState::ExternalScanHT(HashJoinGlobalSinkState &sink, HashJoinGlobalSourceState &gstate, diff --git a/src/duckdb/src/execution/operator/join/physical_iejoin.cpp b/src/duckdb/src/execution/operator/join/physical_iejoin.cpp index 143b1f207..a044383b3 100644 --- a/src/duckdb/src/execution/operator/join/physical_iejoin.cpp +++ b/src/duckdb/src/execution/operator/join/physical_iejoin.cpp @@ -1,18 +1,19 @@ #include "duckdb/execution/operator/join/physical_iejoin.hpp" +#include "duckdb/common/atomic.hpp" #include "duckdb/common/operator/comparison_operators.hpp" #include "duckdb/common/row_operations/row_operations.hpp" #include "duckdb/common/sort/sort.hpp" #include "duckdb/common/sort/sorted_block.hpp" +#include "duckdb/common/thread.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/parallel/event.hpp" #include "duckdb/parallel/meta_pipeline.hpp" #include "duckdb/parallel/thread_context.hpp" +#include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_reference_expression.hpp" -#include "duckdb/common/atomic.hpp" -#include "duckdb/common/thread.hpp" namespace duckdb { @@ -388,18 +389,42 @@ IEJoinUnion::IEJoinUnion(ClientContext &context, const PhysicalIEJoin &op, Sorte auto ref = make_uniq(order1.expression->return_type, 0U); vector orders; orders.emplace_back(order1.type, order1.null_order, std::move(ref)); + // The goal is to make i (from the left table) < j (from the right table), + // if value[i] and value[j] match the condition 1. + // Add a column from_left to solve the problem when there exist multiple equal values in l1. + // If the operator is loose inequality, make t1.from_left (== true) sort BEFORE t2.from_left (== false). + // Otherwise, make t1.from_left sort (== true) sort AFTER t2.from_left (== false). + // For example, if t1.time <= t2.time + // | value | 1 | 1 | 1 | 1 | + // | --------- | ----- | ----- | ----- | ----- | + // | from_left | T(l2) | T(l2) | F(r1) | F(r2) | + // if t1.time < t2.time + // | value | 1 | 1 | 1 | 1 | + // | --------- | ----- | ----- | ----- | ----- | + // | from_left | F(r2) | F(r1) | T(l2) | T(l1) | + // Using this OrderType, if i < j then value[i] (from left table) and value[j] (from right table) match + // the condition (t1.time <= t2.time or t1.time < t2.time), then from_left will force them into the correct order. + auto from_left = make_uniq(Value::BOOLEAN(true)); + orders.emplace_back(SBIterator::ComparisonValue(cmp1) == 0 ? OrderType::DESCENDING : OrderType::ASCENDING, + OrderByNullType::ORDER_DEFAULT, std::move(from_left)); l1 = make_uniq(context, orders, payload_layout, op); // LHS has positive rids ExpressionExecutor l_executor(context); l_executor.AddExpression(*order1.expression); + // add const column true + auto left_const = make_uniq(Value::BOOLEAN(true)); + l_executor.AddExpression(*left_const); l_executor.AddExpression(*order2.expression); AppendKey(t1, l_executor, *l1, 1, 1, b1); // RHS has negative rids ExpressionExecutor r_executor(context); r_executor.AddExpression(*op.rhs_orders[0].expression); + // add const column flase + auto right_const = make_uniq(Value::BOOLEAN(false)); + r_executor.AddExpression(*right_const); r_executor.AddExpression(*op.rhs_orders[1].expression); AppendKey(t2, r_executor, *l1, -1, -1, b2); @@ -463,53 +488,6 @@ IEJoinUnion::IEJoinUnion(ClientContext &context, const PhysicalIEJoin &op, Sorte (void)NextRow(); } -idx_t IEJoinUnion::SearchL1(idx_t pos) { - // Perform an exponential search in the appropriate direction - op1->SetIndex(pos); - - idx_t step = 1; - auto hi = pos; - auto lo = pos; - if (!op1->cmp) { - // Scan left for loose inequality - lo -= MinValue(step, lo); - step *= 2; - off1->SetIndex(lo); - while (lo > 0 && op1->Compare(*off1)) { - hi = lo; - lo -= MinValue(step, lo); - step *= 2; - off1->SetIndex(lo); - } - } else { - // Scan right for strict inequality - hi += MinValue(step, n - hi); - step *= 2; - off1->SetIndex(hi); - while (hi < n && !op1->Compare(*off1)) { - lo = hi; - hi += MinValue(step, n - hi); - step *= 2; - off1->SetIndex(hi); - } - } - - // Binary search the target area - while (lo < hi) { - const auto mid = lo + (hi - lo) / 2; - off1->SetIndex(mid); - if (op1->Compare(*off1)) { - hi = mid; - } else { - lo = mid + 1; - } - } - - off1->SetIndex(lo); - - return lo; -} - bool IEJoinUnion::NextRow() { for (; i < n; ++i) { // 12. pos ← P[i] @@ -539,7 +517,7 @@ bool IEJoinUnion::NextRow() { // Find the leftmost off1 where L1[pos] op1 L1[off1..n] // These are the rows that satisfy the op1 condition // and that is where we should start scanning B from - j = SearchL1(pos); + j = pos; return true; } 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 6c7deb1e8..f7701f845 100644 --- a/src/duckdb/src/execution/operator/join/physical_range_join.cpp +++ b/src/duckdb/src/execution/operator/join/physical_range_join.cpp @@ -62,7 +62,6 @@ PhysicalRangeJoin::GlobalSortedTable::GlobalSortedTable(ClientContext &context, RowLayout &payload_layout, const PhysicalOperator &op_p) : op(op_p), global_sort_state(BufferManager::GetBufferManager(context), orders, payload_layout), has_null(0), count(0), memory_per_thread(0) { - D_ASSERT(orders.size() == 1); // Set external (can be forced with the PRAGMA) auto &config = ClientConfig::GetConfig(context); diff --git a/src/duckdb/src/execution/operator/order/physical_order.cpp b/src/duckdb/src/execution/operator/order/physical_order.cpp index e0bb0c940..71294e9b7 100644 --- a/src/duckdb/src/execution/operator/order/physical_order.cpp +++ b/src/duckdb/src/execution/operator/order/physical_order.cpp @@ -264,10 +264,14 @@ SourceResultType PhysicalOrder::GetData(ExecutionContext &context, DataChunk &ch return chunk.size() == 0 ? SourceResultType::FINISHED : SourceResultType::HAVE_MORE_OUTPUT; } -idx_t PhysicalOrder::GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate_p, - LocalSourceState &lstate_p) const { +OperatorPartitionData PhysicalOrder::GetPartitionData(ExecutionContext &context, DataChunk &chunk, + GlobalSourceState &gstate_p, LocalSourceState &lstate_p, + const OperatorPartitionInfo &partition_info) const { + if (partition_info.RequiresPartitionColumns()) { + throw InternalException("PhysicalOrder::GetPartitionData: partition columns not supported"); + } auto &lstate = lstate_p.Cast(); - return lstate.batch_index; + return OperatorPartitionData(lstate.batch_index); } InsertionOrderPreservingMap PhysicalOrder::ParamsToString() const { diff --git a/src/duckdb/src/execution/operator/order/physical_top_n.cpp b/src/duckdb/src/execution/operator/order/physical_top_n.cpp index aa686878a..1b3ae11ae 100644 --- a/src/duckdb/src/execution/operator/order/physical_top_n.cpp +++ b/src/duckdb/src/execution/operator/order/physical_top_n.cpp @@ -1,12 +1,9 @@ #include "duckdb/execution/operator/order/physical_top_n.hpp" #include "duckdb/common/assert.hpp" -#include "duckdb/common/sort/sort.hpp" -#include "duckdb/common/types/row/row_layout.hpp" -#include "duckdb/common/value_operations/value_operations.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/storage/data_table.hpp" +#include "duckdb/function/create_sort_key.hpp" namespace duckdb { @@ -21,33 +18,41 @@ PhysicalTopN::PhysicalTopN(vector types, vector o //===--------------------------------------------------------------------===// class TopNHeap; -struct TopNScanState { - unique_ptr scanner; - idx_t pos; - bool exclude_offset; -}; +struct TopNEntry { + string_t sort_key; + idx_t index; -class TopNSortState { -public: - explicit TopNSortState(TopNHeap &heap); + bool operator<(const TopNEntry &other) const { + return sort_key < other.sort_key; + } +}; - TopNHeap &heap; - unique_ptr local_state; - unique_ptr global_state; - idx_t count; - bool is_sorted; +struct TopNScanState { + TopNScanState() : pos(0), sel(STANDARD_VECTOR_SIZE) { + } -public: - void Initialize(); - void Append(DataChunk &sort_chunk, DataChunk &payload); + idx_t pos; + vector scan_order; + SelectionVector sel; +}; - void Sink(DataChunk &input); - void Finalize(); +struct TopNBoundaryValue { + mutex lock; + string boundary_value; + bool is_set = false; - void Move(TopNSortState &other); + string GetBoundaryValue() { + lock_guard l(lock); + return boundary_value; + } - void InitializeScan(TopNScanState &state, bool exclude_offset); - void Scan(TopNScanState &state, DataChunk &chunk); + void UpdateValue(string_t boundary_val) { + lock_guard l(lock); + if (!is_set || boundary_val < string_t(boundary_value)) { + boundary_value = boundary_val.GetString(); + is_set = true; + } + } }; class TopNHeap { @@ -61,162 +66,39 @@ class TopNHeap { Allocator &allocator; BufferManager &buffer_manager; + unsafe_vector heap; const vector &payload_types; const vector &orders; idx_t limit; idx_t offset; - TopNSortState sort_state; + idx_t heap_size; ExpressionExecutor executor; DataChunk sort_chunk; - DataChunk compare_chunk; + DataChunk heap_data; DataChunk payload_chunk; - //! A set of boundary values that determine either the minimum or the maximum value we have to consider for our - //! top-n - DataChunk boundary_values; - //! Whether or not the boundary_values has been set. The boundary_values are only set after a reduce step - bool has_boundary_values; + DataChunk sort_keys; + StringHeap sort_key_heap; - SelectionVector final_sel; - SelectionVector true_sel; - SelectionVector false_sel; - SelectionVector new_remaining_sel; + SelectionVector matching_sel; public: - void Sink(DataChunk &input); + void Sink(DataChunk &input, optional_ptr boundary_value = nullptr); void Combine(TopNHeap &other); void Reduce(); void Finalize(); - void ExtractBoundaryValues(DataChunk ¤t_chunk, DataChunk &prev_chunk); - void InitializeScan(TopNScanState &state, bool exclude_offset); void Scan(TopNScanState &state, DataChunk &chunk); - bool CheckBoundaryValues(DataChunk &sort_chunk, DataChunk &payload); -}; - -//===--------------------------------------------------------------------===// -// TopNSortState -//===--------------------------------------------------------------------===// -TopNSortState::TopNSortState(TopNHeap &heap) : heap(heap), count(0), is_sorted(false) { -} - -void TopNSortState::Initialize() { - RowLayout layout; - layout.Initialize(heap.payload_types); - auto &buffer_manager = heap.buffer_manager; - global_state = make_uniq(buffer_manager, heap.orders, layout); - local_state = make_uniq(); - local_state->Initialize(*global_state, buffer_manager); -} - -void TopNSortState::Append(DataChunk &sort_chunk, DataChunk &payload) { - D_ASSERT(!is_sorted); - if (heap.has_boundary_values) { - if (!heap.CheckBoundaryValues(sort_chunk, payload)) { - return; - } - } - - local_state->SinkChunk(sort_chunk, payload); - count += payload.size(); -} - -void TopNSortState::Sink(DataChunk &input) { - // compute the ordering values for the new chunk - heap.sort_chunk.Reset(); - heap.executor.Execute(input, heap.sort_chunk); - - // append the new chunk to what we have already - Append(heap.sort_chunk, input); -} - -void TopNSortState::Move(TopNSortState &other) { - local_state = std::move(other.local_state); - global_state = std::move(other.global_state); - count = other.count; - is_sorted = other.is_sorted; -} - -void TopNSortState::Finalize() { - D_ASSERT(!is_sorted); - global_state->AddLocalState(*local_state); - - global_state->PrepareMergePhase(); - while (global_state->sorted_blocks.size() > 1) { - MergeSorter merge_sorter(*global_state, heap.buffer_manager); - merge_sorter.PerformInMergeRound(); - global_state->CompleteMergeRound(); - } - is_sorted = true; -} - -void TopNSortState::InitializeScan(TopNScanState &state, bool exclude_offset) { - D_ASSERT(is_sorted); - if (global_state->sorted_blocks.empty()) { - state.scanner = nullptr; - } else { - D_ASSERT(global_state->sorted_blocks.size() == 1); - state.scanner = make_uniq(*global_state->sorted_blocks[0]->payload_data, *global_state); +public: + idx_t ReduceThreshold() const { + return MaxValue(STANDARD_VECTOR_SIZE * 5ULL, 2ULL * heap_size); } - state.pos = 0; - state.exclude_offset = exclude_offset && heap.offset > 0; -} -void TopNSortState::Scan(TopNScanState &state, DataChunk &chunk) { - if (!state.scanner) { - return; - } - auto offset = heap.offset; - auto limit = heap.limit; - D_ASSERT(is_sorted); - while (chunk.size() == 0) { - state.scanner->Scan(chunk); - if (chunk.size() == 0) { - break; - } - idx_t start = state.pos; - idx_t end = state.pos + chunk.size(); - state.pos = end; - - idx_t chunk_start = 0; - idx_t chunk_end = chunk.size(); - if (state.exclude_offset) { - // we need to exclude all tuples before the OFFSET - // check if we should include anything - if (end <= offset) { - // end is smaller than offset: include nothing! - chunk.Reset(); - continue; - } else if (start < offset) { - // we need to slice - chunk_start = offset - start; - } - } - // check if we need to truncate at the offset + limit mark - if (start >= offset + limit) { - // we are finished - chunk_end = 0; - } else if (end > offset + limit) { - // the end extends past the offset + limit - // truncate the current chunk - chunk_end = offset + limit - start; - } - D_ASSERT(chunk_end - chunk_start <= STANDARD_VECTOR_SIZE); - if (chunk_end == chunk_start) { - chunk.Reset(); - break; - } else if (chunk_start > 0) { - SelectionVector sel(STANDARD_VECTOR_SIZE); - for (idx_t i = chunk_start; i < chunk_end; i++) { - sel.set_index(i - chunk_start, i); - } - chunk.Slice(sel, chunk_end - chunk_start); - } else if (chunk_end != chunk.size()) { - chunk.SetCardinality(chunk_end); - } + idx_t HeapAllocSize() const { + return MinValue(STANDARD_VECTOR_SIZE * 100ULL, ReduceThreshold()) + STANDARD_VECTOR_SIZE; } -} +}; //===--------------------------------------------------------------------===// // TopNHeap @@ -224,9 +106,8 @@ void TopNSortState::Scan(TopNScanState &state, DataChunk &chunk) { TopNHeap::TopNHeap(ClientContext &context, Allocator &allocator, const vector &payload_types_p, const vector &orders_p, idx_t limit, idx_t offset) : allocator(allocator), buffer_manager(BufferManager::GetBufferManager(context)), payload_types(payload_types_p), - orders(orders_p), limit(limit), offset(offset), sort_state(*this), executor(context), has_boundary_values(false), - final_sel(STANDARD_VECTOR_SIZE), true_sel(STANDARD_VECTOR_SIZE), false_sel(STANDARD_VECTOR_SIZE), - new_remaining_sel(STANDARD_VECTOR_SIZE) { + orders(orders_p), limit(limit), offset(offset), heap_size(limit + offset), executor(context), + matching_sel(STANDARD_VECTOR_SIZE) { // initialize the executor and the sort_chunk vector sort_types; for (auto &order : orders) { @@ -234,11 +115,11 @@ TopNHeap::TopNHeap(ClientContext &context, Allocator &allocator, const vectorreturn_type); executor.AddExpression(*expr); } + vector sort_keys_type {LogicalType::BLOB}; + sort_keys.Initialize(allocator, sort_keys_type); + heap_data.Initialize(allocator, payload_types, HeapAllocSize()); payload_chunk.Initialize(allocator, payload_types); sort_chunk.Initialize(allocator, sort_types); - compare_chunk.Initialize(allocator, sort_types); - boundary_values.Initialize(allocator, sort_types); - sort_state.Initialize(); } TopNHeap::TopNHeap(ClientContext &context, const vector &payload_types, @@ -251,13 +132,93 @@ TopNHeap::TopNHeap(ExecutionContext &context, const vector &payload : TopNHeap(context.client, Allocator::Get(context.client), payload_types, orders, limit, offset) { } -void TopNHeap::Sink(DataChunk &input) { - sort_state.Sink(input); +void TopNHeap::Sink(DataChunk &input, optional_ptr global_boundary) { + // compute the ordering values for the new chunk + sort_chunk.Reset(); + executor.Execute(input, sort_chunk); + + // construct the sort key from the sort chunk + vector modifiers; + for (auto &order : orders) { + modifiers.emplace_back(order.type, order.null_order); + } + sort_keys.Reset(); + auto &sort_keys_vec = sort_keys.data[0]; + CreateSortKeyHelpers::CreateSortKey(sort_chunk, modifiers, sort_keys_vec); + + // fetch the current global boundary (if any) + string boundary_val; + string_t global_boundary_val; + if (global_boundary) { + boundary_val = global_boundary->GetBoundaryValue(); + global_boundary_val = string_t(boundary_val); + } + + // insert the sort keys into the priority queue + constexpr idx_t BASE_INDEX = NumericLimits::Maximum(); + + bool any_added = false; + auto sort_key_values = FlatVector::GetData(sort_keys_vec); + for (idx_t r = 0; r < input.size(); r++) { + auto &sort_key = sort_key_values[r]; + if (!boundary_val.empty() && sort_key > global_boundary_val) { + continue; + } + if (heap.size() >= heap_size) { + // heap is full - check the latest entry + if (sort_key > heap.front().sort_key) { + // current max in the heap is smaller than the new key - skip this entry + continue; + } + } + // replace the previous top entry with the new entry + TopNEntry entry; + entry.sort_key = sort_key; + entry.index = BASE_INDEX + r; + if (heap.size() >= heap_size) { + std::pop_heap(heap.begin(), heap.end()); + heap.pop_back(); + } + heap.push_back(entry); + std::push_heap(heap.begin(), heap.end()); + any_added = true; + } + if (!any_added) { + // early-out: no matches + return; + } + // if we modified the heap we might be able to update the global boundary + // note that the global boundary only applies to FULL heaps + if (heap.size() >= heap_size && global_boundary) { + global_boundary->UpdateValue(heap.front().sort_key); + } + + // for all matching entries we need to copy over the corresponding payload values + idx_t match_count = 0; + for (auto &entry : heap) { + if (entry.index < BASE_INDEX) { + continue; + } + // this entry was added in this chunk + // if not inlined - copy over the string to the string heap + if (!entry.sort_key.IsInlined()) { + entry.sort_key = sort_key_heap.AddBlob(entry.sort_key); + } + // to finalize the addition of this entry we need to move over the payload data + matching_sel.set_index(match_count, entry.index - BASE_INDEX); + entry.index = heap_data.size() + match_count; + match_count++; + } + + // copy over the input rows to the payload chunk + heap_data.Append(input, true, &matching_sel, match_count); } void TopNHeap::Combine(TopNHeap &other) { other.Finalize(); + // FIXME: heaps can be merged directly instead of doing it like this + // that only really speeds things up if heaps are very large, however TopNScanState state; other.InitializeScan(state, false); while (true) { @@ -272,130 +233,59 @@ void TopNHeap::Combine(TopNHeap &other) { } void TopNHeap::Finalize() { - sort_state.Finalize(); } void TopNHeap::Reduce() { - idx_t min_sort_threshold = MaxValue(STANDARD_VECTOR_SIZE * 5ULL, 2ULL * (limit + offset)); - if (sort_state.count < min_sort_threshold) { - // only reduce when we pass two times the limit + offset, or 5 vectors (whichever comes first) + if (payload_chunk.size() < ReduceThreshold()) { + // only reduce when we pass the reduce threshold return; } - sort_state.Finalize(); - TopNSortState new_state(*this); - new_state.Initialize(); - - TopNScanState state; - sort_state.InitializeScan(state, false); - - DataChunk new_chunk; - new_chunk.Initialize(allocator, payload_types); - - DataChunk *current_chunk = &new_chunk; - DataChunk *prev_chunk = &payload_chunk; - has_boundary_values = false; - while (true) { - current_chunk->Reset(); - Scan(state, *current_chunk); - if (current_chunk->size() == 0) { - ExtractBoundaryValues(*current_chunk, *prev_chunk); - break; + // we have too many values in the heap - reduce them + StringHeap new_sort_heap; + DataChunk new_payload_chunk; + new_payload_chunk.Initialize(allocator, payload_types, HeapAllocSize()); + + SelectionVector new_payload_sel(heap.size()); + for (idx_t i = 0; i < heap.size(); i++) { + auto &entry = heap[i]; + // the entry is not inlined - move the sort key to the new sort heap + if (!entry.sort_key.IsInlined()) { + entry.sort_key = new_sort_heap.AddBlob(entry.sort_key); } - new_state.Sink(*current_chunk); - std::swap(current_chunk, prev_chunk); + // move this heap entry to position X in the payload chunk + new_payload_sel.set_index(i, entry.index); + entry.index = i; } - sort_state.Move(new_state); -} + // copy over the data from the current payload chunk to the new payload chunk + payload_chunk.Copy(new_payload_chunk, new_payload_sel, heap.size()); -void TopNHeap::ExtractBoundaryValues(DataChunk ¤t_chunk, DataChunk &prev_chunk) { - // extract the last entry of the prev_chunk and set as minimum value - D_ASSERT(prev_chunk.size() > 0); - for (idx_t col_idx = 0; col_idx < current_chunk.ColumnCount(); col_idx++) { - ConstantVector::Reference(current_chunk.data[col_idx], prev_chunk.data[col_idx], prev_chunk.size() - 1, - prev_chunk.size()); - } - current_chunk.SetCardinality(1); - sort_chunk.Reset(); - executor.Execute(¤t_chunk, sort_chunk); - - boundary_values.Reset(); - boundary_values.Append(sort_chunk); - boundary_values.SetCardinality(1); - for (idx_t i = 0; i < boundary_values.ColumnCount(); i++) { - boundary_values.data[i].SetVectorType(VectorType::CONSTANT_VECTOR); - } - has_boundary_values = true; -} - -bool TopNHeap::CheckBoundaryValues(DataChunk &sort_chunk, DataChunk &payload) { - // we have boundary values - // from these boundary values, determine which values we should insert (if any) - idx_t final_count = 0; - - SelectionVector remaining_sel(nullptr); - idx_t remaining_count = sort_chunk.size(); - for (idx_t i = 0; i < orders.size(); i++) { - if (remaining_sel.data()) { - compare_chunk.data[i].Slice(sort_chunk.data[i], remaining_sel, remaining_count); - } else { - compare_chunk.data[i].Reference(sort_chunk.data[i]); - } - bool is_last = i + 1 == orders.size(); - idx_t true_count; - if (orders[i].null_order == OrderByNullType::NULLS_LAST) { - if (orders[i].type == OrderType::ASCENDING) { - true_count = VectorOperations::DistinctLessThan(compare_chunk.data[i], boundary_values.data[i], - &remaining_sel, remaining_count, &true_sel, &false_sel); - } else { - true_count = VectorOperations::DistinctGreaterThanNullsFirst(compare_chunk.data[i], - boundary_values.data[i], &remaining_sel, - remaining_count, &true_sel, &false_sel); - } - } else { - D_ASSERT(orders[i].null_order == OrderByNullType::NULLS_FIRST); - if (orders[i].type == OrderType::ASCENDING) { - true_count = VectorOperations::DistinctLessThanNullsFirst(compare_chunk.data[i], - boundary_values.data[i], &remaining_sel, - remaining_count, &true_sel, &false_sel); - } else { - true_count = - VectorOperations::DistinctGreaterThan(compare_chunk.data[i], boundary_values.data[i], - &remaining_sel, remaining_count, &true_sel, &false_sel); - } - } - - if (true_count > 0) { - memcpy(final_sel.data() + final_count, true_sel.data(), true_count * sizeof(sel_t)); - final_count += true_count; - } - idx_t false_count = remaining_count - true_count; - if (!is_last && false_count > 0) { - // check what we should continue to check - compare_chunk.data[i].Slice(sort_chunk.data[i], false_sel, false_count); - remaining_count = VectorOperations::NotDistinctFrom(compare_chunk.data[i], boundary_values.data[i], - &false_sel, false_count, &new_remaining_sel, nullptr); - remaining_sel.Initialize(new_remaining_sel); - } else { - break; - } - } - if (final_count == 0) { - return false; - } - if (final_count < sort_chunk.size()) { - sort_chunk.Slice(final_sel, final_count); - payload.Slice(final_sel, final_count); - } - return true; + new_sort_heap.Move(sort_key_heap); + payload_chunk.Reference(new_payload_chunk); } void TopNHeap::InitializeScan(TopNScanState &state, bool exclude_offset) { - sort_state.InitializeScan(state, exclude_offset); + auto heap_copy = heap; + // traverse the rest of the heap + while (!heap_copy.empty()) { + std::pop_heap(heap_copy.begin(), heap_copy.end()); + state.scan_order.push_back(UnsafeNumericCast(heap_copy.back().index)); + heap_copy.pop_back(); + } + std::reverse(state.scan_order.begin(), state.scan_order.end()); + state.pos = exclude_offset ? offset : 0; } void TopNHeap::Scan(TopNScanState &state, DataChunk &chunk) { - sort_state.Scan(state, chunk); + if (state.pos >= state.scan_order.size()) { + return; + } + SelectionVector sel(state.scan_order.data() + state.pos); + idx_t count = MinValue(STANDARD_VECTOR_SIZE, state.scan_order.size() - state.pos); + state.pos += STANDARD_VECTOR_SIZE; + + chunk.Reset(); + chunk.Slice(heap_data, sel, count); } class TopNGlobalState : public GlobalSinkState { @@ -407,6 +297,7 @@ class TopNGlobalState : public GlobalSinkState { mutex lock; TopNHeap heap; + TopNBoundaryValue boundary_value; }; class TopNLocalState : public LocalSinkState { @@ -432,8 +323,9 @@ unique_ptr PhysicalTopN::GetGlobalSinkState(ClientContext &cont //===--------------------------------------------------------------------===// SinkResultType PhysicalTopN::Sink(ExecutionContext &context, DataChunk &chunk, OperatorSinkInput &input) const { // append to the local sink state + auto &gstate = input.global_state.Cast(); auto &sink = input.local_state.Cast(); - sink.heap.Sink(chunk); + sink.heap.Sink(chunk, &gstate.boundary_value); sink.heap.Reduce(); return SinkResultType::NEED_MORE_INPUT; } 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 8bad7cbbb..eb6967038 100644 --- a/src/duckdb/src/execution/operator/persistent/physical_batch_insert.cpp +++ b/src/duckdb/src/execution/operator/persistent/physical_batch_insert.cpp @@ -131,19 +131,21 @@ class BatchInsertGlobalState : public GlobalSinkState { explicit BatchInsertGlobalState(ClientContext &context, DuckTableEntry &table, idx_t minimum_memory_per_thread) : memory_manager(context, minimum_memory_per_thread), table(table), insert_count(0), optimistically_written(false), minimum_memory_per_thread(minimum_memory_per_thread) { + row_group_size = table.GetStorage().GetRowGroupSize(); } BatchMemoryManager memory_manager; BatchTaskManager task_manager; mutex lock; DuckTableEntry &table; + idx_t row_group_size; idx_t insert_count; vector collections; idx_t next_start = 0; atomic optimistically_written; idx_t minimum_memory_per_thread; - static bool ReadyToMerge(idx_t count); + bool ReadyToMerge(idx_t count) const; void ScheduleMergeTasks(idx_t min_batch_index); unique_ptr MergeCollections(ClientContext &context, vector merge_collections, @@ -178,8 +180,8 @@ class BatchInsertLocalState : public LocalSinkState { void CreateNewCollection(DuckTableEntry &table, const vector &insert_types) { auto table_info = table.GetStorage().GetDataTableInfo(); - auto &block_manager = TableIOManager::Get(table.GetStorage()).GetBlockManagerForRowData(); - current_collection = make_uniq(std::move(table_info), block_manager, insert_types, + auto &io_manager = TableIOManager::Get(table.GetStorage()); + current_collection = make_uniq(std::move(table_info), io_manager, insert_types, NumericCast(MAX_ROW_ID)); current_collection->InitializeEmpty(); current_collection->InitializeAppend(current_append_state); @@ -227,21 +229,21 @@ struct BatchMergeTask { idx_t total_count; }; -bool BatchInsertGlobalState::ReadyToMerge(idx_t count) { +bool BatchInsertGlobalState::ReadyToMerge(idx_t count) const { // we try to merge so the count fits nicely into row groups - if (count >= Storage::ROW_GROUP_SIZE / 10 * 9 && count <= Storage::ROW_GROUP_SIZE) { + if (count >= row_group_size / 10 * 9 && count <= row_group_size) { // 90%-100% of row group size return true; } - if (count >= Storage::ROW_GROUP_SIZE / 10 * 18 && count <= Storage::ROW_GROUP_SIZE * 2) { + if (count >= row_group_size / 10 * 18 && count <= row_group_size * 2) { // 180%-200% of row group size return true; } - if (count >= Storage::ROW_GROUP_SIZE / 10 * 27 && count <= Storage::ROW_GROUP_SIZE * 3) { + if (count >= row_group_size / 10 * 27 && count <= row_group_size * 3) { // 270%-300% of row group size return true; } - if (count >= Storage::ROW_GROUP_SIZE / 10 * 36) { + if (count >= row_group_size / 10 * 36) { // >360% of row group size return true; } @@ -346,7 +348,7 @@ void BatchInsertGlobalState::AddCollection(ClientContext &context, idx_t batch_i batch_index, min_batch_index); } auto new_count = current_collection->GetTotalRows(); - auto batch_type = new_count < Storage::ROW_GROUP_SIZE ? RowGroupBatchType::NOT_FLUSHED : RowGroupBatchType::FLUSHED; + auto batch_type = new_count < row_group_size ? RowGroupBatchType::NOT_FLUSHED : RowGroupBatchType::FLUSHED; if (batch_type == RowGroupBatchType::FLUSHED && writer) { writer->WriteLastRowGroup(*current_collection); } @@ -556,7 +558,7 @@ SinkFinalizeType PhysicalBatchInsert::Finalize(Pipeline &pipeline, Event &event, auto &gstate = input.global_state.Cast(); auto &memory_manager = gstate.memory_manager; - if (gstate.optimistically_written || gstate.insert_count >= LocalStorage::MERGE_THRESHOLD) { + if (gstate.optimistically_written || gstate.insert_count >= gstate.row_group_size) { // we have written data to disk optimistically or are inserting a large amount of data // perform a final pass over all of the row groups and merge them together vector> mergers; diff --git a/src/duckdb/src/execution/operator/persistent/physical_export.cpp b/src/duckdb/src/execution/operator/persistent/physical_export.cpp index 733b01f76..b372cd063 100644 --- a/src/duckdb/src/execution/operator/persistent/physical_export.cpp +++ b/src/duckdb/src/execution/operator/persistent/physical_export.cpp @@ -9,16 +9,18 @@ #include "duckdb/parallel/pipeline.hpp" #include "duckdb/parser/keyword_helper.hpp" #include "duckdb/transaction/transaction.hpp" +#include "duckdb/catalog/duck_catalog.hpp" +#include "duckdb/catalog/dependency_manager.hpp" #include #include namespace duckdb { -using std::stringstream; - void ReorderTableEntries(catalog_entry_vector_t &tables); +using std::stringstream; + PhysicalExport::PhysicalExport(vector types, CopyFunction function, unique_ptr info, idx_t estimated_cardinality, unique_ptr exported_tables) : PhysicalOperator(PhysicalOperatorType::EXPORT, std::move(types), estimated_cardinality), @@ -227,36 +229,19 @@ SourceResultType PhysicalExport::GetData(ExecutionContext &context, DataChunk &c auto &ccontext = context.client; auto &fs = FileSystem::GetFileSystem(ccontext); - // gather all catalog types to export - ExportEntries entries; - - auto schema_list = Catalog::GetSchemas(ccontext, info->catalog); - ExtractEntries(context.client, schema_list, entries); + auto &catalog = Catalog::GetCatalog(ccontext, info->catalog); - // consider the order of tables because of foreign key constraint - entries.tables.clear(); - for (idx_t i = 0; i < exported_tables->data.size(); i++) { - entries.tables.push_back(exported_tables->data[i].entry); + catalog_entry_vector_t catalog_entries; + catalog_entries = GetNaiveExportOrder(context.client, catalog); + if (catalog.IsDuckCatalog()) { + auto &duck_catalog = catalog.Cast(); + auto &dependency_manager = duck_catalog.GetDependencyManager(); + dependency_manager.ReorderEntries(catalog_entries, ccontext); } - // order macro's by timestamp so nested macro's are imported nicely - sort(entries.macros.begin(), entries.macros.end(), - [](const reference &lhs, const reference &rhs) { - return lhs.get().oid < rhs.get().oid; - }); - // write the schema.sql file - // export order is SCHEMA -> SEQUENCE -> TABLE -> VIEW -> INDEX - stringstream ss; - WriteCatalogEntries(ss, entries.schemas); - WriteCatalogEntries(ss, entries.custom_types); - WriteCatalogEntries(ss, entries.sequences); - WriteCatalogEntries(ss, entries.tables); - WriteCatalogEntries(ss, entries.views); - WriteCatalogEntries(ss, entries.indexes); - WriteCatalogEntries(ss, entries.macros); - + WriteCatalogEntries(ss, catalog_entries); WriteStringStreamToFile(fs, ss, fs.JoinPath(info->file_path, "schema.sql")); // write the load.sql file diff --git a/src/duckdb/src/execution/operator/persistent/physical_insert.cpp b/src/duckdb/src/execution/operator/persistent/physical_insert.cpp index 626f28b82..999923229 100644 --- a/src/duckdb/src/execution/operator/persistent/physical_insert.cpp +++ b/src/duckdb/src/execution/operator/persistent/physical_insert.cpp @@ -474,8 +474,8 @@ SinkResultType PhysicalInsert::Sink(ExecutionContext &context, DataChunk &chunk, if (!lstate.local_collection) { lock_guard l(gstate.lock); auto table_info = storage.GetDataTableInfo(); - auto &block_manager = TableIOManager::Get(storage).GetBlockManagerForRowData(); - lstate.local_collection = make_uniq(std::move(table_info), block_manager, insert_types, + auto &io_manager = TableIOManager::Get(table.GetStorage()); + lstate.local_collection = make_uniq(std::move(table_info), io_manager, insert_types, NumericCast(MAX_ROW_ID)); lstate.local_collection->InitializeEmpty(); lstate.local_collection->InitializeAppend(lstate.local_append_state); @@ -503,6 +503,10 @@ SinkCombineResultType PhysicalInsert::Combine(ExecutionContext &context, Operato return SinkCombineResultType::FINISHED; } + auto &table = gstate.table; + auto &storage = table.GetStorage(); + const idx_t row_group_size = storage.GetRowGroupSize(); + // parallel append: finalize the append TransactionData tdata(0, 0); lstate.local_collection->FinalizeAppend(tdata, lstate.local_append_state); @@ -511,10 +515,8 @@ SinkCombineResultType PhysicalInsert::Combine(ExecutionContext &context, Operato lock_guard lock(gstate.lock); gstate.insert_count += append_count; - if (append_count < Storage::ROW_GROUP_SIZE) { + if (append_count < row_group_size) { // we have few rows - append to the local storage directly - auto &table = gstate.table; - auto &storage = table.GetStorage(); storage.InitializeLocalAppend(gstate.append_state, table, context.client, bound_constraints); auto &transaction = DuckTransaction::Get(context.client, table.catalog); lstate.local_collection->Scan(transaction, [&](DataChunk &insert_chunk) { diff --git a/src/duckdb/src/execution/operator/scan/physical_positional_scan.cpp b/src/duckdb/src/execution/operator/scan/physical_positional_scan.cpp index e2a67505a..2fad0493a 100644 --- a/src/duckdb/src/execution/operator/scan/physical_positional_scan.cpp +++ b/src/duckdb/src/execution/operator/scan/physical_positional_scan.cpp @@ -208,4 +208,12 @@ bool PhysicalPositionalScan::Equals(const PhysicalOperator &other_p) const { return true; } +vector> PhysicalPositionalScan::GetChildren() const { + auto result = PhysicalOperator::GetChildren(); + for (auto &entry : child_tables) { + result.push_back(*entry); + } + return result; +} + } // namespace duckdb 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 27ba3982a..675ab7d22 100644 --- a/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp +++ b/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp @@ -28,7 +28,8 @@ class TableScanGlobalSourceState : public GlobalSourceState { table_filters = op.dynamic_filters->GetFinalTableFilters(op, op.table_filters.get()); } if (op.function.init_global) { - TableFunctionInitInput input(op.bind_data.get(), op.column_ids, op.projection_ids, GetTableFilters(op)); + TableFunctionInitInput input(op.bind_data.get(), op.column_ids, op.projection_ids, GetTableFilters(op), + op.extra_info.sample_options); global_state = op.function.init_global(context, input); if (global_state) { max_threads = global_state->MaxThreads(); @@ -71,7 +72,7 @@ class TableScanLocalSourceState : public LocalSourceState { const PhysicalTableScan &op) { if (op.function.init_local) { TableFunctionInitInput input(op.bind_data.get(), op.column_ids, op.projection_ids, - gstate.GetTableFilters(op)); + gstate.GetTableFilters(op), op.extra_info.sample_options); local_state = op.function.init_local(context, input, gstate.global_state.get()); } } @@ -120,14 +121,24 @@ double PhysicalTableScan::GetProgress(ClientContext &context, GlobalSourceState return -1; } -idx_t PhysicalTableScan::GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate_p, - LocalSourceState &lstate) const { - D_ASSERT(SupportsBatchIndex()); - D_ASSERT(function.get_batch_index); +bool PhysicalTableScan::SupportsPartitioning(const OperatorPartitionInfo &partition_info) const { + if (!function.get_partition_data) { + return false; + } + // FIXME: actually check if partition info is supported + return true; +} + +OperatorPartitionData PhysicalTableScan::GetPartitionData(ExecutionContext &context, DataChunk &chunk, + GlobalSourceState &gstate_p, LocalSourceState &lstate, + const OperatorPartitionInfo &partition_info) const { + D_ASSERT(SupportsPartitioning(partition_info)); + D_ASSERT(function.get_partition_data); auto &gstate = gstate_p.Cast(); auto &state = lstate.Cast(); - return function.get_batch_index(context.client, bind_data.get(), state.local_state.get(), - gstate.global_state.get()); + TableFunctionGetPartitionInput input(bind_data.get(), state.local_state.get(), gstate.global_state.get(), + partition_info); + return function.get_partition_data(context.client, input); } string PhysicalTableScan::GetName() const { @@ -184,6 +195,9 @@ InsertionOrderPreservingMap PhysicalTableScan::ParamsToString() const { } result["Filters"] = filters_info; } + if (extra_info.sample_options) { + result["Sample Method"] = "System: " + extra_info.sample_options->sample_size.ToString() + "%"; + } if (!extra_info.file_filters.empty()) { result["File Filters"] = extra_info.file_filters; if (extra_info.filtered_files.IsValid() && extra_info.total_files.IsValid()) { diff --git a/src/duckdb/src/execution/operator/schema/physical_alter.cpp b/src/duckdb/src/execution/operator/schema/physical_alter.cpp index 0e73fc29d..0d463e5ad 100644 --- a/src/duckdb/src/execution/operator/schema/physical_alter.cpp +++ b/src/duckdb/src/execution/operator/schema/physical_alter.cpp @@ -11,7 +11,6 @@ namespace duckdb { SourceResultType PhysicalAlter::GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const { auto &catalog = Catalog::GetCatalog(context.client, info->catalog); catalog.Alter(context.client, *info); - return SourceResultType::FINISHED; } diff --git a/src/duckdb/src/execution/operator/schema/physical_attach.cpp b/src/duckdb/src/execution/operator/schema/physical_attach.cpp index 69af179f3..523f0d57e 100644 --- a/src/duckdb/src/execution/operator/schema/physical_attach.cpp +++ b/src/duckdb/src/execution/operator/schema/physical_attach.cpp @@ -36,7 +36,6 @@ SourceResultType PhysicalAttach::GetData(ExecutionContext &context, DataChunk &c // constant-time lookup in the catalog for the db name auto existing_db = db_manager.GetDatabase(context.client, name); if (existing_db) { - if ((existing_db->IsReadOnly() && options.access_mode == AccessMode::READ_WRITE) || (!existing_db->IsReadOnly() && options.access_mode == AccessMode::READ_ONLY)) { @@ -46,7 +45,9 @@ SourceResultType PhysicalAttach::GetData(ExecutionContext &context, DataChunk &c 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); + } return SourceResultType::FINISHED; } } @@ -70,8 +71,11 @@ SourceResultType PhysicalAttach::GetData(ExecutionContext &context, DataChunk &c auto attached_db = db_manager.AttachDatabase(context.client, *info, options); //! Initialize the database. - const auto block_alloc_size = info->GetBlockAllocSize(); - attached_db->Initialize(block_alloc_size); + const auto storage_options = info->GetStorageOptions(); + attached_db->Initialize(storage_options); + if (!options.default_table.name.empty()) { + attached_db->GetCatalog().SetDefaultTable(options.default_table.schema, options.default_table.name); + } 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 index 7eceeecb4..78b96cff9 100644 --- a/src/duckdb/src/execution/operator/schema/physical_create_art_index.cpp +++ b/src/duckdb/src/execution/operator/schema/physical_create_art_index.cpp @@ -16,12 +16,13 @@ namespace duckdb { PhysicalCreateARTIndex::PhysicalCreateARTIndex(LogicalOperator &op, TableCatalogEntry &table_p, const vector &column_ids, unique_ptr info, vector> unbound_expressions, - idx_t estimated_cardinality, const bool sorted) + idx_t estimated_cardinality, const bool sorted, + unique_ptr alter_table_info) : PhysicalOperator(PhysicalOperatorType::CREATE_INDEX, op.types, estimated_cardinality), table(table_p.Cast()), info(std::move(info)), unbound_expressions(std::move(unbound_expressions)), - sorted(sorted) { + sorted(sorted), alter_table_info(std::move(alter_table_info)) { - // Convert the virtual column ids to physical column ids. + // 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); } @@ -123,6 +124,18 @@ SinkResultType PhysicalCreateARTIndex::Sink(ExecutionContext &context, DataChunk 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); + } + } + } + ART::GenerateKeyVectors(l_state.arena_allocator, l_state.key_chunk, chunk.data[chunk.ColumnCount() - 1], l_state.keys, l_state.row_ids); @@ -138,7 +151,7 @@ SinkCombineResultType PhysicalCreateARTIndex::Combine(ExecutionContext &context, auto &g_state = input.global_state.Cast(); auto &l_state = input.local_state.Cast(); - // merge the local index into the global index + // Merge the local index into the global index. if (!g_state.global_index->MergeIndexes(*l_state.local_index)) { throw ConstraintException("Data contains duplicates on indexed column(s)"); } @@ -149,38 +162,54 @@ SinkCombineResultType PhysicalCreateARTIndex::Combine(ExecutionContext &context, SinkFinalizeType PhysicalCreateARTIndex::Finalize(Pipeline &pipeline, Event &event, ClientContext &context, OperatorSinkFinalizeInput &input) const { - // here, we set the resulting global index as the newly created index of the table + // Here, we set the resulting global index as the newly created index of the table. auto &state = input.global_state.Cast(); - // vacuum excess memory and verify + // Vacuum excess memory and verify. state.global_index->Vacuum(); D_ASSERT(!state.global_index->VerifyAndToString(true).empty()); state.global_index->VerifyAllocations(); auto &storage = table.GetStorage(); if (!storage.IsRoot()) { - throw TransactionException("Transaction conflict: cannot add an index to a table that has been altered!"); + throw TransactionException("cannot add an index to a table that has been altered"); } auto &schema = table.schema; info->column_ids = storage_ids; - // Ensure that the index does not yet exist. - // FIXME: We should early-out prior to creating the index. - if (schema.GetEntry(schema.GetCatalogTransaction(context), CatalogType::INDEX_ENTRY, info->index_name)) { - if (info->on_conflict != OnCreateConflict::IGNORE_ON_CONFLICT) { - throw CatalogException("Index with name \"%s\" already exists!", info->index_name); + // FIXME: We should check for catalog exceptions prior to index creation, and later double-check. + 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; } - // 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(); + 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 index to storage + // Add the index to the storage. storage.AddIndex(std::move(state.global_index)); return SinkFinalizeType::READY; } diff --git a/src/duckdb/src/execution/operator/set/physical_union.cpp b/src/duckdb/src/execution/operator/set/physical_union.cpp index 4954dc879..1194b9539 100644 --- a/src/duckdb/src/execution/operator/set/physical_union.cpp +++ b/src/duckdb/src/execution/operator/set/physical_union.cpp @@ -32,7 +32,11 @@ void PhysicalUnion::BuildPipelines(Pipeline ¤t, MetaPipeline &meta_pipelin order_matters = true; } if (sink) { - if (sink->SinkOrderDependent() || sink->RequiresBatchIndex()) { + if (sink->SinkOrderDependent()) { + order_matters = true; + } + auto partition_info = sink->RequiredPartitionInfo(); + if (partition_info.batch_index) { order_matters = true; } if (!sink->ParallelSink()) { diff --git a/src/duckdb/src/execution/physical_operator.cpp b/src/duckdb/src/execution/physical_operator.cpp index 3fe08ddfa..91588dab2 100644 --- a/src/duckdb/src/execution/physical_operator.cpp +++ b/src/duckdb/src/execution/physical_operator.cpp @@ -50,7 +50,7 @@ idx_t PhysicalOperator::EstimatedThreadCount() const { idx_t result = 0; if (children.empty()) { // Terminal operator, e.g., base table, these decide the degree of parallelism of pipelines - result = MaxValue(estimated_cardinality / (Storage::ROW_GROUP_SIZE * 2), 1); + result = MaxValue(estimated_cardinality / (DEFAULT_ROW_GROUP_SIZE * 2), 1); } else if (type == PhysicalOperatorType::UNION) { // We can run union pipelines in parallel, so we sum up the thread count of the children for (auto &child : children) { @@ -116,9 +116,10 @@ SourceResultType PhysicalOperator::GetData(ExecutionContext &context, DataChunk throw InternalException("Calling GetData on a node that is not a source!"); } -idx_t PhysicalOperator::GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate, - LocalSourceState &lstate) const { - throw InternalException("Calling GetBatchIndex on a node that does not support it"); +OperatorPartitionData PhysicalOperator::GetPartitionData(ExecutionContext &context, DataChunk &chunk, + GlobalSourceState &gstate, LocalSourceState &lstate, + const OperatorPartitionInfo &partition_info) const { + throw InternalException("Calling GetPartitionData on a node that does not support it"); } double PhysicalOperator::GetProgress(ClientContext &context, GlobalSourceState &gstate) const { @@ -175,10 +176,13 @@ bool PhysicalOperator::OperatorCachingAllowed(ExecutionContext &context) { return false; } else if (!context.pipeline->GetSink()) { return false; - } else if (context.pipeline->GetSink()->RequiresBatchIndex()) { - return false; } else if (context.pipeline->IsOrderDependent()) { return false; + } else { + auto partition_info = context.pipeline->GetSink()->RequiredPartitionInfo(); + if (partition_info.AnyRequired()) { + return false; + } } return true; @@ -240,7 +244,7 @@ vector> PhysicalOperator::GetSources() const { bool PhysicalOperator::AllSourcesSupportBatchIndex() const { auto sources = GetSources(); for (auto &source : sources) { - if (!source.get().SupportsBatchIndex()) { + if (!source.get().SupportsPartitioning(OperatorPartitionInfo::BatchIndex())) { return false; } } diff --git a/src/duckdb/src/execution/physical_plan/plan_aggregate.cpp b/src/duckdb/src/execution/physical_plan/plan_aggregate.cpp index c069fd9c7..c25c4ef73 100644 --- a/src/duckdb/src/execution/physical_plan/plan_aggregate.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_aggregate.cpp @@ -3,7 +3,9 @@ #include "duckdb/execution/operator/aggregate/physical_hash_aggregate.hpp" #include "duckdb/execution/operator/aggregate/physical_perfecthash_aggregate.hpp" #include "duckdb/execution/operator/aggregate/physical_ungrouped_aggregate.hpp" +#include "duckdb/execution/operator/aggregate/physical_partitioned_aggregate.hpp" #include "duckdb/execution/operator/projection/physical_projection.hpp" +#include "duckdb/execution/operator/scan/physical_table_scan.hpp" #include "duckdb/execution/physical_plan_generator.hpp" #include "duckdb/function/function_binder.hpp" #include "duckdb/main/client_context.hpp" @@ -28,6 +30,88 @@ hugeint_t GetRangeHugeint(const BaseStatistics &nstats) { return Hugeint::Convert(NumericStats::GetMax(nstats)) - Hugeint::Convert(NumericStats::GetMin(nstats)); } +static bool CanUsePartitionedAggregate(ClientContext &context, LogicalAggregate &op, PhysicalOperator &child, + vector &partition_columns) { + if (op.grouping_sets.size() > 1 || !op.grouping_functions.empty()) { + return false; + } + for (auto &expression : op.expressions) { + auto &aggregate = expression->Cast(); + if (aggregate.IsDistinct()) { + // distinct aggregates are not supported in partitioned hash aggregates + return false; + } + } + // check if the source is partitioned by the aggregate columns + // figure out the columns we are grouping by + for (auto &group_expr : op.groups) { + // only support bound reference here + if (group_expr->type != ExpressionType::BOUND_REF) { + return false; + } + auto &ref = group_expr->Cast(); + partition_columns.push_back(ref.index); + } + // traverse the children of the aggregate to find the source operator + reference child_ref(child); + while (child_ref.get().type != PhysicalOperatorType::TABLE_SCAN) { + auto &child_op = child_ref.get(); + switch (child_op.type) { + case PhysicalOperatorType::PROJECTION: { + // recompute partition columns + auto &projection = child_op.Cast(); + vector new_columns; + for (auto &partition_col : partition_columns) { + // we only support bound reference here + auto &expr = projection.select_list[partition_col]; + if (expr->type != ExpressionType::BOUND_REF) { + return false; + } + auto &ref = expr->Cast(); + new_columns.push_back(ref.index); + } + // continue into child node with new columns + partition_columns = std::move(new_columns); + child_ref = *child_op.children[0]; + break; + } + case PhysicalOperatorType::FILTER: + // continue into child operators + child_ref = *child_op.children[0]; + break; + default: + // unsupported operator for partition pass-through + return false; + } + } + auto &table_scan = child_ref.get().Cast(); + if (!table_scan.function.get_partition_info) { + // this source does not expose partition information - skip + return false; + } + // get the base columns by projecting over the projection_ids/column_ids + if (!table_scan.projection_ids.empty()) { + for (auto &partition_col : partition_columns) { + partition_col = table_scan.projection_ids[partition_col]; + } + } + vector base_columns; + for (const auto &partition_idx : partition_columns) { + auto col_idx = partition_idx; + col_idx = table_scan.column_ids[col_idx]; + base_columns.push_back(col_idx); + } + // check if the source operator is partitioned by the grouping columns + TableFunctionPartitionInput input(table_scan.bind_data.get(), base_columns); + auto partition_info = table_scan.function.get_partition_info(context, input); + if (partition_info != TablePartitionInfo::SINGLE_VALUE_PARTITIONS) { + // we only support single-value partitions currently + return false; + } + // we have single value partitions! + return true; +} + static bool CanUsePerfectHashAggregate(ClientContext &context, LogicalAggregate &op, vector &bits_per_group) { if (op.grouping_sets.size() > 1 || !op.grouping_functions.empty()) { return false; @@ -157,19 +241,19 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalAggregate plan = ExtractAggregateExpressions(std::move(plan), op.expressions, op.groups); + bool can_use_simple_aggregation = true; + for (auto &expression : op.expressions) { + auto &aggregate = expression->Cast(); + if (!aggregate.function.simple_update) { + // unsupported aggregate for simple aggregation: use hash aggregation + can_use_simple_aggregation = false; + break; + } + } if (op.groups.empty() && op.grouping_sets.size() <= 1) { // no groups, check if we can use a simple aggregation // special case: aggregate entire columns together - bool use_simple_aggregation = true; - for (auto &expression : op.expressions) { - auto &aggregate = expression->Cast(); - if (!aggregate.function.simple_update) { - // unsupported aggregate for simple aggregation: use hash aggregation - use_simple_aggregation = false; - break; - } - } - if (use_simple_aggregation) { + if (can_use_simple_aggregation) { groupby = make_uniq_base(op.types, std::move(op.expressions), op.estimated_cardinality); } else { @@ -178,9 +262,14 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalAggregate } } else { // groups! create a GROUP BY aggregator - // use a perfect hash aggregate if possible + // use a partitioned or perfect hash aggregate if possible + vector partition_columns; vector required_bits; - if (CanUsePerfectHashAggregate(context, op, required_bits)) { + if (can_use_simple_aggregation && CanUsePartitionedAggregate(context, op, *plan, partition_columns)) { + groupby = make_uniq_base( + context, op.types, std::move(op.expressions), std::move(op.groups), std::move(partition_columns), + op.estimated_cardinality); + } else if (CanUsePerfectHashAggregate(context, op, required_bits)) { groupby = make_uniq_base( context, op.types, std::move(op.expressions), std::move(op.groups), std::move(op.group_stats), std::move(required_bits), op.estimated_cardinality); 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 5a2345bc7..75c1c4d79 100644 --- a/src/duckdb/src/execution/physical_plan/plan_comparison_join.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_comparison_join.cpp @@ -1,4 +1,7 @@ +#include "duckdb/catalog/catalog_entry/duck_table_entry.hpp" +#include "duckdb/common/operator/subtract.hpp" #include "duckdb/execution/operator/join/perfect_hash_join_executor.hpp" +#include "duckdb/execution/operator/join/physical_blockwise_nl_join.hpp" #include "duckdb/execution/operator/join/physical_cross_product.hpp" #include "duckdb/execution/operator/join/physical_hash_join.hpp" #include "duckdb/execution/operator/join/physical_iejoin.hpp" @@ -8,13 +11,10 @@ #include "duckdb/execution/physical_plan_generator.hpp" #include "duckdb/function/table/table_scan.hpp" #include "duckdb/main/client_context.hpp" -#include "duckdb/planner/operator/logical_comparison_join.hpp" -#include "duckdb/transaction/duck_transaction.hpp" -#include "duckdb/common/operator/subtract.hpp" -#include "duckdb/execution/operator/join/physical_blockwise_nl_join.hpp" #include "duckdb/planner/expression/bound_reference_expression.hpp" #include "duckdb/planner/expression_iterator.hpp" -#include "duckdb/catalog/catalog_entry/duck_table_entry.hpp" +#include "duckdb/planner/operator/logical_comparison_join.hpp" +#include "duckdb/transaction/duck_transaction.hpp" namespace duckdb { @@ -129,29 +129,6 @@ static void RewriteJoinCondition(Expression &expr, idx_t offset) { ExpressionIterator::EnumerateChildren(expr, [&](Expression &child) { RewriteJoinCondition(child, offset); }); } -bool PhysicalPlanGenerator::HasEquality(vector &conds, idx_t &range_count) { - for (size_t c = 0; c < conds.size(); ++c) { - auto &cond = conds[c]; - switch (cond.comparison) { - case ExpressionType::COMPARE_EQUAL: - case ExpressionType::COMPARE_NOT_DISTINCT_FROM: - return true; - case ExpressionType::COMPARE_LESSTHAN: - case ExpressionType::COMPARE_GREATERTHAN: - case ExpressionType::COMPARE_LESSTHANOREQUALTO: - case ExpressionType::COMPARE_GREATERTHANOREQUALTO: - ++range_count; - break; - case ExpressionType::COMPARE_NOTEQUAL: - case ExpressionType::COMPARE_DISTINCT_FROM: - break; - default: - throw NotImplementedException("Unimplemented comparison join"); - } - } - return false; -} - unique_ptr PhysicalPlanGenerator::PlanComparisonJoin(LogicalComparisonJoin &op) { // now visit the children D_ASSERT(op.children.size() == 2); @@ -169,7 +146,7 @@ unique_ptr PhysicalPlanGenerator::PlanComparisonJoin(LogicalCo } idx_t has_range = 0; - bool has_equality = HasEquality(op.conditions, has_range); + bool has_equality = op.HasEquality(has_range); bool can_merge = has_range > 0; bool can_iejoin = has_range >= 2 && recursive_cte_tables.empty(); switch (op.join_type) { @@ -200,6 +177,7 @@ unique_ptr PhysicalPlanGenerator::PlanComparisonJoin(LogicalCo op.estimated_cardinality, perfect_join_stats, std::move(op.filter_pushdown)); } else { + D_ASSERT(op.left_projection_map.empty()); if (left->estimated_cardinality <= client_config.nested_loop_join_threshold || right->estimated_cardinality <= client_config.nested_loop_join_threshold) { can_iejoin = false; diff --git a/src/duckdb/src/execution/physical_plan/plan_create_index.cpp b/src/duckdb/src/execution/physical_plan/plan_create_index.cpp index a7e28444b..e2017c233 100644 --- a/src/duckdb/src/execution/physical_plan/plan_create_index.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_create_index.cpp @@ -1,20 +1,17 @@ #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" -#include "duckdb/execution/operator/filter/physical_filter.hpp" -#include "duckdb/execution/operator/schema/physical_create_art_index.hpp" #include "duckdb/execution/physical_plan_generator.hpp" -#include "duckdb/planner/operator/logical_create_index.hpp" - +#include "duckdb/main/client_context.hpp" #include "duckdb/main/database.hpp" -#include "duckdb/execution/index/index_type.hpp" -#include "duckdb/execution/index/bound_index.hpp" +#include "duckdb/planner/expression/bound_operator_expression.hpp" +#include "duckdb/planner/expression/bound_reference_expression.hpp" +#include "duckdb/planner/operator/logical_create_index.hpp" +#include "duckdb/planner/operator/logical_get.hpp" namespace duckdb { unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalCreateIndex &op) { - - // validate that all expressions contain valid scalar functions - // e.g. get_current_timestamp(), random(), and sequence values are not allowed as index keys - // because they make deletions and lookups unfeasible + // Ensure that all expressions contain valid scalar functions. + // E.g., get_current_timestamp(), random(), and sequence values cannot be index keys. for (idx_t i = 0; i < op.unbound_expressions.size(); i++) { auto &expr = op.unbound_expressions[i]; if (!expr->IsConsistent()) { @@ -22,7 +19,7 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalCreateInde } } - // Do we have a valid index type? + // If we get here and the index type is not valid index type, we throw an exception. const auto index_type = context.db->config.GetIndexTypes().FindByName(op.info->index_type); if (!index_type) { throw BinderException("Unknown index type: " + op.info->index_type); @@ -31,12 +28,13 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalCreateInde throw InternalException("Index type '%s' is missing a create_plan function", op.info->index_type); } - // table scan operator for index key columns and row IDs + // Add a dependency for the entire table on which we create the index. dependencies.AddDependency(op.table); - D_ASSERT(op.info->scan_types.size() - 1 <= op.info->names.size()); D_ASSERT(op.info->scan_types.size() - 1 <= op.info->column_ids.size()); + // Generate a physical plan for the parallel index creation. + // TABLE SCAN - PROJECTION - (optional) NOT NULL FILTER - (optional) ORDER BY - CREATE INDEX D_ASSERT(op.children.size() == 1); auto table_scan = CreatePlan(*op.children[0]); diff --git a/src/duckdb/src/execution/physical_plan/plan_distinct.cpp b/src/duckdb/src/execution/physical_plan/plan_distinct.cpp index 355169c33..1eee79c82 100644 --- a/src/duckdb/src/execution/physical_plan/plan_distinct.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_distinct.cpp @@ -1,7 +1,7 @@ #include "duckdb/execution/operator/aggregate/physical_hash_aggregate.hpp" #include "duckdb/execution/operator/projection/physical_projection.hpp" #include "duckdb/execution/physical_plan_generator.hpp" -#include "duckdb/function/aggregate/distributive_functions.hpp" +#include "duckdb/function/aggregate/distributive_function_utils.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" #include "duckdb/planner/expression/bound_reference_expression.hpp" #include "duckdb/planner/operator/logical_distinct.hpp" @@ -59,8 +59,9 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalDistinct & first_children.push_back(std::move(bound)); FunctionBinder function_binder(context); - auto first_aggregate = function_binder.BindAggregateFunction( - FirstFun::GetFunction(logical_type), std::move(first_children), nullptr, AggregateType::NON_DISTINCT); + auto first_aggregate = + function_binder.BindAggregateFunction(FirstFunctionGetter::GetFunction(logical_type), + std::move(first_children), nullptr, AggregateType::NON_DISTINCT); first_aggregate->order_bys = op.order_by ? op.order_by->Copy() : nullptr; if (ClientConfig::GetConfig(context).enable_optimizer) { diff --git a/src/duckdb/src/execution/physical_plan/plan_export.cpp b/src/duckdb/src/execution/physical_plan/plan_export.cpp index 0f4237d9c..ff04115e3 100644 --- a/src/duckdb/src/execution/physical_plan/plan_export.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_export.cpp @@ -6,10 +6,6 @@ namespace duckdb { unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalExport &op) { - auto &config = DBConfig::GetConfig(context); - if (!config.options.enable_external_access) { - throw PermissionException("Export is disabled through configuration"); - } auto export_node = make_uniq(op.types, op.function, std::move(op.copy_info), op.estimated_cardinality, std::move(op.exported_tables)); // plan the underlying copy statements, if any diff --git a/src/duckdb/src/execution/physical_plan/plan_filter.cpp b/src/duckdb/src/execution/physical_plan/plan_filter.cpp index ea87121a3..50c1253d0 100644 --- a/src/duckdb/src/execution/physical_plan/plan_filter.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_filter.cpp @@ -20,7 +20,7 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalFilter &op filter->children.push_back(std::move(plan)); plan = std::move(filter); } - if (!op.projection_map.empty()) { + if (op.HasProjectionMap()) { // there is a projection map, generate a physical projection vector> select_list; for (idx_t i = 0; i < op.projection_map.size(); i++) { diff --git a/src/duckdb/src/execution/physical_plan/plan_order.cpp b/src/duckdb/src/execution/physical_plan/plan_order.cpp index a7161ad30..449e7ee81 100644 --- a/src/duckdb/src/execution/physical_plan/plan_order.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_order.cpp @@ -9,16 +9,16 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalOrder &op) auto plan = CreatePlan(*op.children[0]); if (!op.orders.empty()) { - vector projections; - if (op.projections.empty()) { + vector projection_map; + if (op.HasProjectionMap()) { + projection_map = std::move(op.projection_map); + } else { for (idx_t i = 0; i < plan->types.size(); i++) { - projections.push_back(i); + projection_map.push_back(i); } - } else { - projections = std::move(op.projections); } - auto order = - make_uniq(op.types, std::move(op.orders), std::move(projections), op.estimated_cardinality); + auto order = make_uniq(op.types, std::move(op.orders), std::move(projection_map), + op.estimated_cardinality); order->children.push_back(std::move(plan)); plan = std::move(order); } diff --git a/src/duckdb/src/execution/physical_plan/plan_sample.cpp b/src/duckdb/src/execution/physical_plan/plan_sample.cpp index e13ef8eb1..be5578477 100644 --- a/src/duckdb/src/execution/physical_plan/plan_sample.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_sample.cpp @@ -3,6 +3,7 @@ #include "duckdb/execution/physical_plan_generator.hpp" #include "duckdb/planner/operator/logical_sample.hpp" #include "duckdb/common/enum_util.hpp" +#include "duckdb/common/random_engine.hpp" namespace duckdb { @@ -12,6 +13,10 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalSample &op auto plan = CreatePlan(*op.children[0]); unique_ptr sample; + if (!op.sample_options->seed.IsValid()) { + auto &random_engine = RandomEngine::Get(context); + op.sample_options->SetSeed(random_engine.NextRandomInteger()); + } switch (op.sample_options->method) { case SampleMethod::RESERVOIR_SAMPLE: sample = make_uniq(op.types, std::move(op.sample_options), op.estimated_cardinality); @@ -23,9 +28,9 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalSample &op "reservoir sampling or use a sample_size", EnumUtil::ToString(op.sample_options->method)); } - sample = make_uniq(op.types, op.sample_options->method, - op.sample_options->sample_size.GetValue(), - op.sample_options->seed, op.estimated_cardinality); + sample = make_uniq( + op.types, op.sample_options->method, op.sample_options->sample_size.GetValue(), + static_cast(op.sample_options->seed.GetIndex()), op.estimated_cardinality); break; default: throw InternalException("Unimplemented sample method"); diff --git a/src/duckdb/src/execution/physical_plan/plan_simple.cpp b/src/duckdb/src/execution/physical_plan/plan_simple.cpp index a13b607c4..7c03ff4f0 100644 --- a/src/duckdb/src/execution/physical_plan/plan_simple.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_simple.cpp @@ -1,11 +1,10 @@ #include "duckdb/execution/operator/helper/physical_load.hpp" #include "duckdb/execution/operator/helper/physical_transaction.hpp" -#include "duckdb/execution/operator/helper/physical_vacuum.hpp" #include "duckdb/execution/operator/helper/physical_update_extensions.hpp" +#include "duckdb/execution/operator/helper/physical_vacuum.hpp" #include "duckdb/execution/operator/schema/physical_alter.hpp" #include "duckdb/execution/operator/schema/physical_attach.hpp" #include "duckdb/execution/operator/schema/physical_create_schema.hpp" -#include "duckdb/execution/operator/schema/physical_create_sequence.hpp" #include "duckdb/execution/operator/schema/physical_create_view.hpp" #include "duckdb/execution/operator/schema/physical_detach.hpp" #include "duckdb/execution/operator/schema/physical_drop.hpp" diff --git a/src/duckdb/src/execution/radix_partitioned_hashtable.cpp b/src/duckdb/src/execution/radix_partitioned_hashtable.cpp index cfd968100..179f7fd67 100644 --- a/src/duckdb/src/execution/radix_partitioned_hashtable.cpp +++ b/src/duckdb/src/execution/radix_partitioned_hashtable.cpp @@ -119,8 +119,6 @@ struct RadixHTConfig { static constexpr const idx_t MAXIMUM_INITIAL_SINK_RADIX_BITS = 3; //! Maximum Sink radix bits (independent of threads) static constexpr const idx_t MAXIMUM_FINAL_SINK_RADIX_BITS = 7; - //! By how many radix bits to increment if we go external - static constexpr const idx_t EXTERNAL_RADIX_BITS_INCREMENT = 3; //! The global sink state RadixHTGlobalSinkState &sink; @@ -128,8 +126,6 @@ struct RadixHTConfig { atomic sink_radix_bits; //! Maximum Sink radix bits (set based on number of threads) const idx_t maximum_sink_radix_bits; - //! Radix bits if we go external - const idx_t external_radix_bits; public: //! Capacity of HTs during the Sink @@ -153,6 +149,7 @@ class RadixHTGlobalSinkState : public GlobalSinkState { ClientContext &context; //! Temporary memory state for managing this hash table's memory usage unique_ptr temporary_memory_state; + idx_t minimum_reservation; //! The radix HT const RadixPartitionedHashTable &radix_ht; @@ -174,6 +171,7 @@ class RadixHTGlobalSinkState : public GlobalSinkState { unique_ptr uncombined_data; //! Allocators used during the Sink/Finalize vector> stored_allocators; + idx_t stored_allocators_size; //! Partitions that are finalized during GetData vector> partitions; @@ -192,8 +190,9 @@ RadixHTGlobalSinkState::RadixHTGlobalSinkState(ClientContext &context_p, const R : context(context_p), temporary_memory_state(TemporaryMemoryManager::Get(context).Register(context)), radix_ht(radix_ht_p), config(context, *this), finalized(false), external(false), active_threads(0), number_of_threads(NumericCast(TaskScheduler::GetScheduler(context).NumberOfThreads())), - any_combined(false), finalize_done(0), scan_pin_properties(TupleDataPinProperties::DESTROY_AFTER_DONE), - count_before_combining(0), max_partition_size(0) { + any_combined(false), stored_allocators_size(0), finalize_done(0), + scan_pin_properties(TupleDataPinProperties::DESTROY_AFTER_DONE), count_before_combining(0), + max_partition_size(0) { // Compute minimum reservation auto block_alloc_size = BufferManager::GetBufferManager(context).GetBlockAllocSize(); @@ -210,7 +209,7 @@ RadixHTGlobalSinkState::RadixHTGlobalSinkState(ClientContext &context_p, const R // This really is the minimum reservation that we can do auto num_threads = NumericCast(TaskScheduler::GetScheduler(context).NumberOfThreads()); - auto minimum_reservation = num_threads * ht_size; + minimum_reservation = num_threads * ht_size; temporary_memory_state->SetMinimumReservation(minimum_reservation); temporary_memory_state->SetRemainingSizeAndUpdateReservation(context, minimum_reservation); @@ -253,8 +252,7 @@ void RadixHTGlobalSinkState::Destroy() { RadixHTConfig::RadixHTConfig(ClientContext &context, RadixHTGlobalSinkState &sink_p) : sink(sink_p), sink_radix_bits(InitialSinkRadixBits(context)), - maximum_sink_radix_bits(MaximumSinkRadixBits(context)), - external_radix_bits(ExternalRadixBits(maximum_sink_radix_bits)), sink_capacity(SinkCapacity(context)) { + maximum_sink_radix_bits(MaximumSinkRadixBits(context)), sink_capacity(SinkCapacity(context)) { } void RadixHTConfig::SetRadixBits(idx_t radix_bits_p) { @@ -262,7 +260,7 @@ void RadixHTConfig::SetRadixBits(idx_t radix_bits_p) { } bool RadixHTConfig::SetRadixBitsToExternal() { - SetRadixBitsInternal(external_radix_bits, true); + SetRadixBitsInternal(MAXIMUM_FINAL_SINK_RADIX_BITS, true); return sink.external; } @@ -284,21 +282,18 @@ void RadixHTConfig::SetRadixBitsInternal(const idx_t radix_bits_p, bool external sink.external = true; } sink_radix_bits = radix_bits_p; - return; } idx_t RadixHTConfig::InitialSinkRadixBits(ClientContext &context) { const auto active_threads = NumericCast(TaskScheduler::GetScheduler(context).NumberOfThreads()); - return MinValue(RadixPartitioning::RadixBits(NextPowerOfTwo(active_threads)), MAXIMUM_INITIAL_SINK_RADIX_BITS); + return MinValue(RadixPartitioning::RadixBitsOfPowerOfTwo(NextPowerOfTwo(active_threads)), + MAXIMUM_INITIAL_SINK_RADIX_BITS); } idx_t RadixHTConfig::MaximumSinkRadixBits(ClientContext &context) { const auto active_threads = NumericCast(TaskScheduler::GetScheduler(context).NumberOfThreads()); - return MinValue(RadixPartitioning::RadixBits(NextPowerOfTwo(active_threads)), MAXIMUM_FINAL_SINK_RADIX_BITS); -} - -idx_t RadixHTConfig::ExternalRadixBits(const idx_t &maximum_sink_radix_bits_p) { - return MinValue(maximum_sink_radix_bits_p + EXTERNAL_RADIX_BITS_INCREMENT, MAXIMUM_FINAL_SINK_RADIX_BITS); + return MinValue(RadixPartitioning::RadixBitsOfPowerOfTwo(NextPowerOfTwo(active_threads)), + MAXIMUM_FINAL_SINK_RADIX_BITS); } idx_t RadixHTConfig::SinkCapacity(ClientContext &context) { @@ -370,7 +365,9 @@ bool MaybeRepartition(ClientContext &context, RadixHTGlobalSinkState &gstate, Ra // Check if we're approaching the memory limit auto &temporary_memory_state = *gstate.temporary_memory_state; - const auto total_size = partitioned_data->SizeInBytes() + ht.Capacity() * sizeof(ht_entry_t); + const auto aggregate_allocator_size = ht.GetAggregateAllocator()->AllocationSize(); + const auto total_size = + aggregate_allocator_size + partitioned_data->SizeInBytes() + ht.Capacity() * sizeof(ht_entry_t); idx_t thread_limit = temporary_memory_state.GetReservation() / gstate.number_of_threads; if (total_size > thread_limit) { // We're over the thread memory limit @@ -379,7 +376,9 @@ bool MaybeRepartition(ClientContext &context, RadixHTGlobalSinkState &gstate, Ra auto guard = gstate.Lock(); thread_limit = temporary_memory_state.GetReservation() / gstate.number_of_threads; if (total_size > thread_limit) { - // Out-of-core would be triggered below, try to increase the reservation + // Out-of-core would be triggered below, update minimum reservation and try to increase the reservation + temporary_memory_state.SetMinimumReservation(aggregate_allocator_size * gstate.number_of_threads + + gstate.minimum_reservation); auto remaining_size = MaxValue(gstate.number_of_threads * total_size, temporary_memory_state.GetRemainingSize()); temporary_memory_state.SetRemainingSizeAndUpdateReservation(context, 2 * remaining_size); @@ -411,7 +410,7 @@ bool MaybeRepartition(ClientContext &context, RadixHTGlobalSinkState &gstate, Ra } const auto partition_count = partitioned_data->PartitionCount(); - const auto current_radix_bits = RadixPartitioning::RadixBits(partition_count); + const auto current_radix_bits = RadixPartitioning::RadixBitsOfPowerOfTwo(partition_count); D_ASSERT(current_radix_bits <= config.GetRadixBits()); const auto block_size = BufferManager::GetBufferManager(context).GetBlockSize(); @@ -441,7 +440,8 @@ void RadixPartitionedHashTable::Sink(ExecutionContext &context, DataChunk &chunk auto &gstate = input.global_state.Cast(); auto &lstate = input.local_state.Cast(); if (!lstate.ht) { - lstate.ht = CreateHT(context.client, gstate.config.sink_capacity, gstate.config.GetRadixBits()); + lstate.ht = + CreateHT(context.client, GroupedAggregateHashTable::InitialCapacity(), gstate.config.GetRadixBits()); gstate.active_threads++; } @@ -451,11 +451,11 @@ void RadixPartitionedHashTable::Sink(ExecutionContext &context, DataChunk &chunk auto &ht = *lstate.ht; ht.AddChunk(group_chunk, payload_input, filter); - if (ht.Count() + STANDARD_VECTOR_SIZE < ht.ResizeThreshold()) { + if (ht.Count() + STANDARD_VECTOR_SIZE < GroupedAggregateHashTable::ResizeThreshold(gstate.config.sink_capacity)) { return; // We can fit another chunk } - if (gstate.number_of_threads > 2) { + if (gstate.number_of_threads > 2 || gstate.external) { // 'Reset' the HT without taking its data, we can just keep appending to the same collection // This only works because we never resize the HT ht.ClearPointerTable(); @@ -470,6 +470,9 @@ void RadixPartitionedHashTable::Sink(ExecutionContext &context, DataChunk &chunk // We repartitioned, but we didn't clear the pointer table / reset the count because we're on 1 or 2 threads ht.ClearPointerTable(); ht.ResetCount(); + if (gstate.external) { + ht.Resize(gstate.config.sink_capacity); + } } // TODO: combine early and often @@ -507,6 +510,7 @@ void RadixPartitionedHashTable::Combine(ExecutionContext &context, GlobalSinkSta gstate.uncombined_data = std::move(lstate.abandoned_data); } gstate.stored_allocators.emplace_back(ht.GetAggregateAllocator()); + gstate.stored_allocators_size += gstate.stored_allocators.back()->AllocationSize(); } void RadixPartitionedHashTable::Finalize(ClientContext &context, GlobalSinkState &gstate_p) const { @@ -541,7 +545,7 @@ void RadixPartitionedHashTable::Finalize(ClientContext &context, GlobalSinkState } // Minimum of combining one partition at a time - gstate.temporary_memory_state->SetMinimumReservation(gstate.max_partition_size); + gstate.temporary_memory_state->SetMinimumReservation(gstate.stored_allocators_size + gstate.max_partition_size); // Set size to 0 until the scan actually starts gstate.temporary_memory_state->SetZero(); gstate.finalized = true; @@ -558,12 +562,15 @@ idx_t RadixPartitionedHashTable::MaxThreads(GlobalSinkState &sink_p) const { const auto max_threads = MinValue( NumericCast(TaskScheduler::GetScheduler(sink.context).NumberOfThreads()), sink.partitions.size()); - sink.temporary_memory_state->SetRemainingSizeAndUpdateReservation(sink.context, - max_threads * sink.max_partition_size); + sink.temporary_memory_state->SetRemainingSizeAndUpdateReservation( + sink.context, sink.stored_allocators_size + max_threads * sink.max_partition_size); + // we cannot spill aggregate state memory + const auto usable_memory = sink.temporary_memory_state->GetReservation() > sink.stored_allocators_size + ? sink.temporary_memory_state->GetReservation() - sink.max_partition_size + : 0; // This many partitions will fit given our reservation (at least 1)) - const auto partitions_fit = - MaxValue(sink.temporary_memory_state->GetReservation() / sink.max_partition_size, 1); + const auto partitions_fit = MaxValue(usable_memory / sink.max_partition_size, 1); // Mininum of the two return MinValue(partitions_fit, max_threads); diff --git a/src/duckdb/src/execution/window_executor.cpp b/src/duckdb/src/execution/window_executor.cpp index 937741058..efda8639c 100644 --- a/src/duckdb/src/execution/window_executor.cpp +++ b/src/duckdb/src/execution/window_executor.cpp @@ -2,80 +2,198 @@ #include "duckdb/common/operator/add.hpp" #include "duckdb/common/operator/subtract.hpp" +#include "duckdb/planner/expression/bound_reference_expression.hpp" #include "duckdb/common/array.hpp" namespace duckdb { //===--------------------------------------------------------------------===// -// WindowDataChunk +// WindowCollection //===--------------------------------------------------------------------===// -bool WindowDataChunk::IsSimple(const Vector &v) { - switch (v.GetType().InternalType()) { - case PhysicalType::BOOL: - case PhysicalType::UINT8: - case PhysicalType::INT8: - case PhysicalType::UINT16: - case PhysicalType::INT16: - case PhysicalType::UINT32: - case PhysicalType::INT32: - case PhysicalType::UINT64: - case PhysicalType::INT64: - case PhysicalType::FLOAT: - case PhysicalType::DOUBLE: - case PhysicalType::INTERVAL: - case PhysicalType::UINT128: - case PhysicalType::INT128: - return true; - case PhysicalType::LIST: - case PhysicalType::STRUCT: - case PhysicalType::ARRAY: - case PhysicalType::VARCHAR: - case PhysicalType::BIT: - return false; - default: - break; +WindowCollection::WindowCollection(BufferManager &buffer_manager, idx_t count, const vector &types) + : all_valids(types.size()), types(types), count(count), buffer_manager(buffer_manager) { + if (!types.empty()) { + inputs = make_uniq(buffer_manager, types); } - throw InternalException("Unsupported type for WindowDataChunk"); + validities.resize(types.size()); + + // Atomic vectors can't be constructed with a given value + for (auto &all_valid : all_valids) { + all_valid = true; + } } -WindowDataChunk::WindowDataChunk(DataChunk &chunk) : chunk(chunk) { +void WindowCollection::GetCollection(idx_t row_idx, ColumnDataCollectionSpec &spec) { + if (spec.second && row_idx == spec.first + spec.second->Count()) { + return; + } + + lock_guard collection_guard(lock); + + auto collection = make_uniq(buffer_manager, types); + spec = {row_idx, collection.get()}; + Range probe {row_idx, collections.size()}; + auto i = std::upper_bound(ranges.begin(), ranges.end(), probe); + ranges.insert(i, probe); + collections.emplace_back(std::move(collection)); } -void WindowDataChunk::Initialize(Allocator &allocator, const vector &types, idx_t capacity) { - vector new_locks(types.size()); - locks.swap(new_locks); - chunk.Initialize(allocator, types, capacity); - chunk.SetCardinality(capacity); +void WindowCollection::Combine(const ColumnSet &validity_cols) { + lock_guard collection_guard(lock); - is_simple.clear(); - for (const auto &v : chunk.data) { - is_simple.push_back(IsSimple(v)); + // If there are no columns (COUNT(*)) then this is a NOP + if (types.empty()) { + return; + } + + // Have we already combined? + if (inputs->Count()) { + D_ASSERT(collections.empty()); + D_ASSERT(ranges.empty()); + return; + } + + // If there are columns, we should have data + D_ASSERT(!collections.empty()); + D_ASSERT(!ranges.empty()); + + for (auto &range : ranges) { + inputs->Combine(*collections[range.second]); + } + collections.clear(); + ranges.clear(); + + if (validity_cols.empty()) { + return; + } + + D_ASSERT(inputs.get()); + + // Find all columns with NULLs + vector invalid_cols; + for (auto &col_idx : validity_cols) { + if (!all_valids[col_idx]) { + invalid_cols.emplace_back(col_idx); + validities[col_idx].Initialize(inputs->Count()); + } + } + + if (invalid_cols.empty()) { + return; + } + + WindowCursor cursor(*this, invalid_cols); + idx_t target_offset = 0; + while (cursor.Scan()) { + const auto count = cursor.chunk.size(); + for (idx_t i = 0; i < invalid_cols.size(); ++i) { + auto &other = FlatVector::Validity(cursor.chunk.data[i]); + const auto col_idx = invalid_cols[i]; + validities[col_idx].SliceInPlace(other, target_offset, 0, count); + } + target_offset += count; } } -void WindowDataChunk::Copy(DataChunk &input, idx_t begin) { - const auto source_count = input.size(); - const idx_t end = begin + source_count; - const idx_t count = chunk.size(); - D_ASSERT(end <= count); - // Can we overwrite the validity mask in parallel? - bool aligned = IsMaskAligned(begin, end, count); - for (column_t i = 0; i < chunk.data.size(); ++i) { - auto &src = input.data[i]; - auto &dst = chunk.data[i]; - UnifiedVectorFormat sdata; - src.ToUnifiedFormat(count, sdata); - if (is_simple[i] && aligned && sdata.validity.AllValid()) { - VectorOperations::Copy(src, dst, source_count, 0, begin); - } else { - lock_guard column_guard(locks[i]); - VectorOperations::Copy(src, dst, source_count, 0, begin); +WindowBuilder::WindowBuilder(WindowCollection &collection) : collection(collection) { +} + +void WindowBuilder::Sink(DataChunk &chunk, idx_t input_idx) { + // Check whether we need a a new collection + if (!sink.second || input_idx < sink.first || sink.first + sink.second->Count() < input_idx) { + collection.GetCollection(input_idx, sink); + D_ASSERT(sink.second); + sink.second->InitializeAppend(appender); + } + sink.second->Append(appender, chunk); + + // Record NULLs + for (column_t col_idx = 0; col_idx < chunk.ColumnCount(); ++col_idx) { + if (!collection.all_valids[col_idx]) { + continue; } + + // Column was valid, make sure it still is. + UnifiedVectorFormat data; + chunk.data[col_idx].ToUnifiedFormat(chunk.size(), data); + if (!data.validity.AllValid()) { + collection.all_valids[col_idx] = false; + } + } +} + +WindowCursor::WindowCursor(const WindowCollection &paged, vector column_ids) : paged(paged) { + D_ASSERT(paged.collections.empty()); + D_ASSERT(paged.ranges.empty()); + if (column_ids.empty()) { + // For things like COUNT(*) set the state up to contain the whole range + state.segment_index = 0; + state.chunk_index = 0; + state.current_row_index = 0; + state.next_row_index = paged.size(); + state.properties = ColumnDataScanProperties::ALLOW_ZERO_COPY; + chunk.SetCapacity(state.next_row_index); + chunk.SetCardinality(state.next_row_index); + return; + } else if (chunk.data.empty()) { + auto &inputs = paged.inputs; + D_ASSERT(inputs.get()); + inputs->InitializeScan(state, std::move(column_ids)); + inputs->InitializeScanChunk(state, chunk); } } +WindowCursor::WindowCursor(const WindowCollection &paged, column_t col_idx) + : WindowCursor(paged, vector(1, col_idx)) { +} + +struct WindowInputExpression { + WindowInputExpression(DataChunk &chunk, column_t col_idx) + : ptype(PhysicalType::INVALID), scalar(true), chunk(chunk), col_idx(col_idx) { + if (col_idx < chunk.data.size()) { + auto &col = chunk.data[col_idx]; + ptype = col.GetType().InternalType(); + scalar = (col.GetVectorType() == VectorType::CONSTANT_VECTOR); + } + } + + inline PhysicalType InternalType() const { + return ptype; + } + + template + inline T GetCell(idx_t i) const { + D_ASSERT(!chunk.data.empty()); + const auto data = FlatVector::GetData(chunk.data[col_idx]); + return data[scalar ? 0 : i]; + } + + inline bool CellIsNull(idx_t i) const { + D_ASSERT(!chunk.data.empty()); + auto &col = chunk.data[col_idx]; + + if (scalar) { + return ConstantVector::IsNull(col); + } + return FlatVector::IsNull(col, i); + } + + inline void CopyCell(Vector &target, idx_t target_offset, idx_t width = 1) const { + D_ASSERT(!chunk.data.empty()); + auto &source = chunk.data[col_idx]; + auto source_offset = scalar ? 0 : target_offset; + VectorOperations::Copy(source, target, source_offset + width, source_offset, target_offset); + } + +private: + PhysicalType ptype; + bool scalar; + DataChunk &chunk; + const column_t col_idx; +}; + static idx_t FindNextStart(const ValidityMask &mask, idx_t l, const idx_t r, idx_t &n) { if (mask.AllValid()) { auto start = MinValue(l + n - 1, r); @@ -142,46 +260,6 @@ static idx_t FindPrevStart(const ValidityMask &mask, const idx_t l, idx_t r, idx return l; } -template -static T GetCell(const DataChunk &chunk, idx_t column, idx_t index) { - D_ASSERT(chunk.ColumnCount() > column); - auto &source = chunk.data[column]; - const auto data = FlatVector::GetData(source); - return data[index]; -} - -static bool CellIsNull(const DataChunk &chunk, idx_t column, idx_t index) { - D_ASSERT(chunk.ColumnCount() > column); - auto &source = chunk.data[column]; - return FlatVector::IsNull(source, index); -} - -static void CopyCell(const DataChunk &chunk, idx_t column, idx_t index, Vector &target, idx_t target_offset) { - D_ASSERT(chunk.ColumnCount() > column); - auto &source = chunk.data[column]; - VectorOperations::Copy(source, target, index + 1, index, target_offset); -} - -//===--------------------------------------------------------------------===// -// WindowInputColumn -//===--------------------------------------------------------------------===// -WindowInputColumn::WindowInputColumn(optional_ptr expr_p, ClientContext &context, idx_t count) - : expr(expr_p), scalar(expr ? expr->IsScalar() : true), count(count), wtarget(target) { - - if (expr) { - vector types; - types.emplace_back(expr->return_type); - wtarget.Initialize(Allocator::Get(context), types, count); - ptype = expr->return_type.InternalType(); - } -} - -void WindowInputColumn::Copy(DataChunk &input_chunk, idx_t input_idx) { - if (expr && (!input_idx || !scalar)) { - wtarget.Copy(input_chunk, input_idx); - } -} - //===--------------------------------------------------------------------===// // WindowColumnIterator //===--------------------------------------------------------------------===// @@ -194,12 +272,12 @@ struct WindowColumnIterator { using reference = T; using pointer = idx_t; - explicit WindowColumnIterator(const WindowInputColumn &coll_p, pointer pos_p = 0) : coll(&coll_p), pos(pos_p) { + explicit WindowColumnIterator(WindowCursor &coll, pointer pos = 0) : coll(&coll), pos(pos) { } // Forward iterator inline reference operator*() const { - return coll->GetCell(pos); + return coll->GetCell(0, pos); } inline explicit operator pointer() const { return pos; @@ -237,7 +315,7 @@ struct WindowColumnIterator { } inline reference operator[](difference_type m) const { - return coll->GetCell(pos + m); + return coll->GetCell(0, pos + m); } friend inline iterator &operator+(const iterator &a, difference_type n) { @@ -275,7 +353,8 @@ struct WindowColumnIterator { } private: - optional_ptr coll; + // optional_ptr does not allow us to modify this, but the constructor enforces it. + WindowCursor *coll; pointer pos; }; @@ -287,7 +366,7 @@ struct OperationCompare : public std::function { }; template -static idx_t FindTypedRangeBound(const WindowInputColumn &over, const idx_t order_begin, const idx_t order_end, +static idx_t FindTypedRangeBound(WindowCursor &over, const idx_t order_begin, const idx_t order_end, const WindowBoundary range, WindowInputExpression &boundary, const idx_t chunk_idx, const FrameBounds &prev) { D_ASSERT(!boundary.CellIsNull(chunk_idx)); @@ -298,14 +377,14 @@ static idx_t FindTypedRangeBound(const WindowInputColumn &over, const idx_t orde // Check that the value we are searching for is in range. if (range == WindowBoundary::EXPR_PRECEDING_RANGE) { // Preceding but value past the current value - const auto cur_val = over.GetCell(order_end - 1); + const auto cur_val = over.GetCell(0, order_end - 1); if (comp(cur_val, val)) { throw OutOfRangeException("Invalid RANGE PRECEDING value"); } } else { // Following but value before the current value D_ASSERT(range == WindowBoundary::EXPR_FOLLOWING_RANGE); - const auto cur_val = over.GetCell(order_begin); + const auto cur_val = over.GetCell(0, order_begin); if (comp(val, cur_val)) { throw OutOfRangeException("Invalid RANGE FOLLOWING value"); } @@ -318,14 +397,14 @@ static idx_t FindTypedRangeBound(const WindowInputColumn &over, const idx_t orde WindowColumnIterator end(over, order_end); if (prev.start < prev.end) { if (order_begin < prev.start && prev.start < order_end) { - const auto first = over.GetCell(prev.start); + const auto first = over.GetCell(0, prev.start); if (!comp(val, first)) { // prev.first <= val, so we can start further forward begin += UnsafeNumericCast(prev.start - order_begin); } } if (order_begin < prev.end && prev.end < order_end) { - const auto second = over.GetCell(prev.end - 1); + const auto second = over.GetCell(0, prev.end - 1); if (!comp(second, val)) { // val <= prev.second, so we can end further back // (prev.second is the largest peer) @@ -342,13 +421,10 @@ static idx_t FindTypedRangeBound(const WindowInputColumn &over, const idx_t orde } template -static idx_t FindRangeBound(const WindowInputColumn &over, const idx_t order_begin, const idx_t order_end, +static idx_t FindRangeBound(WindowCursor &over, const idx_t order_begin, const idx_t order_end, const WindowBoundary range, WindowInputExpression &boundary, const idx_t chunk_idx, const FrameBounds &prev) { - D_ASSERT(boundary.chunk.ColumnCount() == 1); - D_ASSERT(boundary.chunk.data[0].GetType().InternalType() == over.ptype); - - switch (over.ptype) { + switch (boundary.InternalType()) { case PhysicalType::INT8: return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); case PhysicalType::INT16: @@ -383,7 +459,7 @@ static idx_t FindRangeBound(const WindowInputColumn &over, const idx_t order_beg } template -static idx_t FindOrderedRangeBound(const WindowInputColumn &over, const OrderType range_sense, const idx_t order_begin, +static idx_t FindOrderedRangeBound(WindowCursor &over, const OrderType range_sense, const idx_t order_begin, const idx_t order_end, const WindowBoundary range, WindowInputExpression &boundary, const idx_t chunk_idx, const FrameBounds &prev) { switch (range_sense) { @@ -397,44 +473,40 @@ static idx_t FindOrderedRangeBound(const WindowInputColumn &over, const OrderTyp } struct WindowBoundariesState { - static inline bool IsScalar(const unique_ptr &expr) { - return !expr || expr->IsScalar(); - } - static inline bool BoundaryNeedsPeer(const WindowBoundary &boundary) { - switch (boundary) { - case WindowBoundary::CURRENT_ROW_RANGE: - case WindowBoundary::EXPR_PRECEDING_RANGE: - case WindowBoundary::EXPR_FOLLOWING_RANGE: - return true; - default: - return false; - } - } + WindowBoundariesState(const BoundWindowExpression &wexpr, const idx_t input_size); - static inline bool ExpressionNeedsPeer(const ExpressionType &type) { - switch (type) { - case ExpressionType::WINDOW_RANK: - case ExpressionType::WINDOW_RANK_DENSE: - case ExpressionType::WINDOW_PERCENT_RANK: - case ExpressionType::WINDOW_CUME_DIST: - return true; - default: - return false; + // Generate the partition start indices + void PartitionBegin(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, + const ValidityMask &partition_mask); + void PartitionEnd(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, + const ValidityMask &partition_mask); + void PeerBegin(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, + const ValidityMask &partition_mask, const ValidityMask &order_mask); + void PeerEnd(DataChunk &bounds, idx_t row_idx, const idx_t count, const ValidityMask &partition_mask, + const ValidityMask &order_mask); + void ValidBegin(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, + const ValidityMask &partition_mask, const ValidityMask &order_mask, + optional_ptr range); + void ValidEnd(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, const ValidityMask &partition_mask, + const ValidityMask &order_mask, optional_ptr range); + void FrameBegin(DataChunk &bounds, idx_t row_idx, const idx_t count, WindowInputExpression &boundary_begin, + optional_ptr range); + void FrameEnd(DataChunk &bounds, idx_t row_idx, const idx_t count, WindowInputExpression &boundary_end, + optional_ptr range); + + static void ClampFrame(const idx_t count, idx_t *values, const idx_t *begin, const idx_t *end) { + for (idx_t i = 0; i < count; ++i) { + values[i] = MinValue(MaxValue(values[i], begin[i]), end[i]); } } - WindowBoundariesState(const BoundWindowExpression &wexpr, const idx_t input_size); - - void Update(const idx_t row_idx, const WindowInputColumn &range_collection, const idx_t chunk_idx, - WindowInputExpression &boundary_start, WindowInputExpression &boundary_end, - const ValidityMask &partition_mask, const ValidityMask &order_mask); - - void Bounds(DataChunk &bounds, idx_t row_idx, const WindowInputColumn &range, const idx_t count, + void Bounds(DataChunk &bounds, idx_t row_idx, optional_ptr range, const idx_t count, WindowInputExpression &boundary_start, WindowInputExpression &boundary_end, const ValidityMask &partition_mask, const ValidityMask &order_mask); // Cached lookups + WindowBoundsSet required; const ExpressionType type; const idx_t input_size; const WindowBoundary start_boundary; @@ -444,70 +516,358 @@ struct WindowBoundariesState { const OrderType range_sense; const bool has_preceding_range; const bool has_following_range; - const bool needs_peer; + // Carried between chunks idx_t next_pos = 0; idx_t partition_start = 0; idx_t partition_end = 0; idx_t peer_start = 0; - idx_t peer_end = 0; idx_t valid_start = 0; idx_t valid_end = 0; - idx_t window_start = NumericLimits::Maximum(); - idx_t window_end = NumericLimits::Maximum(); + FrameBounds prev; }; //===--------------------------------------------------------------------===// // WindowBoundariesState //===--------------------------------------------------------------------===// -void WindowBoundariesState::Update(const idx_t row_idx, const WindowInputColumn &range_collection, - const idx_t chunk_idx, WindowInputExpression &boundary_start, +static bool HasPrecedingRange(const BoundWindowExpression &wexpr) { + return (wexpr.start == WindowBoundary::EXPR_PRECEDING_RANGE || wexpr.end == WindowBoundary::EXPR_PRECEDING_RANGE); +} + +static bool HasFollowingRange(const BoundWindowExpression &wexpr) { + return (wexpr.start == WindowBoundary::EXPR_FOLLOWING_RANGE || wexpr.end == WindowBoundary::EXPR_FOLLOWING_RANGE); +} + +static WindowBoundsSet GetWindowBounds(const BoundWindowExpression &wexpr) { + const auto partition_count = wexpr.partitions.size(); + const auto order_count = wexpr.orders.size(); + + WindowBoundsSet result; + switch (wexpr.type) { + case ExpressionType::WINDOW_ROW_NUMBER: + result.insert(PARTITION_BEGIN); + break; + case ExpressionType::WINDOW_RANK_DENSE: + case ExpressionType::WINDOW_RANK: + result.insert(PARTITION_BEGIN); + result.insert(PEER_BEGIN); + break; + case ExpressionType::WINDOW_PERCENT_RANK: + result.insert(PARTITION_BEGIN); + result.insert(PARTITION_END); + result.insert(PEER_BEGIN); + break; + case ExpressionType::WINDOW_CUME_DIST: + result.insert(PARTITION_BEGIN); + result.insert(PARTITION_END); + result.insert(PEER_END); + break; + case ExpressionType::WINDOW_NTILE: + case ExpressionType::WINDOW_LEAD: + case ExpressionType::WINDOW_LAG: + result.insert(PARTITION_BEGIN); + result.insert(PARTITION_END); + break; + case ExpressionType::WINDOW_FIRST_VALUE: + case ExpressionType::WINDOW_LAST_VALUE: + case ExpressionType::WINDOW_NTH_VALUE: + case ExpressionType::WINDOW_AGGREGATE: + result.insert(PARTITION_BEGIN); + result.insert(PARTITION_END); + result.insert(FRAME_BEGIN); + result.insert(FRAME_END); + + // if we have EXCLUDE GROUP / TIES, we also need peer boundaries + if (wexpr.exclude_clause != WindowExcludeMode::NO_OTHER) { + result.insert(PEER_BEGIN); + result.insert(PEER_END); + } + + // If the frames are RANGE, then we need peer boundaries + // If they are preceding or following, we also need to know + // where the valid values begin or end. + switch (wexpr.start) { + case WindowBoundary::CURRENT_ROW_RANGE: + result.insert(PEER_BEGIN); + break; + case WindowBoundary::EXPR_PRECEDING_RANGE: + result.insert(PEER_BEGIN); + result.insert(VALID_BEGIN); + result.insert(VALID_END); + break; + case WindowBoundary::EXPR_FOLLOWING_RANGE: + result.insert(PEER_BEGIN); + result.insert(VALID_END); + break; + default: + break; + } + + switch (wexpr.end) { + case WindowBoundary::CURRENT_ROW_RANGE: + result.insert(PEER_END); + break; + case WindowBoundary::EXPR_PRECEDING_RANGE: + result.insert(PEER_END); + result.insert(VALID_BEGIN); + break; + case WindowBoundary::EXPR_FOLLOWING_RANGE: + result.insert(PEER_END); + result.insert(VALID_BEGIN); + result.insert(VALID_END); + break; + default: + break; + } + break; + default: + throw InternalException("Window aggregate type %s", ExpressionTypeToString(wexpr.type)); + } + + // Internal dependencies + if (result.count(VALID_END)) { + result.insert(PARTITION_END); + if (HasFollowingRange(wexpr)) { + result.insert(VALID_BEGIN); + } + } + if (result.count(VALID_BEGIN)) { + result.insert(PARTITION_BEGIN); + result.insert(PARTITION_END); + } + if (result.count(PEER_END)) { + result.insert(PARTITION_END); + if (order_count) { + result.insert(PEER_BEGIN); + } + } + if (result.count(PARTITION_END) && (partition_count + order_count)) { + result.insert(PARTITION_BEGIN); + } + + return result; +} + +WindowBoundariesState::WindowBoundariesState(const BoundWindowExpression &wexpr, const idx_t input_size) + : required(GetWindowBounds(wexpr)), type(wexpr.type), input_size(input_size), start_boundary(wexpr.start), + end_boundary(wexpr.end), partition_count(wexpr.partitions.size()), order_count(wexpr.orders.size()), + range_sense(wexpr.orders.empty() ? OrderType::INVALID : wexpr.orders[0].type), + has_preceding_range(HasPrecedingRange(wexpr)), has_following_range(HasFollowingRange(wexpr)) { +} + +void WindowBoundariesState::Bounds(DataChunk &bounds, idx_t row_idx, optional_ptr range, + const idx_t count, WindowInputExpression &boundary_start, WindowInputExpression &boundary_end, const ValidityMask &partition_mask, const ValidityMask &order_mask) { + bounds.Reset(); + D_ASSERT(bounds.ColumnCount() == 8); - if (partition_count + order_count > 0) { + const auto is_jump = (next_pos != row_idx); + if (required.count(PARTITION_BEGIN)) { + PartitionBegin(bounds, row_idx, count, is_jump, partition_mask); + } + if (required.count(PARTITION_END)) { + PartitionEnd(bounds, row_idx, count, is_jump, partition_mask); + } + if (required.count(PEER_BEGIN)) { + PeerBegin(bounds, row_idx, count, is_jump, partition_mask, order_mask); + } + if (required.count(PEER_END)) { + PeerEnd(bounds, row_idx, count, partition_mask, order_mask); + } + if (required.count(VALID_BEGIN)) { + ValidBegin(bounds, row_idx, count, is_jump, partition_mask, order_mask, range); + } + if (required.count(VALID_END)) { + ValidEnd(bounds, row_idx, count, is_jump, partition_mask, order_mask, range); + } + if (required.count(FRAME_BEGIN)) { + FrameBegin(bounds, row_idx, count, boundary_start, range); + } + if (required.count(FRAME_END)) { + FrameEnd(bounds, row_idx, count, boundary_end, range); + } + next_pos += count; + bounds.SetCardinality(count); +} + +void WindowBoundariesState::PartitionBegin(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, + const ValidityMask &partition_mask) { + auto partition_begin_data = FlatVector::GetData(bounds.data[PARTITION_BEGIN]); + + // OVER() + if (partition_count + order_count == 0) { + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + partition_begin_data[chunk_idx] = 0; + } + return; + } + + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { // determine partition and peer group boundaries to ultimately figure out window size const auto is_same_partition = !partition_mask.RowIsValidUnsafe(row_idx); - const auto is_peer = !order_mask.RowIsValidUnsafe(row_idx); - const auto is_jump = (next_pos != row_idx); // when the partition changes, recompute the boundaries if (!is_same_partition || is_jump) { if (is_jump) { idx_t n = 1; partition_start = FindPrevStart(partition_mask, 0, row_idx + 1, n); - n = 1; - peer_start = FindPrevStart(order_mask, 0, row_idx + 1, n); + is_jump = false; } else { partition_start = row_idx; - peer_start = row_idx; } + } + partition_begin_data[chunk_idx] = partition_start; + } +} + +void WindowBoundariesState::PartitionEnd(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, + const ValidityMask &partition_mask) { + auto partition_end_data = FlatVector::GetData(bounds.data[PARTITION_END]); + + // OVER() + if (partition_count + order_count == 0) { + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + partition_end_data[chunk_idx] = input_size; + } + return; + } + + auto partition_begin_data = FlatVector::GetData(bounds.data[PARTITION_BEGIN]); + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + // determine partition and peer group boundaries to ultimately figure out window size + const auto is_same_partition = !partition_mask.RowIsValidUnsafe(row_idx); + + // when the partition changes, recompute the boundaries + if (!is_same_partition || is_jump) { // find end of partition partition_end = input_size; if (partition_count) { + const auto partition_begin = partition_begin_data[chunk_idx]; idx_t n = 1; - partition_end = FindNextStart(partition_mask, partition_start + 1, input_size, n); + partition_end = FindNextStart(partition_mask, partition_begin + 1, input_size, n); + } + is_jump = false; + } + + partition_end_data[chunk_idx] = partition_end; + } +} + +void WindowBoundariesState::PeerBegin(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, + const ValidityMask &partition_mask, const ValidityMask &order_mask) { + + auto peer_begin_data = FlatVector::GetData(bounds.data[PEER_BEGIN]); + + // OVER() + if (partition_count + order_count == 0) { + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + peer_begin_data[chunk_idx] = 0; + } + return; + } + + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + // determine partition and peer group boundaries to ultimately figure out window size + const auto is_same_partition = !partition_mask.RowIsValidUnsafe(row_idx); + const auto is_peer = !order_mask.RowIsValidUnsafe(row_idx); + + // when the partition changes, recompute the boundaries + if (!is_same_partition || is_jump) { + // find end of partition + if (is_jump) { + idx_t n = 1; + peer_start = FindPrevStart(order_mask, 0, row_idx + 1, n); + } else { + peer_start = row_idx; } + is_jump = false; + } else if (!is_peer) { + peer_start = row_idx; + } + + peer_begin_data[chunk_idx] = peer_start; + } +} + +void WindowBoundariesState::PeerEnd(DataChunk &bounds, idx_t row_idx, const idx_t count, + const ValidityMask &partition_mask, const ValidityMask &order_mask) { + // OVER() + if (!order_count) { + bounds.data[PEER_END].Reference(bounds.data[PARTITION_END]); + return; + } + + auto partition_end_data = FlatVector::GetData(bounds.data[PARTITION_END]); + auto peer_begin_data = FlatVector::GetData(bounds.data[PEER_BEGIN]); + auto peer_end_data = FlatVector::GetData(bounds.data[PEER_END]); + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + idx_t n = 1; + const auto peer_start = peer_begin_data[chunk_idx]; + const auto partition_end = partition_end_data[chunk_idx]; + peer_end_data[chunk_idx] = FindNextStart(order_mask, peer_start + 1, partition_end, n); + } +} + +void WindowBoundariesState::ValidBegin(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, + const ValidityMask &partition_mask, const ValidityMask &order_mask, + optional_ptr range) { + auto partition_begin_data = FlatVector::GetData(bounds.data[PARTITION_BEGIN]); + auto partition_end_data = FlatVector::GetData(bounds.data[PARTITION_END]); + auto valid_begin_data = FlatVector::GetData(bounds.data[VALID_BEGIN]); + // OVER() + D_ASSERT(partition_count + order_count != 0); + D_ASSERT(range); + + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + const auto is_same_partition = !partition_mask.RowIsValidUnsafe(row_idx); + + if (!is_same_partition || is_jump) { // Find valid ordering values for the new partition // so we can exclude NULLs from RANGE expression computations - valid_start = partition_start; - valid_end = partition_end; + valid_start = partition_begin_data[chunk_idx]; + const auto valid_end = partition_end_data[chunk_idx]; if ((valid_start < valid_end) && has_preceding_range) { // Exclude any leading NULLs - if (range_collection.CellIsNull(valid_start)) { + if (range->CellIsNull(0, valid_start)) { idx_t n = 1; valid_start = FindNextStart(order_mask, valid_start + 1, valid_end, n); } } + } + + valid_begin_data[chunk_idx] = valid_start; + } +} + +void WindowBoundariesState::ValidEnd(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, + const ValidityMask &partition_mask, const ValidityMask &order_mask, + optional_ptr range) { + auto partition_end_data = FlatVector::GetData(bounds.data[PARTITION_END]); + auto valid_begin_data = FlatVector::GetData(bounds.data[VALID_BEGIN]); + auto valid_end_data = FlatVector::GetData(bounds.data[VALID_END]); + + // OVER() + D_ASSERT(partition_count + order_count != 0); + D_ASSERT(range); + + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + const auto is_same_partition = !partition_mask.RowIsValidUnsafe(row_idx); + + if (!is_same_partition || is_jump) { + // Find valid ordering values for the new partition + // so we can exclude NULLs from RANGE expression computations + valid_end = partition_end_data[chunk_idx]; if ((valid_start < valid_end) && has_following_range) { // Exclude any trailing NULLs - if (range_collection.CellIsNull(valid_end - 1)) { + const auto valid_start = valid_begin_data[chunk_idx]; + if (range->CellIsNull(0, valid_end - 1)) { idx_t n = 1; valid_end = FindPrevStart(order_mask, valid_start, valid_end, n); } @@ -516,190 +876,179 @@ void WindowBoundariesState::Update(const idx_t row_idx, const WindowInputColumn prev.start = valid_start; prev.end = valid_end; } - } else if (!is_peer) { - peer_start = row_idx; - } - - if (needs_peer) { - peer_end = partition_end; - if (order_count) { - idx_t n = 1; - peer_end = FindNextStart(order_mask, peer_start + 1, partition_end, n); - } } - } else { - // OVER() - partition_end = input_size; - peer_end = partition_end; + valid_end_data[chunk_idx] = valid_end; } - next_pos = row_idx + 1; +} + +void WindowBoundariesState::FrameBegin(DataChunk &bounds, idx_t row_idx, const idx_t count, + WindowInputExpression &boundary_begin, optional_ptr range) { + auto partition_begin_data = FlatVector::GetData(bounds.data[PARTITION_BEGIN]); + auto partition_end_data = FlatVector::GetData(bounds.data[PARTITION_END]); + auto peer_begin_data = FlatVector::GetData(bounds.data[PEER_BEGIN]); + auto valid_begin_data = FlatVector::GetData(bounds.data[VALID_BEGIN]); + auto valid_end_data = FlatVector::GetData(bounds.data[VALID_END]); + auto frame_begin_data = FlatVector::GetData(bounds.data[FRAME_BEGIN]); + + idx_t window_start = NumericLimits::Maximum(); - // determine window boundaries depending on the type of expression switch (start_boundary) { case WindowBoundary::UNBOUNDED_PRECEDING: - window_start = partition_start; - break; + bounds.data[FRAME_BEGIN].Reference(bounds.data[PARTITION_BEGIN]); + // No need to clamp + return; case WindowBoundary::CURRENT_ROW_ROWS: - window_start = row_idx; + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + frame_begin_data[chunk_idx] = row_idx; + } break; case WindowBoundary::CURRENT_ROW_RANGE: - window_start = peer_start; + bounds.data[FRAME_BEGIN].Reference(bounds.data[PEER_BEGIN]); + frame_begin_data = peer_begin_data; break; - case WindowBoundary::EXPR_PRECEDING_ROWS: { - int64_t computed_start; - if (!TrySubtractOperator::Operation(static_cast(row_idx), boundary_start.GetCell(chunk_idx), - computed_start)) { - window_start = partition_start; - } else { - window_start = UnsafeNumericCast(MaxValue(computed_start, 0)); + case WindowBoundary::EXPR_PRECEDING_ROWS: + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + int64_t computed_start; + if (!TrySubtractOperator::Operation(static_cast(row_idx), + boundary_begin.GetCell(chunk_idx), computed_start)) { + window_start = partition_begin_data[chunk_idx]; + } else { + window_start = UnsafeNumericCast(MaxValue(computed_start, 0)); + } + frame_begin_data[chunk_idx] = window_start; } break; - } - case WindowBoundary::EXPR_FOLLOWING_ROWS: { - int64_t computed_start; - if (!TryAddOperator::Operation(static_cast(row_idx), boundary_start.GetCell(chunk_idx), - computed_start)) { - window_start = partition_start; - } else { - window_start = UnsafeNumericCast(MaxValue(computed_start, 0)); + case WindowBoundary::EXPR_FOLLOWING_ROWS: + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + int64_t computed_start; + if (!TryAddOperator::Operation(static_cast(row_idx), boundary_begin.GetCell(chunk_idx), + computed_start)) { + window_start = partition_begin_data[chunk_idx]; + } else { + window_start = UnsafeNumericCast(MaxValue(computed_start, 0)); + } + frame_begin_data[chunk_idx] = window_start; } break; - } - case WindowBoundary::EXPR_PRECEDING_RANGE: { - if (boundary_start.CellIsNull(chunk_idx)) { - window_start = peer_start; - } else { - prev.start = FindOrderedRangeBound(range_collection, range_sense, valid_start, row_idx + 1, - start_boundary, boundary_start, chunk_idx, prev); - window_start = prev.start; + case WindowBoundary::EXPR_PRECEDING_RANGE: + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + if (boundary_begin.CellIsNull(chunk_idx)) { + window_start = peer_begin_data[chunk_idx]; + } else { + const auto valid_start = valid_begin_data[chunk_idx]; + prev.end = valid_end_data[chunk_idx]; + window_start = FindOrderedRangeBound(*range, range_sense, valid_start, row_idx + 1, + start_boundary, boundary_begin, chunk_idx, prev); + prev.start = window_start; + } + frame_begin_data[chunk_idx] = window_start; } break; - } - case WindowBoundary::EXPR_FOLLOWING_RANGE: { - if (boundary_start.CellIsNull(chunk_idx)) { - window_start = peer_start; - } else { - prev.start = FindOrderedRangeBound(range_collection, range_sense, row_idx, valid_end, start_boundary, - boundary_start, chunk_idx, prev); - window_start = prev.start; + case WindowBoundary::EXPR_FOLLOWING_RANGE: + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + if (boundary_begin.CellIsNull(chunk_idx)) { + window_start = peer_begin_data[chunk_idx]; + } else { + const auto valid_end = valid_end_data[chunk_idx]; + prev.end = valid_end; + window_start = FindOrderedRangeBound(*range, range_sense, row_idx, valid_end, start_boundary, + boundary_begin, chunk_idx, prev); + prev.start = window_start; + } + frame_begin_data[chunk_idx] = window_start; } break; - } default: throw InternalException("Unsupported window start boundary"); } + ClampFrame(count, frame_begin_data, partition_begin_data, partition_end_data); +} + +void WindowBoundariesState::FrameEnd(DataChunk &bounds, idx_t row_idx, const idx_t count, + WindowInputExpression &boundary_end, optional_ptr range) { + auto partition_begin_data = FlatVector::GetData(bounds.data[PARTITION_BEGIN]); + auto partition_end_data = FlatVector::GetData(bounds.data[PARTITION_END]); + auto peer_end_data = FlatVector::GetData(bounds.data[PEER_END]); + auto valid_begin_data = FlatVector::GetData(bounds.data[VALID_BEGIN]); + auto valid_end_data = FlatVector::GetData(bounds.data[VALID_END]); + auto frame_end_data = FlatVector::GetData(bounds.data[FRAME_END]); + + idx_t window_end = NumericLimits::Maximum(); + switch (end_boundary) { case WindowBoundary::CURRENT_ROW_ROWS: - window_end = row_idx + 1; + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + frame_end_data[chunk_idx] = row_idx + 1; + } break; case WindowBoundary::CURRENT_ROW_RANGE: - window_end = peer_end; + bounds.data[FRAME_END].Reference(bounds.data[PEER_END]); + frame_end_data = peer_end_data; break; case WindowBoundary::UNBOUNDED_FOLLOWING: - window_end = partition_end; - break; + bounds.data[FRAME_END].Reference(bounds.data[PARTITION_END]); + // No need to clamp + return; case WindowBoundary::EXPR_PRECEDING_ROWS: { - int64_t computed_start; - if (!TrySubtractOperator::Operation(int64_t(row_idx + 1), boundary_end.GetCell(chunk_idx), - computed_start)) { - window_end = partition_end; - } else { - window_end = UnsafeNumericCast(MaxValue(computed_start, 0)); + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + int64_t computed_start; + if (!TrySubtractOperator::Operation(int64_t(row_idx + 1), boundary_end.GetCell(chunk_idx), + computed_start)) { + window_end = partition_end_data[chunk_idx]; + } else { + window_end = UnsafeNumericCast(MaxValue(computed_start, 0)); + } + frame_end_data[chunk_idx] = window_end; } break; } - case WindowBoundary::EXPR_FOLLOWING_ROWS: { - int64_t computed_start; - if (!TryAddOperator::Operation(int64_t(row_idx + 1), boundary_end.GetCell(chunk_idx), - computed_start)) { - window_end = partition_end; - } else { - window_end = UnsafeNumericCast(MaxValue(computed_start, 0)); + case WindowBoundary::EXPR_FOLLOWING_ROWS: + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + int64_t computed_start; + if (!TryAddOperator::Operation(int64_t(row_idx + 1), boundary_end.GetCell(chunk_idx), + computed_start)) { + window_end = partition_end_data[chunk_idx]; + } else { + window_end = UnsafeNumericCast(MaxValue(computed_start, 0)); + } + frame_end_data[chunk_idx] = window_end; } break; - } - case WindowBoundary::EXPR_PRECEDING_RANGE: { - if (boundary_end.CellIsNull(chunk_idx)) { - window_end = peer_end; - } else { - prev.end = FindOrderedRangeBound(range_collection, range_sense, valid_start, row_idx + 1, - end_boundary, boundary_end, chunk_idx, prev); - window_end = prev.end; + case WindowBoundary::EXPR_PRECEDING_RANGE: + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + if (boundary_end.CellIsNull(chunk_idx)) { + window_end = peer_end_data[chunk_idx]; + } else { + const auto valid_start = valid_begin_data[chunk_idx]; + prev.start = valid_start; + window_end = FindOrderedRangeBound(*range, range_sense, valid_start, row_idx + 1, end_boundary, + boundary_end, chunk_idx, prev); + prev.end = window_end; + } + frame_end_data[chunk_idx] = window_end; } break; - } - case WindowBoundary::EXPR_FOLLOWING_RANGE: { - if (boundary_end.CellIsNull(chunk_idx)) { - window_end = peer_end; - } else { - prev.end = FindOrderedRangeBound(range_collection, range_sense, row_idx, valid_end, end_boundary, - boundary_end, chunk_idx, prev); - window_end = prev.end; + case WindowBoundary::EXPR_FOLLOWING_RANGE: + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + if (boundary_end.CellIsNull(chunk_idx)) { + window_end = peer_end_data[chunk_idx]; + } else { + const auto valid_end = valid_end_data[chunk_idx]; + prev.start = valid_begin_data[chunk_idx]; + window_end = FindOrderedRangeBound(*range, range_sense, row_idx, valid_end, end_boundary, + boundary_end, chunk_idx, prev); + prev.end = window_end; + } + frame_end_data[chunk_idx] = window_end; } break; - } default: throw InternalException("Unsupported window end boundary"); } - // clamp windows to partitions if they should exceed - if (window_start < partition_start) { - window_start = partition_start; - } - if (window_start > partition_end) { - window_start = partition_end; - } - if (window_end < partition_start) { - window_end = partition_start; - } - if (window_end > partition_end) { - window_end = partition_end; - } -} - -static bool HasPrecedingRange(const BoundWindowExpression &wexpr) { - return (wexpr.start == WindowBoundary::EXPR_PRECEDING_RANGE || wexpr.end == WindowBoundary::EXPR_PRECEDING_RANGE); -} - -static bool HasFollowingRange(const BoundWindowExpression &wexpr) { - return (wexpr.start == WindowBoundary::EXPR_FOLLOWING_RANGE || wexpr.end == WindowBoundary::EXPR_FOLLOWING_RANGE); -} - -WindowBoundariesState::WindowBoundariesState(const BoundWindowExpression &wexpr, const idx_t input_size) - : type(wexpr.type), input_size(input_size), start_boundary(wexpr.start), end_boundary(wexpr.end), - partition_count(wexpr.partitions.size()), order_count(wexpr.orders.size()), - range_sense(wexpr.orders.empty() ? OrderType::INVALID : wexpr.orders[0].type), - has_preceding_range(HasPrecedingRange(wexpr)), has_following_range(HasFollowingRange(wexpr)), - // if we have EXCLUDE GROUP / TIES, we also need peer boundaries - needs_peer(BoundaryNeedsPeer(wexpr.end) || ExpressionNeedsPeer(wexpr.type) || - wexpr.exclude_clause >= WindowExcludeMode::GROUP) { -} - -void WindowBoundariesState::Bounds(DataChunk &bounds, idx_t row_idx, const WindowInputColumn &range, const idx_t count, - WindowInputExpression &boundary_start, WindowInputExpression &boundary_end, - const ValidityMask &partition_mask, const ValidityMask &order_mask) { - bounds.Reset(); - D_ASSERT(bounds.ColumnCount() == 6); - auto partition_begin_data = FlatVector::GetData(bounds.data[PARTITION_BEGIN]); - auto partition_end_data = FlatVector::GetData(bounds.data[PARTITION_END]); - auto peer_begin_data = FlatVector::GetData(bounds.data[PEER_BEGIN]); - auto peer_end_data = FlatVector::GetData(bounds.data[PEER_END]); - auto window_begin_data = FlatVector::GetData(bounds.data[WINDOW_BEGIN]); - auto window_end_data = FlatVector::GetData(bounds.data[WINDOW_END]); - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - Update(row_idx, range, chunk_idx, boundary_start, boundary_end, partition_mask, order_mask); - *partition_begin_data++ = partition_start; - *partition_end_data++ = partition_end; - if (needs_peer) { - *peer_begin_data++ = peer_start; - *peer_end_data++ = peer_end; - } - *window_begin_data++ = UnsafeNumericCast(window_start); - *window_end_data++ = UnsafeNumericCast(window_end); - } - bounds.SetCardinality(count); + ClampFrame(count, frame_end_data, partition_begin_data, partition_end_data); } //===--------------------------------------------------------------------===// @@ -711,34 +1060,30 @@ class WindowExecutorBoundsState : public WindowExecutorLocalState { ~WindowExecutorBoundsState() override { } - virtual void UpdateBounds(idx_t row_idx, DataChunk &input_chunk, const WindowInputColumn &range); + virtual void UpdateBounds(WindowExecutorGlobalState &gstate, idx_t row_idx, DataChunk &eval_chunk, + optional_ptr range); // Frame management const ValidityMask &partition_mask; const ValidityMask &order_mask; DataChunk bounds; WindowBoundariesState state; - - // evaluate boundaries if present. Parser has checked boundary types. - WindowInputExpression boundary_start; - WindowInputExpression boundary_end; }; WindowExecutorBoundsState::WindowExecutorBoundsState(const WindowExecutorGlobalState &gstate) : WindowExecutorLocalState(gstate), partition_mask(gstate.partition_mask), order_mask(gstate.order_mask), - state(gstate.executor.wexpr, gstate.payload_count), - boundary_start(gstate.executor.wexpr.start_expr.get(), gstate.executor.context), - boundary_end(gstate.executor.wexpr.end_expr.get(), gstate.executor.context) { - vector bounds_types(6, LogicalType(LogicalTypeId::UBIGINT)); + state(gstate.executor.wexpr, gstate.payload_count) { + vector bounds_types(8, LogicalType(LogicalTypeId::UBIGINT)); bounds.Initialize(Allocator::Get(gstate.executor.context), bounds_types); } -void WindowExecutorBoundsState::UpdateBounds(idx_t row_idx, DataChunk &input_chunk, const WindowInputColumn &range) { +void WindowExecutorBoundsState::UpdateBounds(WindowExecutorGlobalState &gstate, idx_t row_idx, DataChunk &eval_chunk, + optional_ptr range) { // Evaluate the row-level arguments - boundary_start.Execute(input_chunk); - boundary_end.Execute(input_chunk); + WindowInputExpression boundary_start(eval_chunk, gstate.executor.boundary_start_idx); + WindowInputExpression boundary_end(eval_chunk, gstate.executor.boundary_end_idx); - const auto count = input_chunk.size(); + const auto count = eval_chunk.size(); bounds.Reset(); state.Bounds(bounds, row_idx, range, count, boundary_start, boundary_end, partition_mask, order_mask); } @@ -778,8 +1123,6 @@ class ExclusionFilter { ValidityMask mask; //! The validity mask upon which mask is based const ValidityMask &mask_src; - //! A validity mask consisting of only one entries (needed if no ignore_nulls mask is supplied) - ValidityMask all_ones_mask; }; void ExclusionFilter::FetchFromSource(idx_t begin, idx_t end) { @@ -842,63 +1185,83 @@ void ExclusionFilter::ResetMask(idx_t row_idx, idx_t offset) { } } -//===--------------------------------------------------------------------===// -// WindowExecutor -//===--------------------------------------------------------------------===// -static void PrepareInputExpressions(const vector> &exprs, ExpressionExecutor &executor, - DataChunk &chunk) { - if (exprs.empty()) { - return; +column_t WindowSharedExpressions::RegisterExpr(const unique_ptr &expr, Shared &shared) { + auto pexpr = expr.get(); + if (!pexpr) { + return DConstants::INVALID_INDEX; } + // We need to make separate columns for volatile arguments + const auto is_volatile = expr->IsVolatile(); + auto i = shared.columns.find(*pexpr); + if (i != shared.columns.end() && !is_volatile) { + return i->second.front(); + } + + // New column, find maximum column number + column_t result = shared.size++; + shared.columns[*pexpr].emplace_back(result); + + return result; +} + +vector WindowSharedExpressions::GetSortedExpressions(Shared &shared) { + vector sorted(shared.size, nullptr); + for (auto &col : shared.columns) { + auto &expr = col.first.get(); + for (auto col_idx : col.second) { + sorted[col_idx] = &expr; + } + } + + return sorted; +} +void WindowSharedExpressions::PrepareExecutors(Shared &shared, ExpressionExecutor &exec, DataChunk &chunk) { + const auto sorted = GetSortedExpressions(shared); vector types; - for (idx_t expr_idx = 0; expr_idx < exprs.size(); ++expr_idx) { - types.push_back(exprs[expr_idx]->return_type); - executor.AddExpression(*exprs[expr_idx]); + for (auto expr : sorted) { + exec.AddExpression(*expr); + types.emplace_back(expr->return_type); } if (!types.empty()) { - auto &allocator = executor.GetAllocator(); - chunk.Initialize(allocator, types); + chunk.Initialize(exec.GetAllocator(), types); } } -WindowExecutor::WindowExecutor(BoundWindowExpression &wexpr, ClientContext &context) : wexpr(wexpr), context(context) { +//===--------------------------------------------------------------------===// +// WindowExecutor +//===--------------------------------------------------------------------===// +WindowExecutor::WindowExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared) + : wexpr(wexpr), context(context), + range_expr((HasPrecedingRange(wexpr) || HasFollowingRange(wexpr)) ? wexpr.orders[0].expression.get() : nullptr) { + if (range_expr) { + range_idx = shared.RegisterCollection(wexpr.orders[0].expression, false); + } + + boundary_start_idx = shared.RegisterEvaluate(wexpr.start_expr); + boundary_end_idx = shared.RegisterEvaluate(wexpr.end_expr); } WindowExecutorGlobalState::WindowExecutorGlobalState(const WindowExecutor &executor, const idx_t payload_count, const ValidityMask &partition_mask, const ValidityMask &order_mask) - : executor(executor), payload_count(payload_count), partition_mask(partition_mask), order_mask(order_mask), - range((HasPrecedingRange(executor.wexpr) || HasFollowingRange(executor.wexpr)) - ? executor.wexpr.orders[0].expression.get() - : nullptr, - executor.context, payload_count) { + : executor(executor), payload_count(payload_count), partition_mask(partition_mask), order_mask(order_mask) { for (const auto &child : executor.wexpr.children) { arg_types.emplace_back(child->return_type); } } -WindowExecutorLocalState::WindowExecutorLocalState(const WindowExecutorGlobalState &gstate) - : payload_executor(gstate.executor.context), range_executor(gstate.executor.context) { - // TODO: child may be a scalar, don't need to materialize the whole collection then - - // evaluate inner expressions of window functions, could be more complex - PrepareInputExpressions(gstate.executor.wexpr.children, payload_executor, payload_chunk); - - if (gstate.range.expr) { - vector types; - types.emplace_back(gstate.range.expr->return_type); - range_executor.AddExpression(*gstate.range.expr); +WindowExecutorLocalState::WindowExecutorLocalState(const WindowExecutorGlobalState &gstate) { +} - auto &allocator = range_executor.GetAllocator(); - range_chunk.Initialize(allocator, types); - } +void WindowExecutorLocalState::Sink(WindowExecutorGlobalState &gstate, DataChunk &sink_chunk, DataChunk &coll_chunk, + idx_t input_idx) { } -void WindowExecutorLocalState::Sink(WindowExecutorGlobalState &gstate, DataChunk &input_chunk, idx_t input_idx) { - if (gstate.range.expr && (!input_idx || !gstate.range.scalar)) { - range_executor.Execute(input_chunk, range_chunk); - gstate.range.Copy(range_chunk, input_idx); +void WindowExecutorLocalState::Finalize(WindowExecutorGlobalState &gstate, CollectionPtr collection) { + const auto range_idx = gstate.executor.range_idx; + if (range_idx != DConstants::INVALID_INDEX) { + range_cursor = make_uniq(*collection, range_idx); } } @@ -912,9 +1275,14 @@ unique_ptr WindowExecutor::GetLocalState(const WindowE return make_uniq(gstate); } -void WindowExecutor::Sink(DataChunk &input_chunk, const idx_t input_idx, const idx_t total_count, +void WindowExecutor::Sink(DataChunk &sink_chunk, DataChunk &coll_chunk, const idx_t input_idx, WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const { - lstate.Sink(gstate, input_chunk, input_idx); + lstate.Sink(gstate, sink_chunk, coll_chunk, input_idx); +} + +void WindowExecutor::Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + CollectionPtr collection) const { + lstate.Finalize(gstate, collection); } //===--------------------------------------------------------------------===// @@ -922,22 +1290,17 @@ void WindowExecutor::Sink(DataChunk &input_chunk, const idx_t input_idx, const i //===--------------------------------------------------------------------===// class WindowAggregateExecutorGlobalState : public WindowExecutorGlobalState { public: - bool IsConstantAggregate(); - bool IsCustomAggregate(); - bool IsDistinctAggregate(); - WindowAggregateExecutorGlobalState(const WindowAggregateExecutor &executor, const idx_t payload_count, const ValidityMask &partition_mask, const ValidityMask &order_mask); - // aggregate computation algorithm - unique_ptr aggregator; // aggregate global state unique_ptr gsink; -}; -bool WindowAggregateExecutorGlobalState::IsConstantAggregate() { - const auto &wexpr = executor.wexpr; + // the filter reference expression. + const Expression *filter_ref; +}; +bool WindowAggregateExecutor::IsConstantAggregate() { if (!wexpr.aggregate) { return false; } @@ -995,9 +1358,7 @@ bool WindowAggregateExecutorGlobalState::IsConstantAggregate() { return true; } -bool WindowAggregateExecutorGlobalState::IsDistinctAggregate() { - const auto &wexpr = executor.wexpr; - +bool WindowAggregateExecutor::IsDistinctAggregate() { if (!wexpr.aggregate) { return false; } @@ -1005,10 +1366,7 @@ bool WindowAggregateExecutorGlobalState::IsDistinctAggregate() { return wexpr.distinct; } -bool WindowAggregateExecutorGlobalState::IsCustomAggregate() { - const auto &wexpr = executor.wexpr; - const auto &mode = reinterpret_cast(executor).mode; - +bool WindowAggregateExecutor::IsCustomAggregate() { if (!wexpr.aggregate) { return false; } @@ -1020,53 +1378,56 @@ bool WindowAggregateExecutorGlobalState::IsCustomAggregate() { return (mode < WindowAggregationMode::COMBINE); } -void WindowExecutor::Evaluate(idx_t row_idx, DataChunk &input_chunk, Vector &result, WindowExecutorLocalState &lstate, +void WindowExecutor::Evaluate(idx_t row_idx, DataChunk &eval_chunk, Vector &result, WindowExecutorLocalState &lstate, WindowExecutorGlobalState &gstate) const { auto &lbstate = lstate.Cast(); - lbstate.UpdateBounds(row_idx, input_chunk, gstate.range); + lbstate.UpdateBounds(gstate, row_idx, eval_chunk, lstate.range_cursor); - const auto count = input_chunk.size(); - EvaluateInternal(gstate, lstate, result, count, row_idx); + const auto count = eval_chunk.size(); + EvaluateInternal(gstate, lstate, eval_chunk, result, count, row_idx); result.Verify(count); } WindowAggregateExecutor::WindowAggregateExecutor(BoundWindowExpression &wexpr, ClientContext &context, - WindowAggregationMode mode) - : WindowExecutor(wexpr, context), mode(mode) { -} - -WindowAggregateExecutorGlobalState::WindowAggregateExecutorGlobalState(const WindowAggregateExecutor &executor, - const idx_t group_count, - const ValidityMask &partition_mask, - const ValidityMask &order_mask) - : WindowExecutorGlobalState(executor, group_count, partition_mask, order_mask) { - auto &wexpr = executor.wexpr; - auto &context = executor.context; + WindowSharedExpressions &shared, WindowAggregationMode mode) + : WindowExecutor(wexpr, context, shared), mode(mode) { auto return_type = wexpr.return_type; - const auto &mode = reinterpret_cast(executor).mode; // Force naive for SEPARATE mode or for (currently!) unsupported functionality const auto force_naive = !ClientConfig::GetConfig(context).enable_optimizer || mode == WindowAggregationMode::SEPARATE; - AggregateObject aggr(wexpr); if (force_naive || (wexpr.distinct && wexpr.exclude_clause != WindowExcludeMode::NO_OTHER)) { - aggregator = make_uniq(aggr, arg_types, return_type, wexpr.exclude_clause); + aggregator = make_uniq(wexpr, wexpr.exclude_clause, shared); } else if (IsDistinctAggregate()) { // build a merge sort tree // see https://dl.acm.org/doi/pdf/10.1145/3514221.3526184 - aggregator = make_uniq(aggr, arg_types, return_type, wexpr.exclude_clause, context); + aggregator = make_uniq(wexpr, wexpr.exclude_clause, shared, context); } else if (IsConstantAggregate()) { - aggregator = make_uniq(aggr, arg_types, return_type, wexpr.exclude_clause); + aggregator = make_uniq(wexpr, wexpr.exclude_clause, shared); } else if (IsCustomAggregate()) { - aggregator = make_uniq(aggr, arg_types, return_type, wexpr.exclude_clause); + aggregator = make_uniq(wexpr, wexpr.exclude_clause, shared); } else { // build a segment tree for frame-adhering aggregates // see http://www.vldb.org/pvldb/vol8/p1058-leis.pdf - aggregator = make_uniq(aggr, arg_types, return_type, mode, wexpr.exclude_clause); + aggregator = make_uniq(wexpr, mode, wexpr.exclude_clause, shared); } - gsink = aggregator->GetGlobalState(group_count, partition_mask); + // Compute the FILTER with the other eval columns. + // Anyone who needs it can then convert it to the form they need. + if (wexpr.filter_expr) { + const auto filter_idx = shared.RegisterSink(wexpr.filter_expr); + filter_ref = make_uniq(wexpr.filter_expr->return_type, filter_idx); + } +} + +WindowAggregateExecutorGlobalState::WindowAggregateExecutorGlobalState(const WindowAggregateExecutor &executor, + const idx_t group_count, + const ValidityMask &partition_mask, + const ValidityMask &order_mask) + : WindowExecutorGlobalState(executor, group_count, partition_mask, order_mask), + filter_ref(executor.filter_ref.get()) { + gsink = executor.aggregator->GetGlobalState(executor.context, group_count, partition_mask); } unique_ptr WindowAggregateExecutor::GetGlobalState(const idx_t payload_count, @@ -1084,9 +1445,9 @@ class WindowAggregateExecutorLocalState : public WindowExecutorBoundsState { aggregator_state = aggregator.GetLocalState(*gastate.gsink); // evaluate the FILTER clause and stuff it into a large mask for compactness and reuse - auto &wexpr = gstate.executor.wexpr; - if (wexpr.filter_expr) { - filter_executor.AddExpression(*wexpr.filter_expr); + auto filter_ref = gastate.filter_ref; + if (filter_ref) { + filter_executor.AddExpression(*filter_ref); filter_sel.Initialize(STANDARD_VECTOR_SIZE); } } @@ -1102,43 +1463,29 @@ class WindowAggregateExecutorLocalState : public WindowExecutorBoundsState { unique_ptr WindowAggregateExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) const { - auto &gastate = gstate.Cast(); - auto res = make_uniq(gstate, *gastate.aggregator); - return std::move(res); + return make_uniq(gstate, *aggregator); } -void WindowAggregateExecutor::Sink(DataChunk &input_chunk, const idx_t input_idx, const idx_t total_count, +void WindowAggregateExecutor::Sink(DataChunk &sink_chunk, DataChunk &coll_chunk, const idx_t input_idx, WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const { auto &gastate = gstate.Cast(); auto &lastate = lstate.Cast(); auto &filter_sel = lastate.filter_sel; auto &filter_executor = lastate.filter_executor; - auto &payload_executor = lastate.payload_executor; - auto &payload_chunk = lastate.payload_chunk; - auto &aggregator = gastate.aggregator; idx_t filtered = 0; SelectionVector *filtering = nullptr; - if (wexpr.filter_expr) { + if (gastate.filter_ref) { filtering = &filter_sel; - filtered = filter_executor.SelectExpression(input_chunk, filter_sel); - } - - if (!wexpr.children.empty()) { - payload_chunk.Reset(); - payload_executor.Execute(input_chunk, payload_chunk); - payload_chunk.Verify(); - } else if (aggregator) { - // Zero-argument aggregate (e.g., COUNT(*) - payload_chunk.SetCardinality(input_chunk); + filtered = filter_executor.SelectExpression(sink_chunk, filter_sel); } D_ASSERT(aggregator); auto &gestate = *gastate.gsink; auto &lestate = *lastate.aggregator_state; - aggregator->Sink(gestate, lestate, payload_chunk, input_idx, filtering, filtered); + aggregator->Sink(gestate, lestate, sink_chunk, coll_chunk, input_idx, filtering, filtered); - WindowExecutor::Sink(input_chunk, input_idx, total_count, gstate, lstate); + WindowExecutor::Sink(sink_chunk, coll_chunk, input_idx, gstate, lstate); } static void ApplyWindowStats(const WindowBoundary &boundary, FrameDelta &delta, BaseStatistics *base, bool is_start) { @@ -1199,9 +1546,11 @@ static void ApplyWindowStats(const WindowBoundary &boundary, FrameDelta &delta, } } -void WindowAggregateExecutor::Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const { +void WindowAggregateExecutor::Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + CollectionPtr collection) const { + WindowExecutor::Finalize(gstate, lstate, collection); + auto &gastate = gstate.Cast(); - auto &aggregator = gastate.aggregator; auto &gsink = gastate.gsink; D_ASSERT(aggregator); @@ -1221,14 +1570,14 @@ void WindowAggregateExecutor::Finalize(WindowExecutorGlobalState &gstate, Window ApplyWindowStats(wexpr.end, stats[1], base, false); auto &lastate = lstate.Cast(); - aggregator->Finalize(*gsink, *lastate.aggregator_state, stats); + aggregator->Finalize(*gsink, *lastate.aggregator_state, collection, stats); } void WindowAggregateExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - Vector &result, idx_t count, idx_t row_idx) const { + DataChunk &eval_chunk, Vector &result, idx_t count, + idx_t row_idx) const { auto &gastate = gstate.Cast(); auto &lastate = lstate.Cast(); - auto &aggregator = gastate.aggregator; auto &gsink = gastate.gsink; D_ASSERT(aggregator); @@ -1240,12 +1589,14 @@ void WindowAggregateExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate //===--------------------------------------------------------------------===// // WindowRowNumberExecutor //===--------------------------------------------------------------------===// -WindowRowNumberExecutor::WindowRowNumberExecutor(BoundWindowExpression &wexpr, ClientContext &context) - : WindowExecutor(wexpr, context) { +WindowRowNumberExecutor::WindowRowNumberExecutor(BoundWindowExpression &wexpr, ClientContext &context, + WindowSharedExpressions &shared) + : WindowExecutor(wexpr, context, shared) { } void WindowRowNumberExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - Vector &result, idx_t count, idx_t row_idx) const { + DataChunk &eval_chunk, Vector &result, idx_t count, + idx_t row_idx) const { auto &lbstate = lstate.Cast(); auto partition_begin = FlatVector::GetData(lbstate.bounds.data[PARTITION_BEGIN]); auto rdata = FlatVector::GetData(result); @@ -1283,8 +1634,9 @@ void WindowPeerState::NextRank(idx_t partition_begin, idx_t peer_begin, idx_t ro rank_equal++; } -WindowRankExecutor::WindowRankExecutor(BoundWindowExpression &wexpr, ClientContext &context) - : WindowExecutor(wexpr, context) { +WindowRankExecutor::WindowRankExecutor(BoundWindowExpression &wexpr, ClientContext &context, + WindowSharedExpressions &shared) + : WindowExecutor(wexpr, context, shared) { } unique_ptr WindowRankExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) const { @@ -1292,7 +1644,7 @@ unique_ptr WindowRankExecutor::GetLocalState(const Win } void WindowRankExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - Vector &result, idx_t count, idx_t row_idx) const { + DataChunk &eval_chunk, Vector &result, idx_t count, idx_t row_idx) const { auto &lpeer = lstate.Cast(); auto partition_begin = FlatVector::GetData(lpeer.bounds.data[PARTITION_BEGIN]); auto peer_begin = FlatVector::GetData(lpeer.bounds.data[PEER_BEGIN]); @@ -1308,8 +1660,9 @@ void WindowRankExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, Win } } -WindowDenseRankExecutor::WindowDenseRankExecutor(BoundWindowExpression &wexpr, ClientContext &context) - : WindowExecutor(wexpr, context) { +WindowDenseRankExecutor::WindowDenseRankExecutor(BoundWindowExpression &wexpr, ClientContext &context, + WindowSharedExpressions &shared) + : WindowExecutor(wexpr, context, shared) { } unique_ptr @@ -1318,7 +1671,8 @@ WindowDenseRankExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) } void WindowDenseRankExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - Vector &result, idx_t count, idx_t row_idx) const { + DataChunk &eval_chunk, Vector &result, idx_t count, + idx_t row_idx) const { auto &lpeer = lstate.Cast(); auto &order_mask = gstate.order_mask; @@ -1371,8 +1725,9 @@ void WindowDenseRankExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate } } -WindowPercentRankExecutor::WindowPercentRankExecutor(BoundWindowExpression &wexpr, ClientContext &context) - : WindowExecutor(wexpr, context) { +WindowPercentRankExecutor::WindowPercentRankExecutor(BoundWindowExpression &wexpr, ClientContext &context, + WindowSharedExpressions &shared) + : WindowExecutor(wexpr, context, shared) { } unique_ptr @@ -1381,7 +1736,8 @@ WindowPercentRankExecutor::GetLocalState(const WindowExecutorGlobalState &gstate } void WindowPercentRankExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - Vector &result, idx_t count, idx_t row_idx) const { + DataChunk &eval_chunk, Vector &result, idx_t count, + idx_t row_idx) const { auto &lpeer = lstate.Cast(); auto partition_begin = FlatVector::GetData(lpeer.bounds.data[PARTITION_BEGIN]); auto partition_end = FlatVector::GetData(lpeer.bounds.data[PARTITION_END]); @@ -1403,12 +1759,13 @@ void WindowPercentRankExecutor::EvaluateInternal(WindowExecutorGlobalState &gsta //===--------------------------------------------------------------------===// // WindowCumeDistExecutor //===--------------------------------------------------------------------===// -WindowCumeDistExecutor::WindowCumeDistExecutor(BoundWindowExpression &wexpr, ClientContext &context) - : WindowExecutor(wexpr, context) { +WindowCumeDistExecutor::WindowCumeDistExecutor(BoundWindowExpression &wexpr, ClientContext &context, + WindowSharedExpressions &shared) + : WindowExecutor(wexpr, context, shared) { } void WindowCumeDistExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - Vector &result, idx_t count, idx_t row_idx) const { + DataChunk &eval_chunk, Vector &result, idx_t count, idx_t row_idx) const { auto &lbstate = lstate.Cast(); auto partition_begin = FlatVector::GetData(lbstate.bounds.data[PARTITION_BEGIN]); auto partition_end = FlatVector::GetData(lbstate.bounds.data[PARTITION_END]); @@ -1427,40 +1784,26 @@ void WindowCumeDistExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, class WindowValueGlobalState : public WindowExecutorGlobalState { public: - WindowValueGlobalState(const WindowExecutor &executor, const idx_t payload_count, + using WindowCollectionPtr = unique_ptr; + WindowValueGlobalState(const WindowValueExecutor &executor, const idx_t payload_count, const ValidityMask &partition_mask, const ValidityMask &order_mask) - : WindowExecutorGlobalState(executor, payload_count, partition_mask, order_mask), - payload_collection(payload_data), ignore_nulls(&no_nulls) - - { - if (!arg_types.empty()) { - payload_collection.Initialize(Allocator::Get(executor.context), arg_types, payload_count); - } - - auto &wexpr = executor.wexpr; - if (wexpr.ignore_nulls) { - switch (wexpr.type) { - case ExpressionType::WINDOW_LEAD: - case ExpressionType::WINDOW_LAG: - case ExpressionType::WINDOW_FIRST_VALUE: - case ExpressionType::WINDOW_LAST_VALUE: - case ExpressionType::WINDOW_NTH_VALUE: - ignore_nulls = &FlatVector::Validity(payload_collection.chunk.data[0]); - break; - default: - break; - } + : WindowExecutorGlobalState(executor, payload_count, partition_mask, order_mask), ignore_nulls(&all_valid), + child_idx(executor.child_idx) { + } + + void Finalize(CollectionPtr collection) { + if (child_idx != DConstants::INVALID_INDEX && executor.wexpr.ignore_nulls) { + lock_guard ignore_nulls_guard(lock); + ignore_nulls = &collection->validities[child_idx]; } } - // The partition values - DataChunk payload_data; - // The partition values - WindowDataChunk payload_collection; - // Mask to use for exclusion if we are not ignoring NULLs - ValidityMask no_nulls; // IGNORE NULLS + mutex lock; + ValidityMask all_valid; optional_ptr ignore_nulls; + + const column_t child_idx; }; //===--------------------------------------------------------------------===// @@ -1474,23 +1817,24 @@ class WindowValueLocalState : public WindowExecutorBoundsState { : WindowExecutorBoundsState(gvstate), gvstate(gvstate) { } - //! Lazily initialize for value Execute - void Initialize(); + //! Finish the sinking and prepare to scan + void Finalize(WindowExecutorGlobalState &gstate, CollectionPtr collection) override; //! The corresponding global value state const WindowValueGlobalState &gvstate; - //! Lazy initialization flag - bool initialized = false; //! The exclusion filter handler unique_ptr exclusion_filter; //! The validity mask that combines both the NULLs and exclusion information optional_ptr ignore_nulls_exclude; + + //! The state used for reading the collection + unique_ptr cursor; }; -void WindowValueLocalState::Initialize() { - if (initialized) { - return; - } +void WindowValueLocalState::Finalize(WindowExecutorGlobalState &gstate, CollectionPtr collection) { + WindowExecutorBoundsState::Finalize(gstate, collection); + + // Set up the IGNORE NULLS state auto ignore_nulls = gvstate.ignore_nulls; if (gvstate.executor.wexpr.exclude_clause == WindowExcludeMode::NO_OTHER) { exclusion_filter = nullptr; @@ -1502,18 +1846,35 @@ void WindowValueLocalState::Initialize() { ignore_nulls_exclude = &exclusion_filter->mask; } - initialized = true; + // Prepare to scan + if (!cursor && gvstate.child_idx != DConstants::INVALID_INDEX) { + cursor = make_uniq(*collection, gvstate.child_idx); + } } //===--------------------------------------------------------------------===// // WindowValueExecutor //===--------------------------------------------------------------------===// -WindowValueExecutor::WindowValueExecutor(BoundWindowExpression &wexpr, ClientContext &context) - : WindowExecutor(wexpr, context) { +WindowValueExecutor::WindowValueExecutor(BoundWindowExpression &wexpr, ClientContext &context, + WindowSharedExpressions &shared) + : WindowExecutor(wexpr, context, shared) { + + // The children have to be handled separately because only the first one is global + if (!wexpr.children.empty()) { + child_idx = shared.RegisterCollection(wexpr.children[0], wexpr.ignore_nulls); + + if (wexpr.children.size() > 1) { + nth_idx = shared.RegisterEvaluate(wexpr.children[1]); + } + } + + offset_idx = shared.RegisterEvaluate(wexpr.offset_expr); + default_idx = shared.RegisterEvaluate(wexpr.default_expr); } -WindowNtileExecutor::WindowNtileExecutor(BoundWindowExpression &wexpr, ClientContext &context) - : WindowValueExecutor(wexpr, context) { +WindowNtileExecutor::WindowNtileExecutor(BoundWindowExpression &wexpr, ClientContext &context, + WindowSharedExpressions &shared) + : WindowValueExecutor(wexpr, context, shared) { } unique_ptr WindowValueExecutor::GetGlobalState(const idx_t payload_count, @@ -1522,22 +1883,12 @@ unique_ptr WindowValueExecutor::GetGlobalState(const return make_uniq(*this, payload_count, partition_mask, order_mask); } -void WindowValueExecutor::Sink(DataChunk &input_chunk, const idx_t input_idx, const idx_t total_count, - WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const { +void WindowValueExecutor::Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + CollectionPtr collection) const { auto &gvstate = gstate.Cast(); - auto &lvstate = lstate.Cast(); - auto &payload_chunk = lvstate.payload_chunk; - auto &payload_executor = lvstate.payload_executor; - auto &payload_collection = gvstate.payload_collection; - - if (!wexpr.children.empty()) { - payload_chunk.Reset(); - payload_executor.Execute(input_chunk, payload_chunk); - payload_chunk.Verify(); - payload_collection.Copy(payload_chunk, input_idx); - } + gvstate.Finalize(collection); - WindowExecutor::Sink(input_chunk, input_idx, total_count, gstate, lstate); + WindowExecutor::Finalize(gstate, lstate, collection); } unique_ptr WindowValueExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) const { @@ -1546,19 +1897,17 @@ unique_ptr WindowValueExecutor::GetLocalState(const Wi } void WindowNtileExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - Vector &result, idx_t count, idx_t row_idx) const { - auto &gvstate = gstate.Cast(); - auto &payload_collection = gvstate.payload_collection.chunk; - D_ASSERT(payload_collection.ColumnCount() == 1); - auto &lbstate = lstate.Cast(); - auto partition_begin = FlatVector::GetData(lbstate.bounds.data[PARTITION_BEGIN]); - auto partition_end = FlatVector::GetData(lbstate.bounds.data[PARTITION_END]); + DataChunk &eval_chunk, Vector &result, idx_t count, idx_t row_idx) const { + auto &lvstate = lstate.Cast(); + auto &cursor = *lvstate.cursor; + auto partition_begin = FlatVector::GetData(lvstate.bounds.data[PARTITION_BEGIN]); + auto partition_end = FlatVector::GetData(lvstate.bounds.data[PARTITION_END]); auto rdata = FlatVector::GetData(result); for (idx_t i = 0; i < count; ++i, ++row_idx) { - if (CellIsNull(payload_collection, 0, row_idx)) { + if (cursor.CellIsNull(0, row_idx)) { FlatVector::SetNull(result, i, true); } else { - auto n_param = GetCell(payload_collection, 0, row_idx); + auto n_param = cursor.GetCell(0, row_idx); if (n_param < 1) { throw InvalidInputException("Argument for ntile must be greater than zero"); } @@ -1597,30 +1946,13 @@ void WindowNtileExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, Wi //===--------------------------------------------------------------------===// class WindowLeadLagLocalState : public WindowValueLocalState { public: - explicit WindowLeadLagLocalState(const WindowValueGlobalState &gstate) - : WindowValueLocalState(gstate), - leadlag_offset(gstate.executor.wexpr.offset_expr.get(), gstate.executor.context), - leadlag_default(gstate.executor.wexpr.default_expr.get(), gstate.executor.context) { + explicit WindowLeadLagLocalState(const WindowValueGlobalState &gstate) : WindowValueLocalState(gstate) { } - - void UpdateBounds(idx_t row_idx, DataChunk &input_chunk, const WindowInputColumn &range) override; - -public: - // LEAD/LAG Evaluation - WindowInputExpression leadlag_offset; - WindowInputExpression leadlag_default; }; -void WindowLeadLagLocalState::UpdateBounds(idx_t row_idx, DataChunk &input_chunk, const WindowInputColumn &range) { - // Evaluate the row-level arguments - leadlag_offset.Execute(input_chunk); - leadlag_default.Execute(input_chunk); - - WindowExecutorBoundsState::UpdateBounds(row_idx, input_chunk, range); -} - -WindowLeadLagExecutor::WindowLeadLagExecutor(BoundWindowExpression &wexpr, ClientContext &context) - : WindowValueExecutor(wexpr, context) { +WindowLeadLagExecutor::WindowLeadLagExecutor(BoundWindowExpression &wexpr, ClientContext &context, + WindowSharedExpressions &shared) + : WindowValueExecutor(wexpr, context, shared) { } unique_ptr @@ -1630,11 +1962,14 @@ WindowLeadLagExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) co } void WindowLeadLagExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - Vector &result, idx_t count, idx_t row_idx) const { + DataChunk &eval_chunk, Vector &result, idx_t count, idx_t row_idx) const { auto &gvstate = gstate.Cast(); - auto &payload_collection = gvstate.payload_collection.chunk; auto &ignore_nulls = gvstate.ignore_nulls; auto &llstate = lstate.Cast(); + auto &cursor = *llstate.cursor; + + WindowInputExpression leadlag_offset(eval_chunk, offset_idx); + WindowInputExpression leadlag_default(eval_chunk, default_idx); bool can_shift = ignore_nulls->AllValid(); if (wexpr.offset_expr) { @@ -1650,7 +1985,7 @@ void WindowLeadLagExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, for (idx_t i = 0; i < count;) { int64_t offset = 1; if (wexpr.offset_expr) { - offset = llstate.leadlag_offset.GetCell(i); + offset = leadlag_offset.GetCell(i); } int64_t val_idx = (int64_t)row_idx; if (wexpr.type == ExpressionType::WINDOW_LEAD) { @@ -1674,16 +2009,24 @@ void WindowLeadLagExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, const auto target_limit = MinValue(partition_end[i], row_end) - row_idx; if (!delta) { // Copy source[index:index+width] => result[i:] - const auto index = NumericCast(val_idx); + auto index = NumericCast(val_idx); const auto source_limit = partition_end[i] - index; - const auto width = MinValue(source_limit, target_limit); - auto &source = payload_collection.data[0]; - VectorOperations::Copy(source, result, index + width, index, i); - i += width; - row_idx += width; + auto width = MinValue(source_limit, target_limit); + // We may have to scan multiple blocks here, so loop until we have copied everything + const idx_t col_idx = 0; + while (width) { + const auto source_offset = cursor.Seek(index); + auto &source = cursor.chunk.data[col_idx]; + const auto copied = MinValue(cursor.chunk.size() - source_offset, width); + VectorOperations::Copy(source, result, source_offset + copied, source_offset, i); + i += copied; + row_idx += copied; + index += copied; + width -= copied; + } } else if (wexpr.default_expr) { const auto width = MinValue(delta, target_limit); - llstate.leadlag_default.CopyCell(result, i, width); + leadlag_default.CopyCell(result, i, width); i += width; row_idx += width; } else { @@ -1693,9 +2036,9 @@ void WindowLeadLagExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, } } else { if (!delta) { - CopyCell(payload_collection, 0, NumericCast(val_idx), result, i); + cursor.CopyCell(0, NumericCast(val_idx), result, i); } else if (wexpr.default_expr) { - llstate.leadlag_default.CopyCell(result, i); + leadlag_default.CopyCell(result, i); } else { FlatVector::SetNull(result, i, true); } @@ -1705,18 +2048,18 @@ void WindowLeadLagExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, } } -WindowFirstValueExecutor::WindowFirstValueExecutor(BoundWindowExpression &wexpr, ClientContext &context) - : WindowValueExecutor(wexpr, context) { +WindowFirstValueExecutor::WindowFirstValueExecutor(BoundWindowExpression &wexpr, ClientContext &context, + WindowSharedExpressions &shared) + : WindowValueExecutor(wexpr, context, shared) { } void WindowFirstValueExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - Vector &result, idx_t count, idx_t row_idx) const { - auto &gvstate = gstate.Cast(); - auto &payload_collection = gvstate.payload_collection.chunk; + DataChunk &eval_chunk, Vector &result, idx_t count, + idx_t row_idx) const { auto &lvstate = lstate.Cast(); - lvstate.Initialize(); - auto window_begin = FlatVector::GetData(lvstate.bounds.data[WINDOW_BEGIN]); - auto window_end = FlatVector::GetData(lvstate.bounds.data[WINDOW_END]); + auto &cursor = *lvstate.cursor; + auto window_begin = FlatVector::GetData(lvstate.bounds.data[FRAME_BEGIN]); + auto window_end = FlatVector::GetData(lvstate.bounds.data[FRAME_END]); for (idx_t i = 0; i < count; ++i, ++row_idx) { if (lvstate.exclusion_filter) { @@ -1731,7 +2074,7 @@ void WindowFirstValueExecutor::EvaluateInternal(WindowExecutorGlobalState &gstat idx_t n = 1; const auto first_idx = FindNextStart(*lvstate.ignore_nulls_exclude, window_begin[i], window_end[i], n); if (!n) { - CopyCell(payload_collection, 0, first_idx, result, i); + cursor.CopyCell(0, first_idx, result, i); } else { FlatVector::SetNull(result, i, true); } @@ -1742,18 +2085,18 @@ void WindowFirstValueExecutor::EvaluateInternal(WindowExecutorGlobalState &gstat } } -WindowLastValueExecutor::WindowLastValueExecutor(BoundWindowExpression &wexpr, ClientContext &context) - : WindowValueExecutor(wexpr, context) { +WindowLastValueExecutor::WindowLastValueExecutor(BoundWindowExpression &wexpr, ClientContext &context, + WindowSharedExpressions &shared) + : WindowValueExecutor(wexpr, context, shared) { } void WindowLastValueExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - Vector &result, idx_t count, idx_t row_idx) const { - auto &gvstate = gstate.Cast(); - auto &payload_collection = gvstate.payload_collection.chunk; + DataChunk &eval_chunk, Vector &result, idx_t count, + idx_t row_idx) const { auto &lvstate = lstate.Cast(); - lvstate.Initialize(); - auto window_begin = FlatVector::GetData(lvstate.bounds.data[WINDOW_BEGIN]); - auto window_end = FlatVector::GetData(lvstate.bounds.data[WINDOW_END]); + auto &cursor = *lvstate.cursor; + auto window_begin = FlatVector::GetData(lvstate.bounds.data[FRAME_BEGIN]); + auto window_end = FlatVector::GetData(lvstate.bounds.data[FRAME_END]); for (idx_t i = 0; i < count; ++i, ++row_idx) { if (lvstate.exclusion_filter) { @@ -1767,7 +2110,7 @@ void WindowLastValueExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate idx_t n = 1; const auto last_idx = FindPrevStart(*lvstate.ignore_nulls_exclude, window_begin[i], window_end[i], n); if (!n) { - CopyCell(payload_collection, 0, last_idx, result, i); + cursor.CopyCell(0, last_idx, result, i); } else { FlatVector::SetNull(result, i, true); } @@ -1778,20 +2121,19 @@ void WindowLastValueExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate } } -WindowNthValueExecutor::WindowNthValueExecutor(BoundWindowExpression &wexpr, ClientContext &context) - : WindowValueExecutor(wexpr, context) { +WindowNthValueExecutor::WindowNthValueExecutor(BoundWindowExpression &wexpr, ClientContext &context, + WindowSharedExpressions &shared) + : WindowValueExecutor(wexpr, context, shared) { } void WindowNthValueExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - Vector &result, idx_t count, idx_t row_idx) const { - auto &gvstate = gstate.Cast(); - auto &payload_collection = gvstate.payload_collection.chunk; - D_ASSERT(payload_collection.ColumnCount() == 2); - + DataChunk &eval_chunk, Vector &result, idx_t count, idx_t row_idx) const { auto &lvstate = lstate.Cast(); - lvstate.Initialize(); - auto window_begin = FlatVector::GetData(lvstate.bounds.data[WINDOW_BEGIN]); - auto window_end = FlatVector::GetData(lvstate.bounds.data[WINDOW_END]); + auto &cursor = *lvstate.cursor; + D_ASSERT(cursor.chunk.ColumnCount() == 1); + auto window_begin = FlatVector::GetData(lvstate.bounds.data[FRAME_BEGIN]); + auto window_end = FlatVector::GetData(lvstate.bounds.data[FRAME_END]); + WindowInputExpression nth_col(eval_chunk, nth_idx); for (idx_t i = 0; i < count; ++i, ++row_idx) { if (lvstate.exclusion_filter) { @@ -1804,17 +2146,17 @@ void WindowNthValueExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, } // Returns value evaluated at the row that is the n'th row of the window frame (counting from 1); // returns NULL if there is no such row. - if (CellIsNull(payload_collection, 1, row_idx)) { + if (nth_col.CellIsNull(row_idx)) { FlatVector::SetNull(result, i, true); } else { - auto n_param = GetCell(payload_collection, 1, row_idx); + auto n_param = nth_col.GetCell(row_idx); if (n_param < 1) { FlatVector::SetNull(result, i, true); } else { auto n = idx_t(n_param); const auto nth_index = FindNextStart(*lvstate.ignore_nulls_exclude, window_begin[i], window_end[i], n); if (!n) { - CopyCell(payload_collection, 0, nth_index, result, i); + cursor.CopyCell(0, nth_index, result, i); } else { FlatVector::SetNull(result, i, true); } diff --git a/src/duckdb/src/execution/window_segment_tree.cpp b/src/duckdb/src/execution/window_segment_tree.cpp index be71e85c7..651a25ce7 100644 --- a/src/duckdb/src/execution/window_segment_tree.cpp +++ b/src/duckdb/src/execution/window_segment_tree.cpp @@ -22,13 +22,10 @@ WindowAggregatorState::WindowAggregatorState() : allocator(Allocator::DefaultAll class WindowAggregatorGlobalState : public WindowAggregatorState { public: - WindowAggregatorGlobalState(const WindowAggregator &aggregator_p, idx_t group_count) - : aggregator(aggregator_p), winputs(inputs), locals(0), finalized(0) { + WindowAggregatorGlobalState(ClientContext &context, const WindowAggregator &aggregator_p, idx_t group_count) + : aggregator(aggregator_p), aggr(aggregator.wexpr), locals(0), finalized(0) { - if (!aggregator.arg_types.empty()) { - winputs.Initialize(Allocator::DefaultAllocator(), aggregator.arg_types, group_count); - } - if (aggregator.aggr.filter) { + if (aggr.filter) { // Start with all invalid and set the ones that pass filter_mask.Initialize(group_count, false); } @@ -37,9 +34,8 @@ class WindowAggregatorGlobalState : public WindowAggregatorState { //! The aggregator data const WindowAggregator &aggregator; - //! Partition data chunk - DataChunk inputs; - WindowDataChunk winputs; + //! The aggregate function + const AggregateObject aggr; //! The filtered rows in inputs. ValidityArray filter_mask; @@ -54,35 +50,75 @@ class WindowAggregatorGlobalState : public WindowAggregatorState { std::atomic finalized; }; -WindowAggregator::WindowAggregator(AggregateObject aggr_p, const vector &arg_types_p, - const LogicalType &result_type_p, const WindowExcludeMode exclude_mode_p) - : aggr(std::move(aggr_p)), arg_types(arg_types_p), result_type(result_type_p), - state_size(aggr.function.state_size(aggr.function)), exclude_mode(exclude_mode_p) { +class WindowAggregatorLocalState : public WindowAggregatorState { +public: + using CollectionPtr = optional_ptr; + + WindowAggregatorLocalState() { + } + + void Sink(WindowAggregatorGlobalState &gastate, DataChunk &sink_chunk, DataChunk &coll_chunk, idx_t row_idx); + virtual void Finalize(WindowAggregatorGlobalState &gastate, CollectionPtr collection); + + //! The state used for reading the collection + unique_ptr cursor; +}; + +WindowAggregator::WindowAggregator(const BoundWindowExpression &wexpr, const WindowExcludeMode exclude_mode_p) + : wexpr(wexpr), aggr(wexpr), result_type(wexpr.return_type), state_size(aggr.function.state_size(aggr.function)), + exclude_mode(exclude_mode_p) { + + for (auto &child : wexpr.children) { + arg_types.emplace_back(child->return_type); + } +} + +WindowAggregator::WindowAggregator(const BoundWindowExpression &wexpr, const WindowExcludeMode exclude_mode_p, + WindowSharedExpressions &shared) + : WindowAggregator(wexpr, exclude_mode_p) { + for (auto &child : wexpr.children) { + child_idx.emplace_back(shared.RegisterCollection(child, false)); + } } WindowAggregator::~WindowAggregator() { } -unique_ptr WindowAggregator::GetGlobalState(idx_t group_count, const ValidityMask &) const { - return make_uniq(*this, group_count); +unique_ptr WindowAggregator::GetGlobalState(ClientContext &context, idx_t group_count, + const ValidityMask &) const { + return make_uniq(context, *this, group_count); } -void WindowAggregator::Sink(WindowAggregatorState &gsink, WindowAggregatorState &lstate, DataChunk &arg_chunk, - idx_t input_idx, optional_ptr filter_sel, idx_t filtered) { - auto &gasink = gsink.Cast(); - auto &winputs = gasink.winputs; - auto &filter_mask = gasink.filter_mask; - if (winputs.chunk.ColumnCount()) { - winputs.Copy(arg_chunk, input_idx); - } +void WindowAggregatorLocalState::Sink(WindowAggregatorGlobalState &gastate, DataChunk &sink_chunk, + DataChunk &coll_chunk, idx_t input_idx) { +} + +void WindowAggregator::Sink(WindowAggregatorState &gstate, WindowAggregatorState &lstate, DataChunk &sink_chunk, + DataChunk &coll_chunk, idx_t input_idx, optional_ptr filter_sel, + idx_t filtered) { + auto &gastate = gstate.Cast(); + auto &lastate = lstate.Cast(); + lastate.Sink(gastate, sink_chunk, coll_chunk, input_idx); if (filter_sel) { + auto &filter_mask = gastate.filter_mask; for (idx_t f = 0; f < filtered; ++f) { filter_mask.SetValid(input_idx + filter_sel->get_index(f)); } } } -void WindowAggregator::Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, const FrameStats &stats) { +void WindowAggregatorLocalState::Finalize(WindowAggregatorGlobalState &gastate, CollectionPtr collection) { + // Prepare to scan + if (!cursor) { + cursor = make_uniq(*collection, gastate.aggregator.child_idx); + } +} + +void WindowAggregator::Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, CollectionPtr collection, + const FrameStats &stats) { + auto &gasink = gstate.Cast(); + auto &lastate = lstate.Cast(); + lastate.Finalize(gasink, collection); } //===--------------------------------------------------------------------===// @@ -174,7 +210,7 @@ void WindowAggregateStates::Destroy() { class WindowConstantAggregatorGlobalState : public WindowAggregatorGlobalState { public: - WindowConstantAggregatorGlobalState(const WindowConstantAggregator &aggregator, idx_t count, + WindowConstantAggregatorGlobalState(ClientContext &context, const WindowConstantAggregator &aggregator, idx_t count, const ValidityMask &partition_mask); void Finalize(const FrameStats &stats); @@ -187,13 +223,14 @@ class WindowConstantAggregatorGlobalState : public WindowAggregatorGlobalState { unique_ptr results; }; -class WindowConstantAggregatorLocalState : public WindowAggregatorState { +class WindowConstantAggregatorLocalState : public WindowAggregatorLocalState { public: explicit WindowConstantAggregatorLocalState(const WindowConstantAggregatorGlobalState &gstate); ~WindowConstantAggregatorLocalState() override { } - void Sink(DataChunk &payload_chunk, idx_t input_idx, optional_ptr filter_sel, idx_t filtered); + void Sink(DataChunk &sink_chunk, DataChunk &coll_chunk, idx_t input_idx, optional_ptr filter_sel, + idx_t filtered); void Combine(WindowConstantAggregatorGlobalState &gstate); public: @@ -201,6 +238,8 @@ class WindowConstantAggregatorLocalState : public WindowAggregatorState { const WindowConstantAggregatorGlobalState &gstate; //! Reusable chunk for sinking DataChunk inputs; + //! Chunk for referencing the input columns + DataChunk payload_chunk; //! A vector of pointers to "state", used for intermediate window segment aggregation Vector statep; //! Reused result state container for the window functions @@ -211,10 +250,11 @@ class WindowConstantAggregatorLocalState : public WindowAggregatorState { SelectionVector matches; }; -WindowConstantAggregatorGlobalState::WindowConstantAggregatorGlobalState(const WindowConstantAggregator &aggregator, +WindowConstantAggregatorGlobalState::WindowConstantAggregatorGlobalState(ClientContext &context, + const WindowConstantAggregator &aggregator, idx_t group_count, const ValidityMask &partition_mask) - : WindowAggregatorGlobalState(aggregator, STANDARD_VECTOR_SIZE), statef(aggregator.aggr) { + : WindowAggregatorGlobalState(context, aggregator, STANDARD_VECTOR_SIZE), statef(aggr) { // Locate the partition boundaries if (partition_mask.AllValid()) { @@ -264,35 +304,41 @@ WindowConstantAggregatorLocalState::WindowConstantAggregatorLocalState( // Set up shared buffer inputs.Initialize(Allocator::DefaultAllocator(), aggregator.arg_types); + payload_chunk.InitializeEmpty(inputs.GetTypes()); gstate.locals++; } -WindowConstantAggregator::WindowConstantAggregator(AggregateObject aggr, const vector &arg_types, - const LogicalType &result_type, - const WindowExcludeMode exclude_mode_p) - : WindowAggregator(std::move(aggr), arg_types, result_type, exclude_mode_p) { +WindowConstantAggregator::WindowConstantAggregator(const BoundWindowExpression &wexpr, + const WindowExcludeMode exclude_mode_p, + WindowSharedExpressions &shared) + : WindowAggregator(wexpr, exclude_mode_p) { + + // We only need these values for Sink + for (auto &child : wexpr.children) { + child_idx.emplace_back(shared.RegisterSink(child)); + } } -unique_ptr WindowConstantAggregator::GetGlobalState(idx_t group_count, +unique_ptr WindowConstantAggregator::GetGlobalState(ClientContext &context, idx_t group_count, const ValidityMask &partition_mask) const { - return make_uniq(*this, group_count, partition_mask); + return make_uniq(context, *this, group_count, partition_mask); } -void WindowConstantAggregator::Sink(WindowAggregatorState &gsink, WindowAggregatorState &lstate, DataChunk &arg_chunk, - idx_t input_idx, optional_ptr filter_sel, idx_t filtered) { +void WindowConstantAggregator::Sink(WindowAggregatorState &gsink, WindowAggregatorState &lstate, DataChunk &sink_chunk, + DataChunk &coll_chunk, idx_t input_idx, optional_ptr filter_sel, + idx_t filtered) { auto &lastate = lstate.Cast(); - lastate.Sink(arg_chunk, input_idx, filter_sel, filtered); + lastate.Sink(sink_chunk, coll_chunk, input_idx, filter_sel, filtered); } -void WindowConstantAggregatorLocalState::Sink(DataChunk &payload_chunk, idx_t row, +void WindowConstantAggregatorLocalState::Sink(DataChunk &sink_chunk, DataChunk &coll_chunk, idx_t row, optional_ptr filter_sel, idx_t filtered) { auto &partition_offsets = gstate.partition_offsets; - auto &aggregator = gstate.aggregator; - const auto &aggr = aggregator.aggr; + const auto &aggr = gstate.aggr; const auto chunk_begin = row; - const auto chunk_end = chunk_begin + payload_chunk.size(); + const auto chunk_end = chunk_begin + sink_chunk.size(); idx_t partition = idx_t(std::upper_bound(partition_offsets.begin(), partition_offsets.end(), row) - partition_offsets.begin()) - 1; @@ -300,6 +346,11 @@ void WindowConstantAggregatorLocalState::Sink(DataChunk &payload_chunk, idx_t ro auto state_f_data = statef.GetData(); auto state_p_data = FlatVector::GetData(statep); + auto &child_idx = gstate.aggregator.child_idx; + for (column_t c = 0; c < child_idx.size(); ++c) { + payload_chunk.data[c].Reference(sink_chunk.data[child_idx[c]]); + } + AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); idx_t begin = 0; idx_t filter_idx = 0; @@ -367,7 +418,7 @@ void WindowConstantAggregatorLocalState::Sink(DataChunk &payload_chunk, idx_t ro } void WindowConstantAggregator::Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, - const FrameStats &stats) { + CollectionPtr collection, const FrameStats &stats) { auto &gastate = gstate.Cast(); auto &lastate = lstate.Cast(); @@ -393,7 +444,7 @@ void WindowConstantAggregator::Evaluate(const WindowAggregatorState &gsink, Wind const auto &partition_offsets = gasink.partition_offsets; const auto &results = *gasink.results; - auto begins = FlatVector::GetData(bounds.data[WINDOW_BEGIN]); + auto begins = FlatVector::GetData(bounds.data[FRAME_BEGIN]); // Chunk up the constants and copy them one at a time auto &lcstate = lstate.Cast(); idx_t matched = 0; @@ -429,22 +480,22 @@ void WindowConstantAggregator::Evaluate(const WindowAggregatorState &gsink, Wind //===--------------------------------------------------------------------===// // WindowCustomAggregator //===--------------------------------------------------------------------===// -WindowCustomAggregator::WindowCustomAggregator(AggregateObject aggr, const vector &arg_types, - const LogicalType &result_type, const WindowExcludeMode exclude_mode) - : WindowAggregator(std::move(aggr), arg_types, result_type, exclude_mode) { +WindowCustomAggregator::WindowCustomAggregator(const BoundWindowExpression &wexpr, const WindowExcludeMode exclude_mode, + WindowSharedExpressions &shared) + : WindowAggregator(wexpr, exclude_mode, shared) { } WindowCustomAggregator::~WindowCustomAggregator() { } -class WindowCustomAggregatorState : public WindowAggregatorState { +class WindowCustomAggregatorState : public WindowAggregatorLocalState { public: WindowCustomAggregatorState(const AggregateObject &aggr, const WindowExcludeMode exclude_mode); ~WindowCustomAggregatorState() override; public: //! The aggregate function - const AggregateObject &aggr; + const AggregateObject aggr; //! Data pointer that contains a single state, shared by all the custom evaluators vector state; //! Reused result state container for the window functions @@ -472,12 +523,15 @@ static void InitSubFrames(SubFrames &frames, const WindowExcludeMode exclude_mod class WindowCustomAggregatorGlobalState : public WindowAggregatorGlobalState { public: - explicit WindowCustomAggregatorGlobalState(const WindowCustomAggregator &aggregator, idx_t group_count) - : WindowAggregatorGlobalState(aggregator, group_count) { + explicit WindowCustomAggregatorGlobalState(ClientContext &context, const WindowCustomAggregator &aggregator, + idx_t group_count) + : WindowAggregatorGlobalState(context, aggregator, group_count), context(context) { - gcstate = make_uniq(aggregator.aggr, aggregator.exclude_mode); + gcstate = make_uniq(aggr, aggregator.exclude_mode); } + //! Buffer manager for paging custom accelerator data + ClientContext &context; //! Traditional packed filter mask for API ValidityMask filter_packed; //! Data pointer that contains a single local state, used for global custom window execution state @@ -503,29 +557,34 @@ WindowCustomAggregatorState::~WindowCustomAggregatorState() { } } -unique_ptr WindowCustomAggregator::GetGlobalState(idx_t group_count, +unique_ptr WindowCustomAggregator::GetGlobalState(ClientContext &context, idx_t group_count, const ValidityMask &) const { - return make_uniq(*this, group_count); + return make_uniq(context, *this, group_count); } -void WindowCustomAggregator::Finalize(WindowAggregatorState &gsink, WindowAggregatorState &lstate, - const FrameStats &stats) { +void WindowCustomAggregator::Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, + CollectionPtr collection, const FrameStats &stats) { // Single threaded Finalize for now - auto &gcsink = gsink.Cast(); + auto &gcsink = gstate.Cast(); lock_guard gestate_guard(gcsink.lock); if (gcsink.finalized) { return; } - WindowAggregator::Finalize(gsink, lstate, stats); + WindowAggregator::Finalize(gstate, lstate, collection, stats); - auto &inputs = gcsink.inputs; + auto inputs = collection->inputs.get(); + const auto count = collection->size(); + vector all_valids; + for (auto col_idx : child_idx) { + all_valids.push_back(collection->all_valids[col_idx]); + } auto &filter_mask = gcsink.filter_mask; auto &filter_packed = gcsink.filter_packed; filter_mask.Pack(filter_packed, filter_mask.target_count); gcsink.partition_input = - make_uniq(inputs.data.data(), inputs.ColumnCount(), inputs.size(), filter_packed, stats); + make_uniq(gcsink.context, inputs, count, child_idx, all_valids, filter_packed, stats); if (aggr.function.window_init) { auto &gcstate = *gcsink.gcstate; @@ -544,8 +603,8 @@ unique_ptr WindowCustomAggregator::GetLocalState(const Wi template static void EvaluateSubFrames(const DataChunk &bounds, const WindowExcludeMode exclude_mode, idx_t count, idx_t row_idx, SubFrames &frames, OP operation) { - auto begins = FlatVector::GetData(bounds.data[WINDOW_BEGIN]); - auto ends = FlatVector::GetData(bounds.data[WINDOW_END]); + auto begins = FlatVector::GetData(bounds.data[FRAME_BEGIN]); + auto ends = FlatVector::GetData(bounds.data[FRAME_END]); auto peer_begin = FlatVector::GetData(bounds.data[PEER_BEGIN]); auto peer_end = FlatVector::GetData(bounds.data[PEER_END]); @@ -619,44 +678,44 @@ void WindowCustomAggregator::Evaluate(const WindowAggregatorState &gsink, Window //===--------------------------------------------------------------------===// // WindowNaiveAggregator //===--------------------------------------------------------------------===// -WindowNaiveAggregator::WindowNaiveAggregator(AggregateObject aggr, const vector &arg_types, - const LogicalType &result_type, const WindowExcludeMode exclude_mode) - : WindowAggregator(std::move(aggr), arg_types, result_type, exclude_mode) { +WindowNaiveAggregator::WindowNaiveAggregator(const BoundWindowExpression &wexpr, const WindowExcludeMode exclude_mode, + WindowSharedExpressions &shared) + : WindowAggregator(wexpr, exclude_mode, shared) { } WindowNaiveAggregator::~WindowNaiveAggregator() { } -class WindowNaiveState : public WindowAggregatorState { +class WindowNaiveState : public WindowAggregatorLocalState { public: struct HashRow { - HashRow(WindowNaiveState &state, const DataChunk &inputs) : state(state), inputs(inputs) { + explicit HashRow(WindowNaiveState &state) : state(state) { } - size_t operator()(const idx_t &i) const { - return state.Hash(inputs, i); + inline size_t operator()(const idx_t &i) const { + return state.Hash(i); } WindowNaiveState &state; - const DataChunk &inputs; }; struct EqualRow { - EqualRow(WindowNaiveState &state, const DataChunk &inputs) : state(state), inputs(inputs) { + explicit EqualRow(WindowNaiveState &state) : state(state) { } - bool operator()(const idx_t &lhs, const idx_t &rhs) const { - return state.KeyEqual(inputs, lhs, rhs); + inline bool operator()(const idx_t &lhs, const idx_t &rhs) const { + return state.KeyEqual(lhs, rhs); } WindowNaiveState &state; - const DataChunk &inputs; }; using RowSet = std::unordered_set; explicit WindowNaiveState(const WindowNaiveAggregator &gsink); + void Finalize(WindowAggregatorGlobalState &gastate, CollectionPtr collection) override; + void Evaluate(const WindowAggregatorGlobalState &gsink, const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx); @@ -665,9 +724,9 @@ class WindowNaiveState : public WindowAggregatorState { void FlushStates(const WindowAggregatorGlobalState &gsink); //! Hashes a value for the hash table - size_t Hash(const DataChunk &inputs, idx_t rid); + size_t Hash(idx_t rid); //! Compares two values for the hash table - bool KeyEqual(const DataChunk &inputs, const idx_t &lhs, const idx_t &rhs); + bool KeyEqual(const idx_t &lhs, const idx_t &rhs); //! The global state const WindowNaiveAggregator &aggregator; @@ -687,6 +746,8 @@ class WindowNaiveState : public WindowAggregatorState { SubFrames frames; //! The optional hash table used for DISTINCT Vector hashes; + //! The state used for comparing the collection across chunk boundaries + unique_ptr comparer; }; WindowNaiveState::WindowNaiveState(const WindowNaiveAggregator &aggregator_p) @@ -708,43 +769,70 @@ WindowNaiveState::WindowNaiveState(const WindowNaiveAggregator &aggregator_p) } } +void WindowNaiveState::Finalize(WindowAggregatorGlobalState &gastate, CollectionPtr collection) { + WindowAggregatorLocalState::Finalize(gastate, collection); + + // Set up the comparison scanner just in case + if (!comparer) { + comparer = make_uniq(*collection, gastate.aggregator.child_idx); + } +} + void WindowNaiveState::FlushStates(const WindowAggregatorGlobalState &gsink) { if (!flush_count) { return; } - auto &inputs = gsink.inputs; - leaves.Slice(inputs, update_sel, flush_count); + auto &scanned = cursor->chunk; + leaves.Slice(scanned, update_sel, flush_count); - auto &aggr = aggregator.aggr; + const auto &aggr = gsink.aggr; AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); aggr.function.update(leaves.data.data(), aggr_input_data, leaves.ColumnCount(), statep, flush_count); flush_count = 0; } -size_t WindowNaiveState::Hash(const DataChunk &inputs, idx_t rid) { - auto s = UnsafeNumericCast(rid); +size_t WindowNaiveState::Hash(idx_t rid) { + D_ASSERT(cursor->RowIsVisible(rid)); + auto s = cursor->RowOffset(rid); + auto &scanned = cursor->chunk; SelectionVector sel(&s); - leaves.Slice(inputs, sel, 1); + leaves.Slice(scanned, sel, 1); leaves.Hash(hashes); return *FlatVector::GetData(hashes); } -bool WindowNaiveState::KeyEqual(const DataChunk &inputs, const idx_t &lhs, const idx_t &rhs) { - auto l = UnsafeNumericCast(lhs); +bool WindowNaiveState::KeyEqual(const idx_t &lidx, const idx_t &ridx) { + // One of the indices will be scanned, so make it the left one + auto lhs = lidx; + auto rhs = ridx; + if (!cursor->RowIsVisible(lhs)) { + std::swap(lhs, rhs); + D_ASSERT(cursor->RowIsVisible(lhs)); + } + + auto &scanned = cursor->chunk; + auto l = cursor->RowOffset(lhs); SelectionVector lsel(&l); - auto r = UnsafeNumericCast(rhs); + auto rreader = cursor.get(); + if (!cursor->RowIsVisible(rhs)) { + // Values on different pages! + rreader = comparer.get(); + rreader->Seek(rhs); + } + auto rscanned = &rreader->chunk; + auto r = rreader->RowOffset(rhs); SelectionVector rsel(&r); sel_t f = 0; SelectionVector fsel(&f); - for (auto &input : inputs.data) { - Vector left(input, lsel, 1); - Vector right(input, rsel, 1); + for (column_t c = 0; c < scanned.ColumnCount(); ++c) { + Vector left(scanned.data[c], lsel, 1); + Vector right(rscanned->data[c], rsel, 1); if (!VectorOperations::NotDistinctFrom(left, right, nullptr, 1, nullptr, &fsel)) { return false; } @@ -755,19 +843,19 @@ bool WindowNaiveState::KeyEqual(const DataChunk &inputs, const idx_t &lhs, const void WindowNaiveState::Evaluate(const WindowAggregatorGlobalState &gsink, const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx) { - auto &aggr = aggregator.aggr; + const auto &aggr = gsink.aggr; auto &filter_mask = gsink.filter_mask; - auto &inputs = gsink.inputs; + const auto types = cursor->chunk.GetTypes(); - if (leaves.ColumnCount() == 0 && inputs.ColumnCount() > 0) { - leaves.Initialize(Allocator::DefaultAllocator(), inputs.GetTypes()); + if (leaves.ColumnCount() == 0 && !types.empty()) { + leaves.Initialize(Allocator::DefaultAllocator(), types); } auto fdata = FlatVector::GetData(statef); auto pdata = FlatVector::GetData(statep); - HashRow hash_row(*this, inputs); - EqualRow equal_row(*this, inputs); + HashRow hash_row(*this); + EqualRow equal_row(*this); RowSet row_set(STANDARD_VECTOR_SIZE, hash_row, equal_row); EvaluateSubFrames(bounds, aggregator.exclude_mode, count, row_idx, frames, [&](idx_t rid) { @@ -782,13 +870,20 @@ void WindowNaiveState::Evaluate(const WindowAggregatorGlobalState &gsink, const continue; } + // Seek to the current position + if (!cursor->RowIsVisible(f)) { + // We need to flush when we cross a chunk boundary + FlushStates(gsink); + cursor->Seek(f); + } + // Filter out duplicates if (aggr.IsDistinct() && !row_set.insert(f).second) { continue; } pdata[flush_count] = agg_state; - update_sel[flush_count++] = UnsafeNumericCast(f); + update_sel[flush_count++] = cursor->RowOffset(f); if (flush_count >= STANDARD_VECTOR_SIZE) { FlushStates(gsink); } @@ -827,7 +922,7 @@ class WindowSegmentTreeGlobalState : public WindowAggregatorGlobalState { public: using AtomicCounters = vector>; - WindowSegmentTreeGlobalState(const WindowSegmentTree &aggregator, idx_t group_count); + WindowSegmentTreeGlobalState(ClientContext &context, const WindowSegmentTree &aggregator, idx_t group_count); ArenaAllocator &CreateTreeAllocator() { lock_guard tree_lock(lock); @@ -856,10 +951,9 @@ class WindowSegmentTreeGlobalState : public WindowAggregatorGlobalState { static constexpr idx_t TREE_FANOUT = 16; }; -WindowSegmentTree::WindowSegmentTree(AggregateObject aggr, const vector &arg_types, - const LogicalType &result_type, WindowAggregationMode mode_p, - const WindowExcludeMode exclude_mode_p) - : WindowAggregator(std::move(aggr), arg_types, result_type, exclude_mode_p), mode(mode_p) { +WindowSegmentTree::WindowSegmentTree(const BoundWindowExpression &wexpr, WindowAggregationMode mode_p, + const WindowExcludeMode exclude_mode_p, WindowSharedExpressions &shared) + : WindowAggregator(wexpr, exclude_mode_p, shared), mode(mode_p) { } class WindowSegmentTreePart { @@ -869,12 +963,12 @@ class WindowSegmentTreePart { enum FramePart : uint8_t { FULL = 0, LEFT = 1, RIGHT = 2 }; - WindowSegmentTreePart(ArenaAllocator &allocator, const AggregateObject &aggr, const DataChunk &inputs, + WindowSegmentTreePart(ArenaAllocator &allocator, const AggregateObject &aggr, unique_ptr cursor, const ValidityArray &filter_mask); ~WindowSegmentTreePart(); unique_ptr Copy() const { - return make_uniq(allocator, aggr, inputs, filter_mask); + return make_uniq(allocator, aggr, cursor->Copy(), filter_mask); } void FlushStates(bool combining); @@ -905,14 +999,14 @@ class WindowSegmentTreePart { const AggregateObject &aggr; //! Order insensitive aggregate (we can optimise internal combines) const bool order_insensitive; - //! The partition arguments - const DataChunk &inputs; //! The filtered rows in inputs const ValidityArray &filter_mask; //! The size of a single aggregate state const idx_t state_size; //! Data pointer that contains a vector of states, used for intermediate window segment aggregation vector state; + //! Scanned data state + unique_ptr cursor; //! Input data chunk, used for leaf segment aggregation DataChunk leaves; //! The filtered rows in inputs. @@ -929,12 +1023,12 @@ class WindowSegmentTreePart { vector right_stack; }; -class WindowSegmentTreeState : public WindowAggregatorState { +class WindowSegmentTreeState : public WindowAggregatorLocalState { public: WindowSegmentTreeState() { } - void Finalize(WindowSegmentTreeGlobalState &gstate); + void Finalize(WindowAggregatorGlobalState &gastate, CollectionPtr collection) override; void Evaluate(const WindowSegmentTreeGlobalState &gsink, const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx); //! The left (default) segment tree part @@ -943,29 +1037,23 @@ class WindowSegmentTreeState : public WindowAggregatorState { unique_ptr right_part; }; -void WindowSegmentTree::Finalize(WindowAggregatorState &gsink, WindowAggregatorState &lstate, const FrameStats &stats) { +void WindowSegmentTree::Finalize(WindowAggregatorState &gsink, WindowAggregatorState &lstate, CollectionPtr collection, + const FrameStats &stats) { + WindowAggregator::Finalize(gsink, lstate, collection, stats); auto &gasink = gsink.Cast(); - auto &inputs = gasink.inputs; - - WindowAggregator::Finalize(gsink, lstate, stats); - - if (inputs.ColumnCount() > 0) { - if (aggr.function.combine && UseCombineAPI()) { - lstate.Cast().Finalize(gasink); - } - } - ++gasink.finalized; } WindowSegmentTreePart::WindowSegmentTreePart(ArenaAllocator &allocator, const AggregateObject &aggr, - const DataChunk &inputs, const ValidityArray &filter_mask) + unique_ptr cursor_p, const ValidityArray &filter_mask) : allocator(allocator), aggr(aggr), - order_insensitive(aggr.function.order_dependent == AggregateOrderDependent::NOT_ORDER_DEPENDENT), inputs(inputs), + order_insensitive(aggr.function.order_dependent == AggregateOrderDependent::NOT_ORDER_DEPENDENT), filter_mask(filter_mask), state_size(aggr.function.state_size(aggr.function)), - state(state_size * STANDARD_VECTOR_SIZE), statep(LogicalType::POINTER), statel(LogicalType::POINTER), - statef(LogicalType::POINTER), flush_count(0) { + state(state_size * STANDARD_VECTOR_SIZE), cursor(std::move(cursor_p)), statep(LogicalType::POINTER), + statel(LogicalType::POINTER), statef(LogicalType::POINTER), flush_count(0) { + + auto &inputs = cursor->chunk; if (inputs.ColumnCount() > 0) { leaves.Initialize(Allocator::DefaultAllocator(), inputs.GetTypes()); filter_sel.Initialize(); @@ -986,9 +1074,9 @@ WindowSegmentTreePart::WindowSegmentTreePart(ArenaAllocator &allocator, const Ag WindowSegmentTreePart::~WindowSegmentTreePart() { } -unique_ptr WindowSegmentTree::GetGlobalState(idx_t group_count, +unique_ptr WindowSegmentTree::GetGlobalState(ClientContext &context, idx_t group_count, const ValidityMask &partition_mask) const { - return make_uniq(*this, group_count); + return make_uniq(context, *this, group_count); } unique_ptr WindowSegmentTree::GetLocalState(const WindowAggregatorState &gstate) const { @@ -1005,7 +1093,8 @@ void WindowSegmentTreePart::FlushStates(bool combining) { statel.Verify(flush_count); aggr.function.combine(statel, statep, aggr_input_data, flush_count); } else { - leaves.Slice(inputs, filter_sel, flush_count); + auto &scanned = cursor->chunk; + leaves.Slice(scanned, filter_sel, flush_count); aggr.function.update(&leaves.data[0], aggr_input_data, leaves.ColumnCount(), statep, flush_count); } @@ -1025,9 +1114,10 @@ void WindowSegmentTreePart::ExtractFrame(idx_t begin, idx_t end, data_ptr_t stat // Otherwise set it to the input rows that pass the filter auto states = FlatVector::GetData(statep); if (filter_mask.AllValid()) { + const auto offset = cursor->RowOffset(begin); for (idx_t i = 0; i < count; ++i) { states[flush_count] = state_ptr; - filter_sel.set_index(flush_count++, begin + i); + filter_sel.set_index(flush_count++, offset + i); if (flush_count >= STANDARD_VECTOR_SIZE) { FlushStates(false); } @@ -1036,7 +1126,7 @@ void WindowSegmentTreePart::ExtractFrame(idx_t begin, idx_t end, data_ptr_t stat for (idx_t i = begin; i < end; ++i) { if (filter_mask.RowIsValid(i)) { states[flush_count] = state_ptr; - filter_sel.set_index(flush_count++, i); + filter_sel.set_index(flush_count++, cursor->RowOffset(i)); if (flush_count >= STANDARD_VECTOR_SIZE) { FlushStates(false); } @@ -1048,13 +1138,23 @@ void WindowSegmentTreePart::ExtractFrame(idx_t begin, idx_t end, data_ptr_t stat void WindowSegmentTreePart::WindowSegmentValue(const WindowSegmentTreeGlobalState &tree, idx_t l_idx, idx_t begin, idx_t end, data_ptr_t state_ptr) { D_ASSERT(begin <= end); + auto &inputs = cursor->chunk; if (begin == end || inputs.ColumnCount() == 0) { return; } const auto count = end - begin; if (l_idx == 0) { - ExtractFrame(begin, end, state_ptr); + // Check the leaves when they cross chunk boundaries + while (begin < end) { + if (!cursor->RowIsVisible(begin)) { + FlushStates(false); + cursor->Seek(begin); + } + auto next = MinValue(end, cursor->state.next_row_index); + ExtractFrame(begin, next, state_ptr); + begin = next; + } } else { // find out where the states begin auto begin_ptr = tree.levels_flat_native.GetStatePtr(begin + tree.levels_flat_start[l_idx - 1]); @@ -1082,10 +1182,11 @@ void WindowSegmentTreePart::Finalize(Vector &result, idx_t count) { } } -WindowSegmentTreeGlobalState::WindowSegmentTreeGlobalState(const WindowSegmentTree &aggregator, idx_t group_count) - : WindowAggregatorGlobalState(aggregator, group_count), tree(aggregator), levels_flat_native(aggregator.aggr) { +WindowSegmentTreeGlobalState::WindowSegmentTreeGlobalState(ClientContext &context, const WindowSegmentTree &aggregator, + idx_t group_count) + : WindowAggregatorGlobalState(context, aggregator, group_count), tree(aggregator), levels_flat_native(aggr) { - D_ASSERT(inputs.ColumnCount() > 0); + D_ASSERT(!aggregator.wexpr.children.empty()); // compute space required to store internal nodes of segment tree levels_flat_start.push_back(0); @@ -1096,7 +1197,7 @@ WindowSegmentTreeGlobalState::WindowSegmentTreeGlobalState(const WindowSegmentTr idx_t level_size; // iterate over the levels of the segment tree while ((level_size = - (level_current == 0 ? inputs.size() : levels_flat_offset - levels_flat_start[level_current - 1])) > 1) { + (level_current == 0 ? group_count : levels_flat_offset - levels_flat_start[level_current - 1])) > 1) { for (idx_t pos = 0; pos < level_size; pos += TREE_FANOUT) { levels_flat_offset++; } @@ -1126,12 +1227,15 @@ WindowSegmentTreeGlobalState::WindowSegmentTreeGlobalState(const WindowSegmentTr } } -void WindowSegmentTreeState::Finalize(WindowSegmentTreeGlobalState &gstate) { +void WindowSegmentTreeState::Finalize(WindowAggregatorGlobalState &gastate, CollectionPtr collection) { + WindowAggregatorLocalState::Finalize(gastate, collection); + // Single part for constructing the tree - auto &inputs = gstate.inputs; - auto &tree = gstate.tree; + auto &gstate = gastate.Cast(); + auto cursor = make_uniq(*collection, gastate.aggregator.child_idx); + const auto leaf_count = collection->size(); auto &filter_mask = gstate.filter_mask; - WindowSegmentTreePart gtstate(gstate.CreateTreeAllocator(), tree.aggr, inputs, filter_mask); + WindowSegmentTreePart gtstate(gstate.CreateTreeAllocator(), gastate.aggr, std::move(cursor), filter_mask); auto &levels_flat_native = gstate.levels_flat_native; const auto &levels_flat_start = gstate.levels_flat_start; @@ -1144,8 +1248,7 @@ void WindowSegmentTreeState::Finalize(WindowSegmentTreeGlobalState &gstate) { // level 0 is data itself const auto level_size = - (level_current == 0 ? inputs.size() - : levels_flat_start[level_current] - levels_flat_start[level_current - 1]); + (level_current == 0 ? leaf_count : levels_flat_start[level_current] - levels_flat_start[level_current - 1]); if (level_size <= 1) { break; } @@ -1188,14 +1291,13 @@ void WindowSegmentTree::Evaluate(const WindowAggregatorState &gsink, WindowAggre void WindowSegmentTreeState::Evaluate(const WindowSegmentTreeGlobalState >state, const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx) { - auto window_begin = FlatVector::GetData(bounds.data[WINDOW_BEGIN]); - auto window_end = FlatVector::GetData(bounds.data[WINDOW_END]); + auto window_begin = FlatVector::GetData(bounds.data[FRAME_BEGIN]); + auto window_end = FlatVector::GetData(bounds.data[FRAME_END]); auto peer_begin = FlatVector::GetData(bounds.data[PEER_BEGIN]); auto peer_end = FlatVector::GetData(bounds.data[PEER_END]); if (!part) { - part = - make_uniq(allocator, gtstate.aggregator.aggr, gtstate.inputs, gtstate.filter_mask); + part = make_uniq(allocator, gtstate.aggr, cursor->Copy(), gtstate.filter_mask); } if (gtstate.aggregator.exclude_mode != WindowExcludeMode::NO_OTHER) { @@ -1393,10 +1495,10 @@ void WindowSegmentTreePart::EvaluateLeaves(const WindowSegmentTreeGlobalState &t //===--------------------------------------------------------------------===// // WindowDistinctAggregator //===--------------------------------------------------------------------===// -WindowDistinctAggregator::WindowDistinctAggregator(AggregateObject aggr, const vector &arg_types, - const LogicalType &result_type, - const WindowExcludeMode exclude_mode_p, ClientContext &context) - : WindowAggregator(std::move(aggr), arg_types, result_type, exclude_mode_p), context(context) { +WindowDistinctAggregator::WindowDistinctAggregator(const BoundWindowExpression &wexpr, + const WindowExcludeMode exclude_mode_p, + WindowSharedExpressions &shared, ClientContext &context) + : WindowAggregator(wexpr, exclude_mode_p, shared), context(context) { } class WindowDistinctAggregatorLocalState; @@ -1433,7 +1535,8 @@ class WindowDistinctAggregatorGlobalState : public WindowAggregatorGlobalState { using ZippedTuple = WindowDistinctSortTree::ZippedTuple; using ZippedElements = WindowDistinctSortTree::ZippedElements; - WindowDistinctAggregatorGlobalState(const WindowDistinctAggregator &aggregator, idx_t group_count); + WindowDistinctAggregatorGlobalState(ClientContext &context, const WindowDistinctAggregator &aggregator, + idx_t group_count); //! Compute the block starts void MeasurePayloadBlocks(); @@ -1479,11 +1582,12 @@ class WindowDistinctAggregatorGlobalState : public WindowAggregatorGlobalState { vector levels_flat_start; }; -WindowDistinctAggregatorGlobalState::WindowDistinctAggregatorGlobalState(const WindowDistinctAggregator &aggregator, +WindowDistinctAggregatorGlobalState::WindowDistinctAggregatorGlobalState(ClientContext &context, + const WindowDistinctAggregator &aggregator, idx_t group_count) - : WindowAggregatorGlobalState(aggregator, group_count), context(aggregator.context), + : WindowAggregatorGlobalState(context, aggregator, group_count), context(aggregator.context), stage(PartitionSortStage::INIT), tasks_completed(0), merge_sort_tree(*this, group_count), - levels_flat_native(aggregator.aggr) { + levels_flat_native(aggr) { payload_types.emplace_back(LogicalType::UBIGINT); // 1: functionComputePrevIdcs(𝑖𝑛) @@ -1538,11 +1642,13 @@ WindowDistinctAggregatorGlobalState::WindowDistinctAggregatorGlobalState(const W } } -class WindowDistinctAggregatorLocalState : public WindowAggregatorState { +class WindowDistinctAggregatorLocalState : public WindowAggregatorLocalState { public: explicit WindowDistinctAggregatorLocalState(const WindowDistinctAggregatorGlobalState &aggregator); - void Sink(DataChunk &arg_chunk, idx_t input_idx, optional_ptr filter_sel, idx_t filtered); + void Sink(DataChunk &sink_chunk, DataChunk &coll_chunk, idx_t input_idx, optional_ptr filter_sel, + idx_t filtered); + void Finalize(WindowAggregatorGlobalState &gastate, CollectionPtr collection) override; void Sorted(); void ExecuteTask(); void Evaluate(const WindowDistinctAggregatorGlobalState &gdstate, const DataChunk &bounds, Vector &result, @@ -1584,7 +1690,7 @@ class WindowDistinctAggregatorLocalState : public WindowAggregatorState { WindowDistinctAggregatorLocalState::WindowDistinctAggregatorLocalState( const WindowDistinctAggregatorGlobalState &gastate) : update_v(LogicalType::POINTER), source_v(LogicalType::POINTER), target_v(LogicalType::POINTER), gastate(gastate), - statef(gastate.aggregator.aggr), statep(LogicalType::POINTER), statel(LogicalType::POINTER), flush_count(0) { + statef(gastate.aggr), statep(LogicalType::POINTER), statel(LogicalType::POINTER), flush_count(0) { InitSubFrames(frames, gastate.aggregator.exclude_mode); payload_chunk.Initialize(Allocator::DefaultAllocator(), gastate.payload_types); @@ -1594,41 +1700,41 @@ WindowDistinctAggregatorLocalState::WindowDistinctAggregatorLocalState( sort_chunk.Initialize(Allocator::DefaultAllocator(), gastate.sort_types); sort_chunk.data.back().Reference(payload_chunk.data[0]); - //! Input data chunk, used for leaf segment aggregation - leaves.Initialize(Allocator::DefaultAllocator(), gastate.inputs.GetTypes()); - sel.Initialize(); - gastate.locals++; } -unique_ptr WindowDistinctAggregator::GetGlobalState(idx_t group_count, +unique_ptr WindowDistinctAggregator::GetGlobalState(ClientContext &context, idx_t group_count, const ValidityMask &partition_mask) const { - return make_uniq(*this, group_count); + return make_uniq(context, *this, group_count); } -void WindowDistinctAggregator::Sink(WindowAggregatorState &gsink, WindowAggregatorState &lstate, DataChunk &arg_chunk, - idx_t input_idx, optional_ptr filter_sel, idx_t filtered) { - WindowAggregator::Sink(gsink, lstate, arg_chunk, input_idx, filter_sel, filtered); +void WindowDistinctAggregator::Sink(WindowAggregatorState &gsink, WindowAggregatorState &lstate, DataChunk &sink_chunk, + DataChunk &coll_chunk, idx_t input_idx, optional_ptr filter_sel, + idx_t filtered) { + WindowAggregator::Sink(gsink, lstate, sink_chunk, coll_chunk, input_idx, filter_sel, filtered); auto &ldstate = lstate.Cast(); - ldstate.Sink(arg_chunk, input_idx, filter_sel, filtered); + ldstate.Sink(sink_chunk, coll_chunk, input_idx, filter_sel, filtered); } -void WindowDistinctAggregatorLocalState::Sink(DataChunk &arg_chunk, idx_t input_idx, +void WindowDistinctAggregatorLocalState::Sink(DataChunk &sink_chunk, DataChunk &coll_chunk, idx_t input_idx, optional_ptr filter_sel, idx_t filtered) { // 3: for i ← 0 to in.size do // 4: sorted[i] ← (in[i], i) - const auto count = arg_chunk.size(); + const auto count = sink_chunk.size(); payload_chunk.Reset(); auto &sorted_vec = payload_chunk.data[0]; auto sorted = FlatVector::GetData(sorted_vec); std::iota(sorted, sorted + count, input_idx); - for (column_t c = 0; c < arg_chunk.ColumnCount(); ++c) { - sort_chunk.data[c].Reference(arg_chunk.data[c]); + // Our arguments are being fully materialised, + // but we also need them as sort keys. + auto &child_idx = gastate.aggregator.child_idx; + for (column_t c = 0; c < child_idx.size(); ++c) { + sort_chunk.data[c].Reference(coll_chunk.data[child_idx[c]]); } sort_chunk.data.back().Reference(sorted_vec); - sort_chunk.SetCardinality(arg_chunk); + sort_chunk.SetCardinality(sink_chunk); payload_chunk.SetCardinality(sort_chunk); // Apply FILTER clause, if any @@ -1644,6 +1750,14 @@ void WindowDistinctAggregatorLocalState::Sink(DataChunk &arg_chunk, idx_t input_ } } +void WindowDistinctAggregatorLocalState::Finalize(WindowAggregatorGlobalState &gastate, CollectionPtr collection) { + WindowAggregatorLocalState::Finalize(gastate, collection); + + //! Input data chunk, used for leaf segment aggregation + leaves.Initialize(Allocator::DefaultAllocator(), cursor->chunk.GetTypes()); + sel.Initialize(); +} + void WindowDistinctAggregatorLocalState::ExecuteTask() { auto &global_sort = *gastate.global_sort; switch (stage) { @@ -1754,9 +1868,10 @@ bool WindowDistinctAggregatorGlobalState::TryPrepareNextStage(WindowDistinctAggr } void WindowDistinctAggregator::Finalize(WindowAggregatorState &gsink, WindowAggregatorState &lstate, - const FrameStats &stats) { + CollectionPtr collection, const FrameStats &stats) { auto &gdsink = gsink.Cast(); auto &ldstate = lstate.Cast(); + ldstate.Finalize(gdsink, collection); // 5: Sort sorted lexicographically increasing ldstate.ExecuteTask(); @@ -1920,9 +2035,9 @@ void WindowDistinctSortTree::Build(WindowDistinctAggregatorLocalState &ldastate) } void WindowDistinctSortTree::BuildRun(idx_t level_nr, idx_t run_idx, WindowDistinctAggregatorLocalState &ldastate) { - auto &aggr = gdastate.aggregator.aggr; + auto &aggr = gdastate.aggr; auto &allocator = gdastate.allocator; - auto &inputs = gdastate.inputs; + auto &inputs = ldastate.cursor->chunk; auto &levels_flat_native = gdastate.levels_flat_native; //! Input data chunk, used for leaf segment aggregation @@ -1959,9 +2074,26 @@ void WindowDistinctSortTree::BuildRun(idx_t level_nr, idx_t run_idx, WindowDisti const auto prev_idx = std::get<0>(zipped_level[j]); level[j] = prev_idx; if (prev_idx < i + 1) { + const auto update_idx = std::get<1>(zipped_level[j]); + if (!ldastate.cursor->RowIsVisible(update_idx)) { + // Flush if we have to move the cursor + // Push the updates first so they propagate + leaves.Reference(inputs); + leaves.Slice(sel, nupdate); + aggr.function.update(leaves.data.data(), aggr_input_data, leaves.ColumnCount(), update_v, nupdate); + nupdate = 0; + + // Combine the states sequentially + aggr.function.combine(source_v, target_v, aggr_input_data, ncombine); + ncombine = 0; + + // Move the update into range. + ldastate.cursor->Seek(update_idx); + } + updates[nupdate] = curr_state; // input_idx - sel[nupdate] = UnsafeNumericCast(std::get<1>(zipped_level[j])); + sel[nupdate] = ldastate.cursor->RowOffset(update_idx); ++nupdate; } @@ -2008,7 +2140,7 @@ void WindowDistinctAggregatorLocalState::FlushStates() { return; } - const auto &aggr = gastate.aggregator.aggr; + const auto &aggr = gastate.aggr; AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); statel.Verify(flush_count); aggr.function.combine(statel, statep, aggr_input_data, flush_count); diff --git a/src/duckdb/src/function/aggregate/distributive/count.cpp b/src/duckdb/src/function/aggregate/distributive/count.cpp index 8b5c3be2b..30824b7a2 100644 --- a/src/duckdb/src/function/aggregate/distributive/count.cpp +++ b/src/duckdb/src/function/aggregate/distributive/count.cpp @@ -1,6 +1,7 @@ #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/planner/expression/bound_aggregate_expression.hpp" namespace duckdb { @@ -36,7 +37,7 @@ struct CountStarFunction : public BaseCountFunction { template static void Window(AggregateInputData &aggr_input_data, const WindowPartitionInput &partition, const_data_ptr_t, data_ptr_t l_state, const SubFrames &frames, Vector &result, idx_t rid) { - D_ASSERT(partition.input_count == 0); + D_ASSERT(partition.column_ids.empty()); auto data = FlatVector::GetData(result); RESULT_TYPE total = 0; @@ -210,7 +211,7 @@ struct CountFunction : public BaseCountFunction { } }; -AggregateFunction CountFun::GetFunction() { +AggregateFunction CountFunctionBase::GetFunction() { AggregateFunction fun({LogicalType(LogicalTypeId::ANY)}, LogicalType::BIGINT, AggregateFunction::StateSize, AggregateFunction::StateInitialize, CountFunction::CountScatter, AggregateFunction::StateCombine, @@ -241,21 +242,14 @@ unique_ptr CountPropagateStats(ClientContext &context, BoundAggr return nullptr; } -void CountFun::RegisterFunction(BuiltinFunctions &set) { - AggregateFunction count_function = CountFun::GetFunction(); +AggregateFunctionSet CountFun::GetFunctions() { + AggregateFunction count_function = CountFunctionBase::GetFunction(); count_function.statistics = CountPropagateStats; AggregateFunctionSet count("count"); count.AddFunction(count_function); // the count function can also be called without arguments - count_function = CountStarFun::GetFunction(); - count.AddFunction(count_function); - set.AddFunction(count); -} - -void CountStarFun::RegisterFunction(BuiltinFunctions &set) { - AggregateFunctionSet count("count_star"); count.AddFunction(CountStarFun::GetFunction()); - set.AddFunction(count); + return count; } } // namespace duckdb diff --git a/src/duckdb/src/function/aggregate/distributive/first.cpp b/src/duckdb/src/function/aggregate/distributive/first_last_any.cpp similarity index 94% rename from src/duckdb/src/function/aggregate/distributive/first.cpp rename to src/duckdb/src/function/aggregate/distributive/first_last_any.cpp index 8fed21904..4a8979a55 100644 --- a/src/duckdb/src/function/aggregate/distributive/first.cpp +++ b/src/duckdb/src/function/aggregate/distributive/first_last_any.cpp @@ -1,7 +1,8 @@ #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/core_functions/create_sort_key.hpp" #include "duckdb/function/aggregate/distributive_functions.hpp" +#include "duckdb/function/aggregate/distributive_function_utils.hpp" +#include "duckdb/function/create_sort_key.hpp" #include "duckdb/planner/expression.hpp" namespace duckdb { @@ -68,7 +69,7 @@ struct FirstFunction : public FirstFunctionBase { template struct FirstFunctionStringBase : public FirstFunctionBase { - template + template static void SetValue(STATE &state, AggregateInputData &input_data, string_t value, bool is_null) { if (LAST && state.is_set) { Destroy(state, input_data); @@ -81,7 +82,9 @@ struct FirstFunctionStringBase : public FirstFunctionBase { } else { state.is_set = true; state.is_null = false; - if (value.IsInlined()) { + if ((COMBINE && !LAST) || value.IsInlined()) { + // We use the aggregate allocator for 'first', so the allocation is already done when combining + // Of course, if the value is inlined, we also don't need to allocate state.value = value; } else { // non-inlined string, need to allocate space for it @@ -97,7 +100,7 @@ struct FirstFunctionStringBase : public FirstFunctionBase { template static void Combine(const STATE &source, STATE &target, AggregateInputData &input_data) { if (source.is_set && (LAST || !target.is_set)) { - SetValue(target, input_data, source.value, source.is_null); + SetValue(target, input_data, source.value, source.is_null); } } @@ -291,7 +294,7 @@ static AggregateFunction GetFirstFunction(const LogicalType &type) { } } -AggregateFunction FirstFun::GetFunction(const LogicalType &type) { +AggregateFunction FirstFunctionGetter::GetFunction(const LogicalType &type) { auto fun = GetFirstFunction(type); fun.name = "first"; return fun; @@ -338,22 +341,22 @@ static void AddFirstOperator(AggregateFunctionSet &set) { nullptr, BindFirst)); } -void FirstFun::RegisterFunction(BuiltinFunctions &set) { +AggregateFunctionSet FirstFun::GetFunctions() { AggregateFunctionSet first("first"); - AggregateFunctionSet last("last"); - AggregateFunctionSet any_value("any_value"); - AddFirstOperator(first); - AddFirstOperator(last); - AddFirstOperator(any_value); - - set.AddFunction(first); - first.name = "arbitrary"; - set.AddFunction(first); + return first; +} - set.AddFunction(last); +AggregateFunctionSet LastFun::GetFunctions() { + AggregateFunctionSet last("last"); + AddFirstOperator(last); + return last; +} - set.AddFunction(any_value); +AggregateFunctionSet AnyValueFun::GetFunctions() { + AggregateFunctionSet any_value("any_value"); + AddFirstOperator(any_value); + return any_value; } } // namespace duckdb diff --git a/src/duckdb/src/core_functions/aggregate/distributive/minmax.cpp b/src/duckdb/src/function/aggregate/distributive/minmax.cpp similarity index 95% rename from src/duckdb/src/core_functions/aggregate/distributive/minmax.cpp rename to src/duckdb/src/function/aggregate/distributive/minmax.cpp index 9642da156..3bbeb2210 100644 --- a/src/duckdb/src/core_functions/aggregate/distributive/minmax.cpp +++ b/src/duckdb/src/function/aggregate/distributive/minmax.cpp @@ -1,16 +1,17 @@ #include "duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp" -#include "duckdb/core_functions/aggregate/distributive_functions.hpp" #include "duckdb/common/exception.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/common/operator/comparison_operators.hpp" #include "duckdb/common/types/null_value.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/aggregate/minmax_n_helpers.hpp" +#include "duckdb/function/aggregate/sort_key_helpers.hpp" +#include "duckdb/function/function_binder.hpp" #include "duckdb/main/config.hpp" #include "duckdb/planner/expression.hpp" #include "duckdb/planner/expression/bound_comparison_expression.hpp" #include "duckdb/planner/expression_binder.hpp" -#include "duckdb/function/function_binder.hpp" -#include "duckdb/core_functions/aggregate/sort_key_helpers.hpp" -#include "duckdb/core_functions/aggregate/minmax_n_helpers.hpp" namespace duckdb { @@ -336,8 +337,14 @@ unique_ptr BindMinMax(ClientContext &context, AggregateFunction &f // to make sure the result's correctness. string function_name = function.name == "min" ? "arg_min" : "arg_max"; QueryErrorContext error_context; - auto func = Catalog::GetEntry(context, CatalogType::SCALAR_FUNCTION_ENTRY, "", "", function_name, + auto func = Catalog::GetEntry(context, CatalogType::AGGREGATE_FUNCTION_ENTRY, "", "", function_name, OnEntryNotFound::RETURN_NULL, error_context); + if (!func) { + throw NotImplementedException( + "Failure while binding function \"%s\" using collations - arg_min/arg_max do not exist in the " + "catalog - load the core_functions module to fix this issue", + function.name); + } auto &func_entry = func->Cast(); @@ -383,11 +390,11 @@ static AggregateFunction GetMinMaxOperator(string name) { nullptr, nullptr, BindMinMax); } -AggregateFunction MinFun::GetFunction() { +AggregateFunction MinFunction::GetFunction() { return GetMinMaxOperator("min"); } -AggregateFunction MaxFun::GetFunction() { +AggregateFunction MaxFunction::GetFunction() { return GetMinMaxOperator("max"); } @@ -471,7 +478,7 @@ static void SpecializeMinMaxNFunction(AggregateFunction &function) { using OP = MinMaxNOperation; function.state_size = AggregateFunction::StateSize; - function.initialize = AggregateFunction::StateInitialize; + function.initialize = AggregateFunction::StateInitialize; function.combine = AggregateFunction::StateCombine; function.destructor = AggregateFunction::StateDestroy; @@ -531,17 +538,16 @@ static AggregateFunction GetMinMaxNFunction() { //--------------------------------------------------- // Function Registration //---------------------------------------------------s - AggregateFunctionSet MinFun::GetFunctions() { AggregateFunctionSet min("min"); - min.AddFunction(GetFunction()); + min.AddFunction(MinFunction::GetFunction()); min.AddFunction(GetMinMaxNFunction()); return min; } AggregateFunctionSet MaxFun::GetFunctions() { AggregateFunctionSet max("max"); - max.AddFunction(GetFunction()); + max.AddFunction(MaxFunction::GetFunction()); max.AddFunction(GetMinMaxNFunction()); return max; } diff --git a/src/duckdb/src/function/aggregate/distributive_functions.cpp b/src/duckdb/src/function/aggregate/distributive_functions.cpp deleted file mode 100644 index 5971861c7..000000000 --- a/src/duckdb/src/function/aggregate/distributive_functions.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "duckdb/function/aggregate/distributive_functions.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/types/null_value.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/function/aggregate_function.hpp" - -namespace duckdb { - -void BuiltinFunctions::RegisterDistributiveAggregates() { - Register(); - Register(); - Register(); -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp b/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp index 4e86f930b..87960adb8 100644 --- a/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp +++ b/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp @@ -744,7 +744,8 @@ void FunctionBinder::BindSortedAggregate(ClientContext &context, BoundAggregateE // Replace the aggregate with the wrapper AggregateFunction ordered_aggregate( bound_function.name, arguments, bound_function.return_type, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, + AggregateFunction::StateInitialize, SortedAggregateFunction::ScatterUpdate, AggregateFunction::StateCombine, SortedAggregateFunction::Finalize, bound_function.null_handling, SortedAggregateFunction::SimpleUpdate, nullptr, diff --git a/src/duckdb/src/function/built_in_functions.cpp b/src/duckdb/src/function/built_in_functions.cpp index 23372fcdb..00e7eac64 100644 --- a/src/duckdb/src/function/built_in_functions.cpp +++ b/src/duckdb/src/function/built_in_functions.cpp @@ -1,12 +1,16 @@ #include "duckdb/function/built_in_functions.hpp" + +#include "duckdb/catalog/catalog.hpp" +#include "duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp" +#include "duckdb/main/extension_entries.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_pragma_function_info.hpp" #include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" #include "duckdb/parser/parsed_data/create_table_function_info.hpp" -#include "duckdb/catalog/catalog.hpp" -#include "duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp" +#include "duckdb/main/extension_helper.hpp" +#include "duckdb/main/config.hpp" namespace duckdb { @@ -85,4 +89,83 @@ void BuiltinFunctions::AddFunction(CopyFunction function) { catalog.CreateCopyFunction(transaction, info); } +struct ExtensionFunctionInfo : public ScalarFunctionInfo { + explicit ExtensionFunctionInfo(string extension_p) : extension(std::move(extension_p)) { + } + + string extension; +}; + +unique_ptr BindExtensionFunction(ClientContext &context, ScalarFunction &bound_function, + vector> &arguments) { + // if this is triggered we are trying to call a method that is present in an extension + // but the extension is not loaded + // try to autoload the extension + // first figure out which extension we need to auto-load + auto &function_info = bound_function.function_info->Cast(); + auto &extension_name = function_info.extension; + auto &db = *context.db; + + if (!ExtensionHelper::CanAutoloadExtension(extension_name)) { + throw BinderException("Trying to call function \"%s\" which is present in extension \"%s\" - but the extension " + "is not loaded and could not be auto-loaded", + bound_function.name, extension_name); + } + // auto-load the extension + ExtensionHelper::AutoLoadExtension(db, extension_name); + + // now find the function in the catalog + auto &catalog = Catalog::GetSystemCatalog(db); + auto &function_entry = catalog.GetEntry(context, DEFAULT_SCHEMA, bound_function.name); + // override the function with the extension function + bound_function = function_entry.functions.GetFunctionByArguments(context, bound_function.arguments); + // call the original bind (if any) + if (!bound_function.bind) { + return nullptr; + } + return bound_function.bind(context, bound_function, arguments); +} + +void BuiltinFunctions::AddExtensionFunction(ScalarFunctionSet set) { + CreateScalarFunctionInfo info(std::move(set)); + info.internal = true; + catalog.CreateFunction(transaction, info); +} + +void BuiltinFunctions::RegisterExtensionOverloads() { +#ifdef GENERATE_EXTENSION_ENTRIES + // do not insert auto loading placeholders when generating extension entries + return; +#endif + ScalarFunctionSet current_set; + for (auto &entry : EXTENSION_FUNCTION_OVERLOADS) { + vector arguments; + auto splits = StringUtil::Split(entry.signature, ">"); + auto return_type = DBConfig::ParseLogicalType(splits[1]); + auto argument_splits = StringUtil::Split(splits[0], ","); + for (auto ¶m : argument_splits) { + arguments.push_back(DBConfig::ParseLogicalType(param)); + } + if (entry.type != CatalogType::SCALAR_FUNCTION_ENTRY) { + throw InternalException( + "Extension function overloads only supported for scalar functions currently - %s has a different type", + entry.name); + } + + ScalarFunction function(entry.name, std::move(arguments), std::move(return_type), nullptr, + BindExtensionFunction); + function.function_info = make_shared_ptr(entry.extension); + if (current_set.name != entry.name) { + if (!current_set.name.empty()) { + // create set of functions + AddExtensionFunction(current_set); + } + current_set = ScalarFunctionSet(entry.name); + } + // add this function to the set of function overloads + current_set.AddFunction(std::move(function)); + } + AddExtensionFunction(std::move(current_set)); +} + } // namespace duckdb diff --git a/src/duckdb/src/function/function.cpp b/src/duckdb/src/function/function.cpp index 9427f445b..a1f8c9c71 100644 --- a/src/duckdb/src/function/function.cpp +++ b/src/duckdb/src/function/function.cpp @@ -2,11 +2,13 @@ #include "duckdb/common/string_util.hpp" #include "duckdb/common/types/hash.hpp" +#include "duckdb/function/built_in_functions.hpp" #include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/function/scalar_function.hpp" #include "duckdb/parser/parsed_data/pragma_info.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" +#include "duckdb/main/extension_entries.hpp" namespace duckdb { @@ -92,22 +94,14 @@ void BuiltinFunctions::Initialize() { RegisterTableFunctions(); RegisterArrowFunctions(); - RegisterDistributiveAggregates(); - - RegisterCompressedMaterializationFunctions(); - - RegisterGenericFunctions(); - RegisterOperators(); - RegisterSequenceFunctions(); - RegisterStringFunctions(); - RegisterNestedFunctions(); - RegisterPragmaFunctions(); // initialize collations AddCollation("nocase", LowerFun::GetFunction(), true); AddCollation("noaccent", StripAccentsFun::GetFunction()); AddCollation("nfc", NFCNormalizeFun::GetFunction()); + + RegisterExtensionOverloads(); } hash_t BaseScalarFunction::Hash() const { diff --git a/src/duckdb/src/function/function_list.cpp b/src/duckdb/src/function/function_list.cpp new file mode 100644 index 000000000..a5d601a18 --- /dev/null +++ b/src/duckdb/src/function/function_list.cpp @@ -0,0 +1,174 @@ +#include "duckdb/function/function_list.hpp" + +#include "duckdb/function/aggregate/distributive_functions.hpp" +#include "duckdb/function/scalar/compressed_materialization_functions.hpp" +#include "duckdb/function/scalar/date_functions.hpp" +#include "duckdb/function/scalar/generic_functions.hpp" +#include "duckdb/function/scalar/list_functions.hpp" +#include "duckdb/function/scalar/map_functions.hpp" +#include "duckdb/function/scalar/operator_functions.hpp" +#include "duckdb/function/scalar/sequence_functions.hpp" +#include "duckdb/function/scalar/string_functions.hpp" +#include "duckdb/function/scalar/struct_functions.hpp" +#include "duckdb/function/scalar/system_functions.hpp" +#include "duckdb/parser/parsed_data/create_aggregate_function_info.hpp" +#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" + +namespace duckdb { + +// Scalar Function +#define DUCKDB_SCALAR_FUNCTION_BASE(_PARAM, _NAME) \ + { _NAME, _PARAM::Parameters, _PARAM::Description, _PARAM::Example, _PARAM::GetFunction, nullptr, nullptr, nullptr } +#define DUCKDB_SCALAR_FUNCTION(_PARAM) DUCKDB_SCALAR_FUNCTION_BASE(_PARAM, _PARAM::Name) +#define DUCKDB_SCALAR_FUNCTION_ALIAS(_PARAM) DUCKDB_SCALAR_FUNCTION_BASE(_PARAM::ALIAS, _PARAM::Name) +// Scalar Function Set +#define DUCKDB_SCALAR_FUNCTION_SET_BASE(_PARAM, _NAME) \ + { _NAME, _PARAM::Parameters, _PARAM::Description, _PARAM::Example, nullptr, _PARAM::GetFunctions, nullptr, nullptr } +#define DUCKDB_SCALAR_FUNCTION_SET(_PARAM) DUCKDB_SCALAR_FUNCTION_SET_BASE(_PARAM, _PARAM::Name) +#define DUCKDB_SCALAR_FUNCTION_SET_ALIAS(_PARAM) DUCKDB_SCALAR_FUNCTION_SET_BASE(_PARAM::ALIAS, _PARAM::Name) +// Aggregate Function +#define DUCKDB_AGGREGATE_FUNCTION_BASE(_PARAM, _NAME) \ + { _NAME, _PARAM::Parameters, _PARAM::Description, _PARAM::Example, nullptr, nullptr, _PARAM::GetFunction, nullptr } +#define DUCKDB_AGGREGATE_FUNCTION(_PARAM) DUCKDB_AGGREGATE_FUNCTION_BASE(_PARAM, _PARAM::Name) +#define DUCKDB_AGGREGATE_FUNCTION_ALIAS(_PARAM) DUCKDB_AGGREGATE_FUNCTION_BASE(_PARAM::ALIAS, _PARAM::Name) +// Aggregate Function Set +#define DUCKDB_AGGREGATE_FUNCTION_SET_BASE(_PARAM, _NAME) \ + { _NAME, _PARAM::Parameters, _PARAM::Description, _PARAM::Example, nullptr, nullptr, nullptr, _PARAM::GetFunctions } +#define DUCKDB_AGGREGATE_FUNCTION_SET(_PARAM) DUCKDB_AGGREGATE_FUNCTION_SET_BASE(_PARAM, _PARAM::Name) +#define DUCKDB_AGGREGATE_FUNCTION_SET_ALIAS(_PARAM) DUCKDB_AGGREGATE_FUNCTION_SET_BASE(_PARAM::ALIAS, _PARAM::Name) +#define FINAL_FUNCTION \ + { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr } + +// this list is generated by scripts/generate_functions.py +static const StaticFunctionDefinition function[] = { + DUCKDB_SCALAR_FUNCTION(NotLikeFun), + DUCKDB_SCALAR_FUNCTION(NotILikeFun), + DUCKDB_SCALAR_FUNCTION_SET(OperatorModuloFun), + DUCKDB_SCALAR_FUNCTION_SET(OperatorMultiplyFun), + DUCKDB_SCALAR_FUNCTION_SET(OperatorAddFun), + DUCKDB_SCALAR_FUNCTION_SET(OperatorSubtractFun), + DUCKDB_SCALAR_FUNCTION_SET(OperatorFloatDivideFun), + DUCKDB_SCALAR_FUNCTION_SET(OperatorIntegerDivideFun), + DUCKDB_SCALAR_FUNCTION_SET(InternalCompressIntegralUbigintFun), + DUCKDB_SCALAR_FUNCTION_SET(InternalCompressIntegralUintegerFun), + DUCKDB_SCALAR_FUNCTION_SET(InternalCompressIntegralUsmallintFun), + DUCKDB_SCALAR_FUNCTION_SET(InternalCompressIntegralUtinyintFun), + DUCKDB_SCALAR_FUNCTION(InternalCompressStringHugeintFun), + DUCKDB_SCALAR_FUNCTION(InternalCompressStringUbigintFun), + DUCKDB_SCALAR_FUNCTION(InternalCompressStringUintegerFun), + DUCKDB_SCALAR_FUNCTION(InternalCompressStringUsmallintFun), + DUCKDB_SCALAR_FUNCTION(InternalCompressStringUtinyintFun), + DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressIntegralBigintFun), + DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressIntegralHugeintFun), + DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressIntegralIntegerFun), + DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressIntegralSmallintFun), + DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressIntegralUbigintFun), + DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressIntegralUhugeintFun), + DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressIntegralUintegerFun), + DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressIntegralUsmallintFun), + DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressStringFun), + DUCKDB_SCALAR_FUNCTION_SET_ALIAS(AddFun), + DUCKDB_AGGREGATE_FUNCTION_SET(AnyValueFun), + DUCKDB_AGGREGATE_FUNCTION_SET_ALIAS(ArbitraryFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayCatFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayConcatFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayContainsFun), + DUCKDB_SCALAR_FUNCTION_SET(ArrayExtractFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayHasFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayIndexofFun), + DUCKDB_SCALAR_FUNCTION_SET(ArrayLengthFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayPositionFun), + DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ArrayResizeFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(ArraySelectFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayWhereFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayZipFun), + DUCKDB_SCALAR_FUNCTION_SET(BitLengthFun), + DUCKDB_SCALAR_FUNCTION(CombineFun), + DUCKDB_SCALAR_FUNCTION(ConcatFun), + DUCKDB_SCALAR_FUNCTION(ConcatWsFun), + DUCKDB_SCALAR_FUNCTION(ConstantOrNullFun), + DUCKDB_SCALAR_FUNCTION_SET(ContainsFun), + DUCKDB_AGGREGATE_FUNCTION_SET(CountFun), + DUCKDB_AGGREGATE_FUNCTION(CountStarFun), + DUCKDB_SCALAR_FUNCTION(CreateSortKeyFun), + DUCKDB_SCALAR_FUNCTION(CurrvalFun), + DUCKDB_SCALAR_FUNCTION_SET_ALIAS(DivideFun), + DUCKDB_SCALAR_FUNCTION(ErrorFun), + DUCKDB_SCALAR_FUNCTION(FinalizeFun), + DUCKDB_AGGREGATE_FUNCTION_SET(FirstFun), + DUCKDB_SCALAR_FUNCTION(GetVariableFun), + DUCKDB_SCALAR_FUNCTION(IlikeEscapeFun), + DUCKDB_AGGREGATE_FUNCTION_SET(LastFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(LcaseFun), + DUCKDB_SCALAR_FUNCTION_SET_ALIAS(LenFun), + DUCKDB_SCALAR_FUNCTION_SET(LengthFun), + DUCKDB_SCALAR_FUNCTION_SET(LengthGraphemeFun), + DUCKDB_SCALAR_FUNCTION(LikeEscapeFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(ListCatFun), + DUCKDB_SCALAR_FUNCTION(ListConcatFun), + DUCKDB_SCALAR_FUNCTION(ListContainsFun), + DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ListElementFun), + DUCKDB_SCALAR_FUNCTION_SET(ListExtractFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(ListHasFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(ListIndexofFun), + DUCKDB_SCALAR_FUNCTION(ListPositionFun), + DUCKDB_SCALAR_FUNCTION_SET(ListResizeFun), + DUCKDB_SCALAR_FUNCTION(ListSelectFun), + DUCKDB_SCALAR_FUNCTION(ListWhereFun), + DUCKDB_SCALAR_FUNCTION(ListZipFun), + DUCKDB_SCALAR_FUNCTION(LowerFun), + DUCKDB_SCALAR_FUNCTION(MapContainsFun), + DUCKDB_AGGREGATE_FUNCTION_SET(MaxFun), + DUCKDB_SCALAR_FUNCTION_SET(MD5Fun), + DUCKDB_SCALAR_FUNCTION_SET(MD5NumberFun), + DUCKDB_AGGREGATE_FUNCTION_SET(MinFun), + DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ModFun), + DUCKDB_SCALAR_FUNCTION_SET_ALIAS(MultiplyFun), + DUCKDB_SCALAR_FUNCTION(NextvalFun), + DUCKDB_SCALAR_FUNCTION(NFCNormalizeFun), + DUCKDB_SCALAR_FUNCTION(NotIlikeEscapeFun), + DUCKDB_SCALAR_FUNCTION(NotLikeEscapeFun), + DUCKDB_SCALAR_FUNCTION_SET(OctetLengthFun), + DUCKDB_SCALAR_FUNCTION(PrefixFun), + DUCKDB_SCALAR_FUNCTION(RegexpEscapeFun), + DUCKDB_SCALAR_FUNCTION_SET(RegexpExtractFun), + DUCKDB_SCALAR_FUNCTION_SET(RegexpExtractAllFun), + DUCKDB_SCALAR_FUNCTION_SET(RegexpFun), + DUCKDB_SCALAR_FUNCTION_SET(RegexpMatchesFun), + DUCKDB_SCALAR_FUNCTION_SET(RegexpReplaceFun), + DUCKDB_SCALAR_FUNCTION_SET_ALIAS(RegexpSplitToArrayFun), + DUCKDB_SCALAR_FUNCTION(RowFun), + DUCKDB_SCALAR_FUNCTION_SET(SHA1Fun), + DUCKDB_SCALAR_FUNCTION_SET(SHA256Fun), + DUCKDB_SCALAR_FUNCTION_ALIAS(SplitFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(StrSplitFun), + DUCKDB_SCALAR_FUNCTION_SET_ALIAS(StrSplitRegexFun), + DUCKDB_SCALAR_FUNCTION_SET(StrfTimeFun), + DUCKDB_SCALAR_FUNCTION(StringSplitFun), + DUCKDB_SCALAR_FUNCTION_SET(StringSplitRegexFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(StringToArrayFun), + DUCKDB_SCALAR_FUNCTION(StripAccentsFun), + DUCKDB_SCALAR_FUNCTION(StrlenFun), + DUCKDB_SCALAR_FUNCTION_SET(StrpTimeFun), + DUCKDB_SCALAR_FUNCTION_SET(StructExtractFun), + DUCKDB_SCALAR_FUNCTION(StructPackFun), + DUCKDB_SCALAR_FUNCTION_SET_ALIAS(SubstrFun), + DUCKDB_SCALAR_FUNCTION_SET(SubstringFun), + DUCKDB_SCALAR_FUNCTION_SET(SubstringGraphemeFun), + DUCKDB_SCALAR_FUNCTION_SET_ALIAS(SubtractFun), + DUCKDB_SCALAR_FUNCTION(SuffixFun), + DUCKDB_SCALAR_FUNCTION_SET(TryStrpTimeFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(UcaseFun), + DUCKDB_SCALAR_FUNCTION(UpperFun), + DUCKDB_SCALAR_FUNCTION(ConcatOperatorFun), + DUCKDB_SCALAR_FUNCTION(LikeFun), + DUCKDB_SCALAR_FUNCTION(ILikeFun), + DUCKDB_SCALAR_FUNCTION(GlobPatternFun), + FINAL_FUNCTION +}; + +const StaticFunctionDefinition *FunctionList::GetInternalFunctionList() { + return function; +} + +} // namespace duckdb diff --git a/src/duckdb/src/function/pragma/pragma_queries.cpp b/src/duckdb/src/function/pragma/pragma_queries.cpp index 39db1f12a..66dd6ace7 100644 --- a/src/duckdb/src/function/pragma/pragma_queries.cpp +++ b/src/duckdb/src/function/pragma/pragma_queries.cpp @@ -138,10 +138,6 @@ string PragmaPlatform(ClientContext &context, const FunctionParameters ¶mete } string PragmaImportDatabase(ClientContext &context, const FunctionParameters ¶meters) { - auto &config = DBConfig::GetConfig(context); - if (!config.options.enable_external_access) { - throw PermissionException("Import is disabled through configuration"); - } auto &fs = FileSystem::GetFileSystem(context); string final_query; diff --git a/src/duckdb/src/core_functions/core_functions.cpp b/src/duckdb/src/function/register_function_list.cpp similarity index 75% rename from src/duckdb/src/core_functions/core_functions.cpp rename to src/duckdb/src/function/register_function_list.cpp index ef1687dc6..beadc45bd 100644 --- a/src/duckdb/src/core_functions/core_functions.cpp +++ b/src/duckdb/src/function/register_function_list.cpp @@ -1,20 +1,19 @@ -#include "duckdb/core_functions/core_functions.hpp" -#include "duckdb/core_functions/function_list.hpp" +#include "duckdb/function/function_list.hpp" #include "duckdb/parser/parsed_data/create_aggregate_function_info.hpp" #include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" namespace duckdb { template -void FillExtraInfo(const StaticFunctionDefinition &function, T &info) { +static void FillExtraInfo(const StaticFunctionDefinition &function, T &info) { info.internal = true; info.description = function.description; info.parameter_names = StringUtil::Split(function.parameters, ","); info.example = function.example; } -void CoreFunctions::RegisterFunctions(Catalog &catalog, CatalogTransaction transaction) { - auto functions = StaticFunctionDefinition::GetFunctionList(); +static void RegisterFunctionList(Catalog &catalog, CatalogTransaction transaction, + const StaticFunctionDefinition *functions) { for (idx_t i = 0; functions[i].name; i++) { auto &function = functions[i]; if (function.get_function || function.get_function_set) { @@ -47,4 +46,8 @@ void CoreFunctions::RegisterFunctions(Catalog &catalog, CatalogTransaction trans } } +void FunctionList::RegisterFunctions(Catalog &catalog, CatalogTransaction transaction) { + RegisterFunctionList(catalog, transaction, FunctionList::GetInternalFunctionList()); +} + } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/compressed_materialization/compress_integral.cpp b/src/duckdb/src/function/scalar/compressed_materialization/compress_integral.cpp index e431ae406..1a31ffac2 100644 --- a/src/duckdb/src/function/scalar/compressed_materialization/compress_integral.cpp +++ b/src/duckdb/src/function/scalar/compressed_materialization/compress_integral.cpp @@ -3,6 +3,7 @@ #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/function/function_set.hpp" #include "duckdb/function/scalar/compressed_materialization_functions.hpp" +#include "duckdb/function/scalar/compressed_materialization_utils.hpp" namespace duckdb { @@ -190,8 +191,7 @@ unique_ptr CMIntegralDeserialize(Deserializer &deserializer, Scala ScalarFunction CMIntegralCompressFun::GetFunction(const LogicalType &input_type, const LogicalType &result_type) { ScalarFunction result(IntegralCompressFunctionName(result_type), {input_type, input_type}, result_type, - GetIntegralCompressFunctionInputSwitch(input_type, result_type), - CompressedMaterializationFunctions::Bind); + GetIntegralCompressFunctionInputSwitch(input_type, result_type), CMUtils::Bind); result.serialize = CMIntegralSerialize; result.deserialize = CMIntegralDeserialize; return result; @@ -207,16 +207,9 @@ static ScalarFunctionSet GetIntegralCompressFunctionSet(const LogicalType &resul return set; } -void CMIntegralCompressFun::RegisterFunction(BuiltinFunctions &set) { - for (const auto &result_type : CompressedMaterializationFunctions::IntegralTypes()) { - set.AddFunction(GetIntegralCompressFunctionSet(result_type)); - } -} - ScalarFunction CMIntegralDecompressFun::GetFunction(const LogicalType &input_type, const LogicalType &result_type) { ScalarFunction result(IntegralDecompressFunctionName(result_type), {input_type, result_type}, result_type, - GetIntegralDecompressFunctionInputSwitch(input_type, result_type), - CompressedMaterializationFunctions::Bind); + GetIntegralDecompressFunctionInputSwitch(input_type, result_type), CMUtils::Bind); result.serialize = CMIntegralSerialize; result.deserialize = CMIntegralDeserialize; return result; @@ -224,7 +217,7 @@ ScalarFunction CMIntegralDecompressFun::GetFunction(const LogicalType &input_typ static ScalarFunctionSet GetIntegralDecompressFunctionSet(const LogicalType &result_type) { ScalarFunctionSet set(IntegralDecompressFunctionName(result_type)); - for (const auto &input_type : CompressedMaterializationFunctions::IntegralTypes()) { + for (const auto &input_type : CMUtils::IntegralTypes()) { if (GetTypeIdSize(result_type.InternalType()) > GetTypeIdSize(input_type.InternalType())) { set.AddFunction(CMIntegralDecompressFun::GetFunction(input_type, result_type)); } @@ -232,12 +225,52 @@ static ScalarFunctionSet GetIntegralDecompressFunctionSet(const LogicalType &res return set; } -void CMIntegralDecompressFun::RegisterFunction(BuiltinFunctions &set) { - for (const auto &result_type : LogicalType::Integral()) { - if (GetTypeIdSize(result_type.InternalType()) > 1) { - set.AddFunction(GetIntegralDecompressFunctionSet(result_type)); - } - } +ScalarFunctionSet InternalCompressIntegralUtinyintFun::GetFunctions() { + return GetIntegralCompressFunctionSet(LogicalType(LogicalTypeId::UTINYINT)); +} + +ScalarFunctionSet InternalCompressIntegralUsmallintFun::GetFunctions() { + return GetIntegralCompressFunctionSet(LogicalType(LogicalTypeId::USMALLINT)); +} + +ScalarFunctionSet InternalCompressIntegralUintegerFun::GetFunctions() { + return GetIntegralCompressFunctionSet(LogicalType(LogicalTypeId::UINTEGER)); +} + +ScalarFunctionSet InternalCompressIntegralUbigintFun::GetFunctions() { + return GetIntegralCompressFunctionSet(LogicalType(LogicalTypeId::UBIGINT)); +} + +ScalarFunctionSet InternalDecompressIntegralSmallintFun::GetFunctions() { + return GetIntegralDecompressFunctionSet(LogicalType(LogicalTypeId::SMALLINT)); +} + +ScalarFunctionSet InternalDecompressIntegralIntegerFun::GetFunctions() { + return GetIntegralDecompressFunctionSet(LogicalType(LogicalTypeId::INTEGER)); +} + +ScalarFunctionSet InternalDecompressIntegralBigintFun::GetFunctions() { + return GetIntegralDecompressFunctionSet(LogicalType(LogicalTypeId::BIGINT)); +} + +ScalarFunctionSet InternalDecompressIntegralHugeintFun::GetFunctions() { + return GetIntegralDecompressFunctionSet(LogicalType(LogicalTypeId::HUGEINT)); +} + +ScalarFunctionSet InternalDecompressIntegralUsmallintFun::GetFunctions() { + return GetIntegralDecompressFunctionSet(LogicalType(LogicalTypeId::USMALLINT)); +} + +ScalarFunctionSet InternalDecompressIntegralUintegerFun::GetFunctions() { + return GetIntegralDecompressFunctionSet(LogicalType(LogicalTypeId::UINTEGER)); +} + +ScalarFunctionSet InternalDecompressIntegralUbigintFun::GetFunctions() { + return GetIntegralDecompressFunctionSet(LogicalType(LogicalTypeId::UBIGINT)); +} + +ScalarFunctionSet InternalDecompressIntegralUhugeintFun::GetFunctions() { + return GetIntegralDecompressFunctionSet(LogicalType(LogicalTypeId::UHUGEINT)); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/compressed_materialization/compress_string.cpp b/src/duckdb/src/function/scalar/compressed_materialization/compress_string.cpp index 907b8c455..b1a60070c 100644 --- a/src/duckdb/src/function/scalar/compressed_materialization/compress_string.cpp +++ b/src/duckdb/src/function/scalar/compressed_materialization/compress_string.cpp @@ -1,5 +1,6 @@ #include "duckdb/common/bswap.hpp" #include "duckdb/function/scalar/compressed_materialization_functions.hpp" +#include "duckdb/function/scalar/compressed_materialization_utils.hpp" #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/common/serializer/deserializer.hpp" @@ -203,18 +204,12 @@ unique_ptr CMStringCompressDeserialize(Deserializer &deserializer, ScalarFunction CMStringCompressFun::GetFunction(const LogicalType &result_type) { ScalarFunction result(StringCompressFunctionName(result_type), {LogicalType::VARCHAR}, result_type, - GetStringCompressFunctionSwitch(result_type), CompressedMaterializationFunctions::Bind); + GetStringCompressFunctionSwitch(result_type), CMUtils::Bind); result.serialize = CMStringCompressSerialize; result.deserialize = CMStringCompressDeserialize; return result; } -void CMStringCompressFun::RegisterFunction(BuiltinFunctions &set) { - for (const auto &result_type : CompressedMaterializationFunctions::StringTypes()) { - set.AddFunction(CMStringCompressFun::GetFunction(result_type)); - } -} - static void CMStringDecompressSerialize(Serializer &serializer, const optional_ptr bind_data, const ScalarFunction &function) { serializer.WriteProperty(100, "arguments", function.arguments); @@ -229,8 +224,8 @@ unique_ptr CMStringDecompressDeserialize(Deserializer &deserialize ScalarFunction CMStringDecompressFun::GetFunction(const LogicalType &input_type) { ScalarFunction result(StringDecompressFunctionName(), {input_type}, LogicalType::VARCHAR, - GetStringDecompressFunctionSwitch(input_type), CompressedMaterializationFunctions::Bind, - nullptr, nullptr, StringDecompressLocalState::Init); + GetStringDecompressFunctionSwitch(input_type), CMUtils::Bind, nullptr, nullptr, + StringDecompressLocalState::Init); result.serialize = CMStringDecompressSerialize; result.deserialize = CMStringDecompressDeserialize; return result; @@ -238,14 +233,34 @@ ScalarFunction CMStringDecompressFun::GetFunction(const LogicalType &input_type) static ScalarFunctionSet GetStringDecompressFunctionSet() { ScalarFunctionSet set(StringDecompressFunctionName()); - for (const auto &input_type : CompressedMaterializationFunctions::StringTypes()) { + for (const auto &input_type : CMUtils::StringTypes()) { set.AddFunction(CMStringDecompressFun::GetFunction(input_type)); } return set; } -void CMStringDecompressFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction(GetStringDecompressFunctionSet()); +ScalarFunction InternalCompressStringUtinyintFun::GetFunction() { + return CMStringCompressFun::GetFunction(LogicalType(LogicalTypeId::UTINYINT)); +} + +ScalarFunction InternalCompressStringUsmallintFun::GetFunction() { + return CMStringCompressFun::GetFunction(LogicalType(LogicalTypeId::USMALLINT)); +} + +ScalarFunction InternalCompressStringUintegerFun::GetFunction() { + return CMStringCompressFun::GetFunction(LogicalType(LogicalTypeId::UINTEGER)); +} + +ScalarFunction InternalCompressStringUbigintFun::GetFunction() { + return CMStringCompressFun::GetFunction(LogicalType(LogicalTypeId::UBIGINT)); +} + +ScalarFunction InternalCompressStringHugeintFun::GetFunction() { + return CMStringCompressFun::GetFunction(LogicalType(LogicalTypeId::HUGEINT)); +} + +ScalarFunctionSet InternalDecompressStringFun::GetFunctions() { + return GetStringDecompressFunctionSet(); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/compressed_materialization_functions.cpp b/src/duckdb/src/function/scalar/compressed_materialization_functions.cpp deleted file mode 100644 index 456d1bb8a..000000000 --- a/src/duckdb/src/function/scalar/compressed_materialization_functions.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "duckdb/function/scalar/compressed_materialization_functions.hpp" - -namespace duckdb { - -const vector CompressedMaterializationFunctions::IntegralTypes() { - return {LogicalType::UTINYINT, LogicalType::USMALLINT, LogicalType::UINTEGER, LogicalType::UBIGINT}; -} - -const vector CompressedMaterializationFunctions::StringTypes() { - return {LogicalType::UTINYINT, LogicalType::USMALLINT, LogicalType::UINTEGER, LogicalType::UBIGINT, - LogicalType::HUGEINT}; -} - -// LCOV_EXCL_START -unique_ptr CompressedMaterializationFunctions::Bind(ClientContext &context, - ScalarFunction &bound_function, - vector> &arguments) { - throw BinderException("Compressed materialization functions are for internal use only!"); -} -// LCOV_EXCL_STOP - -void BuiltinFunctions::RegisterCompressedMaterializationFunctions() { - Register(); - Register(); - Register(); - Register(); -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/scalar/compressed_materialization_utils.cpp b/src/duckdb/src/function/scalar/compressed_materialization_utils.cpp new file mode 100644 index 000000000..2d09a7e7f --- /dev/null +++ b/src/duckdb/src/function/scalar/compressed_materialization_utils.cpp @@ -0,0 +1,21 @@ +#include "duckdb/function/scalar/compressed_materialization_utils.hpp" + +namespace duckdb { + +const vector CMUtils::IntegralTypes() { + return {LogicalType::UTINYINT, LogicalType::USMALLINT, LogicalType::UINTEGER, LogicalType::UBIGINT}; +} + +const vector CMUtils::StringTypes() { + return {LogicalType::UTINYINT, LogicalType::USMALLINT, LogicalType::UINTEGER, LogicalType::UBIGINT, + LogicalType::HUGEINT}; +} + +// LCOV_EXCL_START +unique_ptr CMUtils::Bind(ClientContext &context, ScalarFunction &bound_function, + vector> &arguments) { + throw BinderException("Compressed materialization functions are for internal use only!"); +} +// LCOV_EXCL_STOP + +} // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/blob/create_sort_key.cpp b/src/duckdb/src/function/scalar/create_sort_key.cpp similarity index 98% rename from src/duckdb/src/core_functions/scalar/blob/create_sort_key.cpp rename to src/duckdb/src/function/scalar/create_sort_key.cpp index 5a6438094..06d87f688 100644 --- a/src/duckdb/src/core_functions/scalar/blob/create_sort_key.cpp +++ b/src/duckdb/src/function/scalar/create_sort_key.cpp @@ -1,10 +1,11 @@ -#include "duckdb/core_functions/scalar/blob_functions.hpp" -#include "duckdb/execution/expression_executor.hpp" +#include "duckdb/function/create_sort_key.hpp" + #include "duckdb/common/enums/order_type.hpp" #include "duckdb/common/radix.hpp" +#include "duckdb/function/scalar/generic_functions.hpp" +#include "duckdb/execution/expression_executor.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression_binder.hpp" -#include "duckdb/core_functions/create_sort_key.hpp" namespace duckdb { @@ -729,6 +730,15 @@ void CreateSortKeyHelpers::CreateSortKey(Vector &input, idx_t input_count, Order CreateSortKeyInternal(sort_key_data, modifiers, result, input_count); } +void CreateSortKeyHelpers::CreateSortKey(DataChunk &input, const vector &modifiers, Vector &result) { + vector> sort_key_data; + D_ASSERT(modifiers.size() == input.ColumnCount()); + for (idx_t r = 0; r < modifiers.size(); r++) { + sort_key_data.push_back(make_uniq(input.data[r], input.size(), modifiers[r])); + } + CreateSortKeyInternal(sort_key_data, modifiers, result, input.size()); +} + void CreateSortKeyHelpers::CreateSortKeyWithValidity(Vector &input, Vector &result, const OrderModifiers &modifiers, const idx_t count) { CreateSortKey(input, count, modifiers, result); diff --git a/src/duckdb/src/core_functions/scalar/date/strftime.cpp b/src/duckdb/src/function/scalar/date/strftime.cpp similarity index 98% rename from src/duckdb/src/core_functions/scalar/date/strftime.cpp rename to src/duckdb/src/function/scalar/date/strftime.cpp index 8aa34d325..1671ff54c 100644 --- a/src/duckdb/src/core_functions/scalar/date/strftime.cpp +++ b/src/duckdb/src/function/scalar/date/strftime.cpp @@ -4,7 +4,7 @@ #include "duckdb/execution/expression_executor.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression/bound_parameter_expression.hpp" -#include "duckdb/core_functions/scalar/date_functions.hpp" +#include "duckdb/function/scalar/date_functions.hpp" #include #include @@ -94,7 +94,7 @@ static void StrfTimeFunctionTimestampNS(DataChunk &args, ExpressionState &state, } ScalarFunctionSet StrfTimeFun::GetFunctions() { - ScalarFunctionSet strftime; + ScalarFunctionSet strftime("strftime"); strftime.AddFunction(ScalarFunction({LogicalType::DATE, LogicalType::VARCHAR}, LogicalType::VARCHAR, StrfTimeFunctionDate, StrfTimeBindFunction)); @@ -296,7 +296,7 @@ struct StrpTimeFunction { }; ScalarFunctionSet StrpTimeFun::GetFunctions() { - ScalarFunctionSet strptime; + ScalarFunctionSet strptime("strptime"); const auto list_type = LogicalType::LIST(LogicalType::VARCHAR); auto fun = ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::TIMESTAMP, @@ -312,7 +312,7 @@ ScalarFunctionSet StrpTimeFun::GetFunctions() { } ScalarFunctionSet TryStrpTimeFun::GetFunctions() { - ScalarFunctionSet try_strptime; + ScalarFunctionSet try_strptime("try_strptime"); const auto list_type = LogicalType::LIST(LogicalType::VARCHAR); auto fun = ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::TIMESTAMP, diff --git a/src/duckdb/src/function/scalar/generic/binning.cpp b/src/duckdb/src/function/scalar/generic/binning.cpp deleted file mode 100644 index aaa9d19db..000000000 --- a/src/duckdb/src/function/scalar/generic/binning.cpp +++ /dev/null @@ -1,507 +0,0 @@ -#include "duckdb/common/exception.hpp" -#include "duckdb/common/hugeint.hpp" -#include "duckdb/common/types/date.hpp" -#include "duckdb/common/types/time.hpp" -#include "duckdb/common/types/timestamp.hpp" -#include "duckdb/common/vector_operations/generic_executor.hpp" -#include "duckdb/core_functions/scalar/generic_functions.hpp" -#include "duckdb/common/operator/subtract.hpp" -#include "duckdb/common/serializer/deserializer.hpp" - -namespace duckdb { - -static hugeint_t GetPreviousPowerOfTen(hugeint_t input) { - hugeint_t power_of_ten = 1; - while (power_of_ten < input) { - power_of_ten *= 10; - } - return power_of_ten / 10; -} - -enum class NiceRounding { CEILING, ROUND }; - -hugeint_t RoundToNumber(hugeint_t input, hugeint_t num, NiceRounding rounding) { - if (rounding == NiceRounding::ROUND) { - return (input + (num / 2)) / num * num; - } else { - return (input + (num - 1)) / num * num; - } -} - -hugeint_t MakeNumberNice(hugeint_t input, hugeint_t step, NiceRounding rounding) { - // we consider numbers nice if they are divisible by 2 or 5 times the power-of-ten one lower than the current - // e.g. 120 is a nice number because it is divisible by 20 - // 122 is not a nice number -> we make it nice by turning it into 120 [/20] - // 153 is not a nice number -> we make it nice by turning it into 150 [/50] - // 1220 is not a nice number -> we turn it into 1200 [/200] - // first figure out the previous power of 10 (i.e. for 67 we return 10) - // now the power of ten is the power BELOW the current number - // i.e. for 67, it is not 10 - // now we can get the 2 or 5 divisors - hugeint_t power_of_ten = GetPreviousPowerOfTen(step); - hugeint_t two = power_of_ten * 2; - hugeint_t five = power_of_ten; - if (power_of_ten * 3 <= step) { - two *= 5; - } - if (power_of_ten * 2 <= step) { - five *= 5; - } - - // compute the closest round number by adding the divisor / 2 and truncating - // do this for both divisors - hugeint_t round_to_two = RoundToNumber(input, two, rounding); - hugeint_t round_to_five = RoundToNumber(input, five, rounding); - // now pick the closest number of the two (i.e. for 147 we pick 150, not 140) - if (AbsValue(input - round_to_two) < AbsValue(input - round_to_five)) { - return round_to_two; - } else { - return round_to_five; - } -} - -static double GetPreviousPowerOfTen(double input) { - double power_of_ten = 1; - if (input < 1) { - while (power_of_ten > input) { - power_of_ten /= 10; - } - return power_of_ten; - } - while (power_of_ten < input) { - power_of_ten *= 10; - } - return power_of_ten / 10; -} - -double RoundToNumber(double input, double num, NiceRounding rounding) { - double result; - if (rounding == NiceRounding::ROUND) { - result = std::round(input / num) * num; - } else { - result = std::ceil(input / num) * num; - } - if (!Value::IsFinite(result)) { - return input; - } - return result; -} - -double MakeNumberNice(double input, const double step, NiceRounding rounding) { - if (input == 0) { - return 0; - } - // now the power of ten is the power BELOW the current number - // i.e. for 67, it is not 10 - // now we can get the 2 or 5 divisors - double power_of_ten = GetPreviousPowerOfTen(step); - double two = power_of_ten * 2; - double five = power_of_ten; - if (power_of_ten * 3 <= step) { - two *= 5; - } - if (power_of_ten * 2 <= step) { - five *= 5; - } - - double round_to_two = RoundToNumber(input, two, rounding); - double round_to_five = RoundToNumber(input, five, rounding); - // now pick the closest number of the two (i.e. for 147 we pick 150, not 140) - if (AbsValue(input - round_to_two) < AbsValue(input - round_to_five)) { - return round_to_two; - } else { - return round_to_five; - } -} - -struct EquiWidthBinsInteger { - static constexpr LogicalTypeId LOGICAL_TYPE = LogicalTypeId::BIGINT; - - static vector> Operation(const Expression &expr, int64_t input_min, int64_t input_max, - idx_t bin_count, bool nice_rounding) { - vector> result; - // to prevent integer truncation from affecting the bin boundaries we calculate them with numbers multiplied by - // 1000 we then divide to get the actual boundaries - const auto FACTOR = hugeint_t(1000); - auto min = hugeint_t(input_min) * FACTOR; - auto max = hugeint_t(input_max) * FACTOR; - - const hugeint_t span = max - min; - hugeint_t step = span / Hugeint::Convert(bin_count); - if (nice_rounding) { - // when doing nice rounding we try to make the max/step values nicer - hugeint_t new_step = MakeNumberNice(step, step, NiceRounding::ROUND); - hugeint_t new_max = RoundToNumber(max, new_step, NiceRounding::CEILING); - if (new_max != min && new_step != 0) { - max = new_max; - step = new_step; - } - // we allow for more bins when doing nice rounding since the bin count is approximate - bin_count *= 2; - } - for (hugeint_t bin_boundary = max; bin_boundary > min; bin_boundary -= step) { - const hugeint_t target_boundary = bin_boundary / FACTOR; - int64_t real_boundary = Hugeint::Cast(target_boundary); - if (!result.empty()) { - if (real_boundary < input_min || result.size() >= bin_count) { - // we can never generate input_min - break; - } - if (real_boundary == result.back().val) { - // we cannot generate the same value multiple times in a row - skip this step - continue; - } - } - result.push_back(real_boundary); - } - return result; - } -}; - -struct EquiWidthBinsDouble { - static constexpr LogicalTypeId LOGICAL_TYPE = LogicalTypeId::DOUBLE; - - static vector> Operation(const Expression &expr, double min, double input_max, - idx_t bin_count, bool nice_rounding) { - double max = input_max; - if (!Value::IsFinite(min) || !Value::IsFinite(max)) { - throw InvalidInputException("equi_width_bucket does not support infinite or nan as min/max value"); - } - vector> result; - const double span = max - min; - double step; - if (!Value::IsFinite(span)) { - // max - min does not fit - step = max / static_cast(bin_count) - min / static_cast(bin_count); - } else { - step = span / static_cast(bin_count); - } - const double step_power_of_ten = GetPreviousPowerOfTen(step); - if (nice_rounding) { - // when doing nice rounding we try to make the max/step values nicer - step = MakeNumberNice(step, step, NiceRounding::ROUND); - max = RoundToNumber(input_max, step, NiceRounding::CEILING); - // we allow for more bins when doing nice rounding since the bin count is approximate - bin_count *= 2; - } - if (step == 0) { - throw InternalException("step is 0!?"); - } - - const double round_multiplication = 10 / step_power_of_ten; - for (double bin_boundary = max; bin_boundary > min; bin_boundary -= step) { - // because floating point addition adds inaccuracies, we add rounding at every step - double real_boundary = bin_boundary; - if (nice_rounding) { - real_boundary = std::round(bin_boundary * round_multiplication) / round_multiplication; - } - if (!result.empty() && result.back().val == real_boundary) { - // skip this step - continue; - } - if (real_boundary <= min || result.size() >= bin_count) { - // we can never generate below input_min - break; - } - result.push_back(real_boundary); - } - return result; - } -}; - -void NextMonth(int32_t &year, int32_t &month) { - month++; - if (month == 13) { - year++; - month = 1; - } -} - -void NextDay(int32_t &year, int32_t &month, int32_t &day) { - day++; - if (!Date::IsValid(year, month, day)) { - // day is out of range for month, move to next month - NextMonth(year, month); - day = 1; - } -} - -void NextHour(int32_t &year, int32_t &month, int32_t &day, int32_t &hour) { - hour++; - if (hour >= 24) { - NextDay(year, month, day); - hour = 0; - } -} - -void NextMinute(int32_t &year, int32_t &month, int32_t &day, int32_t &hour, int32_t &minute) { - minute++; - if (minute >= 60) { - NextHour(year, month, day, hour); - minute = 0; - } -} - -void NextSecond(int32_t &year, int32_t &month, int32_t &day, int32_t &hour, int32_t &minute, int32_t &sec) { - sec++; - if (sec >= 60) { - NextMinute(year, month, day, hour, minute); - sec = 0; - } -} - -timestamp_t MakeTimestampNice(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t minute, int32_t sec, - int32_t micros, interval_t step) { - // how to make a timestamp nice depends on the step - if (step.months >= 12) { - // if the step involves one year or more, ceil to months - // set time component to 00:00:00.00 - if (day > 1 || hour > 0 || minute > 0 || sec > 0 || micros > 0) { - // move to next month - NextMonth(year, month); - hour = minute = sec = micros = 0; - day = 1; - } - } else if (step.months > 0 || step.days >= 1) { - // if the step involves more than one day, ceil to days - if (hour > 0 || minute > 0 || sec > 0 || micros > 0) { - NextDay(year, month, day); - hour = minute = sec = micros = 0; - } - } else if (step.days > 0 || step.micros >= Interval::MICROS_PER_HOUR) { - // if the step involves more than one hour, ceil to hours - if (minute > 0 || sec > 0 || micros > 0) { - NextHour(year, month, day, hour); - minute = sec = micros = 0; - } - } else if (step.micros >= Interval::MICROS_PER_MINUTE) { - // if the step involves more than one minute, ceil to minutes - if (sec > 0 || micros > 0) { - NextMinute(year, month, day, hour, minute); - sec = micros = 0; - } - } else if (step.micros >= Interval::MICROS_PER_SEC) { - // if the step involves more than one second, ceil to seconds - if (micros > 0) { - NextSecond(year, month, day, hour, minute, sec); - micros = 0; - } - } - return Timestamp::FromDatetime(Date::FromDate(year, month, day), Time::FromTime(hour, minute, sec, micros)); -} - -int64_t RoundNumberToDivisor(int64_t number, int64_t divisor) { - return (number + (divisor / 2)) / divisor * divisor; -} - -interval_t MakeIntervalNice(interval_t interval) { - if (interval.months >= 6) { - // if we have more than 6 months, we don't care about days - interval.days = 0; - interval.micros = 0; - } else if (interval.months > 0 || interval.days >= 5) { - // if we have any months or more than 5 days, we don't care about micros - interval.micros = 0; - } else if (interval.days > 0 || interval.micros >= 6 * Interval::MICROS_PER_HOUR) { - // if we any days or more than 6 hours, we want micros to be roundable by hours at least - interval.micros = RoundNumberToDivisor(interval.micros, Interval::MICROS_PER_HOUR); - } else if (interval.micros >= Interval::MICROS_PER_HOUR) { - // if we have more than an hour, we want micros to be divisible by quarter hours - interval.micros = RoundNumberToDivisor(interval.micros, Interval::MICROS_PER_MINUTE * 15); - } else if (interval.micros >= Interval::MICROS_PER_MINUTE * 10) { - // if we have more than 10 minutes, we want micros to be divisible by minutes - interval.micros = RoundNumberToDivisor(interval.micros, Interval::MICROS_PER_MINUTE); - } else if (interval.micros >= Interval::MICROS_PER_MINUTE) { - // if we have more than a minute, we want micros to be divisible by quarter minutes - interval.micros = RoundNumberToDivisor(interval.micros, Interval::MICROS_PER_SEC * 15); - } else if (interval.micros >= Interval::MICROS_PER_SEC * 10) { - // if we have more than 10 seconds, we want micros to be divisible by seconds - interval.micros = RoundNumberToDivisor(interval.micros, Interval::MICROS_PER_SEC); - } - return interval; -} - -void GetTimestampComponents(timestamp_t input, int32_t &year, int32_t &month, int32_t &day, int32_t &hour, - int32_t &minute, int32_t &sec, int32_t µs) { - date_t date; - dtime_t time; - - Timestamp::Convert(input, date, time); - Date::Convert(date, year, month, day); - Time::Convert(time, hour, minute, sec, micros); -} - -struct EquiWidthBinsTimestamp { - static constexpr LogicalTypeId LOGICAL_TYPE = LogicalTypeId::TIMESTAMP; - - static vector> Operation(const Expression &expr, timestamp_t input_min, - timestamp_t input_max, idx_t bin_count, bool nice_rounding) { - if (!Value::IsFinite(input_min) || !Value::IsFinite(input_max)) { - throw InvalidInputException(expr, "equi_width_bucket does not support infinite or nan as min/max value"); - } - - if (!nice_rounding) { - // if we are not doing nice rounding it is pretty simple - just interpolate between the timestamp values - auto interpolated_values = - EquiWidthBinsInteger::Operation(expr, input_min.value, input_max.value, bin_count, false); - - vector> result; - for (auto &val : interpolated_values) { - result.push_back(timestamp_t(val.val)); - } - return result; - } - // fetch the components of the timestamps - int32_t min_year, min_month, min_day, min_hour, min_minute, min_sec, min_micros; - int32_t max_year, max_month, max_day, max_hour, max_minute, max_sec, max_micros; - GetTimestampComponents(input_min, min_year, min_month, min_day, min_hour, min_minute, min_sec, min_micros); - GetTimestampComponents(input_max, max_year, max_month, max_day, max_hour, max_minute, max_sec, max_micros); - - // get the interval differences per component - // note: these can be negative (except for the largest non-zero difference) - interval_t interval_diff; - interval_diff.months = (max_year - min_year) * Interval::MONTHS_PER_YEAR + (max_month - min_month); - interval_diff.days = max_day - min_day; - interval_diff.micros = (max_hour - min_hour) * Interval::MICROS_PER_HOUR + - (max_minute - min_minute) * Interval::MICROS_PER_MINUTE + - (max_sec - min_sec) * Interval::MICROS_PER_SEC + (max_micros - min_micros); - - double step_months = static_cast(interval_diff.months) / static_cast(bin_count); - double step_days = static_cast(interval_diff.days) / static_cast(bin_count); - double step_micros = static_cast(interval_diff.micros) / static_cast(bin_count); - // since we truncate the months/days, propagate any fractional component to the unit below (i.e. 0.2 months - // becomes 6 days) - if (step_months > 0) { - double overflow_months = step_months - std::floor(step_months); - step_days += overflow_months * Interval::DAYS_PER_MONTH; - } - if (step_days > 0) { - double overflow_days = step_days - std::floor(step_days); - step_micros += overflow_days * Interval::MICROS_PER_DAY; - } - interval_t step; - step.months = static_cast(step_months); - step.days = static_cast(step_days); - step.micros = static_cast(step_micros); - - // now we make the max, and the step nice - step = MakeIntervalNice(step); - timestamp_t timestamp_val = - MakeTimestampNice(max_year, max_month, max_day, max_hour, max_minute, max_sec, max_micros, step); - if (step.months <= 0 && step.days <= 0 && step.micros <= 0) { - // interval must be at least one microsecond - step.months = step.days = 0; - step.micros = 1; - } - - vector> result; - while (timestamp_val.value >= input_min.value && result.size() < bin_count) { - result.push_back(timestamp_val); - timestamp_val = SubtractOperator::Operation(timestamp_val, step); - } - return result; - } -}; - -unique_ptr BindEquiWidthFunction(ClientContext &, ScalarFunction &bound_function, - vector> &arguments) { - // while internally the bins are computed over a unified type - // the equi_width_bins function returns the same type as the input MAX - LogicalType child_type; - switch (arguments[1]->return_type.id()) { - case LogicalTypeId::UNKNOWN: - case LogicalTypeId::SQLNULL: - return nullptr; - case LogicalTypeId::DECIMAL: - // for decimals we promote to double because - child_type = LogicalType::DOUBLE; - break; - default: - child_type = arguments[1]->return_type; - break; - } - bound_function.return_type = LogicalType::LIST(child_type); - return nullptr; -} - -template -static void EquiWidthBinFunction(DataChunk &args, ExpressionState &state, Vector &result) { - static constexpr int64_t MAX_BIN_COUNT = 1000000; - auto &min_arg = args.data[0]; - auto &max_arg = args.data[1]; - auto &bin_count = args.data[2]; - auto &nice_rounding = args.data[3]; - - Vector intermediate_result(LogicalType::LIST(OP::LOGICAL_TYPE)); - GenericExecutor::ExecuteQuaternary, PrimitiveType, PrimitiveType, PrimitiveType, - GenericListType>>( - min_arg, max_arg, bin_count, nice_rounding, intermediate_result, args.size(), - [&](PrimitiveType min_p, PrimitiveType max_p, PrimitiveType bins_p, - PrimitiveType nice_rounding_p) { - if (max_p.val < min_p.val) { - throw InvalidInputException(state.expr, - "Invalid input for bin function - max value is smaller than min value"); - } - if (bins_p.val <= 0) { - throw InvalidInputException(state.expr, "Invalid input for bin function - there must be > 0 bins"); - } - if (bins_p.val > MAX_BIN_COUNT) { - throw InvalidInputException(state.expr, "Invalid input for bin function - max bin count of %d exceeded", - MAX_BIN_COUNT); - } - GenericListType> result_bins; - if (max_p.val == min_p.val) { - // if max = min return a single bucket - result_bins.values.push_back(max_p.val); - } else { - result_bins.values = OP::Operation(state.expr, min_p.val, max_p.val, static_cast(bins_p.val), - nice_rounding_p.val); - // last bin should always be the input max - if (result_bins.values[0].val < max_p.val) { - result_bins.values[0].val = max_p.val; - } - std::reverse(result_bins.values.begin(), result_bins.values.end()); - } - return result_bins; - }); - VectorOperations::DefaultCast(intermediate_result, result, args.size()); -} - -static void UnsupportedEquiWidth(DataChunk &args, ExpressionState &state, Vector &) { - throw BinderException(state.expr, "Unsupported type \"%s\" for equi_width_bins", args.data[0].GetType()); -} - -void EquiWidthBinSerialize(Serializer &, const optional_ptr, const ScalarFunction &) { - return; -} - -unique_ptr EquiWidthBinDeserialize(Deserializer &deserializer, ScalarFunction &function) { - function.return_type = deserializer.Get(); - return nullptr; -} - -ScalarFunctionSet EquiWidthBinsFun::GetFunctions() { - ScalarFunctionSet functions("equi_width_bins"); - functions.AddFunction( - ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT, LogicalType::BIGINT, LogicalType::BOOLEAN}, - LogicalType::LIST(LogicalType::ANY), EquiWidthBinFunction, - BindEquiWidthFunction)); - functions.AddFunction(ScalarFunction( - {LogicalType::DOUBLE, LogicalType::DOUBLE, LogicalType::BIGINT, LogicalType::BOOLEAN}, - LogicalType::LIST(LogicalType::ANY), EquiWidthBinFunction, BindEquiWidthFunction)); - functions.AddFunction( - ScalarFunction({LogicalType::TIMESTAMP, LogicalType::TIMESTAMP, LogicalType::BIGINT, LogicalType::BOOLEAN}, - LogicalType::LIST(LogicalType::ANY), EquiWidthBinFunction, - BindEquiWidthFunction)); - functions.AddFunction( - ScalarFunction({LogicalType::ANY_PARAMS(LogicalType::ANY, 150), LogicalType::ANY_PARAMS(LogicalType::ANY, 150), - LogicalType::BIGINT, LogicalType::BOOLEAN}, - LogicalType::LIST(LogicalType::ANY), UnsupportedEquiWidth, BindEquiWidthFunction)); - for (auto &function : functions.functions) { - function.serialize = EquiWidthBinSerialize; - function.deserialize = EquiWidthBinDeserialize; - } - return functions; -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/scalar/generic/constant_or_null.cpp b/src/duckdb/src/function/scalar/generic/constant_or_null.cpp index 05b0ebce6..32b9f855c 100644 --- a/src/duckdb/src/function/scalar/generic/constant_or_null.cpp +++ b/src/duckdb/src/function/scalar/generic/constant_or_null.cpp @@ -1,3 +1,4 @@ +#include "duckdb/function/scalar/generic_common.hpp" #include "duckdb/function/scalar/generic_functions.hpp" #include "duckdb/common/operator/comparison_operators.hpp" #include "duckdb/execution/expression_executor.hpp" @@ -65,10 +66,6 @@ static void ConstantOrNullFunction(DataChunk &args, ExpressionState &state, Vect } } -ScalarFunction ConstantOrNull::GetFunction(const LogicalType &return_type) { - return ScalarFunction("constant_or_null", {return_type, LogicalType::ANY}, return_type, ConstantOrNullFunction); -} - unique_ptr ConstantOrNull::Bind(Value value) { return make_uniq(std::move(value)); } @@ -97,11 +94,12 @@ unique_ptr ConstantOrNullBind(ClientContext &context, ScalarFuncti return make_uniq(std::move(value)); } -void ConstantOrNull::RegisterFunction(BuiltinFunctions &set) { - auto fun = ConstantOrNull::GetFunction(LogicalType::ANY); +ScalarFunction ConstantOrNullFun::GetFunction() { + auto fun = ScalarFunction("constant_or_null", {LogicalType::ANY, LogicalType::ANY}, LogicalType::ANY, + ConstantOrNullFunction); fun.bind = ConstantOrNullBind; fun.varargs = LogicalType::ANY; - set.AddFunction(fun); + return fun; } } // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/generic/error.cpp b/src/duckdb/src/function/scalar/generic/error.cpp similarity index 90% rename from src/duckdb/src/core_functions/scalar/generic/error.cpp rename to src/duckdb/src/function/scalar/generic/error.cpp index e90473784..7563b75a6 100644 --- a/src/duckdb/src/core_functions/scalar/generic/error.cpp +++ b/src/duckdb/src/function/scalar/generic/error.cpp @@ -1,4 +1,5 @@ -#include "duckdb/core_functions/scalar/generic_functions.hpp" +#include "duckdb/function/scalar/generic_functions.hpp" + #include namespace duckdb { diff --git a/src/duckdb/src/function/scalar/generic/getvariable.cpp b/src/duckdb/src/function/scalar/generic/getvariable.cpp index b46ab60db..14d32954d 100644 --- a/src/duckdb/src/function/scalar/generic/getvariable.cpp +++ b/src/duckdb/src/function/scalar/generic/getvariable.cpp @@ -49,10 +49,10 @@ unique_ptr BindGetVariableExpression(FunctionBindExpressionInput &in return make_uniq(bind_data.value); } -void GetVariableFun::RegisterFunction(BuiltinFunctions &set) { +ScalarFunction GetVariableFun::GetFunction() { ScalarFunction getvar("getvariable", {LogicalType::VARCHAR}, LogicalType::ANY, nullptr, GetVariableBind, nullptr); getvar.bind_expression = BindGetVariableExpression; - set.AddFunction(getvar); + return getvar; } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/generic_functions.cpp b/src/duckdb/src/function/scalar/generic_functions.cpp deleted file mode 100644 index 27330ab1f..000000000 --- a/src/duckdb/src/function/scalar/generic_functions.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "duckdb/function/scalar/generic_functions.hpp" - -namespace duckdb { - -void BuiltinFunctions::RegisterGenericFunctions() { - Register(); - Register(); - Register(); -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/scalar/list/contains_or_position.cpp b/src/duckdb/src/function/scalar/list/contains_or_position.cpp index c10e467b2..309d78c39 100644 --- a/src/duckdb/src/function/scalar/list/contains_or_position.cpp +++ b/src/duckdb/src/function/scalar/list/contains_or_position.cpp @@ -1,3 +1,4 @@ +#include "duckdb/function/scalar/list_functions.hpp" #include "duckdb/function/scalar/nested_functions.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" #include "duckdb/planner/expression_binder.hpp" @@ -66,11 +67,4 @@ ScalarFunction ListPositionFun::GetFunction() { ListSearchFunction, ListSearchBind); } -void ListContainsFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction({"list_contains", "array_contains", "list_has", "array_has"}, GetFunction()); -} - -void ListPositionFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction({"list_position", "list_indexof", "array_position", "array_indexof"}, GetFunction()); -} } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/list/list_extract.cpp b/src/duckdb/src/function/scalar/list/list_extract.cpp index 37176f23a..55017f5cb 100644 --- a/src/duckdb/src/function/scalar/list/list_extract.cpp +++ b/src/duckdb/src/function/scalar/list/list_extract.cpp @@ -4,7 +4,8 @@ #include "duckdb/common/uhugeint.hpp" #include "duckdb/common/vector_operations/binary_executor.hpp" #include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/function/scalar/string_functions.hpp" +#include "duckdb/function/scalar/string_common.hpp" +#include "duckdb/function/scalar/list_functions.hpp" #include "duckdb/parser/expression/bound_expression.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" @@ -105,9 +106,8 @@ static void ExecuteListExtract(Vector &result, Vector &list, Vector &offsets, co static void ExecuteStringExtract(Vector &result, Vector &input_vector, Vector &subscript_vector, const idx_t count) { BinaryExecutor::Execute( - input_vector, subscript_vector, result, count, [&](string_t input_string, int64_t subscript) { - return SubstringFun::SubstringUnicode(result, input_string, subscript, 1); - }); + input_vector, subscript_vector, result, count, + [&](string_t input_string, int64_t subscript) { return SubstringUnicode(result, input_string, subscript, 1); }); } static void ListExtractFunction(DataChunk &args, ExpressionState &state, Vector &result) { @@ -156,29 +156,34 @@ static unique_ptr ListExtractStats(ClientContext &context, Funct return child_copy.ToUnique(); } -void ListExtractFun::RegisterFunction(BuiltinFunctions &set) { +ScalarFunctionSet ListExtractFun::GetFunctions() { + ScalarFunctionSet list_extract_set("list_extract"); + + // the arguments and return types are actually set in the binder function + ScalarFunction lfun({LogicalType::LIST(LogicalType::ANY), LogicalType::BIGINT}, LogicalType::ANY, + ListExtractFunction, ListExtractBind, nullptr, ListExtractStats); + + ScalarFunction sfun({LogicalType::VARCHAR, LogicalType::BIGINT}, LogicalType::VARCHAR, ListExtractFunction); + + list_extract_set.AddFunction(lfun); + list_extract_set.AddFunction(sfun); + return list_extract_set; +} + +ScalarFunctionSet ArrayExtractFun::GetFunctions() { + ScalarFunctionSet array_extract_set("array_extract"); + // the arguments and return types are actually set in the binder function ScalarFunction lfun({LogicalType::LIST(LogicalType::ANY), LogicalType::BIGINT}, LogicalType::ANY, ListExtractFunction, ListExtractBind, nullptr, ListExtractStats); ScalarFunction sfun({LogicalType::VARCHAR, LogicalType::BIGINT}, LogicalType::VARCHAR, ListExtractFunction); - ScalarFunctionSet list_extract("list_extract"); - list_extract.AddFunction(lfun); - list_extract.AddFunction(sfun); - set.AddFunction(list_extract); - - ScalarFunctionSet list_element("list_element"); - list_element.AddFunction(lfun); - list_element.AddFunction(sfun); - set.AddFunction(list_element); - - ScalarFunctionSet array_extract("array_extract"); - array_extract.AddFunction(lfun); - array_extract.AddFunction(sfun); - array_extract.AddFunction(StructExtractFun::KeyExtractFunction()); - array_extract.AddFunction(StructExtractFun::IndexExtractFunction()); - set.AddFunction(array_extract); + array_extract_set.AddFunction(lfun); + array_extract_set.AddFunction(sfun); + array_extract_set.AddFunction(GetKeyExtractFunction()); + array_extract_set.AddFunction(GetIndexExtractFunction()); + return array_extract_set; } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/list/list_resize.cpp b/src/duckdb/src/function/scalar/list/list_resize.cpp index 86d21fd58..dc20d00b9 100644 --- a/src/duckdb/src/function/scalar/list/list_resize.cpp +++ b/src/duckdb/src/function/scalar/list/list_resize.cpp @@ -1,5 +1,6 @@ #include "duckdb/common/types/data_chunk.hpp" #include "duckdb/function/scalar/nested_functions.hpp" +#include "duckdb/function/scalar/list_functions.hpp" #include "duckdb/function/scalar_function.hpp" #include "duckdb/function/built_in_functions.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" @@ -154,7 +155,7 @@ static unique_ptr ListResizeBind(ClientContext &context, ScalarFun return make_uniq(bound_function.return_type); } -void ListResizeFun::RegisterFunction(BuiltinFunctions &set) { +ScalarFunctionSet ListResizeFun::GetFunctions() { ScalarFunction simple_fun({LogicalType::LIST(LogicalTypeId::ANY), LogicalTypeId::ANY}, LogicalType::LIST(LogicalTypeId::ANY), ListResizeFunction, ListResizeBind); simple_fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; @@ -163,15 +164,10 @@ void ListResizeFun::RegisterFunction(BuiltinFunctions &set) { LogicalType::LIST(LogicalTypeId::ANY), ListResizeFunction, ListResizeBind); default_value_fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - ScalarFunctionSet list_resize("list_resize"); - list_resize.AddFunction(simple_fun); - list_resize.AddFunction(default_value_fun); - set.AddFunction(list_resize); - - ScalarFunctionSet array_resize("array_resize"); - array_resize.AddFunction(simple_fun); - array_resize.AddFunction(default_value_fun); - set.AddFunction(array_resize); + ScalarFunctionSet list_resize_set("list_resize"); + list_resize_set.AddFunction(simple_fun); + list_resize_set.AddFunction(default_value_fun); + return list_resize_set; } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/list/list_select.cpp b/src/duckdb/src/function/scalar/list/list_select.cpp index 07413977b..55c6a9f1d 100644 --- a/src/duckdb/src/function/scalar/list/list_select.cpp +++ b/src/duckdb/src/function/scalar/list/list_select.cpp @@ -4,6 +4,7 @@ #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression/bound_parameter_expression.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" +#include "duckdb/function/scalar/list_functions.hpp" namespace duckdb { @@ -179,8 +180,4 @@ ScalarFunction ListSelectFun::GetFunction() { return fun; } -void ListSelectFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction({"list_select", "array_select"}, ListSelectFun::GetFunction()); - set.AddFunction({"list_where", "array_where"}, ListWhereFun::GetFunction()); -} } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/list/list_zip.cpp b/src/duckdb/src/function/scalar/list/list_zip.cpp index 6e24689cf..9aa0ec397 100644 --- a/src/duckdb/src/function/scalar/list/list_zip.cpp +++ b/src/duckdb/src/function/scalar/list/list_zip.cpp @@ -1,4 +1,5 @@ #include "duckdb/common/types/data_chunk.hpp" +#include "duckdb/function/scalar/list_functions.hpp" #include "duckdb/function/scalar/nested_functions.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" #include "duckdb/planner/expression_binder.hpp" @@ -164,7 +165,4 @@ ScalarFunction ListZipFun::GetFunction() { return fun; } -void ListZipFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction({"list_zip", "array_zip"}, GetFunction()); -} } // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/map/map_contains.cpp b/src/duckdb/src/function/scalar/map/map_contains.cpp similarity index 97% rename from src/duckdb/src/core_functions/scalar/map/map_contains.cpp rename to src/duckdb/src/function/scalar/map/map_contains.cpp index 19a46015c..068e67bc7 100644 --- a/src/duckdb/src/core_functions/scalar/map/map_contains.cpp +++ b/src/duckdb/src/function/scalar/map/map_contains.cpp @@ -1,6 +1,6 @@ -#include "duckdb/core_functions/scalar/map_functions.hpp" #include "duckdb/function/scalar/list/contains_or_position.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" +#include "duckdb/function/scalar/map_functions.hpp" namespace duckdb { @@ -48,9 +48,9 @@ static unique_ptr MapContainsBind(ClientContext &context, ScalarFu } ScalarFunction MapContainsFun::GetFunction() { - ScalarFunction fun("map_contains", {LogicalType::MAP(LogicalType::ANY, LogicalType::ANY), LogicalType::ANY}, LogicalType::BOOLEAN, MapContainsFunction, MapContainsBind); return fun; } + } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/nested_functions.cpp b/src/duckdb/src/function/scalar/nested_functions.cpp index 8685ad4aa..2d5359c4e 100644 --- a/src/duckdb/src/function/scalar/nested_functions.cpp +++ b/src/duckdb/src/function/scalar/nested_functions.cpp @@ -37,15 +37,4 @@ void MapUtil::ReinterpretMap(Vector &result, Vector &input, idx_t count) { result.SetVectorType(input.GetVectorType()); } -void BuiltinFunctions::RegisterNestedFunctions() { - Register(); - Register(); - Register(); - Register(); - Register(); - Register(); - Register(); - Register(); -} - } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/operators/add.cpp b/src/duckdb/src/function/scalar/operator/add.cpp similarity index 100% rename from src/duckdb/src/function/scalar/operators/add.cpp rename to src/duckdb/src/function/scalar/operator/add.cpp diff --git a/src/duckdb/src/function/scalar/operators/arithmetic.cpp b/src/duckdb/src/function/scalar/operator/arithmetic.cpp similarity index 91% rename from src/duckdb/src/function/scalar/operators/arithmetic.cpp rename to src/duckdb/src/function/scalar/operator/arithmetic.cpp index 037897830..ed85071ff 100644 --- a/src/duckdb/src/function/scalar/operators/arithmetic.cpp +++ b/src/duckdb/src/function/scalar/operator/arithmetic.cpp @@ -12,6 +12,7 @@ #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/function/scalar/nested_functions.hpp" #include "duckdb/function/scalar/operators.hpp" +#include "duckdb/function/scalar/operator_functions.hpp" #include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" @@ -298,7 +299,7 @@ unique_ptr NopDecimalBind(ClientContext &context, ScalarFunction & return nullptr; } -ScalarFunction AddFun::GetFunction(const LogicalType &type) { +ScalarFunction AddFunction::GetFunction(const LogicalType &type) { D_ASSERT(type.IsNumeric()); if (type.id() == LogicalTypeId::DECIMAL) { return ScalarFunction("+", {type}, type, ScalarFunction::NopFunction, NopDecimalBind); @@ -307,7 +308,7 @@ ScalarFunction AddFun::GetFunction(const LogicalType &type) { } } -ScalarFunction AddFun::GetFunction(const LogicalType &left_type, const LogicalType &right_type) { +ScalarFunction AddFunction::GetFunction(const LogicalType &left_type, const LogicalType &right_type) { if (left_type.IsNumeric() && left_type.id() == right_type.id()) { if (left_type.id() == LogicalTypeId::DECIMAL) { auto function = ScalarFunction("+", {left_type, right_type}, left_type, nullptr, @@ -398,47 +399,44 @@ ScalarFunction AddFun::GetFunction(const LogicalType &left_type, const LogicalTy // LCOV_EXCL_STOP } -void AddFun::RegisterFunction(BuiltinFunctions &set) { - ScalarFunctionSet functions("+"); +ScalarFunctionSet OperatorAddFun::GetFunctions() { + ScalarFunctionSet add("+"); for (auto &type : LogicalType::Numeric()) { // unary add function is a nop, but only exists for numeric types - functions.AddFunction(GetFunction(type)); + add.AddFunction(AddFunction::GetFunction(type)); // binary add function adds two numbers together - functions.AddFunction(GetFunction(type, type)); + add.AddFunction(AddFunction::GetFunction(type, type)); } // we can add integers to dates - functions.AddFunction(GetFunction(LogicalType::DATE, LogicalType::INTEGER)); - functions.AddFunction(GetFunction(LogicalType::INTEGER, LogicalType::DATE)); + add.AddFunction(AddFunction::GetFunction(LogicalType::DATE, LogicalType::INTEGER)); + add.AddFunction(AddFunction::GetFunction(LogicalType::INTEGER, LogicalType::DATE)); // we can add intervals together - functions.AddFunction(GetFunction(LogicalType::INTERVAL, LogicalType::INTERVAL)); + add.AddFunction(AddFunction::GetFunction(LogicalType::INTERVAL, LogicalType::INTERVAL)); // we can add intervals to dates/times/timestamps - functions.AddFunction(GetFunction(LogicalType::DATE, LogicalType::INTERVAL)); - functions.AddFunction(GetFunction(LogicalType::INTERVAL, LogicalType::DATE)); + add.AddFunction(AddFunction::GetFunction(LogicalType::DATE, LogicalType::INTERVAL)); + add.AddFunction(AddFunction::GetFunction(LogicalType::INTERVAL, LogicalType::DATE)); - functions.AddFunction(GetFunction(LogicalType::TIME, LogicalType::INTERVAL)); - functions.AddFunction(GetFunction(LogicalType::INTERVAL, LogicalType::TIME)); + add.AddFunction(AddFunction::GetFunction(LogicalType::TIME, LogicalType::INTERVAL)); + add.AddFunction(AddFunction::GetFunction(LogicalType::INTERVAL, LogicalType::TIME)); - functions.AddFunction(GetFunction(LogicalType::TIMESTAMP, LogicalType::INTERVAL)); - functions.AddFunction(GetFunction(LogicalType::INTERVAL, LogicalType::TIMESTAMP)); + add.AddFunction(AddFunction::GetFunction(LogicalType::TIMESTAMP, LogicalType::INTERVAL)); + add.AddFunction(AddFunction::GetFunction(LogicalType::INTERVAL, LogicalType::TIMESTAMP)); - functions.AddFunction(GetFunction(LogicalType::TIME_TZ, LogicalType::INTERVAL)); - functions.AddFunction(GetFunction(LogicalType::INTERVAL, LogicalType::TIME_TZ)); + add.AddFunction(AddFunction::GetFunction(LogicalType::TIME_TZ, LogicalType::INTERVAL)); + add.AddFunction(AddFunction::GetFunction(LogicalType::INTERVAL, LogicalType::TIME_TZ)); // we can add times to dates - functions.AddFunction(GetFunction(LogicalType::TIME, LogicalType::DATE)); - functions.AddFunction(GetFunction(LogicalType::DATE, LogicalType::TIME)); + add.AddFunction(AddFunction::GetFunction(LogicalType::TIME, LogicalType::DATE)); + add.AddFunction(AddFunction::GetFunction(LogicalType::DATE, LogicalType::TIME)); // we can add times with time zones (offsets) to dates - functions.AddFunction(GetFunction(LogicalType::TIME_TZ, LogicalType::DATE)); - functions.AddFunction(GetFunction(LogicalType::DATE, LogicalType::TIME_TZ)); + add.AddFunction(AddFunction::GetFunction(LogicalType::TIME_TZ, LogicalType::DATE)); + add.AddFunction(AddFunction::GetFunction(LogicalType::DATE, LogicalType::TIME_TZ)); // we can add lists together - functions.AddFunction(ListConcatFun::GetFunction()); + add.AddFunction(ListConcatFun::GetFunction()); - set.AddFunction(functions); - - functions.name = "add"; - set.AddFunction(functions); + return add; } //===--------------------------------------------------------------------===// @@ -578,7 +576,7 @@ static unique_ptr NegateBindStatistics(ClientContext &context, F return stats.ToUnique(); } -ScalarFunction SubtractFun::GetFunction(const LogicalType &type) { +ScalarFunction SubtractFunction::GetFunction(const LogicalType &type) { if (type.id() == LogicalTypeId::INTERVAL) { return ScalarFunction("-", {type}, type, ScalarFunction::UnaryFunction); } else if (type.id() == LogicalTypeId::DECIMAL) { @@ -590,7 +588,7 @@ ScalarFunction SubtractFun::GetFunction(const LogicalType &type) { } } -ScalarFunction SubtractFun::GetFunction(const LogicalType &left_type, const LogicalType &right_type) { +ScalarFunction SubtractFunction::GetFunction(const LogicalType &left_type, const LogicalType &right_type) { if (left_type.IsNumeric() && left_type.id() == right_type.id()) { if (left_type.id() == LogicalTypeId::DECIMAL) { auto function = @@ -664,33 +662,31 @@ ScalarFunction SubtractFun::GetFunction(const LogicalType &left_type, const Logi // LCOV_EXCL_STOP } -void SubtractFun::RegisterFunction(BuiltinFunctions &set) { - ScalarFunctionSet functions("-"); +ScalarFunctionSet OperatorSubtractFun::GetFunctions() { + ScalarFunctionSet subtract("-"); for (auto &type : LogicalType::Numeric()) { // unary subtract function, negates the input (i.e. multiplies by -1) - functions.AddFunction(GetFunction(type)); + subtract.AddFunction(SubtractFunction::GetFunction(type)); // binary subtract function "a - b", subtracts b from a - functions.AddFunction(GetFunction(type, type)); + subtract.AddFunction(SubtractFunction::GetFunction(type, type)); } // we can subtract dates from each other - functions.AddFunction(GetFunction(LogicalType::DATE, LogicalType::DATE)); + subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::DATE, LogicalType::DATE)); // we can subtract integers from dates - functions.AddFunction(GetFunction(LogicalType::DATE, LogicalType::INTEGER)); + subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::DATE, LogicalType::INTEGER)); // we can subtract timestamps from each other - functions.AddFunction(GetFunction(LogicalType::TIMESTAMP, LogicalType::TIMESTAMP)); + subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::TIMESTAMP, LogicalType::TIMESTAMP)); // we can subtract intervals from each other - functions.AddFunction(GetFunction(LogicalType::INTERVAL, LogicalType::INTERVAL)); + subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::INTERVAL, LogicalType::INTERVAL)); // we can subtract intervals from dates/times/timestamps, but not the other way around - functions.AddFunction(GetFunction(LogicalType::DATE, LogicalType::INTERVAL)); - functions.AddFunction(GetFunction(LogicalType::TIME, LogicalType::INTERVAL)); - functions.AddFunction(GetFunction(LogicalType::TIMESTAMP, LogicalType::INTERVAL)); - functions.AddFunction(GetFunction(LogicalType::TIME_TZ, LogicalType::INTERVAL)); + subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::DATE, LogicalType::INTERVAL)); + subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::TIME, LogicalType::INTERVAL)); + subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::TIMESTAMP, LogicalType::INTERVAL)); + subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::TIME_TZ, LogicalType::INTERVAL)); // we can negate intervals - functions.AddFunction(GetFunction(LogicalType::INTERVAL)); - set.AddFunction(functions); + subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::INTERVAL)); - functions.name = "subtract"; - set.AddFunction(functions); + return subtract; } //===--------------------------------------------------------------------===// @@ -803,34 +799,32 @@ unique_ptr BindDecimalMultiply(ClientContext &context, ScalarFunct return std::move(bind_data); } -void MultiplyFun::RegisterFunction(BuiltinFunctions &set) { - ScalarFunctionSet functions("*"); +ScalarFunctionSet OperatorMultiplyFun::GetFunctions() { + ScalarFunctionSet multiply("*"); for (auto &type : LogicalType::Numeric()) { if (type.id() == LogicalTypeId::DECIMAL) { ScalarFunction function({type, type}, type, nullptr, BindDecimalMultiply); function.serialize = SerializeDecimalArithmetic; function.deserialize = DeserializeDecimalArithmetic; - functions.AddFunction(function); + multiply.AddFunction(function); } else if (TypeIsIntegral(type.InternalType())) { - functions.AddFunction(ScalarFunction( + multiply.AddFunction(ScalarFunction( {type, type}, type, GetScalarIntegerFunction(type.InternalType()), nullptr, nullptr, PropagateNumericStats)); } else { - functions.AddFunction( + multiply.AddFunction( ScalarFunction({type, type}, type, GetScalarBinaryFunction(type.InternalType()))); } } - functions.AddFunction( + multiply.AddFunction( ScalarFunction({LogicalType::INTERVAL, LogicalType::BIGINT}, LogicalType::INTERVAL, ScalarFunction::BinaryFunction)); - functions.AddFunction( + multiply.AddFunction( ScalarFunction({LogicalType::BIGINT, LogicalType::INTERVAL}, LogicalType::INTERVAL, ScalarFunction::BinaryFunction)); - set.AddFunction(functions); - functions.name = "multiply"; - set.AddFunction(functions); + return multiply; } //===--------------------------------------------------------------------===// @@ -965,7 +959,7 @@ unique_ptr BindBinaryFloatingPoint(ClientContext &context, ScalarF return nullptr; } -void DivideFun::RegisterFunction(BuiltinFunctions &set) { +ScalarFunctionSet OperatorFloatDivideFun::GetFunctions() { ScalarFunctionSet fp_divide("/"); fp_divide.AddFunction(ScalarFunction({LogicalType::FLOAT, LogicalType::FLOAT}, LogicalType::FLOAT, nullptr, BindBinaryFloatingPoint)); @@ -974,8 +968,10 @@ void DivideFun::RegisterFunction(BuiltinFunctions &set) { fp_divide.AddFunction( ScalarFunction({LogicalType::INTERVAL, LogicalType::BIGINT}, LogicalType::INTERVAL, BinaryScalarFunctionIgnoreZero)); - set.AddFunction(fp_divide); + return fp_divide; +} +ScalarFunctionSet OperatorIntegerDivideFun::GetFunctions() { ScalarFunctionSet full_divide("//"); for (auto &type : LogicalType::Numeric()) { if (type.id() == LogicalTypeId::DECIMAL) { @@ -985,10 +981,7 @@ void DivideFun::RegisterFunction(BuiltinFunctions &set) { ScalarFunction({type, type}, type, GetBinaryFunctionIgnoreZero(type.InternalType()))); } } - set.AddFunction(full_divide); - - full_divide.name = "divide"; - set.AddFunction(full_divide); + return full_divide; } //===--------------------------------------------------------------------===// @@ -1031,21 +1024,19 @@ hugeint_t ModuloOperator::Operation(hugeint_t left, hugeint_t right) { return left % right; } -void ModFun::RegisterFunction(BuiltinFunctions &set) { - ScalarFunctionSet functions("%"); +ScalarFunctionSet OperatorModuloFun::GetFunctions() { + ScalarFunctionSet modulo("%"); for (auto &type : LogicalType::Numeric()) { if (type.id() == LogicalTypeId::FLOAT || type.id() == LogicalTypeId::DOUBLE) { - functions.AddFunction(ScalarFunction({type, type}, type, nullptr, BindBinaryFloatingPoint)); + modulo.AddFunction(ScalarFunction({type, type}, type, nullptr, BindBinaryFloatingPoint)); } else if (type.id() == LogicalTypeId::DECIMAL) { - functions.AddFunction(ScalarFunction({type, type}, type, nullptr, BindDecimalModulo)); + modulo.AddFunction(ScalarFunction({type, type}, type, nullptr, BindDecimalModulo)); } else { - functions.AddFunction( + modulo.AddFunction( ScalarFunction({type, type}, type, GetBinaryFunctionIgnoreZero(type.InternalType()))); } } - set.AddFunction(functions); - functions.name = "mod"; - set.AddFunction(functions); + return modulo; } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/operators/multiply.cpp b/src/duckdb/src/function/scalar/operator/multiply.cpp similarity index 100% rename from src/duckdb/src/function/scalar/operators/multiply.cpp rename to src/duckdb/src/function/scalar/operator/multiply.cpp diff --git a/src/duckdb/src/function/scalar/operators/subtract.cpp b/src/duckdb/src/function/scalar/operator/subtract.cpp similarity index 100% rename from src/duckdb/src/function/scalar/operators/subtract.cpp rename to src/duckdb/src/function/scalar/operator/subtract.cpp diff --git a/src/duckdb/src/function/scalar/operators.cpp b/src/duckdb/src/function/scalar/operators.cpp deleted file mode 100644 index 2862b13c2..000000000 --- a/src/duckdb/src/function/scalar/operators.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "duckdb/function/scalar/operators.hpp" -#include "duckdb/common/exception.hpp" - -namespace duckdb { - -void BuiltinFunctions::RegisterOperators() { - Register(); - Register(); - Register(); - Register(); - Register(); -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/scalar/sequence/nextval.cpp b/src/duckdb/src/function/scalar/sequence/nextval.cpp index f25fac67d..d70168c9a 100644 --- a/src/duckdb/src/function/scalar/sequence/nextval.cpp +++ b/src/duckdb/src/function/scalar/sequence/nextval.cpp @@ -1,4 +1,5 @@ #include "duckdb/function/scalar/sequence_functions.hpp" +#include "duckdb/function/scalar/sequence_utils.hpp" #include "duckdb/catalog/catalog.hpp" #include "duckdb/catalog/dependency_list.hpp" @@ -129,7 +130,7 @@ void NextValModifiedDatabases(ClientContext &context, FunctionModifiedDatabasesI input.properties.RegisterDBModify(seq.sequence.ParentCatalog(), context); } -void NextvalFun::RegisterFunction(BuiltinFunctions &set) { +ScalarFunction NextvalFun::GetFunction() { ScalarFunction next_val("nextval", {LogicalType::VARCHAR}, LogicalType::BIGINT, NextValFunction, NextValBind, NextValDependency); next_val.stability = FunctionStability::VOLATILE; @@ -137,17 +138,17 @@ void NextvalFun::RegisterFunction(BuiltinFunctions &set) { next_val.deserialize = Deserialize; next_val.get_modified_databases = NextValModifiedDatabases; next_val.init_local_state = NextValLocalFunction; - set.AddFunction(next_val); + return next_val; } -void CurrvalFun::RegisterFunction(BuiltinFunctions &set) { +ScalarFunction CurrvalFun::GetFunction() { ScalarFunction curr_val("currval", {LogicalType::VARCHAR}, LogicalType::BIGINT, NextValFunction, NextValBind, NextValDependency); curr_val.stability = FunctionStability::VOLATILE; curr_val.serialize = Serialize; curr_val.deserialize = Deserialize; curr_val.init_local_state = NextValLocalFunction; - set.AddFunction(curr_val); + return curr_val; } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/sequence_functions.cpp b/src/duckdb/src/function/scalar/sequence_functions.cpp deleted file mode 100644 index 30b0c0659..000000000 --- a/src/duckdb/src/function/scalar/sequence_functions.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "duckdb/function/scalar/sequence_functions.hpp" - -namespace duckdb { - -void BuiltinFunctions::RegisterSequenceFunctions() { - Register(); - Register(); -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/caseconvert.cpp b/src/duckdb/src/function/scalar/string/caseconvert.cpp index b6240d062..d0d850f5a 100644 --- a/src/duckdb/src/function/scalar/string/caseconvert.cpp +++ b/src/duckdb/src/function/scalar/string/caseconvert.cpp @@ -1,6 +1,8 @@ #include "duckdb/function/scalar/string_functions.hpp" +#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/common/exception.hpp" +#include "duckdb/common/string_util.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/common/vector_operations/unary_executor.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" @@ -11,41 +13,14 @@ namespace duckdb { -const uint8_t UpperFun::ASCII_TO_UPPER_MAP[] = { - 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, 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, 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, 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}; -const uint8_t LowerFun::ASCII_TO_LOWER_MAP[] = { - 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, 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}; - template static string_t ASCIICaseConvert(Vector &result, const char *input_data, idx_t input_length) { idx_t output_length = input_length; auto result_str = StringVector::EmptyString(result, output_length); auto result_data = result_str.GetDataWriteable(); for (idx_t i = 0; i < input_length; i++) { - result_data[i] = UnsafeNumericCast(IS_UPPER ? UpperFun::ASCII_TO_UPPER_MAP[uint8_t(input_data[i])] - : LowerFun::ASCII_TO_LOWER_MAP[uint8_t(input_data[i])]); + result_data[i] = UnsafeNumericCast(IS_UPPER ? StringUtil::ASCII_TO_UPPER_MAP[uint8_t(input_data[i])] + : StringUtil::ASCII_TO_LOWER_MAP[uint8_t(input_data[i])]); } result_str.Finalize(); return result_str; @@ -90,19 +65,19 @@ static void CaseConvert(const char *input_data, idx_t input_length, char *result i += UnsafeNumericCast(sz); } else { // ascii - *result_data = UnsafeNumericCast(IS_UPPER ? UpperFun::ASCII_TO_UPPER_MAP[uint8_t(input_data[i])] - : LowerFun::ASCII_TO_LOWER_MAP[uint8_t(input_data[i])]); + *result_data = UnsafeNumericCast(IS_UPPER ? StringUtil::ASCII_TO_UPPER_MAP[uint8_t(input_data[i])] + : StringUtil::ASCII_TO_LOWER_MAP[uint8_t(input_data[i])]); result_data++; i++; } } } -idx_t LowerFun::LowerLength(const char *input_data, idx_t input_length) { +idx_t LowerLength(const char *input_data, idx_t input_length) { return GetResultLength(input_data, input_length); } -void LowerFun::LowerCase(const char *input_data, idx_t input_length, char *result_data) { +void LowerCase(const char *input_data, idx_t input_length, char *result_data) { CaseConvert(input_data, input_length, result_data); } @@ -166,14 +141,9 @@ ScalarFunction LowerFun::GetFunction() { nullptr, CaseConvertPropagateStats); } -void LowerFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction({"lower", "lcase"}, LowerFun::GetFunction()); -} - -void UpperFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction({"upper", "ucase"}, - ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, CaseConvertFunction, nullptr, - nullptr, CaseConvertPropagateStats)); +ScalarFunction UpperFun::GetFunction() { + return ScalarFunction("upper", {LogicalType::VARCHAR}, LogicalType::VARCHAR, CaseConvertFunction, nullptr, + nullptr, CaseConvertPropagateStats); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/concat.cpp b/src/duckdb/src/function/scalar/string/concat.cpp index 0f1d35099..a6a495a95 100644 --- a/src/duckdb/src/function/scalar/string/concat.cpp +++ b/src/duckdb/src/function/scalar/string/concat.cpp @@ -4,6 +4,7 @@ #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/function/scalar/nested_functions.hpp" #include "duckdb/function/scalar/string_functions.hpp" + #include "duckdb/planner/expression/bound_cast_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" @@ -154,14 +155,14 @@ struct ListConcatInputData { const list_entry_t *input_entries = nullptr; }; -static void ListConcatFunction(DataChunk &args, ExpressionState &state, Vector &result) { +static void ListConcatFunction(DataChunk &args, ExpressionState &state, Vector &result, bool is_operator) { auto count = args.size(); auto result_entries = FlatVector::GetData(result); vector input_data; for (auto &input : args.data) { - if (input.GetType().id() == LogicalTypeId::SQLNULL) { - // ignore NULL values + if (!is_operator && input.GetType().id() == LogicalTypeId::SQLNULL) { + // LIST_CONCAT ignores NULL values continue; } @@ -177,6 +178,7 @@ static void ListConcatFunction(DataChunk &args, ExpressionState &state, Vector & input_data.push_back(std::move(data)); } + auto &result_validity = FlatVector::Validity(result); idx_t offset = 0; for (idx_t i = 0; i < count; i++) { auto &result_entry = result_entries[i]; @@ -185,6 +187,10 @@ static void ListConcatFunction(DataChunk &args, ExpressionState &state, Vector & for (auto &data : input_data) { auto list_index = data.vdata.sel->get_index(i); if (!data.vdata.validity.RowIsValid(list_index)) { + // LIST_CONCAT ignores NULL values, but || does not + if (is_operator) { + result_validity.SetInvalid(i); + } continue; } const auto &list_entry = data.input_entries[list_index]; @@ -205,7 +211,7 @@ static void ConcatFunction(DataChunk &args, ExpressionState &state, Vector &resu auto &func_expr = state.expr.Cast(); auto &info = func_expr.bind_info->Cast(); if (info.return_type.id() == LogicalTypeId::LIST) { - return ListConcatFunction(args, state, result); + return ListConcatFunction(args, state, result, info.is_operator); } else if (info.is_operator) { return ConcatOperator(args, state, result); } @@ -336,30 +342,26 @@ ScalarFunction ListConcatFun::GetFunction() { return fun; } -void ListConcatFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction({"list_concat", "list_cat", "array_concat", "array_cat"}, GetFunction()); -} - -void ConcatFun::RegisterFunction(BuiltinFunctions &set) { - // the concat operator and concat function have different behavior regarding NULLs - // this is strange but seems consistent with postgresql and mysql - // (sqlite does not support the concat function, only the concat operator) - - // the concat operator behaves as one would expect: any NULL value present results in a NULL - // i.e. NULL || 'hello' = NULL - // the concat function, however, treats NULL values as an empty string - // i.e. concat(NULL, 'hello') = 'hello' +// the concat operator and concat function have different behavior regarding NULLs +// this is strange but seems consistent with postgresql and mysql +// (sqlite does not support the concat function, only the concat operator) +// the concat operator behaves as one would expect: any NULL value present results in a NULL +// i.e. NULL || 'hello' = NULL +// the concat function, however, treats NULL values as an empty string +// i.e. concat(NULL, 'hello') = 'hello' +ScalarFunction ConcatFun::GetFunction() { ScalarFunction concat = ScalarFunction("concat", {LogicalType::ANY}, LogicalType::ANY, ConcatFunction, BindConcatFunction); concat.varargs = LogicalType::ANY; concat.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - set.AddFunction(concat); + return concat; +} +ScalarFunction ConcatOperatorFun::GetFunction() { ScalarFunction concat_op = ScalarFunction("||", {LogicalType::ANY, LogicalType::ANY}, LogicalType::ANY, ConcatFunction, BindConcatOperator); - concat.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - set.AddFunction(concat_op); + return concat_op; } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/concat_ws.cpp b/src/duckdb/src/function/scalar/string/concat_ws.cpp index 7689738c4..ebc1e8b3a 100644 --- a/src/duckdb/src/function/scalar/string/concat_ws.cpp +++ b/src/duckdb/src/function/scalar/string/concat_ws.cpp @@ -130,7 +130,7 @@ static unique_ptr BindConcatWSFunction(ClientContext &context, Sca return nullptr; } -void ConcatWSFun::RegisterFunction(BuiltinFunctions &set) { +ScalarFunction ConcatWsFun::GetFunction() { // concat_ws functions similarly to the concat function, except the result is NULL if the separator is NULL // if the separator is not NULL, however, NULL values are counted as empty string // there is one separate rule: there are no separators added between NULL values, @@ -143,7 +143,7 @@ void ConcatWSFun::RegisterFunction(BuiltinFunctions &set) { LogicalType::VARCHAR, ConcatWSFunction, BindConcatWSFunction); concat_ws.varargs = LogicalType::ANY; concat_ws.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - set.AddFunction(concat_ws); + return ScalarFunction(concat_ws); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/contains.cpp b/src/duckdb/src/function/scalar/string/contains.cpp index f1c3f8dca..8288b59d8 100644 --- a/src/duckdb/src/function/scalar/string/contains.cpp +++ b/src/duckdb/src/function/scalar/string/contains.cpp @@ -1,10 +1,11 @@ -#include "duckdb/function/scalar/string_functions.hpp" - #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" +#include "duckdb/function/scalar/list_functions.hpp" +#include "duckdb/function/scalar/map_functions.hpp" +#include "duckdb/function/scalar/string_common.hpp" +#include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/core_functions/scalar/map_functions.hpp" + namespace duckdb { template @@ -99,8 +100,7 @@ idx_t ContainsGeneric(const unsigned char *haystack, idx_t haystack_size, const } } -idx_t ContainsFun::Find(const unsigned char *haystack, idx_t haystack_size, const unsigned char *needle, - idx_t needle_size) { +idx_t FindStrInStr(const unsigned char *haystack, idx_t haystack_size, const unsigned char *needle, idx_t needle_size) { D_ASSERT(needle_size > 0); // start off by performing a memchr to find the first character of the auto location = memchr(haystack, needle[0], haystack_size); @@ -133,7 +133,7 @@ idx_t ContainsFun::Find(const unsigned char *haystack, idx_t haystack_size, cons } } -idx_t ContainsFun::Find(const string_t &haystack_s, const string_t &needle_s) { +idx_t FindStrInStr(const string_t &haystack_s, const string_t &needle_s) { auto haystack = const_uchar_ptr_cast(haystack_s.GetData()); auto haystack_size = haystack_s.GetSize(); auto needle = const_uchar_ptr_cast(needle_s.GetData()); @@ -142,16 +142,22 @@ idx_t ContainsFun::Find(const string_t &haystack_s, const string_t &needle_s) { // empty needle: always true return 0; } - return ContainsFun::Find(haystack, haystack_size, needle, needle_size); + return FindStrInStr(haystack, haystack_size, needle, needle_size); } struct ContainsOperator { template static inline TR Operation(TA left, TB right) { - return ContainsFun::Find(left, right) != DConstants::INVALID_INDEX; + return FindStrInStr(left, right) != DConstants::INVALID_INDEX; } }; +ScalarFunction GetStringContains() { + ScalarFunction string_fun("contains", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, + ScalarFunction::BinaryFunction); + return string_fun; +} + ScalarFunctionSet ContainsFun::GetFunctions() { auto string_fun = GetStringContains(); auto list_fun = ListContainsFun::GetFunction(); @@ -163,14 +169,4 @@ ScalarFunctionSet ContainsFun::GetFunctions() { return set; } -ScalarFunction ContainsFun::GetStringContains() { - ScalarFunction string_fun("contains", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, - ScalarFunction::BinaryFunction); - return string_fun; -} - -void ContainsFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction(GetFunctions()); -} - } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/length.cpp b/src/duckdb/src/function/scalar/string/length.cpp index 5ad1438cf..b757596e2 100644 --- a/src/duckdb/src/function/scalar/string/length.cpp +++ b/src/duckdb/src/function/scalar/string/length.cpp @@ -1,10 +1,9 @@ -#include "duckdb/function/scalar/string_functions.hpp" -#include "duckdb/common/types/bit.hpp" - #include "duckdb/common/exception.hpp" +#include "duckdb/common/types/bit.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" +#include "duckdb/function/scalar/string_common.hpp" +#include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" - #include "duckdb/planner/expression/bound_parameter_expression.hpp" #include "utf8proc.hpp" @@ -14,14 +13,14 @@ namespace duckdb { struct StringLengthOperator { template static inline TR Operation(TA input) { - return LengthFun::Length(input); + return Length(input); } }; struct GraphemeCountOperator { template static inline TR Operation(TA input) { - return LengthFun::GraphemeCount(input); + return GraphemeCount(input); } }; @@ -216,47 +215,57 @@ static unique_ptr ArrayOrListLengthBinaryBind(ClientContext &conte } } -void LengthFun::RegisterFunction(BuiltinFunctions &set) { - ScalarFunction array_length_unary = - ScalarFunction({LogicalType::LIST(LogicalType::ANY)}, LogicalType::BIGINT, nullptr, ArrayOrListLengthBind); +ScalarFunctionSet LengthFun::GetFunctions() { ScalarFunctionSet length("length"); length.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::BIGINT, ScalarFunction::UnaryFunction, nullptr, nullptr, LengthPropagateStats)); length.AddFunction(ScalarFunction({LogicalType::BIT}, LogicalType::BIGINT, ScalarFunction::UnaryFunction)); - length.AddFunction(array_length_unary); - set.AddFunction(length); - length.name = "len"; - set.AddFunction(length); + length.AddFunction( + ScalarFunction({LogicalType::LIST(LogicalType::ANY)}, LogicalType::BIGINT, nullptr, ArrayOrListLengthBind)); + return (length); +} +ScalarFunctionSet LengthGraphemeFun::GetFunctions() { ScalarFunctionSet length_grapheme("length_grapheme"); length_grapheme.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::BIGINT, ScalarFunction::UnaryFunction, nullptr, nullptr, LengthPropagateStats)); - set.AddFunction(length_grapheme); + return (length_grapheme); +} +ScalarFunctionSet ArrayLengthFun::GetFunctions() { ScalarFunctionSet array_length("array_length"); - array_length.AddFunction(array_length_unary); + array_length.AddFunction( + ScalarFunction({LogicalType::LIST(LogicalType::ANY)}, LogicalType::BIGINT, nullptr, ArrayOrListLengthBind)); array_length.AddFunction(ScalarFunction({LogicalType::LIST(LogicalType::ANY), LogicalType::BIGINT}, LogicalType::BIGINT, nullptr, ArrayOrListLengthBinaryBind)); - set.AddFunction(array_length); + return (array_length); +} + +ScalarFunction StrlenFun::GetFunction() { + return ScalarFunction("strlen", {LogicalType::VARCHAR}, LogicalType::BIGINT, + ScalarFunction::UnaryFunction); +} - set.AddFunction(ScalarFunction("strlen", {LogicalType::VARCHAR}, LogicalType::BIGINT, - ScalarFunction::UnaryFunction)); +ScalarFunctionSet BitLengthFun::GetFunctions() { ScalarFunctionSet bit_length("bit_length"); bit_length.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::BIGINT, ScalarFunction::UnaryFunction)); bit_length.AddFunction(ScalarFunction({LogicalType::BIT}, LogicalType::BIGINT, ScalarFunction::UnaryFunction)); - set.AddFunction(bit_length); + return (bit_length); +} + +ScalarFunctionSet OctetLengthFun::GetFunctions() { // length for BLOB type ScalarFunctionSet octet_length("octet_length"); octet_length.AddFunction(ScalarFunction({LogicalType::BLOB}, LogicalType::BIGINT, ScalarFunction::UnaryFunction)); octet_length.AddFunction(ScalarFunction({LogicalType::BIT}, LogicalType::BIGINT, ScalarFunction::UnaryFunction)); - set.AddFunction(octet_length); + return (octet_length); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/like.cpp b/src/duckdb/src/function/scalar/string/like.cpp index b82711787..901bd499b 100644 --- a/src/duckdb/src/function/scalar/string/like.cpp +++ b/src/duckdb/src/function/scalar/string/like.cpp @@ -1,5 +1,7 @@ #include "duckdb/common/exception.hpp" +#include "duckdb/common/string_util.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" +#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" @@ -10,7 +12,7 @@ namespace duckdb { struct StandardCharacterReader { static void NextCharacter(const char *sdata, idx_t slen, idx_t &sidx) { sidx++; - while (sidx < slen && !LengthFun::IsCharacter(sdata[sidx])) { + while (sidx < slen && !IsCharacter(sdata[sidx])) { sidx++; } } @@ -26,7 +28,7 @@ struct ASCIILCaseReader { } static char Operation(const char *data, idx_t pos) { - return (char)LowerFun::ASCII_TO_LOWER_MAP[(uint8_t)data[pos]]; + return (char)StringUtil::ASCII_TO_LOWER_MAP[(uint8_t)data[pos]]; } }; @@ -116,8 +118,8 @@ struct LikeMatcher : public FunctionData { for (; segment_idx < end_idx; segment_idx++) { auto &segment = segments[segment_idx]; // find the pattern of the current segment - idx_t next_offset = ContainsFun::Find(str_data, str_len, const_uchar_ptr_cast(segment.pattern.c_str()), - segment.pattern.size()); + idx_t next_offset = + FindStrInStr(str_data, str_len, const_uchar_ptr_cast(segment.pattern.c_str()), segment.pattern.size()); if (next_offset == DConstants::INVALID_INDEX) { // could not find this pattern in the string: no match return false; @@ -141,8 +143,8 @@ struct LikeMatcher : public FunctionData { } else { auto &segment = segments.back(); // find the pattern of the current segment - idx_t next_offset = ContainsFun::Find(str_data, str_len, const_uchar_ptr_cast(segment.pattern.c_str()), - segment.pattern.size()); + idx_t next_offset = + FindStrInStr(str_data, str_len, const_uchar_ptr_cast(segment.pattern.c_str()), segment.pattern.size()); return next_offset != DConstants::INVALID_INDEX; } } @@ -228,7 +230,7 @@ bool LikeOperatorFunction(string_t &s, string_t &pat, char escape) { return LikeOperatorFunction(s.GetData(), s.GetSize(), pat.GetData(), pat.GetSize(), escape); } -bool LikeFun::Glob(const char *string, idx_t slen, const char *pattern, idx_t plen, bool allow_question_mark) { +bool Glob(const char *string, idx_t slen, const char *pattern, idx_t plen, bool allow_question_mark) { idx_t sidx = 0; idx_t pidx = 0; main_loop : { @@ -250,7 +252,7 @@ main_loop : { } // recursively match the remainder of the pattern for (; sidx < slen; sidx++) { - if (LikeFun::Glob(string + sidx, slen - sidx, pattern + pidx, plen - pidx)) { + if (Glob(string + sidx, slen - sidx, pattern + pidx, plen - pidx)) { return true; } } @@ -402,13 +404,13 @@ bool ILikeOperatorFunction(string_t &str, string_t &pattern, char escape = '\0') auto pat_size = pattern.GetSize(); // lowercase both the str and the pattern - idx_t str_llength = LowerFun::LowerLength(str_data, str_size); + idx_t str_llength = LowerLength(str_data, str_size); auto str_ldata = make_unsafe_uniq_array_uninitialized(str_llength); - LowerFun::LowerCase(str_data, str_size, str_ldata.get()); + LowerCase(str_data, str_size, str_ldata.get()); - idx_t pat_llength = LowerFun::LowerLength(pat_data, pat_size); + idx_t pat_llength = LowerLength(pat_data, pat_size); auto pat_ldata = make_unsafe_uniq_array_uninitialized(pat_llength); - LowerFun::LowerCase(pat_data, pat_size, pat_ldata.get()); + LowerCase(pat_data, pat_size, pat_ldata.get()); string_t str_lcase(str_ldata.get(), UnsafeNumericCast(str_llength)); string_t pat_lcase(pat_ldata.get(), UnsafeNumericCast(pat_llength)); return LikeOperatorFunction(str_lcase, pat_lcase, escape); @@ -468,7 +470,7 @@ struct NotILikeOperatorASCII { struct GlobOperator { template static inline TR Operation(TA str, TB pattern) { - return LikeFun::Glob(str.GetData(), str.GetSize(), pattern.GetData(), pattern.GetSize()); + return Glob(str.GetData(), str.GetSize(), pattern.GetData(), pattern.GetSize()); } }; @@ -510,45 +512,51 @@ static void RegularLikeFunction(DataChunk &input, ExpressionState &state, Vector input.size()); } } -void LikeFun::RegisterFunction(BuiltinFunctions &set) { - // like - set.AddFunction(GetLikeFunction()); - // not like - set.AddFunction(ScalarFunction("!~~", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, - RegularLikeFunction, LikeBindFunction)); - // glob - set.AddFunction(ScalarFunction("~~~", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, - ScalarFunction::BinaryFunction)); - // ilike - set.AddFunction(ScalarFunction("~~*", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, - ScalarFunction::BinaryFunction, nullptr, - nullptr, ILikePropagateStats)); - // not ilike - set.AddFunction(ScalarFunction("!~~*", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, - ScalarFunction::BinaryFunction, nullptr, - nullptr, ILikePropagateStats)); + +ScalarFunction NotLikeFun::GetFunction() { + return ScalarFunction("!~~", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, + RegularLikeFunction, LikeBindFunction); +} + +ScalarFunction GlobPatternFun::GetFunction() { + return ScalarFunction("~~~", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, + ScalarFunction::BinaryFunction); } -ScalarFunction LikeFun::GetLikeFunction() { +ScalarFunction ILikeFun::GetFunction() { + return ScalarFunction("~~*", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, + ScalarFunction::BinaryFunction, nullptr, nullptr, + ILikePropagateStats); +} + +ScalarFunction NotILikeFun::GetFunction() { + return ScalarFunction("!~~*", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, + ScalarFunction::BinaryFunction, nullptr, nullptr, + ILikePropagateStats); +} + +ScalarFunction LikeFun::GetFunction() { return ScalarFunction("~~", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, RegularLikeFunction, LikeBindFunction); } -void LikeEscapeFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction(GetLikeEscapeFun()); - set.AddFunction({"not_like_escape"}, - ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, - LogicalType::BOOLEAN, LikeEscapeFunction)); - - set.AddFunction({"ilike_escape"}, ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, - LogicalType::BOOLEAN, LikeEscapeFunction)); - set.AddFunction({"not_ilike_escape"}, - ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, - LogicalType::BOOLEAN, LikeEscapeFunction)); +ScalarFunction NotLikeEscapeFun::GetFunction() { + return ScalarFunction("not_like_escape", {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, + LogicalType::BOOLEAN, LikeEscapeFunction); +} + +ScalarFunction IlikeEscapeFun::GetFunction() { + return ScalarFunction("ilike_escape", {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, + LogicalType::BOOLEAN, LikeEscapeFunction); } -ScalarFunction LikeEscapeFun::GetLikeEscapeFun() { +ScalarFunction NotIlikeEscapeFun::GetFunction() { + return ScalarFunction("not_ilike_escape", {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, + LogicalType::BOOLEAN, LikeEscapeFunction); +} +ScalarFunction LikeEscapeFun::GetFunction() { return ScalarFunction("like_escape", {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, LikeEscapeFunction); } + } // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/md5.cpp b/src/duckdb/src/function/scalar/string/md5.cpp similarity index 96% rename from src/duckdb/src/core_functions/scalar/string/md5.cpp rename to src/duckdb/src/function/scalar/string/md5.cpp index 399e3a90a..837f97c12 100644 --- a/src/duckdb/src/core_functions/scalar/string/md5.cpp +++ b/src/duckdb/src/function/scalar/string/md5.cpp @@ -1,7 +1,7 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" +#include "duckdb/common/crypto/md5.hpp" +#include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/common/exception.hpp" -#include "duckdb/common/crypto/md5.hpp" #include "duckdb/common/vector_operations/unary_executor.hpp" namespace duckdb { diff --git a/src/duckdb/src/function/scalar/string/nfc_normalize.cpp b/src/duckdb/src/function/scalar/string/nfc_normalize.cpp index 289843356..92a061494 100644 --- a/src/duckdb/src/function/scalar/string/nfc_normalize.cpp +++ b/src/duckdb/src/function/scalar/string/nfc_normalize.cpp @@ -1,5 +1,5 @@ +#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/function/scalar/string_functions.hpp" - #include "utf8proc_wrapper.hpp" namespace duckdb { @@ -9,7 +9,7 @@ struct NFCNormalizeOperator { static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { auto input_data = input.GetData(); auto input_length = input.GetSize(); - if (StripAccentsFun::IsAscii(input_data, input_length)) { + if (IsAscii(input_data, input_length)) { return input; } auto normalized_str = Utf8Proc::Normalize(input_data, input_length); @@ -31,8 +31,4 @@ ScalarFunction NFCNormalizeFun::GetFunction() { return ScalarFunction("nfc_normalize", {LogicalType::VARCHAR}, LogicalType::VARCHAR, NFCNormalizeFunction); } -void NFCNormalizeFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction(NFCNormalizeFun::GetFunction()); -} - } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/prefix.cpp b/src/duckdb/src/function/scalar/string/prefix.cpp index d15c1e02e..2b46610fa 100644 --- a/src/duckdb/src/function/scalar/string/prefix.cpp +++ b/src/duckdb/src/function/scalar/string/prefix.cpp @@ -65,8 +65,4 @@ ScalarFunction PrefixFun::GetFunction() { ScalarFunction::BinaryFunction); } -void PrefixFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction(GetFunction()); -} - } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/regexp.cpp b/src/duckdb/src/function/scalar/string/regexp.cpp index 265e84be7..201181327 100644 --- a/src/duckdb/src/function/scalar/string/regexp.cpp +++ b/src/duckdb/src/function/scalar/string/regexp.cpp @@ -382,7 +382,7 @@ static unique_ptr RegexExtractBind(ClientContext &context, ScalarF std::move(group_string)); } -void RegexpFun::RegisterFunction(BuiltinFunctions &set) { +ScalarFunctionSet RegexpFun::GetFunctions() { ScalarFunctionSet regexp_full_match("regexp_full_match"); regexp_full_match.AddFunction( ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, @@ -392,7 +392,10 @@ void RegexpFun::RegisterFunction(BuiltinFunctions &set) { ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, RegexpMatchesFunction, RegexpMatchesBind, nullptr, nullptr, RegexInitLocalState, LogicalType::INVALID, FunctionStability::CONSISTENT, FunctionNullHandling::SPECIAL_HANDLING)); + return (regexp_full_match); +} +ScalarFunctionSet RegexpMatchesFun::GetFunctions() { ScalarFunctionSet regexp_partial_match("regexp_matches"); regexp_partial_match.AddFunction(ScalarFunction( {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, RegexpMatchesFunction, @@ -402,7 +405,10 @@ void RegexpFun::RegisterFunction(BuiltinFunctions &set) { {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, RegexpMatchesFunction, RegexpMatchesBind, nullptr, nullptr, RegexInitLocalState, LogicalType::INVALID, FunctionStability::CONSISTENT, FunctionNullHandling::SPECIAL_HANDLING)); + return (regexp_partial_match); +} +ScalarFunctionSet RegexpReplaceFun::GetFunctions() { ScalarFunctionSet regexp_replace("regexp_replace"); regexp_replace.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::VARCHAR, RegexReplaceFunction, RegexReplaceBind, nullptr, @@ -410,7 +416,10 @@ void RegexpFun::RegisterFunction(BuiltinFunctions &set) { regexp_replace.AddFunction(ScalarFunction( {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::VARCHAR, RegexReplaceFunction, RegexReplaceBind, nullptr, nullptr, RegexInitLocalState)); + return (regexp_replace); +} +ScalarFunctionSet RegexpExtractFun::GetFunctions() { ScalarFunctionSet regexp_extract("regexp_extract"); regexp_extract.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::VARCHAR, RegexExtractFunction, RegexExtractBind, nullptr, nullptr, @@ -434,7 +443,10 @@ void RegexpFun::RegisterFunction(BuiltinFunctions &set) { {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::LIST(LogicalType::VARCHAR), LogicalType::VARCHAR}, LogicalType::VARCHAR, RegexExtractStructFunction, RegexExtractBind, nullptr, nullptr, RegexInitLocalState, LogicalType::INVALID, FunctionStability::CONSISTENT, FunctionNullHandling::SPECIAL_HANDLING)); + return (regexp_extract); +} +ScalarFunctionSet RegexpExtractAllFun::GetFunctions() { ScalarFunctionSet regexp_extract_all("regexp_extract_all"); regexp_extract_all.AddFunction(ScalarFunction( {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::LIST(LogicalType::VARCHAR), @@ -449,12 +461,7 @@ void RegexpFun::RegisterFunction(BuiltinFunctions &set) { LogicalType::LIST(LogicalType::VARCHAR), RegexpExtractAll::Execute, RegexpExtractAll::Bind, nullptr, nullptr, RegexpExtractAll::InitLocalState, LogicalType::INVALID, FunctionStability::CONSISTENT, FunctionNullHandling::SPECIAL_HANDLING)); - - set.AddFunction(regexp_full_match); - set.AddFunction(regexp_partial_match); - set.AddFunction(regexp_replace); - set.AddFunction(regexp_extract); - set.AddFunction(regexp_extract_all); + return (regexp_extract_all); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/regexp/regexp_extract_all.cpp b/src/duckdb/src/function/scalar/string/regexp/regexp_extract_all.cpp index 0e6cfa7dd..144dcff03 100644 --- a/src/duckdb/src/function/scalar/string/regexp/regexp_extract_all.cpp +++ b/src/duckdb/src/function/scalar/string/regexp/regexp_extract_all.cpp @@ -1,4 +1,5 @@ #include "duckdb/function/scalar/regexp.hpp" +#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/function/scalar/string_functions.hpp" @@ -36,7 +37,7 @@ bool ExtractAll(duckdb_re2::StringPiece &input, duckdb_re2::RE2 &pattern, idx_t // to avoid an infinite loop // FIXME: support unicode characters consumed++; - while (*startpos + consumed < input.length() && !LengthFun::IsCharacter(input[*startpos + consumed])) { + while (*startpos + consumed < input.length() && !IsCharacter(input[*startpos + consumed])) { consumed++; } } diff --git a/src/duckdb/src/core_functions/scalar/string/regexp_escape.cpp b/src/duckdb/src/function/scalar/string/regexp_escape.cpp similarity index 77% rename from src/duckdb/src/core_functions/scalar/string/regexp_escape.cpp rename to src/duckdb/src/function/scalar/string/regexp_escape.cpp index 32517c9c8..3d72fe681 100644 --- a/src/duckdb/src/core_functions/scalar/string/regexp_escape.cpp +++ b/src/duckdb/src/function/scalar/string/regexp_escape.cpp @@ -1,4 +1,4 @@ -#include "duckdb/core_functions/scalar/string_functions.hpp" +#include "duckdb/function/scalar/string_functions.hpp" #include "re2/re2.h" namespace duckdb { @@ -16,7 +16,7 @@ static void RegexpEscapeFunction(DataChunk &args, ExpressionState &state, Vector } ScalarFunction RegexpEscapeFun::GetFunction() { - return ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, RegexpEscapeFunction); + return ScalarFunction("regexp_escape", {LogicalType::VARCHAR}, LogicalType::VARCHAR, RegexpEscapeFunction); } } // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/string/sha1.cpp b/src/duckdb/src/function/scalar/string/sha1.cpp similarity index 94% rename from src/duckdb/src/core_functions/scalar/string/sha1.cpp rename to src/duckdb/src/function/scalar/string/sha1.cpp index 82ec9b7ab..c59dcf252 100644 --- a/src/duckdb/src/core_functions/scalar/string/sha1.cpp +++ b/src/duckdb/src/function/scalar/string/sha1.cpp @@ -1,6 +1,6 @@ +#include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/unary_executor.hpp" -#include "duckdb/core_functions/scalar/string_functions.hpp" #include "mbedtls_wrapper.hpp" namespace duckdb { diff --git a/src/duckdb/src/core_functions/scalar/string/sha256.cpp b/src/duckdb/src/function/scalar/string/sha256.cpp similarity index 94% rename from src/duckdb/src/core_functions/scalar/string/sha256.cpp rename to src/duckdb/src/function/scalar/string/sha256.cpp index 32ca5f5c2..a48ccf93f 100644 --- a/src/duckdb/src/core_functions/scalar/string/sha256.cpp +++ b/src/duckdb/src/function/scalar/string/sha256.cpp @@ -1,6 +1,6 @@ +#include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/unary_executor.hpp" -#include "duckdb/core_functions/scalar/string_functions.hpp" #include "mbedtls_wrapper.hpp" namespace duckdb { diff --git a/src/duckdb/src/core_functions/scalar/string/string_split.cpp b/src/duckdb/src/function/scalar/string/string_split.cpp similarity index 96% rename from src/duckdb/src/core_functions/scalar/string/string_split.cpp rename to src/duckdb/src/function/scalar/string/string_split.cpp index c62cacd75..9673eca96 100644 --- a/src/duckdb/src/core_functions/scalar/string/string_split.cpp +++ b/src/duckdb/src/function/scalar/string/string_split.cpp @@ -1,10 +1,10 @@ +#include "duckdb/function/scalar/string_functions.hpp" +#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/types/data_chunk.hpp" #include "duckdb/common/types/vector.hpp" #include "duckdb/common/vector_size.hpp" -#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/function/scalar/regexp.hpp" -#include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" namespace duckdb { @@ -36,8 +36,7 @@ struct RegularStringSplit { if (delim_size == 0) { return 0; } - return ContainsFun::Find(const_uchar_ptr_cast(input_data), input_size, const_uchar_ptr_cast(delim_data), - delim_size); + return FindStrInStr(const_uchar_ptr_cast(input_data), input_size, const_uchar_ptr_cast(delim_data), delim_size); } }; @@ -84,7 +83,7 @@ struct StringSplitter { // special case: 0 length match and pos is 0 // move to the next character for (pos++; pos < input_size; pos++) { - if (LengthFun::IsCharacter(input_data[pos])) { + if (IsCharacter(input_data[pos])) { break; } } diff --git a/src/duckdb/src/function/scalar/string/strip_accents.cpp b/src/duckdb/src/function/scalar/string/strip_accents.cpp index 1883c60f0..2ab7ca497 100644 --- a/src/duckdb/src/function/scalar/string/strip_accents.cpp +++ b/src/duckdb/src/function/scalar/string/strip_accents.cpp @@ -1,10 +1,11 @@ +#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/function/scalar/string_functions.hpp" #include "utf8proc.hpp" namespace duckdb { -bool StripAccentsFun::IsAscii(const char *input, idx_t n) { +bool IsAscii(const char *input, idx_t n) { for (idx_t i = 0; i < n; i++) { if (input[i] & 0x80) { // non-ascii character @@ -17,7 +18,7 @@ bool StripAccentsFun::IsAscii(const char *input, idx_t n) { struct StripAccentsOperator { template static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - if (StripAccentsFun::IsAscii(input.GetData(), input.GetSize())) { + if (IsAscii(input.GetData(), input.GetSize())) { return input; } @@ -41,8 +42,4 @@ ScalarFunction StripAccentsFun::GetFunction() { return ScalarFunction("strip_accents", {LogicalType::VARCHAR}, LogicalType::VARCHAR, StripAccentsFunction); } -void StripAccentsFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction(StripAccentsFun::GetFunction()); -} - } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/substring.cpp b/src/duckdb/src/function/scalar/string/substring.cpp index f7ff13f34..58c93624a 100644 --- a/src/duckdb/src/function/scalar/string/substring.cpp +++ b/src/duckdb/src/function/scalar/string/substring.cpp @@ -1,3 +1,4 @@ +#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/common/algorithm.hpp" @@ -94,7 +95,7 @@ string_t SubstringASCII(Vector &result, string_t input, int64_t offset, int64_t return SubstringSlice(result, input_data, start, UnsafeNumericCast(end - start)); } -string_t SubstringFun::SubstringUnicode(Vector &result, string_t input, int64_t offset, int64_t length) { +string_t SubstringUnicode(Vector &result, string_t input, int64_t offset, int64_t length) { auto input_data = input.GetData(); auto input_size = input.GetSize(); @@ -129,7 +130,7 @@ string_t SubstringFun::SubstringUnicode(Vector &result, string_t input, int64_t } int64_t current_character = 0; for (idx_t i = input_size; i > 0; i--) { - if (LengthFun::IsCharacter(input_data[i - 1])) { + if (IsCharacter(input_data[i - 1])) { current_character++; if (current_character == start) { start_pos = i; @@ -139,10 +140,10 @@ string_t SubstringFun::SubstringUnicode(Vector &result, string_t input, int64_t } } } - while (!LengthFun::IsCharacter(input_data[start_pos])) { + while (!IsCharacter(input_data[start_pos])) { start_pos++; } - while (end_pos < input_size && !LengthFun::IsCharacter(input_data[end_pos])) { + while (end_pos < input_size && !IsCharacter(input_data[end_pos])) { end_pos++; } @@ -170,7 +171,7 @@ string_t SubstringFun::SubstringUnicode(Vector &result, string_t input, int64_t int64_t current_character = 0; for (idx_t i = 0; i < input_size; i++) { - if (LengthFun::IsCharacter(input_data[i])) { + if (IsCharacter(input_data[i])) { if (current_character == start) { start_pos = i; } else if (current_character == end) { @@ -190,7 +191,7 @@ string_t SubstringFun::SubstringUnicode(Vector &result, string_t input, int64_t UnsafeNumericCast(end_pos - start_pos)); } -string_t SubstringFun::SubstringGrapheme(Vector &result, string_t input, int64_t offset, int64_t length) { +string_t SubstringGrapheme(Vector &result, string_t input, int64_t offset, int64_t length) { auto input_data = input.GetData(); auto input_size = input.GetSize(); @@ -251,13 +252,13 @@ string_t SubstringFun::SubstringGrapheme(Vector &result, string_t input, int64_t struct SubstringUnicodeOp { static string_t Substring(Vector &result, string_t input, int64_t offset, int64_t length) { - return SubstringFun::SubstringUnicode(result, input, offset, length); + return SubstringUnicode(result, input, offset, length); } }; struct SubstringGraphemeOp { static string_t Substring(Vector &result, string_t input, int64_t offset, int64_t length) { - return SubstringFun::SubstringGrapheme(result, input, offset, length); + return SubstringGrapheme(result, input, offset, length); } }; @@ -311,7 +312,7 @@ static unique_ptr SubstringPropagateStats(ClientContext &context return nullptr; } -void SubstringFun::RegisterFunction(BuiltinFunctions &set) { +ScalarFunctionSet SubstringFun::GetFunctions() { ScalarFunctionSet substr("substring"); substr.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::BIGINT, LogicalType::BIGINT}, LogicalType::VARCHAR, SubstringFunction, nullptr, nullptr, @@ -319,10 +320,10 @@ void SubstringFun::RegisterFunction(BuiltinFunctions &set) { substr.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::BIGINT}, LogicalType::VARCHAR, SubstringFunction, nullptr, nullptr, SubstringPropagateStats)); - set.AddFunction(substr); - substr.name = "substr"; - set.AddFunction(substr); + return (substr); +} +ScalarFunctionSet SubstringGraphemeFun::GetFunctions() { ScalarFunctionSet substr_grapheme("substring_grapheme"); substr_grapheme.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::BIGINT, LogicalType::BIGINT}, LogicalType::VARCHAR, SubstringFunction, nullptr, @@ -330,7 +331,7 @@ void SubstringFun::RegisterFunction(BuiltinFunctions &set) { substr_grapheme.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::BIGINT}, LogicalType::VARCHAR, SubstringFunction, nullptr, nullptr, SubstringPropagateStats)); - set.AddFunction(substr_grapheme); + return (substr_grapheme); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/suffix.cpp b/src/duckdb/src/function/scalar/string/suffix.cpp index df1484571..21175f61d 100644 --- a/src/duckdb/src/function/scalar/string/suffix.cpp +++ b/src/duckdb/src/function/scalar/string/suffix.cpp @@ -40,8 +40,4 @@ ScalarFunction SuffixFun::GetFunction() { ScalarFunction::BinaryFunction); } -void SuffixFun::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction({"suffix", "ends_with"}, GetFunction()); -} - } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string_functions.cpp b/src/duckdb/src/function/scalar/string_functions.cpp deleted file mode 100644 index e3ccbe0af..000000000 --- a/src/duckdb/src/function/scalar/string_functions.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "duckdb/function/scalar/string_functions.hpp" - -namespace duckdb { - -void BuiltinFunctions::RegisterStringFunctions() { - Register(); - Register(); - Register(); - Register(); - Register(); - Register(); - Register(); - Register(); - Register(); - Register(); - Register(); - Register(); - Register(); - Register(); -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/scalar/struct/struct_extract.cpp b/src/duckdb/src/function/scalar/struct/struct_extract.cpp index b4ef1c8d6..adfd74a3b 100644 --- a/src/duckdb/src/function/scalar/struct/struct_extract.cpp +++ b/src/duckdb/src/function/scalar/struct/struct_extract.cpp @@ -1,5 +1,6 @@ #include "duckdb/common/string_util.hpp" #include "duckdb/execution/expression_executor.hpp" +#include "duckdb/function/scalar/struct_functions.hpp" #include "duckdb/function/scalar/nested_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression/bound_parameter_expression.hpp" @@ -98,7 +99,7 @@ static unique_ptr StructExtractBind(ClientContext &context, Scalar } bound_function.return_type = std::move(return_type); - return StructExtractFun::GetBindData(key_index); + return GetBindData(key_index); } static unique_ptr StructExtractBindIndex(ClientContext &context, ScalarFunction &bound_function, @@ -134,7 +135,7 @@ static unique_ptr StructExtractBindIndex(ClientContext &context, S index, struct_children.size()); } bound_function.return_type = struct_children[NumericCast(index - 1)].second; - return StructExtractFun::GetBindData(NumericCast(index - 1)); + return GetBindData(NumericCast(index - 1)); } static unique_ptr PropagateStructExtractStats(ClientContext &context, FunctionStatisticsInput &input) { @@ -146,30 +147,26 @@ static unique_ptr PropagateStructExtractStats(ClientContext &con return struct_child_stats[info.index].ToUnique(); } -unique_ptr StructExtractFun::GetBindData(idx_t index) { +unique_ptr GetBindData(idx_t index) { return make_uniq(index); } -ScalarFunction StructExtractFun::KeyExtractFunction() { +ScalarFunction GetKeyExtractFunction() { return ScalarFunction("struct_extract", {LogicalTypeId::STRUCT, LogicalType::VARCHAR}, LogicalType::ANY, StructExtractFunction, StructExtractBind, nullptr, PropagateStructExtractStats); } -ScalarFunction StructExtractFun::IndexExtractFunction() { +ScalarFunction GetIndexExtractFunction() { return ScalarFunction("struct_extract", {LogicalTypeId::STRUCT, LogicalType::BIGINT}, LogicalType::ANY, StructExtractFunction, StructExtractBindIndex); } ScalarFunctionSet StructExtractFun::GetFunctions() { - ScalarFunctionSet functions("struct_extract"); - functions.AddFunction(KeyExtractFunction()); - functions.AddFunction(IndexExtractFunction()); - return functions; -} - -void StructExtractFun::RegisterFunction(BuiltinFunctions &set) { // the arguments and return types are actually set in the binder function - set.AddFunction(GetFunctions()); + ScalarFunctionSet struct_extract_set("struct_extract"); + struct_extract_set.AddFunction(GetKeyExtractFunction()); + struct_extract_set.AddFunction(GetIndexExtractFunction()); + return struct_extract_set; } } // namespace duckdb diff --git a/src/duckdb/src/core_functions/scalar/struct/struct_pack.cpp b/src/duckdb/src/function/scalar/struct/struct_pack.cpp similarity index 98% rename from src/duckdb/src/core_functions/scalar/struct/struct_pack.cpp rename to src/duckdb/src/function/scalar/struct/struct_pack.cpp index 4e71ea36f..1cc0c6377 100644 --- a/src/duckdb/src/core_functions/scalar/struct/struct_pack.cpp +++ b/src/duckdb/src/function/scalar/struct/struct_pack.cpp @@ -1,11 +1,11 @@ -#include "duckdb/core_functions/scalar/struct_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/parser/expression/bound_expression.hpp" #include "duckdb/function/scalar/nested_functions.hpp" +#include "duckdb/function/scalar/struct_functions.hpp" #include "duckdb/common/case_insensitive_map.hpp" -#include "duckdb/storage/statistics/struct_stats.hpp" +#include "duckdb/common/string_util.hpp" +#include "duckdb/parser/expression/bound_expression.hpp" +#include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression_binder.hpp" +#include "duckdb/storage/statistics/struct_stats.hpp" namespace duckdb { diff --git a/src/duckdb/src/function/scalar/system/aggregate_export.cpp b/src/duckdb/src/function/scalar/system/aggregate_export.cpp index 92fea109a..90d94dcb4 100644 --- a/src/duckdb/src/function/scalar/system/aggregate_export.cpp +++ b/src/duckdb/src/function/scalar/system/aggregate_export.cpp @@ -1,5 +1,7 @@ #include "duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp" #include "duckdb/function/function_binder.hpp" +#include "duckdb/function/scalar/generic_common.hpp" +#include "duckdb/function/scalar/system_functions.hpp" #include "duckdb/function/scalar/generic_functions.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/main/database.hpp" @@ -339,7 +341,7 @@ ExportAggregateFunction::Bind(unique_ptr child_aggrega child_aggregate->aggr_type); } -ScalarFunction ExportAggregateFunction::GetFinalize() { +ScalarFunction FinalizeFun::GetFunction() { auto result = ScalarFunction("finalize", {LogicalTypeId::AGGREGATE_STATE}, LogicalTypeId::INVALID, AggregateStateFinalize, BindAggregateState, nullptr, nullptr, InitFinalizeState); result.null_handling = FunctionNullHandling::SPECIAL_HANDLING; @@ -348,7 +350,7 @@ ScalarFunction ExportAggregateFunction::GetFinalize() { return result; } -ScalarFunction ExportAggregateFunction::GetCombine() { +ScalarFunction CombineFun::GetFunction() { auto result = ScalarFunction("combine", {LogicalTypeId::AGGREGATE_STATE, LogicalTypeId::ANY}, LogicalTypeId::AGGREGATE_STATE, AggregateStateCombine, BindAggregateState, nullptr, nullptr, InitCombineState); @@ -358,9 +360,4 @@ ScalarFunction ExportAggregateFunction::GetCombine() { return result; } -void ExportAggregateFunction::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction(ExportAggregateFunction::GetCombine()); - set.AddFunction(ExportAggregateFunction::GetFinalize()); -} - } // namespace duckdb diff --git a/src/duckdb/src/function/table/arrow.cpp b/src/duckdb/src/function/table/arrow.cpp index 634d6d71c..f5bea5a3a 100644 --- a/src/duckdb/src/function/table/arrow.cpp +++ b/src/duckdb/src/function/table/arrow.cpp @@ -526,11 +526,13 @@ unique_ptr ArrowTableFunction::ArrowScanCardinality(ClientContex return make_uniq(); } -idx_t ArrowTableFunction::ArrowGetBatchIndex(ClientContext &context, const FunctionData *bind_data_p, - LocalTableFunctionState *local_state, - GlobalTableFunctionState *global_state) { - auto &state = local_state->Cast(); - return state.batch_index; +OperatorPartitionData ArrowTableFunction::ArrowGetPartitionData(ClientContext &context, + TableFunctionGetPartitionInput &input) { + if (input.partition_info.RequiresPartitionColumns()) { + throw InternalException("ArrowTableFunction::GetPartitionData: partition columns not supported"); + } + auto &state = input.local_state->Cast(); + return OperatorPartitionData(state.batch_index); } bool ArrowTableFunction::ArrowPushdownType(const LogicalType &type) { @@ -584,7 +586,7 @@ void ArrowTableFunction::RegisterFunction(BuiltinFunctions &set) { TableFunction arrow("arrow_scan", {LogicalType::POINTER, LogicalType::POINTER, LogicalType::POINTER}, ArrowScanFunction, ArrowScanBind, ArrowScanInitGlobal, ArrowScanInitLocal); arrow.cardinality = ArrowScanCardinality; - arrow.get_batch_index = ArrowGetBatchIndex; + arrow.get_partition_data = ArrowGetPartitionData; arrow.projection_pushdown = true; arrow.filter_pushdown = true; arrow.filter_prune = true; @@ -594,7 +596,7 @@ void ArrowTableFunction::RegisterFunction(BuiltinFunctions &set) { TableFunction arrow_dumb("arrow_scan_dumb", {LogicalType::POINTER, LogicalType::POINTER, LogicalType::POINTER}, ArrowScanFunction, ArrowScanBind, ArrowScanInitGlobal, ArrowScanInitLocal); arrow_dumb.cardinality = ArrowScanCardinality; - arrow_dumb.get_batch_index = ArrowGetBatchIndex; + arrow_dumb.get_partition_data = ArrowGetPartitionData; arrow_dumb.projection_pushdown = false; arrow_dumb.filter_pushdown = false; arrow_dumb.filter_prune = false; diff --git a/src/duckdb/src/function/table/glob.cpp b/src/duckdb/src/function/table/glob.cpp index d31462450..736c2778e 100644 --- a/src/duckdb/src/function/table/glob.cpp +++ b/src/duckdb/src/function/table/glob.cpp @@ -8,7 +8,7 @@ namespace duckdb { struct GlobFunctionBindData : public TableFunctionData { - unique_ptr file_list; + shared_ptr file_list; }; static unique_ptr GlobFunctionBind(ClientContext &context, TableFunctionBindInput &input, diff --git a/src/duckdb/src/function/table/read_csv.cpp b/src/duckdb/src/function/table/read_csv.cpp index 0c6dcf127..0dbe19b7b 100644 --- a/src/duckdb/src/function/table/read_csv.cpp +++ b/src/duckdb/src/function/table/read_csv.cpp @@ -222,10 +222,12 @@ static void ReadCSVFunction(ClientContext &context, TableFunctionInput &data_p, } while (true); } -static idx_t CSVReaderGetBatchIndex(ClientContext &context, const FunctionData *bind_data_p, - LocalTableFunctionState *local_state, GlobalTableFunctionState *global_state) { - auto &data = local_state->Cast(); - return data.csv_reader->scanner_idx; +static OperatorPartitionData CSVReaderGetPartitionData(ClientContext &context, TableFunctionGetPartitionInput &input) { + if (input.partition_info.RequiresPartitionColumns()) { + throw InternalException("CSVReader::GetPartitionData: partition columns not supported"); + } + auto &data = input.local_state->Cast(); + return OperatorPartitionData(data.csv_reader->scanner_idx); } void ReadCSVTableFunction::ReadCSVAddNamedParameters(TableFunction &table_function) { @@ -337,7 +339,7 @@ TableFunction ReadCSVTableFunction::GetFunction() { read_csv.pushdown_complex_filter = CSVComplexFilterPushdown; read_csv.serialize = CSVReaderSerialize; read_csv.deserialize = CSVReaderDeserialize; - read_csv.get_batch_index = CSVReaderGetBatchIndex; + read_csv.get_partition_data = CSVReaderGetPartitionData; read_csv.cardinality = CSVReaderCardinality; read_csv.projection_pushdown = true; read_csv.type_pushdown = PushdownTypeToCSVScanner; diff --git a/src/duckdb/src/function/table/sniff_csv.cpp b/src/duckdb/src/function/table/sniff_csv.cpp index 9c845bbfd..413901bd0 100644 --- a/src/duckdb/src/function/table/sniff_csv.cpp +++ b/src/duckdb/src/function/table/sniff_csv.cpp @@ -21,6 +21,8 @@ struct CSVSniffFunctionData : public TableFunctionData { vector return_types_csv; // Column Names of CSV (If given by the user) vector names_csv; + // If we want to force the match of the sniffer types + bool force_match = true; }; struct CSVSniffGlobalState : public GlobalTableFunctionState { @@ -36,10 +38,6 @@ static unique_ptr CSVSniffInitGlobal(ClientContext &co static unique_ptr CSVSniffBind(ClientContext &context, TableFunctionBindInput &input, vector &return_types, vector &names) { auto result = make_uniq(); - auto &config = DBConfig::GetConfig(context); - if (!config.options.enable_external_access) { - throw PermissionException("sniff_csv is disabled through configuration"); - } result->path = input.inputs[0].ToString(); auto it = input.named_parameters.find("auto_detect"); if (it != input.named_parameters.end()) { @@ -49,8 +47,16 @@ static unique_ptr CSVSniffBind(ClientContext &context, TableFuncti // otherwise remove it input.named_parameters.erase("auto_detect"); } + + // If we want to force the match of the sniffer + it = input.named_parameters.find("force_match"); + if (it != input.named_parameters.end()) { + result->force_match = it->second.GetValue(); + input.named_parameters.erase("force_match"); + } result->options.FromNamedParameters(input.named_parameters, context); result->options.Verify(); + // We want to return the whole CSV Configuration // 1. Delimiter return_types.emplace_back(LogicalType::VARCHAR); @@ -132,7 +138,7 @@ static void CSVSniffFunction(ClientContext &context, TableFunctionInput &data_p, sniffer_options.sql_type_list = data.return_types_csv; } CSVSniffer sniffer(sniffer_options, buffer_manager, CSVStateMachineCache::Get(context)); - auto sniffer_result = sniffer.SniffCSV(true); + auto sniffer_result = sniffer.SniffCSV(data.force_match); string str_opt; string separator = ", "; // Set output @@ -294,6 +300,7 @@ void CSVSnifferFunction::RegisterFunction(BuiltinFunctions &set) { TableFunction csv_sniffer("sniff_csv", {LogicalType::VARCHAR}, CSVSniffFunction, CSVSniffBind, CSVSniffInitGlobal); // Accept same options as the actual csv reader ReadCSVTableFunction::ReadCSVAddNamedParameters(csv_sniffer); + csv_sniffer.named_parameters["force_match"] = LogicalType::BOOLEAN; set.AddFunction(csv_sniffer); } } // namespace duckdb diff --git a/src/duckdb/src/function/table/system/duckdb_columns.cpp b/src/duckdb/src/function/table/system/duckdb_columns.cpp index 1632a9e5c..d30ea5300 100644 --- a/src/duckdb/src/function/table/system/duckdb_columns.cpp +++ b/src/duckdb/src/function/table/system/duckdb_columns.cpp @@ -115,7 +115,7 @@ class TableColumnHelper : public ColumnHelper { explicit TableColumnHelper(TableCatalogEntry &entry) : entry(entry) { for (auto &constraint : entry.GetConstraints()) { if (constraint->type == ConstraintType::NOT_NULL) { - auto ¬_null = *reinterpret_cast(constraint.get()); + auto ¬_null = constraint->Cast(); not_null_cols.insert(not_null.index.index); } } diff --git a/src/duckdb/src/function/table/system/duckdb_constraints.cpp b/src/duckdb/src/function/table/system/duckdb_constraints.cpp index 8637feaf3..5f436f2c8 100644 --- a/src/duckdb/src/function/table/system/duckdb_constraints.cpp +++ b/src/duckdb/src/function/table/system/duckdb_constraints.cpp @@ -307,7 +307,6 @@ void DuckDBConstraintsFunction(ClientContext &context, TableFunctionInput &data_ for (auto &name : info.referenced_columns) { referenced_column_name_list.push_back(Value(std::move(name))); } - // constraint_column_indexes, LIST output.SetValue(col++, count, Value::LIST(LogicalType::BIGINT, std::move(column_index_list))); @@ -325,6 +324,7 @@ void DuckDBConstraintsFunction(ClientContext &context, TableFunctionInput &data_ output.SetValue(col++, count, Value::LIST(LogicalType::VARCHAR, std::move(referenced_column_name_list))); count++; } + if (data.constraint_offset >= constraints.size()) { data.constraint_offset = 0; data.offset++; diff --git a/src/duckdb/src/function/table/system/duckdb_settings.cpp b/src/duckdb/src/function/table/system/duckdb_settings.cpp index eec5bbfe1..b7c3a56b8 100644 --- a/src/duckdb/src/function/table/system/duckdb_settings.cpp +++ b/src/duckdb/src/function/table/system/duckdb_settings.cpp @@ -54,7 +54,7 @@ unique_ptr DuckDBSettingsInit(ClientContext &context, value.name = option->name; value.value = option->get_setting(context).ToString(); value.description = option->description; - value.input_type = EnumUtil::ToString(option->parameter_type); + value.input_type = option->parameter_type; value.scope = EnumUtil::ToString(scope); result->settings.push_back(std::move(value)); diff --git a/src/duckdb/src/function/table/system/duckdb_tables.cpp b/src/duckdb/src/function/table/system/duckdb_tables.cpp index 7f1386ab3..5e007bbff 100644 --- a/src/duckdb/src/function/table/system/duckdb_tables.cpp +++ b/src/duckdb/src/function/table/system/duckdb_tables.cpp @@ -86,18 +86,6 @@ unique_ptr DuckDBTablesInit(ClientContext &context, Ta return std::move(result); } -static bool TableHasPrimaryKey(TableCatalogEntry &table) { - for (auto &constraint : table.GetConstraints()) { - if (constraint->type == ConstraintType::UNIQUE) { - auto &unique = constraint->Cast(); - if (unique.IsPrimaryKey()) { - return true; - } - } - } - return false; -} - static idx_t CheckConstraintCount(TableCatalogEntry &table) { idx_t check_count = 0; for (auto &constraint : table.GetConstraints()) { @@ -148,7 +136,7 @@ void DuckDBTablesFunction(ClientContext &context, TableFunctionInput &data_p, Da // temporary, LogicalType::BOOLEAN output.SetValue(col++, count, Value::BOOLEAN(table.temporary)); // has_primary_key, LogicalType::BOOLEAN - output.SetValue(col++, count, Value::BOOLEAN(TableHasPrimaryKey(table))); + output.SetValue(col++, count, Value::BOOLEAN(table.HasPrimaryKey())); // estimated_size, LogicalType::BIGINT Value card_val = !storage_info.cardinality.IsValid() 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 3e47ff398..56205d900 100644 --- a/src/duckdb/src/function/table/system/pragma_table_info.cpp +++ b/src/duckdb/src/function/table/system/pragma_table_info.cpp @@ -215,6 +215,12 @@ static ColumnConstraintInfo CheckConstraints(TableCatalogEntry &table, const Col return result; } +void PragmaTableInfo::GetColumnInfo(TableCatalogEntry &table, const ColumnDefinition &column, DataChunk &output, + idx_t index) { + auto constraint_info = CheckConstraints(table, column); + PragmaShowHelper::GetTableColumns(column, constraint_info, output, index); +} + static void PragmaTableInfoTable(PragmaTableOperatorData &data, TableCatalogEntry &table, DataChunk &output, bool is_table_info) { if (data.offset >= table.GetColumns().LogicalColumnCount()) { diff --git a/src/duckdb/src/function/table/table_scan.cpp b/src/duckdb/src/function/table/table_scan.cpp index 7733bf2b4..228e57e0c 100644 --- a/src/duckdb/src/function/table/table_scan.cpp +++ b/src/duckdb/src/function/table/table_scan.cpp @@ -73,7 +73,7 @@ static unique_ptr TableScanInitLocal(ExecutionContext & auto storage_idx = GetStorageIndex(bind_data.table, col); col = storage_idx; } - result->scan_state.Initialize(std::move(column_ids), input.filters.get()); + result->scan_state.Initialize(std::move(column_ids), input.filters.get(), input.sample_options.get()); TableScanParallelStateNext(context.client, input.bind_data.get(), result.get(), gstate); if (input.CanRemoveFilterColumns()) { auto &tsgs = gstate->Cast(); @@ -175,16 +175,19 @@ double TableScanProgress(ClientContext &context, const FunctionData *bind_data_p return percentage; } -idx_t TableScanGetBatchIndex(ClientContext &context, const FunctionData *bind_data_p, - LocalTableFunctionState *local_state, GlobalTableFunctionState *gstate_p) { - auto &state = local_state->Cast(); +OperatorPartitionData TableScanGetPartitionData(ClientContext &context, TableFunctionGetPartitionInput &input) { + if (input.partition_info.RequiresPartitionColumns()) { + throw InternalException("TableScan::GetPartitionData: partition columns not supported"); + } + auto &state = input.local_state->Cast(); if (state.scan_state.table_state.row_group) { - return state.scan_state.table_state.batch_index; + return OperatorPartitionData(state.scan_state.table_state.batch_index); } if (state.scan_state.local_state.row_group) { - return state.scan_state.table_state.batch_index + state.scan_state.local_state.batch_index; + return OperatorPartitionData(state.scan_state.table_state.batch_index + + state.scan_state.local_state.batch_index); } - return 0; + return OperatorPartitionData(0); } BindInfo TableScanGetBindInfo(const optional_ptr bind_data_p) { @@ -346,8 +349,8 @@ void TableScanPushdownComplexFilter(ClientContext &context, LogicalGet &get, Fun if (index_state != nullptr) { auto &db_config = DBConfig::GetConfig(context); - auto index_scan_percentage = db_config.options.index_scan_percentage; - auto index_scan_max_count = db_config.options.index_scan_max_count; + auto index_scan_percentage = db_config.GetSetting(context); + auto index_scan_max_count = db_config.GetSetting(context); auto total_rows = storage.GetTotalRows(); auto total_rows_from_percentage = LossyNumericCast(double(total_rows) * index_scan_percentage); @@ -412,7 +415,7 @@ TableFunction TableScanFunction::GetIndexScanFunction() { scan_function.pushdown_complex_filter = nullptr; scan_function.to_string = TableScanToString; scan_function.table_scan_progress = nullptr; - scan_function.get_batch_index = nullptr; + scan_function.get_partition_data = nullptr; scan_function.projection_pushdown = true; scan_function.filter_pushdown = false; scan_function.get_bind_info = TableScanGetBindInfo; @@ -431,11 +434,12 @@ TableFunction TableScanFunction::GetFunction() { scan_function.pushdown_complex_filter = TableScanPushdownComplexFilter; scan_function.to_string = TableScanToString; scan_function.table_scan_progress = TableScanProgress; - scan_function.get_batch_index = TableScanGetBatchIndex; + scan_function.get_partition_data = TableScanGetPartitionData; scan_function.get_bind_info = TableScanGetBindInfo; scan_function.projection_pushdown = true; scan_function.filter_pushdown = true; scan_function.filter_prune = true; + scan_function.sampling_pushdown = true; scan_function.serialize = TableScanSerialize; scan_function.deserialize = TableScanDeserialize; return scan_function; diff --git a/src/duckdb/src/function/table/version/pragma_version.cpp b/src/duckdb/src/function/table/version/pragma_version.cpp index f1f4ecf19..4aeec966b 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 "3-dev165" +#define DUCKDB_PATCH_VERSION "4-dev1486" #endif #ifndef DUCKDB_MINOR_VERSION #define DUCKDB_MINOR_VERSION 1 @@ -8,10 +8,10 @@ #define DUCKDB_MAJOR_VERSION 1 #endif #ifndef DUCKDB_VERSION -#define DUCKDB_VERSION "v1.1.3-dev165" +#define DUCKDB_VERSION "v1.1.4-dev1486" #endif #ifndef DUCKDB_SOURCE_ID -#define DUCKDB_SOURCE_ID "19864453f7" +#define DUCKDB_SOURCE_ID "059ac75f62" #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 a5190aeea..dd371eb57 100644 --- a/src/duckdb/src/function/table_function.cpp +++ b/src/duckdb/src/function/table_function.cpp @@ -17,10 +17,10 @@ TableFunction::TableFunction(string name, vector arguments, table_f : SimpleNamedParameterFunction(std::move(name), std::move(arguments)), bind(bind), bind_replace(nullptr), init_global(init_global), init_local(init_local), function(function), in_out_function(nullptr), in_out_function_final(nullptr), statistics(nullptr), dependency(nullptr), cardinality(nullptr), - pushdown_complex_filter(nullptr), to_string(nullptr), table_scan_progress(nullptr), get_batch_index(nullptr), + pushdown_complex_filter(nullptr), 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), - serialize(nullptr), deserialize(nullptr), projection_pushdown(false), filter_pushdown(false), - filter_prune(false) { + get_partition_info(nullptr), serialize(nullptr), deserialize(nullptr), projection_pushdown(false), + filter_pushdown(false), filter_prune(false), sampling_pushdown(false) { } TableFunction::TableFunction(const vector &arguments, table_function_t function, @@ -32,9 +32,9 @@ TableFunction::TableFunction() : SimpleNamedParameterFunction("", {}), bind(nullptr), bind_replace(nullptr), init_global(nullptr), init_local(nullptr), function(nullptr), in_out_function(nullptr), statistics(nullptr), dependency(nullptr), cardinality(nullptr), pushdown_complex_filter(nullptr), to_string(nullptr), table_scan_progress(nullptr), - get_batch_index(nullptr), get_bind_info(nullptr), type_pushdown(nullptr), get_multi_file_reader(nullptr), - supports_pushdown_type(nullptr), serialize(nullptr), deserialize(nullptr), projection_pushdown(false), - filter_pushdown(false), filter_prune(false) { + get_partition_data(nullptr), get_bind_info(nullptr), type_pushdown(nullptr), get_multi_file_reader(nullptr), + supports_pushdown_type(nullptr), get_partition_info(nullptr), serialize(nullptr), deserialize(nullptr), + projection_pushdown(false), filter_pushdown(false), filter_prune(false), sampling_pushdown(false) { } bool TableFunction::Equal(const TableFunction &rhs) const { diff --git a/src/duckdb/src/include/duckdb.h b/src/duckdb/src/include/duckdb.h index 30b79fd9a..47b1ee838 100644 --- a/src/duckdb/src/include/duckdb.h +++ b/src/duckdb/src/include/duckdb.h @@ -1471,6 +1471,19 @@ Returns `DUCKDB_TYPE_INVALID` if the parameter index is out of range or the stat */ DUCKDB_API duckdb_type duckdb_param_type(duckdb_prepared_statement prepared_statement, idx_t param_idx); +/*! +Returns the parameter logical type for the parameter at the given index. + +Returns `nullptr` if the parameter index is out of range or the statement was not successfully prepared. + +The return type of this call should be destroyed with `duckdb_destroy_logical_type`. + +* @param prepared_statement The prepared statement. +* @param param_idx The parameter index. +* @return The parameter logical type +*/ +DUCKDB_API duckdb_logical_type duckdb_param_logical_type(duckdb_prepared_statement prepared_statement, idx_t param_idx); + /*! Clear the params bind to the prepared statement. */ @@ -3509,6 +3522,22 @@ Note that the object must be destroyed with `duckdb_appender_destroy`. DUCKDB_API duckdb_state duckdb_appender_create(duckdb_connection connection, const char *schema, const char *table, duckdb_appender *out_appender); +/*! +Creates an appender object. + +Note that the object must be destroyed with `duckdb_appender_destroy`. + +* @param connection The connection context to create the appender in. +* @param catalog The catalog of the table to append to, or `nullptr` for the default catalog. +* @param schema The schema of the table to append to, or `nullptr` for the default schema. +* @param table The table name to append to. +* @param out_appender The resulting appender object. +* @return `DuckDBSuccess` on success or `DuckDBError` on failure. +*/ +DUCKDB_API duckdb_state duckdb_appender_create_ext(duckdb_connection connection, const char *catalog, + const char *schema, const char *table, + duckdb_appender *out_appender); + /*! Returns the number of columns in the table that belongs to the appender. @@ -3726,6 +3755,21 @@ resulting table_description, even if the function returns `DuckDBError`. DUCKDB_API duckdb_state duckdb_table_description_create(duckdb_connection connection, const char *schema, const char *table, duckdb_table_description *out); +/*! +Creates a table description object. Note that `duckdb_table_description_destroy` must be called on the resulting +table_description, even if the function returns `DuckDBError`. + +* @param connection The connection context. +* @param catalog The catalog (database) name of the table, or `nullptr` for the default catalog. +* @param schema The schema of the table, or `nullptr` for the default schema. +* @param table The table name. +* @param out The resulting table description object. +* @return `DuckDBSuccess` on success or `DuckDBError` on failure. +*/ +DUCKDB_API duckdb_state duckdb_table_description_create_ext(duckdb_connection connection, const char *catalog, + const char *schema, const char *table, + duckdb_table_description *out); + /*! Destroy the TableDescription object. @@ -3753,6 +3797,16 @@ Check if the column at 'index' index of the table has a DEFAULT expression. */ DUCKDB_API duckdb_state duckdb_column_has_default(duckdb_table_description table_description, idx_t index, bool *out); +/*! +Obtain the column name at 'index'. +The out result must be destroyed with `duckdb_free`. + +* @param table_description The table_description to query. +* @param index The index of the column to query. +* @return The column name. +*/ +DUCKDB_API char *duckdb_table_description_get_column_name(duckdb_table_description table_description, idx_t index); + //===--------------------------------------------------------------------===// // Arrow Interface //===--------------------------------------------------------------------===// diff --git a/src/duckdb/src/include/duckdb/catalog/catalog.hpp b/src/duckdb/src/include/duckdb/catalog/catalog.hpp index 278866020..e629ff291 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog.hpp @@ -9,17 +9,18 @@ #pragma once #include "duckdb/catalog/catalog_entry.hpp" -#include "duckdb/common/mutex.hpp" -#include "duckdb/parser/query_error_context.hpp" #include "duckdb/catalog/catalog_transaction.hpp" -#include "duckdb/common/reference_map.hpp" #include "duckdb/common/atomic.hpp" -#include "duckdb/common/map.hpp" -#include "duckdb/common/optional_ptr.hpp" +#include "duckdb/common/enums/catalog_lookup_behavior.hpp" #include "duckdb/common/enums/on_entry_not_found.hpp" #include "duckdb/common/error_data.hpp" #include "duckdb/common/exception/catalog_exception.hpp" -#include "duckdb/common/enums/catalog_lookup_behavior.hpp" +#include "duckdb/common/map.hpp" +#include "duckdb/common/mutex.hpp" +#include "duckdb/common/optional_ptr.hpp" +#include "duckdb/common/reference_map.hpp" +#include "duckdb/parser/query_error_context.hpp" + #include namespace duckdb { @@ -70,6 +71,18 @@ class LogicalInsert; class LogicalDelete; class LogicalUpdate; class CreateStatement; +class CatalogEntryRetriever; + +//! Return value of Catalog::LookupEntry +struct CatalogEntryLookup { + optional_ptr schema; + optional_ptr entry; + ErrorData error; + + DUCKDB_API bool Found() const { + return entry; + } +}; //! The Catalog object represents the catalog of the database. class Catalog { @@ -84,10 +97,15 @@ class Catalog { DUCKDB_API static Catalog &GetSystemCatalog(DatabaseInstance &db); //! Get the specified Catalog from the ClientContext DUCKDB_API static Catalog &GetCatalog(ClientContext &context, const string &catalog_name); + //! Get the specified Catalog from the ClientContext + DUCKDB_API static Catalog &GetCatalog(CatalogEntryRetriever &retriever, const string &catalog_name); //! Get the specified Catalog from the DatabaseInstance DUCKDB_API static Catalog &GetCatalog(DatabaseInstance &db, const string &catalog_name); //! Gets the specified Catalog from the database if it exists DUCKDB_API static optional_ptr GetCatalogEntry(ClientContext &context, const string &catalog_name); + //! Gets the specified Catalog from the database if it exists + DUCKDB_API static optional_ptr GetCatalogEntry(CatalogEntryRetriever &retriever, + const string &catalog_name); //! Get the specific Catalog from the AttachedDatabase DUCKDB_API static Catalog &GetCatalog(AttachedDatabase &db); @@ -214,6 +232,10 @@ class Catalog { const string &schema_name, OnEntryNotFound if_not_found, QueryErrorContext error_context = QueryErrorContext()); + DUCKDB_API static optional_ptr GetSchema(CatalogEntryRetriever &retriever, + const string &catalog_name, const string &schema_name, + OnEntryNotFound if_not_found, + QueryErrorContext error_context = QueryErrorContext()); //! Scans all the schemas in the system one-by-one, invoking the callback for each entry DUCKDB_API virtual void ScanSchemas(ClientContext &context, std::function callback) = 0; @@ -221,6 +243,10 @@ class Catalog { DUCKDB_API optional_ptr GetEntry(ClientContext &context, CatalogType type, const string &schema, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context = QueryErrorContext()); + DUCKDB_API optional_ptr GetEntry(CatalogEntryRetriever &retriever, CatalogType type, + const string &schema, const string &name, + OnEntryNotFound if_not_found, + QueryErrorContext error_context = QueryErrorContext()); DUCKDB_API CatalogEntry &GetEntry(ClientContext &context, CatalogType type, const string &schema, const string &name, QueryErrorContext error_context = QueryErrorContext()); //! Gets the "catalog.schema.name" entry of the specified type, if entry does not exist behavior depends on @@ -229,6 +255,10 @@ class Catalog { const string &catalog, const string &schema, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context = QueryErrorContext()); + DUCKDB_API static optional_ptr GetEntry(CatalogEntryRetriever &retriever, CatalogType type, + const string &catalog, const string &schema, + const string &name, OnEntryNotFound if_not_found, + QueryErrorContext error_context = QueryErrorContext()); DUCKDB_API static CatalogEntry &GetEntry(ClientContext &context, CatalogType type, const string &catalog, const string &schema, const string &name, QueryErrorContext error_context = QueryErrorContext()); @@ -281,6 +311,12 @@ class Catalog { return CatalogLookupBehavior::STANDARD; } + //! The default table is used for `SELECT * FROM ;` + DUCKDB_API bool HasDefaultTable() const; + DUCKDB_API void SetDefaultTable(const string &schema, const string &name); + DUCKDB_API string GetDefaultTable() const; + DUCKDB_API string GetDefaultTableSchema() const; + public: template static optional_ptr GetEntry(ClientContext &context, const string &catalog_name, const string &schema_name, @@ -306,6 +342,8 @@ class Catalog { DUCKDB_API vector> GetSchemas(ClientContext &context); DUCKDB_API static vector> GetSchemas(ClientContext &context, const string &catalog_name); + DUCKDB_API static vector> GetSchemas(CatalogEntryRetriever &retriever, + const string &catalog_name); DUCKDB_API static vector> GetAllSchemas(ClientContext &context); virtual void Verify(); @@ -322,35 +360,47 @@ class Catalog { //! Reference to the database AttachedDatabase &db; + //! (optionally) a default table to query for `SELECT * FROM ;` + string default_table; + string default_table_schema; + public: + //! Lookup an entry using TryLookupEntry, throws if entry not found and if_not_found == THROW_EXCEPTION + CatalogEntryLookup LookupEntry(CatalogEntryRetriever &retriever, CatalogType type, const string &schema, + const string &name, OnEntryNotFound if_not_found, + QueryErrorContext error_context = QueryErrorContext()); + private: //! Lookup an entry in the schema, returning a lookup with the entry and schema if they exist CatalogEntryLookup TryLookupEntryInternal(CatalogTransaction transaction, CatalogType type, const string &schema, const string &name); //! Calls LookupEntryInternal on the schema, trying other schemas if the schema is invalid. Sets //! CatalogEntryLookup->error depending on if_not_found when no entry is found - CatalogEntryLookup TryLookupEntry(ClientContext &context, CatalogType type, const string &schema, + CatalogEntryLookup TryLookupEntry(CatalogEntryRetriever &retriever, CatalogType type, const string &schema, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context = QueryErrorContext()); - //! Lookup an entry using TryLookupEntry, throws if entry not found and if_not_found == THROW_EXCEPTION - CatalogEntryLookup LookupEntry(ClientContext &context, CatalogType type, const string &schema, const string &name, - OnEntryNotFound if_not_found, QueryErrorContext error_context = QueryErrorContext()); - static CatalogEntryLookup TryLookupEntry(ClientContext &context, vector &lookups, CatalogType type, - const string &name, OnEntryNotFound if_not_found, + static CatalogEntryLookup TryLookupEntry(CatalogEntryRetriever &retriever, vector &lookups, + CatalogType type, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context = QueryErrorContext()); - static CatalogEntryLookup TryLookupEntry(ClientContext &context, CatalogType type, const string &catalog, + static CatalogEntryLookup TryLookupEntry(CatalogEntryRetriever &retriever, CatalogType type, const string &catalog, const string &schema, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context); + //! Looks for a Catalog with a DefaultTable that matches the lookup + static CatalogEntryLookup TryLookupDefaultTable(CatalogEntryRetriever &retriever, CatalogType type, + const string &catalog, const string &schema, const string &name, + OnEntryNotFound if_not_found, QueryErrorContext error_context); + //! Return an exception with did-you-mean suggestion. - static CatalogException CreateMissingEntryException(ClientContext &context, const string &entry_name, + static CatalogException CreateMissingEntryException(CatalogEntryRetriever &retriever, const string &entry_name, CatalogType type, const reference_set_t &schemas, QueryErrorContext error_context); //! Return the close entry name, the distance and the belonging schema. - static SimilarCatalogEntry SimilarEntryInSchemas(ClientContext &context, const string &entry_name, CatalogType type, - const reference_set_t &schemas); + static vector SimilarEntriesInSchemas(ClientContext &context, const string &entry_name, + CatalogType type, + const reference_set_t &schemas); virtual void DropSchema(ClientContext &context, DropInfo &info) = 0; diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry.hpp index 33802d1d9..f7a380bed 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry.hpp @@ -18,15 +18,16 @@ #include namespace duckdb { -struct AlterInfo; + class Catalog; class CatalogSet; class ClientContext; +class Deserializer; class SchemaCatalogEntry; class Serializer; -class Deserializer; class Value; +struct AlterInfo; struct CatalogTransaction; struct CreateInfo; @@ -68,6 +69,7 @@ class CatalogEntry { virtual unique_ptr AlterEntry(ClientContext &context, AlterInfo &info); virtual unique_ptr AlterEntry(CatalogTransaction transaction, AlterInfo &info); virtual void UndoAlter(ClientContext &context, AlterInfo &info); + virtual void Rollback(CatalogEntry &prev_entry); virtual unique_ptr Copy(ClientContext &context) const; diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_index_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_index_entry.hpp index 541963429..bb3ecd596 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_index_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_index_entry.hpp @@ -16,7 +16,6 @@ class TableCatalogEntry; //! Wrapper class to allow copying a DuckIndexEntry (for altering the DuckIndexEntry metadata such as comments) struct IndexDataTableInfo { IndexDataTableInfo(shared_ptr info_p, const string &index_name_p); - ~IndexDataTableInfo(); //! Pointer to the DataTableInfo shared_ptr info; @@ -34,6 +33,7 @@ class DuckIndexEntry : public IndexCatalogEntry { shared_ptr storage_info); unique_ptr Copy(ClientContext &context) const override; + void Rollback(CatalogEntry &prev_entry) override; //! The indexed table information shared_ptr info; diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_table_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_table_entry.hpp index c728b2954..ce09c4fe5 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_table_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_table_entry.hpp @@ -9,9 +9,13 @@ #pragma once #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" +#include "duckdb/parser/constraints/unique_constraint.hpp" +#include "duckdb/planner/constraints/bound_unique_constraint.hpp" namespace duckdb { +struct AddConstraintInfo; + //! A table catalog entry class DuckTableEntry : public TableCatalogEntry { public: @@ -23,6 +27,8 @@ class DuckTableEntry : public TableCatalogEntry { unique_ptr AlterEntry(ClientContext &context, AlterInfo &info) override; unique_ptr AlterEntry(CatalogTransaction, AlterInfo &info) override; void UndoAlter(ClientContext &context, AlterInfo &info) override; + void Rollback(CatalogEntry &prev_entry) override; + //! Returns the underlying storage of the table DataTable &GetStorage() override; @@ -57,6 +63,7 @@ class DuckTableEntry : public TableCatalogEntry { unique_ptr AddForeignKeyConstraint(optional_ptr context, AlterForeignKeyInfo &info); unique_ptr DropForeignKeyConstraint(ClientContext &context, AlterForeignKeyInfo &info); unique_ptr SetColumnComment(ClientContext &context, SetColumnCommentInfo &info); + unique_ptr AddConstraint(ClientContext &context, AddConstraintInfo &info); void UpdateConstraintsOnColumnDrop(const LogicalIndex &removed_index, const vector &adjusted_indices, const RemoveColumnInfo &info, CreateTableInfo &create_info, diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/function_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/function_entry.hpp index 788c6561f..cf7114377 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/function_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/function_entry.hpp @@ -22,6 +22,7 @@ class FunctionEntry : public StandardEntry { parameter_names = std::move(info.parameter_names); example = std::move(info.example); this->dependencies = info.dependencies; + this->internal = info.internal; } //! The description (if any) diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp index a4440a862..512bff24c 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp @@ -28,6 +28,6 @@ class ScalarFunctionCatalogEntry : public FunctionEntry { ScalarFunctionSet functions; public: - unique_ptr AlterEntry(ClientContext &context, AlterInfo &info) override; + unique_ptr AlterEntry(CatalogTransaction transaction, AlterInfo &info) override; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_catalog_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_catalog_entry.hpp index 0dd78f3cc..d2e47e6d4 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_catalog_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_catalog_entry.hpp @@ -21,8 +21,6 @@ namespace duckdb { class DataTable; -struct CreateTableInfo; -struct BoundCreateTableInfo; struct RenameColumnInfo; struct AddColumnInfo; @@ -33,12 +31,13 @@ struct AlterForeignKeyInfo; struct SetNotNullInfo; struct DropNotNullInfo; struct SetColumnCommentInfo; +struct CreateTableInfo; +struct BoundCreateTableInfo; class TableFunction; struct FunctionData; class Binder; -class TableColumnInfo; struct ColumnSegmentInfo; class TableStorageInfo; @@ -98,6 +97,9 @@ class TableCatalogEntry : public StandardEntry { DUCKDB_API static string ColumnsToSQL(const ColumnList &columns, const vector> &constraints); + //! Returns the expression string list of the column names e.g. (col1, col2, col3) + static string ColumnNamesToSQL(const ColumnList &columns); + //! Returns a list of segment information for this table, if exists virtual vector GetColumnSegmentInfo(); @@ -107,6 +109,11 @@ class TableCatalogEntry : public StandardEntry { virtual void BindUpdateConstraints(Binder &binder, LogicalGet &get, LogicalProjection &proj, LogicalUpdate &update, ClientContext &context); + //! Returns a pointer to the table's primary key, if exists, else nullptr. + optional_ptr GetPrimaryKey() const; + //! Returns true, if the table has a primary key, else false. + bool HasPrimaryKey() const; + protected: //! A list of columns that are part of this table ColumnList columns; diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp index fc784e554..a2e275700 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp @@ -28,6 +28,6 @@ class TableFunctionCatalogEntry : public FunctionEntry { TableFunctionSet functions; public: - unique_ptr AlterEntry(ClientContext &context, AlterInfo &info) override; + unique_ptr AlterEntry(CatalogTransaction transaction, AlterInfo &info) override; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/type_catalog_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/type_catalog_entry.hpp index 064ba4c08..8d608d074 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/type_catalog_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/type_catalog_entry.hpp @@ -11,6 +11,7 @@ #include "duckdb/catalog/standard_entry.hpp" #include "duckdb/common/mutex.hpp" #include "duckdb/parser/parsed_data/create_type_info.hpp" +#include "duckdb/catalog/dependency_list.hpp" namespace duckdb { diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry_retriever.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry_retriever.hpp index 14466cb37..4e771cdc5 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry_retriever.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry_retriever.hpp @@ -1,3 +1,11 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/catalog/catalog_entry_retriever.hpp +// +// +//===----------------------------------------------------------------------===// + #pragma once #include @@ -6,6 +14,7 @@ #include "duckdb/common/string.hpp" #include "duckdb/parser/query_error_context.hpp" #include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" +#include "duckdb/catalog/catalog_search_path.hpp" namespace duckdb { @@ -24,6 +33,11 @@ class CatalogEntryRetriever { } public: + void Inherit(const CatalogEntryRetriever &parent); + ClientContext &GetContext() { + return context; + } + optional_ptr GetEntry(CatalogType type, const string &catalog, const string &schema, const string &name, OnEntryNotFound on_entry_not_found = OnEntryNotFound::THROW_EXCEPTION, @@ -42,31 +56,20 @@ class CatalogEntryRetriever { OnEntryNotFound on_entry_not_found = OnEntryNotFound::THROW_EXCEPTION, QueryErrorContext error_context = QueryErrorContext()); - void SetCallback(catalog_entry_callback_t callback) { - this->callback = std::move(callback); - } - catalog_entry_callback_t GetCallback() { - return callback; - } + CatalogSearchPath &GetSearchPath(); + void SetSearchPath(vector entries); + + void SetCallback(catalog_entry_callback_t callback); + catalog_entry_callback_t GetCallback(); private: - using catalog_entry_retrieve_func_t = std::function()>; - optional_ptr GetEntryInternal(const catalog_entry_retrieve_func_t &retriever) { - auto result = retriever(); - if (!result) { - return result; - } - if (callback) { - // Call the callback if it's set - callback(*result); - } - return result; - } + optional_ptr ReturnAndCallback(optional_ptr result); private: //! (optional) callback, called on every successful entry retrieval catalog_entry_callback_t callback = nullptr; ClientContext &context; + shared_ptr search_path; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_search_path.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_search_path.hpp index 479d6c529..ff0def0fc 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_search_path.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_search_path.hpp @@ -41,6 +41,7 @@ enum class CatalogSetPathType { SET_SCHEMA, SET_SCHEMAS }; class CatalogSearchPath { public: DUCKDB_API explicit CatalogSearchPath(ClientContext &client_p); + DUCKDB_API CatalogSearchPath(ClientContext &client_p, vector entries); CatalogSearchPath(const CatalogSearchPath &other) = delete; DUCKDB_API void Set(CatalogSearchEntry new_value, CatalogSetPathType set_type); @@ -61,8 +62,8 @@ class CatalogSearchPath { DUCKDB_API bool SchemaInSearchPath(ClientContext &context, const string &catalog_name, const string &schema_name); private: - void SetPaths(vector new_paths); - + //! Set paths without checking if they exist + void SetPathsInternal(vector new_paths); string GetSetName(CatalogSetPathType set_type); private: diff --git a/src/duckdb/src/include/duckdb/catalog/dependency_manager.hpp b/src/duckdb/src/include/duckdb/catalog/dependency_manager.hpp index 9b191036f..73d3ed2ef 100644 --- a/src/duckdb/src/include/duckdb/catalog/dependency_manager.hpp +++ b/src/duckdb/src/include/duckdb/catalog/dependency_manager.hpp @@ -91,6 +91,10 @@ class DependencyManager { void AddOwnership(CatalogTransaction transaction, CatalogEntry &owner, CatalogEntry &entry); + //! Get the order of entries needed by EXPORT, the objects with no dependencies are exported first + void ReorderEntries(catalog_entry_vector_t &entries); + void ReorderEntries(catalog_entry_vector_t &entries, ClientContext &context); + private: DuckCatalog &catalog; CatalogSet subjects; @@ -110,6 +114,9 @@ class DependencyManager { static CatalogEntryInfo GetLookupProperties(const CatalogEntry &entry); private: + void ReorderEntry(CatalogTransaction transaction, CatalogEntry &entry, catalog_entry_set_t &visited, + catalog_entry_vector_t &order); + void ReorderEntries(catalog_entry_vector_t &entries, CatalogTransaction transaction); void AddObject(CatalogTransaction transaction, CatalogEntry &object, const LogicalDependencyList &dependencies); void DropObject(CatalogTransaction transaction, CatalogEntry &object, bool cascade); void AlterObject(CatalogTransaction transaction, CatalogEntry &old_obj, CatalogEntry &new_obj, AlterInfo &info); diff --git a/src/duckdb/src/include/duckdb/common/arrow/appender/list_data.hpp b/src/duckdb/src/include/duckdb/common/arrow/appender/list_data.hpp index 0c2a1de6c..5f0f86215 100644 --- a/src/duckdb/src/include/duckdb/common/arrow/appender/list_data.hpp +++ b/src/duckdb/src/include/duckdb/common/arrow/appender/list_data.hpp @@ -1,6 +1,7 @@ #pragma once #include "duckdb/common/arrow/appender/append_data.hpp" +#include "duckdb/common/arrow/arrow_appender.hpp" namespace duckdb { @@ -74,7 +75,8 @@ struct ArrowListData { (uint64_t)last_offset + list_length > NumericLimits::Maximum()) { throw InvalidInputException( "Arrow Appender: The maximum combined list offset for regular list buffers is " - "%u but the offset of %lu exceeds this.", + "%u but the offset of %lu exceeds this.\n* SET arrow_large_buffer_size=true to use large list " + "buffers", NumericLimits::Maximum(), last_offset); } last_offset += list_length; diff --git a/src/duckdb/src/include/duckdb/common/arrow/appender/list_view_data.hpp b/src/duckdb/src/include/duckdb/common/arrow/appender/list_view_data.hpp index 889e2614f..158120c46 100644 --- a/src/duckdb/src/include/duckdb/common/arrow/appender/list_view_data.hpp +++ b/src/duckdb/src/include/duckdb/common/arrow/appender/list_view_data.hpp @@ -1,6 +1,7 @@ #pragma once #include "duckdb/common/arrow/appender/append_data.hpp" +#include "duckdb/common/arrow/arrow_appender.hpp" namespace duckdb { @@ -75,7 +76,8 @@ struct ArrowListViewData { (uint64_t)last_offset + list_length > NumericLimits::Maximum()) { throw InvalidInputException( "Arrow Appender: The maximum combined list offset for regular list buffers is " - "%u but the offset of %lu exceeds this.", + "%u but the offset of %lu exceeds this.\n* SET arrow_large_buffer_size=true to use large list " + "buffers", NumericLimits::Maximum(), last_offset); } offset_data[offset_idx] = last_offset; diff --git a/src/duckdb/src/include/duckdb/common/chrono.hpp b/src/duckdb/src/include/duckdb/common/chrono.hpp index 797a867c5..c46e27b15 100644 --- a/src/duckdb/src/include/duckdb/common/chrono.hpp +++ b/src/duckdb/src/include/duckdb/common/chrono.hpp @@ -15,6 +15,7 @@ using std::chrono::duration; using std::chrono::duration_cast; using std::chrono::high_resolution_clock; using std::chrono::milliseconds; +using std::chrono::nanoseconds; using std::chrono::system_clock; using std::chrono::time_point; } // 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 3e6a235aa..0cd552a9c 100644 --- a/src/duckdb/src/include/duckdb/common/enum_util.hpp +++ b/src/duckdb/src/include/duckdb/common/enum_util.hpp @@ -322,6 +322,8 @@ enum class TableColumnType : uint8_t; enum class TableFilterType : uint8_t; +enum class TablePartitionInfo : uint8_t; + enum class TableReferenceType : uint8_t; enum class TableScanType : uint8_t; @@ -330,6 +332,10 @@ enum class TaskExecutionMode : uint8_t; enum class TaskExecutionResult : uint8_t; +enum class TemporaryBufferSize : uint64_t; + +enum class TemporaryCompressionLevel : int; + enum class TimestampCastResult : uint8_t; enum class TransactionModifierType : uint8_t; @@ -796,6 +802,9 @@ const char* EnumUtil::ToChars(TableColumnType value); template<> const char* EnumUtil::ToChars(TableFilterType value); +template<> +const char* EnumUtil::ToChars(TablePartitionInfo value); + template<> const char* EnumUtil::ToChars(TableReferenceType value); @@ -808,6 +817,12 @@ const char* EnumUtil::ToChars(TaskExecutionMode value); template<> const char* EnumUtil::ToChars(TaskExecutionResult value); +template<> +const char* EnumUtil::ToChars(TemporaryBufferSize value); + +template<> +const char* EnumUtil::ToChars(TemporaryCompressionLevel value); + template<> const char* EnumUtil::ToChars(TimestampCastResult value); @@ -1289,6 +1304,9 @@ TableColumnType EnumUtil::FromString(const char *value); template<> TableFilterType EnumUtil::FromString(const char *value); +template<> +TablePartitionInfo EnumUtil::FromString(const char *value); + template<> TableReferenceType EnumUtil::FromString(const char *value); @@ -1301,6 +1319,12 @@ TaskExecutionMode EnumUtil::FromString(const char *value); template<> TaskExecutionResult EnumUtil::FromString(const char *value); +template<> +TemporaryBufferSize EnumUtil::FromString(const char *value); + +template<> +TemporaryCompressionLevel EnumUtil::FromString(const char *value); + template<> TimestampCastResult EnumUtil::FromString(const char *value); 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 109332b17..e38a720e4 100644 --- a/src/duckdb/src/include/duckdb/common/enums/memory_tag.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/memory_tag.hpp @@ -24,9 +24,10 @@ enum class MemoryTag : uint8_t { OVERFLOW_STRINGS = 8, IN_MEMORY_TABLE = 9, ALLOCATOR = 10, - EXTENSION = 11 + EXTENSION = 11, + TRANSACTION = 12 }; -static constexpr const idx_t MEMORY_TAG_COUNT = 12; +static constexpr const idx_t MEMORY_TAG_COUNT = 13; } // 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 6510abbea..74db7e86c 100644 --- a/src/duckdb/src/include/duckdb/common/enums/metric_type.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/metric_type.hpp @@ -57,6 +57,7 @@ enum class MetricsType : uint8_t { OPTIMIZER_COLUMN_LIFETIME, OPTIMIZER_BUILD_SIDE_PROBE_SIDE, OPTIMIZER_LIMIT_PUSHDOWN, + OPTIMIZER_SAMPLING_PUSHDOWN, OPTIMIZER_TOP_N, OPTIMIZER_COMPRESSED_MATERIALIZATION, OPTIMIZER_DUPLICATE_GROUPS, @@ -64,6 +65,7 @@ enum class MetricsType : uint8_t { OPTIMIZER_JOIN_FILTER_PUSHDOWN, OPTIMIZER_EXTENSION, OPTIMIZER_MATERIALIZED_CTE, + OPTIMIZER_EMPTY_RESULT_PULLUP }; struct MetricsTypeHashFunction { 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 8eea1ca48..0ff14aa91 100644 --- a/src/duckdb/src/include/duckdb/common/enums/optimizer_type.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/optimizer_type.hpp @@ -18,6 +18,7 @@ enum class OptimizerType : uint32_t { EXPRESSION_REWRITER, FILTER_PULLUP, FILTER_PUSHDOWN, + EMPTY_RESULT_PULLUP, CTE_FILTER_PUSHER, REGEX_RANGE, IN_CLAUSE, @@ -35,6 +36,7 @@ enum class OptimizerType : uint32_t { COMPRESSED_MATERIALIZATION, DUPLICATE_GROUPS, REORDER_FILTER, + SAMPLING_PUSHDOWN, JOIN_FILTER_PUSHDOWN, EXTENSION, MATERIALIZED_CTE, diff --git a/src/duckdb/src/include/duckdb/common/enums/physical_operator_type.hpp b/src/duckdb/src/include/duckdb/common/enums/physical_operator_type.hpp index 4f170b497..607588c11 100644 --- a/src/duckdb/src/include/duckdb/common/enums/physical_operator_type.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/physical_operator_type.hpp @@ -27,6 +27,7 @@ enum class PhysicalOperatorType : uint8_t { UNGROUPED_AGGREGATE, HASH_GROUP_BY, PERFECT_HASH_GROUP_BY, + PARTITIONED_AGGREGATE, FILTER, PROJECTION, COPY_TO_FILE, diff --git a/src/duckdb/src/include/duckdb/common/enums/profiler_format.hpp b/src/duckdb/src/include/duckdb/common/enums/profiler_format.hpp index 25a7912fd..1a416d546 100644 --- a/src/duckdb/src/include/duckdb/common/enums/profiler_format.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/profiler_format.hpp @@ -12,6 +12,6 @@ namespace duckdb { -enum class ProfilerPrintFormat : uint8_t { QUERY_TREE, JSON, QUERY_TREE_OPTIMIZER, NO_OUTPUT }; +enum class ProfilerPrintFormat : uint8_t { QUERY_TREE, JSON, QUERY_TREE_OPTIMIZER, NO_OUTPUT, HTML, GRAPHVIZ }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_enum.hpp b/src/duckdb/src/include/duckdb/common/enums/quantile_enum.hpp similarity index 83% rename from src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_enum.hpp rename to src/duckdb/src/include/duckdb/common/enums/quantile_enum.hpp index 161f1a90e..bcb90b2ce 100644 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_enum.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/quantile_enum.hpp @@ -1,13 +1,15 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/core_functions/aggregate/quantile_enum.hpp +// duckdb/common/enums/quantile_enum.hpp // // //===----------------------------------------------------------------------===// #pragma once +#include "duckdb/common/constants.hpp" + namespace duckdb { enum class QuantileSerializationType : uint8_t { diff --git a/src/duckdb/src/include/duckdb/common/exception/parser_exception.hpp b/src/duckdb/src/include/duckdb/common/exception/parser_exception.hpp index 5ae6a5e87..363a34457 100644 --- a/src/duckdb/src/include/duckdb/common/exception/parser_exception.hpp +++ b/src/duckdb/src/include/duckdb/common/exception/parser_exception.hpp @@ -26,6 +26,10 @@ class ParserException : public Exception { explicit ParserException(optional_idx error_location, const string &msg, ARGS... params) : ParserException(ConstructMessage(msg, params...), Exception::InitializeExtraInfo(error_location)) { } + template + explicit ParserException(const ParsedExpression &expr, const string &msg, ARGS... params) + : ParserException(ConstructMessage(msg, params...), Exception::InitializeExtraInfo(expr)) { + } static ParserException SyntaxError(const string &query, const string &error_message, optional_idx error_location); }; diff --git a/src/duckdb/src/include/duckdb/common/extra_operator_info.hpp b/src/duckdb/src/include/duckdb/common/extra_operator_info.hpp index ceb24638a..117be6c61 100644 --- a/src/duckdb/src/include/duckdb/common/extra_operator_info.hpp +++ b/src/duckdb/src/include/duckdb/common/extra_operator_info.hpp @@ -12,14 +12,17 @@ #include #include #include "duckdb/common/operator/comparison_operators.hpp" +#include "duckdb/common/optional_idx.hpp" +#include "duckdb/parser/parsed_data/sample_options.hpp" namespace duckdb { class ExtraOperatorInfo { public: - ExtraOperatorInfo() : file_filters("") { + ExtraOperatorInfo() : file_filters(""), sample_options(nullptr) { } - ExtraOperatorInfo(ExtraOperatorInfo &extra_info) : file_filters(extra_info.file_filters) { + ExtraOperatorInfo(ExtraOperatorInfo &extra_info) + : file_filters(extra_info.file_filters), sample_options(std::move(extra_info.sample_options)) { if (extra_info.total_files.IsValid()) { total_files = extra_info.total_files.GetIndex(); } @@ -34,6 +37,8 @@ class ExtraOperatorInfo { optional_idx total_files; //! Size of file list after applying filters optional_idx filtered_files; + //! Sample options that have been pushed down into the table scan + unique_ptr sample_options; }; } // 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 1a3e6e9cb..f32a2c416 100644 --- a/src/duckdb/src/include/duckdb/common/file_buffer.hpp +++ b/src/duckdb/src/include/duckdb/common/file_buffer.hpp @@ -17,7 +17,7 @@ struct FileHandle; enum class FileBufferType : uint8_t { BLOCK = 1, MANAGED_BUFFER = 2, TINY_BUFFER = 3 }; -static constexpr const idx_t FILE_BUFFER_TYPE_COUNT = 3; +static constexpr idx_t FILE_BUFFER_TYPE_COUNT = 3; //! The FileBuffer represents a buffer that can be read or written to a Direct IO FileHandle. class FileBuffer { diff --git a/src/duckdb/src/include/duckdb/common/multi_file_reader.hpp b/src/duckdb/src/include/duckdb/common/multi_file_reader.hpp index ad848187d..fe99482df 100644 --- a/src/duckdb/src/include/duckdb/common/multi_file_reader.hpp +++ b/src/duckdb/src/include/duckdb/common/multi_file_reader.hpp @@ -132,11 +132,11 @@ struct MultiFileReader { //! Parse a Value containing 1 or more paths into a vector of paths. Note: no expansion is performed here DUCKDB_API virtual vector ParsePaths(const Value &input); //! Create a MultiFileList from a vector of paths. Any globs will be expanded using the default filesystem - DUCKDB_API virtual unique_ptr + DUCKDB_API virtual shared_ptr CreateFileList(ClientContext &context, const vector &paths, FileGlobOptions options = FileGlobOptions::DISALLOW_EMPTY); //! Shorthand for ParsePaths + CreateFileList - DUCKDB_API unique_ptr CreateFileList(ClientContext &context, const Value &input, + DUCKDB_API shared_ptr CreateFileList(ClientContext &context, const Value &input, FileGlobOptions options = FileGlobOptions::DISALLOW_EMPTY); //! Parse the named parameters of a multi-file reader @@ -195,6 +195,13 @@ struct MultiFileReader { const MultiFileReaderData &reader_data, DataChunk &chunk, optional_ptr global_state); + //! Fetch the partition data for the current chunk + DUCKDB_API virtual void GetPartitionData(ClientContext &context, const MultiFileReaderBindData &bind_data, + const MultiFileReaderData &reader_data, + optional_ptr global_state, + const OperatorPartitionInfo &partition_info, + OperatorPartitionData &partition_data); + template MultiFileReaderBindData BindUnionReader(ClientContext &context, vector &return_types, vector &names, MultiFileList &files, RESULT_CLASS &result, @@ -287,6 +294,11 @@ struct MultiFileReader { } } + //! Get partition info + DUCKDB_API virtual TablePartitionInfo GetPartitionInfo(ClientContext &context, + const MultiFileReaderBindData &bind_data, + TableFunctionPartitionInput &input); + protected: virtual void CreateNameMapping(const string &file_name, const vector &local_types, const vector &local_names, const vector &global_types, 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 2d35512b2..216f393d6 100644 --- a/src/duckdb/src/include/duckdb/common/opener_file_system.hpp +++ b/src/duckdb/src/include/duckdb/common/opener_file_system.hpp @@ -18,15 +18,14 @@ class OpenerFileSystem : public FileSystem { virtual FileSystem &GetFileSystem() const = 0; virtual optional_ptr GetOpener() const = 0; - void VerifyNoOpener(optional_ptr opener) { - if (opener) { - throw InternalException("OpenerFileSystem cannot take an opener - the opener is pushed automatically"); - } - } + void VerifyNoOpener(optional_ptr opener); + void VerifyCanAccessDirectory(const string &path); + void VerifyCanAccessFile(const string &path); unique_ptr OpenFile(const string &path, FileOpenFlags flags, optional_ptr opener = nullptr) override { VerifyNoOpener(opener); + VerifyCanAccessFile(path); return GetFileSystem().OpenFile(path, flags, GetOpener()); } @@ -66,26 +65,32 @@ class OpenerFileSystem : public FileSystem { bool DirectoryExists(const string &directory, optional_ptr opener) override { VerifyNoOpener(opener); + VerifyCanAccessDirectory(directory); return GetFileSystem().DirectoryExists(directory, GetOpener()); } void CreateDirectory(const string &directory, optional_ptr opener) override { VerifyNoOpener(opener); + VerifyCanAccessDirectory(directory); return GetFileSystem().CreateDirectory(directory, GetOpener()); } void RemoveDirectory(const string &directory, optional_ptr opener) override { VerifyNoOpener(opener); + VerifyCanAccessDirectory(directory); return GetFileSystem().RemoveDirectory(directory, GetOpener()); } bool ListFiles(const string &directory, const std::function &callback, FileOpener *opener = nullptr) override { VerifyNoOpener(opener); + VerifyCanAccessDirectory(directory); return GetFileSystem().ListFiles(directory, callback, GetOpener().get()); } void MoveFile(const string &source, const string &target, optional_ptr opener) override { VerifyNoOpener(opener); + VerifyCanAccessFile(source); + VerifyCanAccessFile(target); GetFileSystem().MoveFile(source, target, GetOpener()); } @@ -99,6 +104,7 @@ class OpenerFileSystem : public FileSystem { bool FileExists(const string &filename, optional_ptr opener) override { VerifyNoOpener(opener); + VerifyCanAccessFile(filename); return GetFileSystem().FileExists(filename, GetOpener()); } @@ -108,6 +114,7 @@ class OpenerFileSystem : public FileSystem { } void RemoveFile(const string &filename, optional_ptr opener) override { VerifyNoOpener(opener); + VerifyCanAccessFile(filename); GetFileSystem().RemoveFile(filename, GetOpener()); } @@ -117,6 +124,7 @@ class OpenerFileSystem : public FileSystem { vector Glob(const string &path, FileOpener *opener = nullptr) override { VerifyNoOpener(opener); + VerifyCanAccessFile(path); return GetFileSystem().Glob(path, GetOpener().get()); } @@ -143,6 +151,9 @@ class OpenerFileSystem : public FileSystem { vector ListSubSystems() override { return GetFileSystem().ListSubSystems(); } + +private: + void VerifyCanAccessFileInternal(const string &path, FileType type); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/operator/comparison_operators.hpp b/src/duckdb/src/include/duckdb/common/operator/comparison_operators.hpp index f1a6f6eb3..1a05f2436 100644 --- a/src/duckdb/src/include/duckdb/common/operator/comparison_operators.hpp +++ b/src/duckdb/src/include/duckdb/common/operator/comparison_operators.hpp @@ -107,13 +107,6 @@ struct DistinctGreaterThan { } }; -struct DistinctGreaterThanNullsFirst { - template - static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) { - return DistinctGreaterThan::Operation(left, right, right_null, left_null); - } -}; - struct DistinctGreaterThanEquals { template static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) { @@ -128,13 +121,6 @@ struct DistinctLessThan { } }; -struct DistinctLessThanNullsFirst { - template - static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) { - return DistinctGreaterThan::Operation(right, left, left_null, right_null); - } -}; - struct DistinctLessThanEquals { template static inline bool Operation(const T &left, const T &right, bool left_null, bool right_null) { diff --git a/src/duckdb/src/include/duckdb/common/optional_idx.hpp b/src/duckdb/src/include/duckdb/common/optional_idx.hpp index 7656fe6e7..fc88f8234 100644 --- a/src/duckdb/src/include/duckdb/common/optional_idx.hpp +++ b/src/duckdb/src/include/duckdb/common/optional_idx.hpp @@ -32,6 +32,10 @@ class optional_idx { return index != INVALID_INDEX; } + void SetInvalid() { + index = INVALID_INDEX; + } + idx_t GetIndex() const { if (index == INVALID_INDEX) { throw InternalException("Attempting to get the index of an optional_idx that is not set"); diff --git a/src/duckdb/src/include/duckdb/common/platform.hpp b/src/duckdb/src/include/duckdb/common/platform.hpp index 3166ff968..94eea304d 100644 --- a/src/duckdb/src/include/duckdb/common/platform.hpp +++ b/src/duckdb/src/include/duckdb/common/platform.hpp @@ -48,9 +48,9 @@ std::string DuckDBPlatform() { // NOLINT: allow definition in header #ifdef __MINGW32__ postfix = "_mingw"; #endif -// this is used for the windows R builds which use a separate build environment +// this is used for the windows R builds which use `mingw` equivalent extensions #ifdef DUCKDB_PLATFORM_RTOOLS - postfix = "_rtools"; + postfix = "_mingw"; #endif return os + "_" + arch + postfix; } diff --git a/src/duckdb/src/include/duckdb/common/radix_partitioning.hpp b/src/duckdb/src/include/duckdb/common/radix_partitioning.hpp index aa5efc286..66b74ef7a 100644 --- a/src/duckdb/src/include/duckdb/common/radix_partitioning.hpp +++ b/src/duckdb/src/include/duckdb/common/radix_partitioning.hpp @@ -8,7 +8,7 @@ #pragma once -#include "duckdb/common/fast_mem.hpp" +#include "duckdb/common/bit_utils.hpp" #include "duckdb/common/types/column/partitioned_column_data.hpp" #include "duckdb/common/types/row/partitioned_tuple_data.hpp" @@ -30,15 +30,15 @@ struct RadixPartitioning { return idx_t(1) << radix_bits; } + template + static inline idx_t RadixBits(T n) { + return sizeof(T) * 8 - CountZeros::Leading(n); + } + //! Inverse of NumberOfPartitions, given a number of partitions, get the number of radix bits - static inline idx_t RadixBits(idx_t n_partitions) { + static inline idx_t RadixBitsOfPowerOfTwo(idx_t n_partitions) { D_ASSERT(IsPowerOfTwo(n_partitions)); - for (idx_t r = 0; r < sizeof(idx_t) * 8; r++) { - if (n_partitions == NumberOfPartitions(r)) { - return r; - } - } - throw InternalException("RadixPartitioning::RadixBits unable to find partition count!"); + return RadixBits(n_partitions) - 1; } //! Radix bits begin after uint16_t because these bits are used as salt in the aggregate HT @@ -132,9 +132,6 @@ class RadixPartitionedTupleData : public PartitionedTupleData { return RadixPartitioning::NumberOfPartitions(radix_bits) - 1; } - bool RepartitionReverseOrder() const override { - return true; - } void RepartitionFinalizeStates(PartitionedTupleData &old_partitioned_data, PartitionedTupleData &new_partitioned_data, PartitionedTupleDataAppendState &state, idx_t finished_partition_idx) const override; diff --git a/src/duckdb/src/include/duckdb/common/random_engine.hpp b/src/duckdb/src/include/duckdb/common/random_engine.hpp index 224a5a203..970db6ce4 100644 --- a/src/duckdb/src/include/duckdb/common/random_engine.hpp +++ b/src/duckdb/src/include/duckdb/common/random_engine.hpp @@ -28,8 +28,12 @@ struct RandomEngine { //! Generate a random number between 0 and 1 double NextRandom(); + //! Generate a random number between 0 and 1, using 32-bits as a base + double NextRandom32(); + double NextRandom32(double min, double max); uint32_t NextRandomInteger(); uint32_t NextRandomInteger(uint32_t min, uint32_t max); + uint64_t NextRandomInteger64(); void SetSeed(uint32_t seed); diff --git a/src/duckdb/src/include/duckdb/common/serializer/serialization_traits.hpp b/src/duckdb/src/include/duckdb/common/serializer/serialization_traits.hpp index a1c91b8e6..5bde0f9a1 100644 --- a/src/duckdb/src/include/duckdb/common/serializer/serialization_traits.hpp +++ b/src/duckdb/src/include/duckdb/common/serializer/serialization_traits.hpp @@ -32,6 +32,7 @@ using void_t = void; // Check for anything implementing a `void Serialize(Serializer &Serializer)` method template struct has_serialize : std::false_type {}; + template struct has_serialize< T, typename std::enable_if< diff --git a/src/duckdb/src/include/duckdb/common/string_util.hpp b/src/duckdb/src/include/duckdb/common/string_util.hpp index bf8c272d3..5d7299d87 100644 --- a/src/duckdb/src/include/duckdb/common/string_util.hpp +++ b/src/duckdb/src/include/duckdb/common/string_util.hpp @@ -296,6 +296,18 @@ class StringUtil { DUCKDB_API static string GetFileExtension(const string &file_name); DUCKDB_API static string GetFileStem(const string &file_name); DUCKDB_API static string GetFilePath(const string &file_path); + + struct EnumStringLiteral { + uint32_t number; + const char *string; + }; + + DUCKDB_API static uint32_t StringToEnum(const EnumStringLiteral enum_list[], idx_t enum_count, + const char *enum_name, const char *str_value); + DUCKDB_API static const char *EnumToString(const EnumStringLiteral enum_list[], idx_t enum_count, + const char *enum_name, uint32_t enum_value); + DUCKDB_API static const uint8_t ASCII_TO_LOWER_MAP[]; + DUCKDB_API static const uint8_t ASCII_TO_UPPER_MAP[]; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/tree_renderer.hpp b/src/duckdb/src/include/duckdb/common/tree_renderer.hpp index 4e0337405..981836b63 100644 --- a/src/duckdb/src/include/duckdb/common/tree_renderer.hpp +++ b/src/duckdb/src/include/duckdb/common/tree_renderer.hpp @@ -30,6 +30,8 @@ class TreeRenderer { virtual bool UsesRawKeyNames() { return false; } + virtual void Render(const ProfilingNode &op, std::ostream &ss) { + } }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/tree_renderer/graphviz_tree_renderer.hpp b/src/duckdb/src/include/duckdb/common/tree_renderer/graphviz_tree_renderer.hpp index 5f9cebf17..a4ed7f75f 100644 --- a/src/duckdb/src/include/duckdb/common/tree_renderer/graphviz_tree_renderer.hpp +++ b/src/duckdb/src/include/duckdb/common/tree_renderer/graphviz_tree_renderer.hpp @@ -35,7 +35,7 @@ class GRAPHVIZTreeRenderer : public TreeRenderer { void Render(const LogicalOperator &op, std::ostream &ss); void Render(const PhysicalOperator &op, std::ostream &ss); - void Render(const ProfilingNode &op, std::ostream &ss); + void Render(const ProfilingNode &op, std::ostream &ss) override; void Render(const Pipeline &op, std::ostream &ss); void ToStreamInternal(RenderTree &root, std::ostream &ss) override; diff --git a/src/duckdb/src/include/duckdb/common/tree_renderer/html_tree_renderer.hpp b/src/duckdb/src/include/duckdb/common/tree_renderer/html_tree_renderer.hpp index 56cdb4b17..e5d038a27 100644 --- a/src/duckdb/src/include/duckdb/common/tree_renderer/html_tree_renderer.hpp +++ b/src/duckdb/src/include/duckdb/common/tree_renderer/html_tree_renderer.hpp @@ -35,7 +35,7 @@ class HTMLTreeRenderer : public TreeRenderer { void Render(const LogicalOperator &op, std::ostream &ss); void Render(const PhysicalOperator &op, std::ostream &ss); - void Render(const ProfilingNode &op, std::ostream &ss); + void Render(const ProfilingNode &op, std::ostream &ss) override; void Render(const Pipeline &op, std::ostream &ss); void ToStreamInternal(RenderTree &root, std::ostream &ss) override; diff --git a/src/duckdb/src/include/duckdb/common/tree_renderer/json_tree_renderer.hpp b/src/duckdb/src/include/duckdb/common/tree_renderer/json_tree_renderer.hpp index 13a5383e4..15e7c5037 100644 --- a/src/duckdb/src/include/duckdb/common/tree_renderer/json_tree_renderer.hpp +++ b/src/duckdb/src/include/duckdb/common/tree_renderer/json_tree_renderer.hpp @@ -35,7 +35,7 @@ class JSONTreeRenderer : public TreeRenderer { void Render(const LogicalOperator &op, std::ostream &ss); void Render(const PhysicalOperator &op, std::ostream &ss); - void Render(const ProfilingNode &op, std::ostream &ss); + void Render(const ProfilingNode &op, std::ostream &ss) override; void Render(const Pipeline &op, std::ostream &ss); void ToStreamInternal(RenderTree &root, std::ostream &ss) override; diff --git a/src/duckdb/src/include/duckdb/common/tree_renderer/text_tree_renderer.hpp b/src/duckdb/src/include/duckdb/common/tree_renderer/text_tree_renderer.hpp index fa560e65a..b34144a38 100644 --- a/src/duckdb/src/include/duckdb/common/tree_renderer/text_tree_renderer.hpp +++ b/src/duckdb/src/include/duckdb/common/tree_renderer/text_tree_renderer.hpp @@ -84,7 +84,7 @@ class TextTreeRenderer : public TreeRenderer { void Render(const LogicalOperator &op, std::ostream &ss); void Render(const PhysicalOperator &op, std::ostream &ss); - void Render(const ProfilingNode &op, std::ostream &ss); + void Render(const ProfilingNode &op, std::ostream &ss) override; void Render(const Pipeline &op, std::ostream &ss); void ToStreamInternal(RenderTree &root, std::ostream &ss) override; diff --git a/src/duckdb/src/include/duckdb/common/types/column/column_data_allocator.hpp b/src/duckdb/src/include/duckdb/common/types/column/column_data_allocator.hpp index 194b40ca3..38a295320 100644 --- a/src/duckdb/src/include/duckdb/common/types/column/column_data_allocator.hpp +++ b/src/duckdb/src/include/duckdb/common/types/column/column_data_allocator.hpp @@ -62,6 +62,12 @@ class ColumnDataAllocator { idx_t AllocationSize() const { return allocated_size; } + //! Sets the partition index of this tuple data collection + void SetPartitionIndex(idx_t index) { + D_ASSERT(!partition_index.IsValid()); + D_ASSERT(blocks.empty() && allocated_data.empty()); + partition_index = index; + } public: void AllocateData(idx_t size, uint32_t &block_id, uint32_t &offset, ChunkManagementState *chunk_state); @@ -107,6 +113,8 @@ class ColumnDataAllocator { mutex lock; //! Total allocated size idx_t allocated_size = 0; + //! Partition index (optional, if partitioned) + optional_idx partition_index; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/types/column/column_data_collection.hpp b/src/duckdb/src/include/duckdb/common/types/column/column_data_collection.hpp index 1a7473236..f02d49001 100644 --- a/src/duckdb/src/include/duckdb/common/types/column/column_data_collection.hpp +++ b/src/duckdb/src/include/duckdb/common/types/column/column_data_collection.hpp @@ -65,6 +65,8 @@ class ColumnDataCollection { idx_t SizeInBytes() const; //! The allocation size (in bytes) of this ColumnDataCollection - this property is cached idx_t AllocationSize() const; + //! Sets the partition index of this ColumnDataCollection + void SetPartitionIndex(idx_t index); //! Get the allocator DUCKDB_API Allocator &GetAllocator() const; @@ -141,10 +143,17 @@ class ColumnDataCollection { //! Obtains the next scan index to scan from bool NextScanIndex(ColumnDataScanState &state, idx_t &chunk_index, idx_t &segment_index, idx_t &row_index) const; + //! Obtains the previous scan index to scan from + bool PrevScanIndex(ColumnDataScanState &state, idx_t &chunk_index, idx_t &segment_index, idx_t &row_index) const; //! Scans at the indices (obtained from NextScanIndex) void ScanAtIndex(ColumnDataParallelScanState &state, ColumnDataLocalScanState &lstate, DataChunk &result, idx_t chunk_index, idx_t segment_index, idx_t row_index) const; + //! Seeks to the chunk _containing_ the row. Returns false if it is past the end. + //! Note that the returned chunk will likely not be aligned to the given row + //! but the scan state will provide the actual range + bool Seek(idx_t row_idx, ColumnDataScanState &state, DataChunk &result) const; + //! Initialize the column data collection void Initialize(vector types); @@ -178,6 +187,8 @@ class ColumnDataCollection { vector copy_functions; //! When the column data collection is marked as finished - new tuples can no longer be appended to it bool finished_append; + //! Partition index (optional, if partitioned) + optional_idx partition_index; }; //! The ColumnDataRowCollection represents a set of materialized rows, as obtained from the ColumnDataCollection @@ -190,8 +201,8 @@ class ColumnDataRowCollection { public: // container API - bool empty() const { // NOLINT: match stl API - return rows.empty(); + bool empty() const { // NOLINT: match stl API + return rows.empty(); // NOLINT } idx_t size() const { // NOLINT: match stl API return rows.size(); diff --git a/src/duckdb/src/include/duckdb/common/types/column/column_data_collection_segment.hpp b/src/duckdb/src/include/duckdb/common/types/column/column_data_collection_segment.hpp index 33dba6ad9..76ba2b90c 100644 --- a/src/duckdb/src/include/duckdb/common/types/column/column_data_collection_segment.hpp +++ b/src/duckdb/src/include/duckdb/common/types/column/column_data_collection_segment.hpp @@ -137,7 +137,8 @@ class ColumnDataCollectionSegment { void Verify(); static idx_t GetDataSize(idx_t type_size); - static validity_t *GetValidityPointer(data_ptr_t base_ptr, idx_t type_size); + static validity_t *GetValidityPointerForWriting(data_ptr_t base_ptr, idx_t type_size); + static validity_t *GetValidityPointer(data_ptr_t base_ptr, idx_t type_size, idx_t count); private: idx_t ReadVectorInternal(ChunkManagementState &state, VectorDataIndex vector_index, Vector &result); diff --git a/src/duckdb/src/include/duckdb/common/types/data_chunk.hpp b/src/duckdb/src/include/duckdb/common/types/data_chunk.hpp index 7433c93aa..3369f5e00 100644 --- a/src/duckdb/src/include/duckdb/common/types/data_chunk.hpp +++ b/src/duckdb/src/include/duckdb/common/types/data_chunk.hpp @@ -106,7 +106,7 @@ class DataChunk { //! Destroy all data and columns owned by this DataChunk DUCKDB_API void Destroy(); - //! Copies the data from this vector to another vector. + //! Copies the data from this chunk to another chunk. DUCKDB_API void Copy(DataChunk &other, idx_t offset = 0) const; DUCKDB_API void Copy(DataChunk &other, const SelectionVector &sel, const idx_t source_count, const idx_t offset = 0) const; diff --git a/src/duckdb/src/include/duckdb/common/types/row/partitioned_tuple_data.hpp b/src/duckdb/src/include/duckdb/common/types/row/partitioned_tuple_data.hpp index 999c7218a..878b1bfa0 100644 --- a/src/duckdb/src/include/duckdb/common/types/row/partitioned_tuple_data.hpp +++ b/src/duckdb/src/include/duckdb/common/types/row/partitioned_tuple_data.hpp @@ -153,10 +153,6 @@ class PartitionedTupleData { return DConstants::INVALID_INDEX; } - //! Whether or not to iterate over the original partitions in reverse order when repartitioning (optional) - virtual bool RepartitionReverseOrder() const { - return false; - } //! Finalize states while repartitioning - useful for unpinning blocks that are no longer needed (optional) virtual void RepartitionFinalizeStates(PartitionedTupleData &old_partitioned_data, PartitionedTupleData &new_partitioned_data, diff --git a/src/duckdb/src/include/duckdb/common/types/row/tuple_data_allocator.hpp b/src/duckdb/src/include/duckdb/common/types/row/tuple_data_allocator.hpp index 840d48602..b68d3606b 100644 --- a/src/duckdb/src/include/duckdb/common/types/row/tuple_data_allocator.hpp +++ b/src/duckdb/src/include/duckdb/common/types/row/tuple_data_allocator.hpp @@ -67,6 +67,8 @@ class TupleDataAllocator { idx_t RowBlockCount() const; //! Number of heap blocks idx_t HeapBlockCount() const; + //! Sets the partition index of this tuple data allocator + void SetPartitionIndex(idx_t index); public: //! Builds out the chunks for next append, given the metadata in the append state @@ -113,6 +115,8 @@ class TupleDataAllocator { BufferManager &buffer_manager; //! The layout of the data const TupleDataLayout layout; + //! Partition index (optional, if partitioned) + optional_idx partition_index; //! Blocks storing the fixed-size rows unsafe_vector row_blocks; //! Blocks storing the variable-size data of the fixed-size rows (e.g., string, list) diff --git a/src/duckdb/src/include/duckdb/common/types/row/tuple_data_collection.hpp b/src/duckdb/src/include/duckdb/common/types/row/tuple_data_collection.hpp index b87b40024..71b700922 100644 --- a/src/duckdb/src/include/duckdb/common/types/row/tuple_data_collection.hpp +++ b/src/duckdb/src/include/duckdb/common/types/row/tuple_data_collection.hpp @@ -66,6 +66,8 @@ class TupleDataCollection { idx_t SizeInBytes() const; //! Unpins all held pins void Unpin(); + //! Sets the partition index of this tuple data collection + void SetPartitionIndex(idx_t index); //! Gets the scatter function for the given type static TupleDataScatterFunction GetScatterFunction(const LogicalType &type, bool within_collection = false); @@ -252,6 +254,8 @@ class TupleDataCollection { vector scatter_functions; //! The set of gather functions vector gather_functions; + //! Partition index (optional, if partitioned) + optional_idx partition_index; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/vector_operations/aggregate_executor.hpp b/src/duckdb/src/include/duckdb/common/vector_operations/aggregate_executor.hpp index 87895f7b2..6abe7ff1e 100644 --- a/src/duckdb/src/include/duckdb/common/vector_operations/aggregate_executor.hpp +++ b/src/duckdb/src/include/duckdb/common/vector_operations/aggregate_executor.hpp @@ -31,6 +31,7 @@ using SubFrames = vector; class AggregateExecutor { private: +#ifndef DUCKDB_SMALLER_BINARY template static inline void NullaryFlatLoop(STATE_TYPE **__restrict states, AggregateInputData &aggr_input_data, idx_t count) { @@ -38,6 +39,7 @@ class AggregateExecutor { OP::template Operation(*states[i], aggr_input_data, i); } } +#endif template static inline void NullaryScatterLoop(STATE_TYPE **__restrict states, AggregateInputData &aggr_input_data, @@ -49,6 +51,7 @@ class AggregateExecutor { } } +#ifndef DUCKDB_SMALLER_BINARY template static inline void UnaryFlatLoop(const INPUT_TYPE *__restrict idata, AggregateInputData &aggr_input_data, STATE_TYPE **__restrict states, ValidityMask &mask, idx_t count) { @@ -88,6 +91,7 @@ class AggregateExecutor { } } } +#endif template static inline void UnaryScatterLoop(const INPUT_TYPE *__restrict idata, AggregateInputData &aggr_input_data, @@ -114,6 +118,7 @@ class AggregateExecutor { } } +#ifndef DUCKDB_SMALLER_BINARY template static inline void UnaryFlatUpdateLoop(const INPUT_TYPE *__restrict idata, AggregateInputData &aggr_input_data, STATE_TYPE *__restrict state, idx_t count, ValidityMask &mask) { @@ -144,6 +149,7 @@ class AggregateExecutor { } } } +#endif template static inline void UnaryUpdateLoop(const INPUT_TYPE *__restrict idata, AggregateInputData &aggr_input_data, @@ -230,9 +236,11 @@ class AggregateExecutor { if (states.GetVectorType() == VectorType::CONSTANT_VECTOR) { auto sdata = ConstantVector::GetData(states); OP::template ConstantOperation(**sdata, aggr_input_data, count); +#ifndef DUCKDB_SMALLER_BINARY } else if (states.GetVectorType() == VectorType::FLAT_VECTOR) { auto sdata = FlatVector::GetData(states); NullaryFlatLoop(sdata, aggr_input_data, count); +#endif } else { UnifiedVectorFormat sdata; states.ToUnifiedFormat(count, sdata); @@ -258,12 +266,14 @@ class AggregateExecutor { auto sdata = ConstantVector::GetData(states); AggregateUnaryInput input_data(aggr_input_data, ConstantVector::Validity(input)); OP::template ConstantOperation(**sdata, *idata, input_data, count); +#ifndef DUCKDB_SMALLER_BINARY } else if (input.GetVectorType() == VectorType::FLAT_VECTOR && states.GetVectorType() == VectorType::FLAT_VECTOR) { auto idata = FlatVector::GetData(input); auto sdata = FlatVector::GetData(states); UnaryFlatLoop(idata, aggr_input_data, sdata, FlatVector::Validity(input), count); +#endif } else { UnifiedVectorFormat idata, sdata; input.ToUnifiedFormat(count, idata); @@ -287,12 +297,14 @@ class AggregateExecutor { input_data, count); break; } +#ifndef DUCKDB_SMALLER_BINARY case VectorType::FLAT_VECTOR: { auto idata = FlatVector::GetData(input); UnaryFlatUpdateLoop(idata, aggr_input_data, (STATE_TYPE *)state, count, FlatVector::Validity(input)); break; } +#endif default: { UnifiedVectorFormat idata; input.ToUnifiedFormat(count, idata); @@ -387,19 +399,6 @@ class AggregateExecutor { } } - template - static void UnaryWindow(const Vector &input, const ValidityMask &ifilter, AggregateInputData &aggr_input_data, - data_ptr_t state_p, const SubFrames &frames, Vector &result, idx_t ridx, - const_data_ptr_t gstate_p) { - - auto idata = FlatVector::GetData(input); - const auto &ivalid = FlatVector::Validity(input); - auto &state = *reinterpret_cast(state_p); - auto gstate = reinterpret_cast(gstate_p); - OP::template Window(idata, ifilter, ivalid, aggr_input_data, state, frames, - result, ridx, gstate); - } - template static void IntersectFrames(const SubFrames &lefts, const SubFrames &rights, OP &op) { const auto cover_start = MinValue(rights[0].start, lefts[0].start); diff --git a/src/duckdb/src/include/duckdb/common/vector_operations/binary_executor.hpp b/src/duckdb/src/include/duckdb/common/vector_operations/binary_executor.hpp index 55c10bb28..57e669d5d 100644 --- a/src/duckdb/src/include/duckdb/common/vector_operations/binary_executor.hpp +++ b/src/duckdb/src/include/duckdb/common/vector_operations/binary_executor.hpp @@ -68,6 +68,7 @@ struct BinaryLambdaWrapperWithNulls { }; struct BinaryExecutor { +#ifndef DUCKDB_SMALLER_BINARY template static void ExecuteFlatLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata, @@ -121,6 +122,7 @@ struct BinaryExecutor { } } } +#endif template static void ExecuteConstant(Vector &left, Vector &right, Vector &result, FUNC fun) { @@ -138,6 +140,7 @@ struct BinaryExecutor { fun, *ldata, *rdata, ConstantVector::Validity(result), 0); } +#ifndef DUCKDB_SMALLER_BINARY template static void ExecuteFlat(Vector &left, Vector &right, Vector &result, idx_t count, FUNC fun) { @@ -182,6 +185,7 @@ struct BinaryExecutor { ExecuteFlatLoop( ldata, rdata, result_data, count, result_validity, fun); } +#endif template static void ExecuteGenericLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata, @@ -232,6 +236,7 @@ struct BinaryExecutor { auto right_vector_type = right.GetVectorType(); if (left_vector_type == VectorType::CONSTANT_VECTOR && right_vector_type == VectorType::CONSTANT_VECTOR) { ExecuteConstant(left, right, result, fun); +#ifndef DUCKDB_SMALLER_BINARY } else if (left_vector_type == VectorType::FLAT_VECTOR && right_vector_type == VectorType::CONSTANT_VECTOR) { ExecuteFlat(left, right, result, count, fun); @@ -241,6 +246,7 @@ struct BinaryExecutor { } else if (left_vector_type == VectorType::FLAT_VECTOR && right_vector_type == VectorType::FLAT_VECTOR) { ExecuteFlat(left, right, result, count, fun); +#endif } else { ExecuteGeneric(left, right, result, count, fun); } @@ -299,6 +305,7 @@ struct BinaryExecutor { } } +#ifndef DUCKDB_SMALLER_BINARY template static inline idx_t SelectFlatLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata, @@ -417,14 +424,24 @@ struct BinaryExecutor { ldata, rdata, sel, count, combined_mask, true_sel, false_sel); } } +#endif +#ifndef DUCKDB_SMALLER_BINARY template +#else + template +#endif static inline idx_t SelectGenericLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata, const SelectionVector *__restrict lsel, const SelectionVector *__restrict rsel, const SelectionVector *__restrict result_sel, idx_t count, ValidityMask &lvalidity, ValidityMask &rvalidity, SelectionVector *true_sel, SelectionVector *false_sel) { idx_t true_count = 0, false_count = 0; +#ifdef DUCKDB_SMALLER_BINARY + const bool HAS_TRUE_SEL = true_sel; + const bool HAS_FALSE_SEL = false_sel; + const bool NO_NULL = false; +#endif for (idx_t i = 0; i < count; i++) { auto result_idx = result_sel->get_index(i); auto lindex = lsel->get_index(i); @@ -446,6 +463,8 @@ struct BinaryExecutor { return count - false_count; } } + +#ifndef DUCKDB_SMALLER_BINARY template static inline idx_t SelectGenericLoopSelSwitch(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata, @@ -464,6 +483,7 @@ struct BinaryExecutor { ldata, rdata, lsel, rsel, result_sel, count, lvalidity, rvalidity, true_sel, false_sel); } } +#endif template static inline idx_t @@ -471,6 +491,7 @@ struct BinaryExecutor { const SelectionVector *__restrict lsel, const SelectionVector *__restrict rsel, const SelectionVector *__restrict result_sel, idx_t count, ValidityMask &lvalidity, ValidityMask &rvalidity, SelectionVector *true_sel, SelectionVector *false_sel) { +#ifndef DUCKDB_SMALLER_BINARY if (!lvalidity.AllValid() || !rvalidity.AllValid()) { return SelectGenericLoopSelSwitch( ldata, rdata, lsel, rsel, result_sel, count, lvalidity, rvalidity, true_sel, false_sel); @@ -478,6 +499,10 @@ struct BinaryExecutor { return SelectGenericLoopSelSwitch( ldata, rdata, lsel, rsel, result_sel, count, lvalidity, rvalidity, true_sel, false_sel); } +#else + return SelectGenericLoop(ldata, rdata, lsel, rsel, result_sel, count, lvalidity, + rvalidity, true_sel, false_sel); +#endif } template @@ -502,6 +527,7 @@ struct BinaryExecutor { if (left.GetVectorType() == VectorType::CONSTANT_VECTOR && right.GetVectorType() == VectorType::CONSTANT_VECTOR) { return SelectConstant(left, right, sel, count, true_sel, false_sel); +#ifndef DUCKDB_SMALLER_BINARY } else if (left.GetVectorType() == VectorType::CONSTANT_VECTOR && right.GetVectorType() == VectorType::FLAT_VECTOR) { return SelectFlat(left, right, sel, count, true_sel, false_sel); @@ -511,6 +537,7 @@ struct BinaryExecutor { } else if (left.GetVectorType() == VectorType::FLAT_VECTOR && right.GetVectorType() == VectorType::FLAT_VECTOR) { return SelectFlat(left, right, sel, count, true_sel, false_sel); +#endif } else { return SelectGeneric(left, right, sel, count, true_sel, false_sel); } diff --git a/src/duckdb/src/include/duckdb/common/vector_operations/unary_executor.hpp b/src/duckdb/src/include/duckdb/common/vector_operations/unary_executor.hpp index 9f29d7410..16adee632 100644 --- a/src/duckdb/src/include/duckdb/common/vector_operations/unary_executor.hpp +++ b/src/duckdb/src/include/duckdb/common/vector_operations/unary_executor.hpp @@ -90,6 +90,7 @@ struct UnaryExecutor { } } +#ifndef DUCKDB_SMALLER_BINARY template static inline void ExecuteFlat(const INPUT_TYPE *__restrict ldata, RESULT_TYPE *__restrict result_data, idx_t count, ValidityMask &mask, ValidityMask &result_mask, void *dataptr, bool adds_nulls) { @@ -135,6 +136,7 @@ struct UnaryExecutor { } } } +#endif template static inline void ExecuteStandard(Vector &input, Vector &result, idx_t count, void *dataptr, bool adds_nulls) { @@ -153,6 +155,7 @@ struct UnaryExecutor { } break; } +#ifndef DUCKDB_SMALLER_BINARY case VectorType::FLAT_VECTOR: { result.SetVectorType(VectorType::FLAT_VECTOR); auto result_data = FlatVector::GetData(result); @@ -162,6 +165,7 @@ struct UnaryExecutor { FlatVector::Validity(result), dataptr, adds_nulls); break; } +#endif default: { UnifiedVectorFormat vdata; input.ToUnifiedFormat(count, vdata); diff --git a/src/duckdb/src/include/duckdb/common/vector_operations/vector_operations.hpp b/src/duckdb/src/include/duckdb/common/vector_operations/vector_operations.hpp index bd772fcad..57861f073 100644 --- a/src/duckdb/src/include/duckdb/common/vector_operations/vector_operations.hpp +++ b/src/duckdb/src/include/duckdb/common/vector_operations/vector_operations.hpp @@ -130,17 +130,6 @@ struct VectorOperations { optional_ptr false_sel, optional_ptr null_mask = nullptr); - // true := A > B with nulls being minimal - static idx_t DistinctGreaterThanNullsFirst(Vector &left, Vector &right, optional_ptr sel, - idx_t count, optional_ptr true_sel, - optional_ptr false_sel, - optional_ptr null_mask = nullptr); - // true := A < B with nulls being minimal - static idx_t DistinctLessThanNullsFirst(Vector &left, Vector &right, optional_ptr sel, - idx_t count, optional_ptr true_sel, - optional_ptr false_sel, - optional_ptr null_mask = nullptr); - //===--------------------------------------------------------------------===// // Nested Comparisons //===--------------------------------------------------------------------===// diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/corr.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/corr.hpp deleted file mode 100644 index 0d595b11a..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/corr.hpp +++ /dev/null @@ -1,74 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/aggregate/algebraic/corr.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/aggregate_function.hpp" -#include "duckdb/core_functions/aggregate/algebraic/covar.hpp" -#include "duckdb/core_functions/aggregate/algebraic/stddev.hpp" - -namespace duckdb { - -struct CorrState { - CovarState cov_pop; - StddevState dev_pop_x; - StddevState dev_pop_y; -}; - -// Returns the correlation coefficient for non-null pairs in a group. -// CORR(y, x) = COVAR_POP(y, x) / (STDDEV_POP(x) * STDDEV_POP(y)) -struct CorrOperation { - template - static void Initialize(STATE &state) { - CovarOperation::Initialize(state.cov_pop); - STDDevBaseOperation::Initialize(state.dev_pop_x); - STDDevBaseOperation::Initialize(state.dev_pop_y); - } - - template - static void Operation(STATE &state, const A_TYPE &y, const B_TYPE &x, AggregateBinaryInput &idata) { - CovarOperation::Operation(state.cov_pop, y, x, idata); - STDDevBaseOperation::Execute(state.dev_pop_x, x); - STDDevBaseOperation::Execute(state.dev_pop_y, y); - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &aggr_input_data) { - CovarOperation::Combine(source.cov_pop, target.cov_pop, aggr_input_data); - STDDevBaseOperation::Combine(source.dev_pop_x, target.dev_pop_x, aggr_input_data); - STDDevBaseOperation::Combine(source.dev_pop_y, target.dev_pop_y, aggr_input_data); - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.cov_pop.count == 0 || state.dev_pop_x.count == 0 || state.dev_pop_y.count == 0) { - finalize_data.ReturnNull(); - } else { - auto cov = state.cov_pop.co_moment / state.cov_pop.count; - auto std_x = state.dev_pop_x.count > 1 ? sqrt(state.dev_pop_x.dsquared / state.dev_pop_x.count) : 0; - if (!Value::DoubleIsFinite(std_x)) { - throw OutOfRangeException("STDDEV_POP for X is out of range!"); - } - auto std_y = state.dev_pop_y.count > 1 ? sqrt(state.dev_pop_y.dsquared / state.dev_pop_y.count) : 0; - if (!Value::DoubleIsFinite(std_y)) { - throw OutOfRangeException("STDDEV_POP for Y is out of range!"); - } - if (std_x * std_y == 0) { - finalize_data.ReturnNull(); - return; - } - target = cov / (std_x * std_y); - } - } - - static bool IgnoreNull() { - return true; - } -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/covar.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/covar.hpp deleted file mode 100644 index 1908dfad1..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/covar.hpp +++ /dev/null @@ -1,101 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/aggregate/algebraic/covar.hpp -// -// -//===----------------------------------------------------------------------===// -// COVAR_POP(y,x) - -#pragma once - -#include "duckdb/function/aggregate_function.hpp" - -namespace duckdb { - -struct CovarState { - uint64_t count; - double meanx; - double meany; - double co_moment; -}; - -struct CovarOperation { - template - static void Initialize(STATE &state) { - state.count = 0; - state.meanx = 0; - state.meany = 0; - state.co_moment = 0; - } - - template - static void Operation(STATE &state, const A_TYPE &y, const B_TYPE &x, AggregateBinaryInput &idata) { - // update running mean and d^2 - const double n = static_cast(++(state.count)); - - const double dx = (x - state.meanx); - const double meanx = state.meanx + dx / n; - - const double dy = (y - state.meany); - const double meany = state.meany + dy / n; - - // Schubert and Gertz SSDBM 2018 (4.3) - const double C = state.co_moment + dx * (y - meany); - - state.meanx = meanx; - state.meany = meany; - state.co_moment = C; - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - if (target.count == 0) { - target = source; - } else if (source.count > 0) { - const auto count = target.count + source.count; - D_ASSERT(count >= target.count); // This is a check that we are not overflowing - const auto target_count = static_cast(target.count); - const auto source_count = static_cast(source.count); - const auto total_count = static_cast(count); - const auto meanx = (source_count * source.meanx + target_count * target.meanx) / total_count; - const auto meany = (source_count * source.meany + target_count * target.meany) / total_count; - - // Schubert and Gertz SSDBM 2018, equation 21 - const auto deltax = target.meanx - source.meanx; - const auto deltay = target.meany - source.meany; - target.co_moment = - source.co_moment + target.co_moment + deltax * deltay * source_count * target_count / total_count; - target.meanx = meanx; - target.meany = meany; - target.count = count; - } - } - - static bool IgnoreNull() { - return true; - } -}; - -struct CovarPopOperation : public CovarOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.count == 0) { - finalize_data.ReturnNull(); - } else { - target = state.co_moment / state.count; - } - } -}; - -struct CovarSampOperation : public CovarOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.count < 2) { - finalize_data.ReturnNull(); - } else { - target = state.co_moment / (state.count - 1); - } - } -}; -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/stddev.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/stddev.hpp deleted file mode 100644 index bdcafae95..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/stddev.hpp +++ /dev/null @@ -1,151 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/aggregate/algebraic/stddev.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/aggregate_function.hpp" -#include - -namespace duckdb { - -struct StddevState { - uint64_t count; // n - double mean; // M1 - double dsquared; // M2 -}; - -// Streaming approximate standard deviation using Welford's -// method, DOI: 10.2307/1266577 -struct STDDevBaseOperation { - template - static void Initialize(STATE &state) { - state.count = 0; - state.mean = 0; - state.dsquared = 0; - } - - template - static void Execute(STATE &state, const INPUT_TYPE &input) { - // update running mean and d^2 - state.count++; - const double mean_differential = (input - state.mean) / state.count; - const double new_mean = state.mean + mean_differential; - const double dsquared_increment = (input - new_mean) * (input - state.mean); - const double new_dsquared = state.dsquared + dsquared_increment; - - state.mean = new_mean; - state.dsquared = new_dsquared; - } - - template - static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &) { - Execute(state, input); - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, - idx_t count) { - for (idx_t i = 0; i < count; i++) { - Operation(state, input, unary_input); - } - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - if (target.count == 0) { - target = source; - } else if (source.count > 0) { - const auto count = target.count + source.count; - D_ASSERT(count >= target.count); // This is a check that we are not overflowing - const double target_count = static_cast(target.count); - const double source_count = static_cast(source.count); - const double total_count = static_cast(count); - const auto mean = (source_count * source.mean + target_count * target.mean) / total_count; - const auto delta = source.mean - target.mean; - target.dsquared = - source.dsquared + target.dsquared + delta * delta * source_count * target_count / total_count; - target.mean = mean; - target.count = count; - } - } - - static bool IgnoreNull() { - return true; - } -}; - -struct VarSampOperation : public STDDevBaseOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.count <= 1) { - finalize_data.ReturnNull(); - } else { - target = state.dsquared / (state.count - 1); - if (!Value::DoubleIsFinite(target)) { - throw OutOfRangeException("VARSAMP is out of range!"); - } - } - } -}; - -struct VarPopOperation : public STDDevBaseOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.count == 0) { - finalize_data.ReturnNull(); - } else { - target = state.count > 1 ? (state.dsquared / state.count) : 0; - if (!Value::DoubleIsFinite(target)) { - throw OutOfRangeException("VARPOP is out of range!"); - } - } - } -}; - -struct STDDevSampOperation : public STDDevBaseOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.count <= 1) { - finalize_data.ReturnNull(); - } else { - target = sqrt(state.dsquared / (state.count - 1)); - if (!Value::DoubleIsFinite(target)) { - throw OutOfRangeException("STDDEV_SAMP is out of range!"); - } - } - } -}; - -struct STDDevPopOperation : public STDDevBaseOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.count == 0) { - finalize_data.ReturnNull(); - } else { - target = state.count > 1 ? sqrt(state.dsquared / state.count) : 0; - if (!Value::DoubleIsFinite(target)) { - throw OutOfRangeException("STDDEV_POP is out of range!"); - } - } - } -}; - -struct StandardErrorOfTheMeanOperation : public STDDevBaseOperation { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.count == 0) { - finalize_data.ReturnNull(); - } else { - target = sqrt(state.dsquared / state.count) / sqrt((state.count)); - if (!Value::DoubleIsFinite(target)) { - throw OutOfRangeException("SEM is out of range!"); - } - } - } -}; -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic_functions.hpp deleted file mode 100644 index 41ecd18a4..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic_functions.hpp +++ /dev/null @@ -1,126 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/aggregate/algebraic_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct AvgFun { - static constexpr const char *Name = "avg"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Calculates the average value for all tuples in x."; - static constexpr const char *Example = "SUM(x) / COUNT(*)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct MeanFun { - using ALIAS = AvgFun; - - static constexpr const char *Name = "mean"; -}; - -struct CorrFun { - static constexpr const char *Name = "corr"; - static constexpr const char *Parameters = "y,x"; - static constexpr const char *Description = "Returns the correlation coefficient for non-null pairs in a group."; - static constexpr const char *Example = "COVAR_POP(y, x) / (STDDEV_POP(x) * STDDEV_POP(y))"; - - static AggregateFunction GetFunction(); -}; - -struct CovarPopFun { - static constexpr const char *Name = "covar_pop"; - static constexpr const char *Parameters = "y,x"; - static constexpr const char *Description = "Returns the population covariance of input values."; - static constexpr const char *Example = "(SUM(x*y) - SUM(x) * SUM(y) / COUNT(*)) / COUNT(*)"; - - static AggregateFunction GetFunction(); -}; - -struct CovarSampFun { - static constexpr const char *Name = "covar_samp"; - static constexpr const char *Parameters = "y,x"; - static constexpr const char *Description = "Returns the sample covariance for non-null pairs in a group."; - static constexpr const char *Example = "(SUM(x*y) - SUM(x) * SUM(y) / COUNT(*)) / (COUNT(*) - 1)"; - - static AggregateFunction GetFunction(); -}; - -struct FAvgFun { - static constexpr const char *Name = "favg"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Calculates the average using a more accurate floating point summation (Kahan Sum)"; - static constexpr const char *Example = "favg(A)"; - - static AggregateFunction GetFunction(); -}; - -struct StandardErrorOfTheMeanFun { - static constexpr const char *Name = "sem"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns the standard error of the mean"; - static constexpr const char *Example = ""; - - static AggregateFunction GetFunction(); -}; - -struct StdDevPopFun { - static constexpr const char *Name = "stddev_pop"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns the population standard deviation."; - static constexpr const char *Example = "sqrt(var_pop(x))"; - - static AggregateFunction GetFunction(); -}; - -struct StdDevSampFun { - static constexpr const char *Name = "stddev_samp"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns the sample standard deviation"; - static constexpr const char *Example = "sqrt(var_samp(x))"; - - static AggregateFunction GetFunction(); -}; - -struct StddevFun { - using ALIAS = StdDevSampFun; - - static constexpr const char *Name = "stddev"; -}; - -struct VarPopFun { - static constexpr const char *Name = "var_pop"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns the population variance."; - static constexpr const char *Example = ""; - - static AggregateFunction GetFunction(); -}; - -struct VarSampFun { - static constexpr const char *Name = "var_samp"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns the sample variance of all input values."; - static constexpr const char *Example = "(SUM(x^2) - SUM(x)^2 / COUNT(x)) / (COUNT(x) - 1)"; - - static AggregateFunction GetFunction(); -}; - -struct VarianceFun { - using ALIAS = VarSampFun; - - static constexpr const char *Name = "variance"; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/distributive_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/distributive_functions.hpp deleted file mode 100644 index 8891a2dd0..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/distributive_functions.hpp +++ /dev/null @@ -1,266 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/aggregate/distributive_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct ApproxCountDistinctFun { - static constexpr const char *Name = "approx_count_distinct"; - static constexpr const char *Parameters = "any"; - static constexpr const char *Description = "Computes the approximate count of distinct elements using HyperLogLog."; - static constexpr const char *Example = "approx_count_distinct(A)"; - - static AggregateFunction GetFunction(); -}; - -struct ArgMinFun { - static constexpr const char *Name = "arg_min"; - static constexpr const char *Parameters = "arg,val"; - static constexpr const char *Description = "Finds the row with the minimum val. Calculates the non-NULL arg expression at that row."; - static constexpr const char *Example = "arg_min(A,B)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct ArgminFun { - using ALIAS = ArgMinFun; - - static constexpr const char *Name = "argmin"; -}; - -struct MinByFun { - using ALIAS = ArgMinFun; - - static constexpr const char *Name = "min_by"; -}; - -struct ArgMinNullFun { - static constexpr const char *Name = "arg_min_null"; - static constexpr const char *Parameters = "arg,val"; - static constexpr const char *Description = "Finds the row with the minimum val. Calculates the arg expression at that row."; - static constexpr const char *Example = "arg_min_null(A,B)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct ArgMaxFun { - static constexpr const char *Name = "arg_max"; - static constexpr const char *Parameters = "arg,val"; - static constexpr const char *Description = "Finds the row with the maximum val. Calculates the non-NULL arg expression at that row."; - static constexpr const char *Example = "arg_max(A,B)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct ArgmaxFun { - using ALIAS = ArgMaxFun; - - static constexpr const char *Name = "argmax"; -}; - -struct MaxByFun { - using ALIAS = ArgMaxFun; - - static constexpr const char *Name = "max_by"; -}; - -struct ArgMaxNullFun { - static constexpr const char *Name = "arg_max_null"; - static constexpr const char *Parameters = "arg,val"; - static constexpr const char *Description = "Finds the row with the maximum val. Calculates the arg expression at that row."; - static constexpr const char *Example = "arg_max_null(A,B)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct BitAndFun { - static constexpr const char *Name = "bit_and"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Returns the bitwise AND of all bits in a given expression."; - static constexpr const char *Example = "bit_and(A)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct BitOrFun { - static constexpr const char *Name = "bit_or"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Returns the bitwise OR of all bits in a given expression."; - static constexpr const char *Example = "bit_or(A)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct BitXorFun { - static constexpr const char *Name = "bit_xor"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Returns the bitwise XOR of all bits in a given expression."; - static constexpr const char *Example = "bit_xor(A)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct BitstringAggFun { - static constexpr const char *Name = "bitstring_agg"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Returns a bitstring with bits set for each distinct value."; - static constexpr const char *Example = "bitstring_agg(A)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct BoolAndFun { - static constexpr const char *Name = "bool_and"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Returns TRUE if every input value is TRUE, otherwise FALSE."; - static constexpr const char *Example = "bool_and(A)"; - - static AggregateFunction GetFunction(); -}; - -struct BoolOrFun { - static constexpr const char *Name = "bool_or"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Returns TRUE if any input value is TRUE, otherwise FALSE."; - static constexpr const char *Example = "bool_or(A)"; - - static AggregateFunction GetFunction(); -}; - -struct EntropyFun { - static constexpr const char *Name = "entropy"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns the log-2 entropy of count input-values."; - static constexpr const char *Example = ""; - - static AggregateFunctionSet GetFunctions(); -}; - -struct KahanSumFun { - static constexpr const char *Name = "kahan_sum"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Calculates the sum using a more accurate floating point summation (Kahan Sum)."; - static constexpr const char *Example = "kahan_sum(A)"; - - static AggregateFunction GetFunction(); -}; - -struct FsumFun { - using ALIAS = KahanSumFun; - - static constexpr const char *Name = "fsum"; -}; - -struct SumkahanFun { - using ALIAS = KahanSumFun; - - static constexpr const char *Name = "sumkahan"; -}; - -struct KurtosisFun { - static constexpr const char *Name = "kurtosis"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns the excess kurtosis (Fisher’s definition) of all input values, with a bias correction according to the sample size"; - static constexpr const char *Example = ""; - - static AggregateFunction GetFunction(); -}; - -struct KurtosisPopFun { - static constexpr const char *Name = "kurtosis_pop"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns the excess kurtosis (Fisher’s definition) of all input values, without bias correction"; - static constexpr const char *Example = ""; - - static AggregateFunction GetFunction(); -}; - -struct MinFun { - static constexpr const char *Name = "min"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Returns the minimum value present in arg."; - static constexpr const char *Example = "min(A)"; - - static AggregateFunctionSet GetFunctions(); - static AggregateFunction GetFunction(); -}; - -struct MaxFun { - static constexpr const char *Name = "max"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Returns the maximum value present in arg."; - static constexpr const char *Example = "max(A)"; - - static AggregateFunctionSet GetFunctions(); - static AggregateFunction GetFunction(); -}; - -struct ProductFun { - static constexpr const char *Name = "product"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Calculates the product of all tuples in arg."; - static constexpr const char *Example = "product(A)"; - - static AggregateFunction GetFunction(); -}; - -struct SkewnessFun { - static constexpr const char *Name = "skewness"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns the skewness of all input values."; - static constexpr const char *Example = "skewness(A)"; - - static AggregateFunction GetFunction(); -}; - -struct StringAggFun { - static constexpr const char *Name = "string_agg"; - static constexpr const char *Parameters = "str,arg"; - static constexpr const char *Description = "Concatenates the column string values with an optional separator."; - static constexpr const char *Example = "string_agg(A, '-')"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct GroupConcatFun { - using ALIAS = StringAggFun; - - static constexpr const char *Name = "group_concat"; -}; - -struct ListaggFun { - using ALIAS = StringAggFun; - - static constexpr const char *Name = "listagg"; -}; - -struct SumFun { - static constexpr const char *Name = "sum"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Calculates the sum value for all tuples in arg."; - static constexpr const char *Example = "sum(A)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct SumNoOverflowFun { - static constexpr const char *Name = "sum_no_overflow"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Internal only. Calculates the sum value for all tuples in arg without overflow checks."; - static constexpr const char *Example = "sum_no_overflow(A)"; - - static AggregateFunctionSet GetFunctions(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/histogram_helpers.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/histogram_helpers.hpp deleted file mode 100644 index 3b8240776..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/histogram_helpers.hpp +++ /dev/null @@ -1,99 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/aggregate/histogram_helpers.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/common.hpp" -#include "duckdb/core_functions/create_sort_key.hpp" - -namespace duckdb { - -struct HistogramFunctor { - template - static void HistogramFinalize(T value, Vector &result, idx_t offset) { - FlatVector::GetData(result)[offset] = value; - } - - static bool CreateExtraState(idx_t count) { - return false; - } - - static void PrepareData(Vector &input, idx_t count, bool &, UnifiedVectorFormat &result) { - input.ToUnifiedFormat(count, result); - } - - template - static T ExtractValue(UnifiedVectorFormat &bin_data, idx_t offset, AggregateInputData &) { - return UnifiedVectorFormat::GetData(bin_data)[bin_data.sel->get_index(offset)]; - } - - static bool RequiresExtract() { - return false; - } -}; - -struct HistogramStringFunctorBase { - template - static T ExtractValue(UnifiedVectorFormat &bin_data, idx_t offset, AggregateInputData &aggr_input) { - auto &input_str = UnifiedVectorFormat::GetData(bin_data)[bin_data.sel->get_index(offset)]; - if (input_str.IsInlined()) { - // inlined strings can be inserted directly - return input_str; - } - // if the string is not inlined we need to allocate space for it - auto input_str_size = UnsafeNumericCast(input_str.GetSize()); - auto string_memory = aggr_input.allocator.Allocate(input_str_size); - // copy over the string - memcpy(string_memory, input_str.GetData(), input_str_size); - // now insert it into the histogram - string_t histogram_str(char_ptr_cast(string_memory), input_str_size); - return histogram_str; - } - - static bool RequiresExtract() { - return true; - } -}; - -struct HistogramStringFunctor : HistogramStringFunctorBase { - template - static void HistogramFinalize(T value, Vector &result, idx_t offset) { - FlatVector::GetData(result)[offset] = StringVector::AddStringOrBlob(result, value); - } - - static bool CreateExtraState(idx_t count) { - return false; - } - - static void PrepareData(Vector &input, idx_t count, bool &, UnifiedVectorFormat &result) { - input.ToUnifiedFormat(count, result); - } -}; - -struct HistogramGenericFunctor : HistogramStringFunctorBase { - template - static void HistogramFinalize(T value, Vector &result, idx_t offset) { - CreateSortKeyHelpers::DecodeSortKey(value, result, offset, - OrderModifiers(OrderType::ASCENDING, OrderByNullType::NULLS_LAST)); - } - - static Vector CreateExtraState(idx_t count) { - return Vector(LogicalType::BLOB, count); - } - - static void PrepareData(Vector &input, idx_t count, Vector &extra_state, UnifiedVectorFormat &result) { - OrderModifiers modifiers(OrderType::ASCENDING, OrderByNullType::NULLS_LAST); - CreateSortKeyHelpers::CreateSortKey(input, count, modifiers, extra_state); - input.Flatten(count); - extra_state.Flatten(count); - FlatVector::Validity(extra_state).Initialize(FlatVector::Validity(input)); - extra_state.ToUnifiedFormat(count, result); - } -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/holistic_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/holistic_functions.hpp deleted file mode 100644 index 99b216498..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/holistic_functions.hpp +++ /dev/null @@ -1,96 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/aggregate/holistic_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct ApproxQuantileFun { - static constexpr const char *Name = "approx_quantile"; - static constexpr const char *Parameters = "x,pos"; - static constexpr const char *Description = "Computes the approximate quantile using T-Digest."; - static constexpr const char *Example = "approx_quantile(x, 0.5)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct MadFun { - static constexpr const char *Name = "mad"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns the median absolute deviation for the values within x. NULL values are ignored. Temporal types return a positive INTERVAL. "; - static constexpr const char *Example = "mad(x)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct MedianFun { - static constexpr const char *Name = "median"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns the middle value of the set. NULL values are ignored. For even value counts, quantitative values are averaged and ordinal values return the lower value."; - static constexpr const char *Example = "median(x)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct ModeFun { - static constexpr const char *Name = "mode"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns the most frequent value for the values within x. NULL values are ignored."; - static constexpr const char *Example = ""; - - static AggregateFunctionSet GetFunctions(); -}; - -struct QuantileDiscFun { - static constexpr const char *Name = "quantile_disc"; - static constexpr const char *Parameters = "x,pos"; - static constexpr const char *Description = "Returns the exact quantile number between 0 and 1 . If pos is a LIST of FLOATs, then the result is a LIST of the corresponding exact quantiles."; - static constexpr const char *Example = "quantile_disc(x, 0.5)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct QuantileFun { - using ALIAS = QuantileDiscFun; - - static constexpr const char *Name = "quantile"; -}; - -struct QuantileContFun { - static constexpr const char *Name = "quantile_cont"; - static constexpr const char *Parameters = "x,pos"; - static constexpr const char *Description = "Returns the interpolated quantile number between 0 and 1 . If pos is a LIST of FLOATs, then the result is a LIST of the corresponding interpolated quantiles. "; - static constexpr const char *Example = "quantile_cont(x, 0.5)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct ReservoirQuantileFun { - static constexpr const char *Name = "reservoir_quantile"; - static constexpr const char *Parameters = "x,quantile,sample_size"; - static constexpr const char *Description = "Gives the approximate quantile using reservoir sampling, the sample size is optional and uses 8192 as a default size."; - static constexpr const char *Example = "reservoir_quantile(A,0.5,1024)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct ApproxTopKFun { - static constexpr const char *Name = "approx_top_k"; - static constexpr const char *Parameters = "val,k"; - static constexpr const char *Description = "Finds the k approximately most occurring values in the data set"; - static constexpr const char *Example = "approx_top_k(x, 5)"; - - static AggregateFunction GetFunction(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/nested_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/nested_functions.hpp deleted file mode 100644 index faaa2f4d6..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/nested_functions.hpp +++ /dev/null @@ -1,53 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/aggregate/nested_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct HistogramFun { - static constexpr const char *Name = "histogram"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Returns a LIST of STRUCTs with the fields bucket and count."; - static constexpr const char *Example = "histogram(A)"; - - static AggregateFunctionSet GetFunctions(); - static AggregateFunction GetHistogramUnorderedMap(LogicalType &type); - static AggregateFunction BinnedHistogramFunction(); -}; - -struct HistogramExactFun { - static constexpr const char *Name = "histogram_exact"; - static constexpr const char *Parameters = "arg,bins"; - static constexpr const char *Description = "Returns a LIST of STRUCTs with the fields bucket and count matching the buckets exactly."; - static constexpr const char *Example = "histogram_exact(A, [0, 1, 2])"; - - static AggregateFunction GetFunction(); -}; - -struct ListFun { - static constexpr const char *Name = "list"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Returns a LIST containing all the values of a column."; - static constexpr const char *Example = "list(A)"; - - static AggregateFunction GetFunction(); -}; - -struct ArrayAggFun { - using ALIAS = ListFun; - - static constexpr const char *Name = "array_agg"; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_helpers.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_helpers.hpp deleted file mode 100644 index a2d41deba..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_helpers.hpp +++ /dev/null @@ -1,65 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/aggregate/quantile_helpers.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/common.hpp" -#include "duckdb/core_functions/aggregate/quantile_enum.hpp" -#include "duckdb/core_functions/aggregate/holistic_functions.hpp" - -namespace duckdb { - -// Avoid using naked Values in inner loops... -struct QuantileValue { - explicit QuantileValue(const Value &v) : val(v), dbl(v.GetValue()) { - const auto &type = val.type(); - switch (type.id()) { - case LogicalTypeId::DECIMAL: { - integral = IntegralValue::Get(v); - scaling = Hugeint::POWERS_OF_TEN[DecimalType::GetScale(type)]; - break; - } - default: - break; - } - } - - Value val; - - // DOUBLE - double dbl; - - // DECIMAL - hugeint_t integral; - hugeint_t scaling; - - inline bool operator==(const QuantileValue &other) const { - return val == other.val; - } -}; - -struct QuantileBindData : public FunctionData { - QuantileBindData(); - explicit QuantileBindData(const Value &quantile_p); - explicit QuantileBindData(const vector &quantiles_p); - QuantileBindData(const QuantileBindData &other); - - unique_ptr Copy() const override; - bool Equals(const FunctionData &other_p) const override; - - static void Serialize(Serializer &serializer, const optional_ptr bind_data_p, - const AggregateFunction &function); - - static unique_ptr Deserialize(Deserializer &deserializer, AggregateFunction &function); - - vector quantiles; - vector order; - bool desc; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_sort_tree.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_sort_tree.hpp deleted file mode 100644 index 146c1259f..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_sort_tree.hpp +++ /dev/null @@ -1,349 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/aggregate/quantile_sort_tree.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/core_functions/aggregate/quantile_helpers.hpp" -#include "duckdb/execution/merge_sort_tree.hpp" -#include "duckdb/common/operator/cast_operators.hpp" -#include "duckdb/common/operator/multiply.hpp" -#include -#include -#include -#include - -namespace duckdb { - -// Direct access -template -struct QuantileDirect { - using INPUT_TYPE = T; - using RESULT_TYPE = T; - - inline const INPUT_TYPE &operator()(const INPUT_TYPE &x) const { - return x; - } -}; - -// Indirect access -template -struct QuantileIndirect { - using INPUT_TYPE = idx_t; - using RESULT_TYPE = T; - const RESULT_TYPE *data; - - explicit QuantileIndirect(const RESULT_TYPE *data_p) : data(data_p) { - } - - inline RESULT_TYPE operator()(const idx_t &input) const { - return data[input]; - } -}; - -// Composed access -template -struct QuantileComposed { - using INPUT_TYPE = typename INNER::INPUT_TYPE; - using RESULT_TYPE = typename OUTER::RESULT_TYPE; - - const OUTER &outer; - const INNER &inner; - - explicit QuantileComposed(const OUTER &outer_p, const INNER &inner_p) : outer(outer_p), inner(inner_p) { - } - - inline RESULT_TYPE operator()(const idx_t &input) const { - return outer(inner(input)); - } -}; - -// Accessed comparison -template -struct QuantileCompare { - using INPUT_TYPE = typename ACCESSOR::INPUT_TYPE; - const ACCESSOR &accessor; - const bool desc; - explicit QuantileCompare(const ACCESSOR &accessor_p, bool desc_p) : accessor(accessor_p), desc(desc_p) { - } - - inline bool operator()(const INPUT_TYPE &lhs, const INPUT_TYPE &rhs) const { - const auto lval = accessor(lhs); - const auto rval = accessor(rhs); - - return desc ? (rval < lval) : (lval < rval); - } -}; - -struct CastInterpolation { - template - static inline TARGET_TYPE Cast(const INPUT_TYPE &src, Vector &result) { - return Cast::Operation(src); - } - template - static inline TARGET_TYPE Interpolate(const TARGET_TYPE &lo, const double d, const TARGET_TYPE &hi) { - const auto delta = hi - lo; - return LossyNumericCast(lo + delta * d); - } -}; - -template <> -interval_t CastInterpolation::Cast(const dtime_t &src, Vector &result); -template <> -double CastInterpolation::Interpolate(const double &lo, const double d, const double &hi); -template <> -dtime_t CastInterpolation::Interpolate(const dtime_t &lo, const double d, const dtime_t &hi); -template <> -timestamp_t CastInterpolation::Interpolate(const timestamp_t &lo, const double d, const timestamp_t &hi); -template <> -hugeint_t CastInterpolation::Interpolate(const hugeint_t &lo, const double d, const hugeint_t &hi); -template <> -interval_t CastInterpolation::Interpolate(const interval_t &lo, const double d, const interval_t &hi); -template <> -string_t CastInterpolation::Cast(const string_t &src, Vector &result); - -// Continuous interpolation -template -struct Interpolator { - Interpolator(const QuantileValue &q, const idx_t n_p, const bool desc_p) - : desc(desc_p), RN((double)(n_p - 1) * q.dbl), FRN(ExactNumericCast(floor(RN))), - CRN(ExactNumericCast(ceil(RN))), begin(0), end(n_p) { - } - - template > - TARGET_TYPE Interpolate(INPUT_TYPE lidx, INPUT_TYPE hidx, Vector &result, const ACCESSOR &accessor) const { - using ACCESS_TYPE = typename ACCESSOR::RESULT_TYPE; - if (lidx == hidx) { - return CastInterpolation::Cast(accessor(lidx), result); - } else { - auto lo = CastInterpolation::Cast(accessor(lidx), result); - auto hi = CastInterpolation::Cast(accessor(hidx), result); - return CastInterpolation::Interpolate(lo, RN - FRN, hi); - } - } - - template > - TARGET_TYPE Operation(INPUT_TYPE *v_t, Vector &result, const ACCESSOR &accessor = ACCESSOR()) const { - using ACCESS_TYPE = typename ACCESSOR::RESULT_TYPE; - QuantileCompare comp(accessor, desc); - if (CRN == FRN) { - std::nth_element(v_t + begin, v_t + FRN, v_t + end, comp); - return CastInterpolation::Cast(accessor(v_t[FRN]), result); - } else { - std::nth_element(v_t + begin, v_t + FRN, v_t + end, comp); - std::nth_element(v_t + FRN, v_t + CRN, v_t + end, comp); - auto lo = CastInterpolation::Cast(accessor(v_t[FRN]), result); - auto hi = CastInterpolation::Cast(accessor(v_t[CRN]), result); - return CastInterpolation::Interpolate(lo, RN - FRN, hi); - } - } - - template - inline TARGET_TYPE Extract(const INPUT_TYPE **dest, Vector &result) const { - if (CRN == FRN) { - return CastInterpolation::Cast(*dest[0], result); - } else { - auto lo = CastInterpolation::Cast(*dest[0], result); - auto hi = CastInterpolation::Cast(*dest[1], result); - return CastInterpolation::Interpolate(lo, RN - FRN, hi); - } - } - - const bool desc; - const double RN; - const idx_t FRN; - const idx_t CRN; - - idx_t begin; - idx_t end; -}; - -// Discrete "interpolation" -template <> -struct Interpolator { - static inline idx_t Index(const QuantileValue &q, const idx_t n) { - idx_t floored; - switch (q.val.type().id()) { - case LogicalTypeId::DECIMAL: { - // Integer arithmetic for accuracy - const auto integral = q.integral; - const auto scaling = q.scaling; - const auto scaled_q = - DecimalMultiplyOverflowCheck::Operation(Hugeint::Convert(n), integral); - const auto scaled_n = - DecimalMultiplyOverflowCheck::Operation(Hugeint::Convert(n), scaling); - floored = Cast::Operation((scaled_n - scaled_q) / scaling); - break; - } - default: - const auto scaled_q = double(n) * q.dbl; - floored = LossyNumericCast(floor(double(n) - scaled_q)); - break; - } - - return MaxValue(1, n - floored) - 1; - } - - Interpolator(const QuantileValue &q, const idx_t n_p, bool desc_p) - : desc(desc_p), FRN(Index(q, n_p)), CRN(FRN), begin(0), end(n_p) { - } - - template > - TARGET_TYPE Interpolate(INPUT_TYPE lidx, INPUT_TYPE hidx, Vector &result, const ACCESSOR &accessor) const { - using ACCESS_TYPE = typename ACCESSOR::RESULT_TYPE; - return CastInterpolation::Cast(accessor(lidx), result); - } - - template > - typename ACCESSOR::RESULT_TYPE InterpolateInternal(INPUT_TYPE *v_t, const ACCESSOR &accessor = ACCESSOR()) const { - QuantileCompare comp(accessor, desc); - std::nth_element(v_t + begin, v_t + FRN, v_t + end, comp); - return accessor(v_t[FRN]); - } - - template > - TARGET_TYPE Operation(INPUT_TYPE *v_t, Vector &result, const ACCESSOR &accessor = ACCESSOR()) const { - using ACCESS_TYPE = typename ACCESSOR::RESULT_TYPE; - return CastInterpolation::Cast(InterpolateInternal(v_t, accessor), result); - } - - template - TARGET_TYPE Extract(const INPUT_TYPE **dest, Vector &result) const { - return CastInterpolation::Cast(*dest[0], result); - } - - const bool desc; - const idx_t FRN; - const idx_t CRN; - - idx_t begin; - idx_t end; -}; - -struct QuantileIncluded { - inline explicit QuantileIncluded(const ValidityMask &fmask_p, const ValidityMask &dmask_p) - : fmask(fmask_p), dmask(dmask_p) { - } - - inline bool operator()(const idx_t &idx) const { - return fmask.RowIsValid(idx) && dmask.RowIsValid(idx); - } - - inline bool AllValid() const { - return fmask.AllValid() && dmask.AllValid(); - } - - const ValidityMask &fmask; - const ValidityMask &dmask; -}; - -template -struct QuantileSortTree : public MergeSortTree { - - using BaseTree = MergeSortTree; - using Elements = typename BaseTree::Elements; - - explicit QuantileSortTree(Elements &&lowest_level) { - BaseTree::Allocate(lowest_level.size()); - BaseTree::LowestLevel() = std::move(lowest_level); - } - - template - static unique_ptr WindowInit(const INPUT_TYPE *data, AggregateInputData &aggr_input_data, - const ValidityMask &data_mask, const ValidityMask &filter_mask, - idx_t count) { - // Build the indirection array - using ElementType = typename QuantileSortTree::ElementType; - vector sorted(count); - if (filter_mask.AllValid() && data_mask.AllValid()) { - std::iota(sorted.begin(), sorted.end(), 0); - } else { - size_t valid = 0; - QuantileIncluded included(filter_mask, data_mask); - for (ElementType i = 0; i < count; ++i) { - if (included(i)) { - sorted[valid++] = i; - } - } - sorted.resize(valid); - } - - // Sort it - auto &bind_data = aggr_input_data.bind_data->Cast(); - using Accessor = QuantileIndirect; - Accessor indirect(data); - QuantileCompare cmp(indirect, bind_data.desc); - std::sort(sorted.begin(), sorted.end(), cmp); - - return make_uniq(std::move(sorted)); - } - - inline IDX SelectNth(const SubFrames &frames, size_t n) const { - return BaseTree::NthElement(BaseTree::SelectNth(frames, n)); - } - - template - RESULT_TYPE WindowScalar(const INPUT_TYPE *data, const SubFrames &frames, const idx_t n, Vector &result, - const QuantileValue &q) { - D_ASSERT(n > 0); - - // Thread safe and idempotent. - BaseTree::Build(); - - // Find the interpolated indicies within the frame - Interpolator interp(q, n, false); - const auto lo_data = SelectNth(frames, interp.FRN); - auto hi_data = lo_data; - if (interp.CRN != interp.FRN) { - hi_data = SelectNth(frames, interp.CRN); - } - - // Interpolate indirectly - using ID = QuantileIndirect; - ID indirect(data); - return interp.template Interpolate(lo_data, hi_data, result, indirect); - } - - template - void WindowList(const INPUT_TYPE *data, const SubFrames &frames, const idx_t n, Vector &list, const idx_t lidx, - const QuantileBindData &bind_data) { - D_ASSERT(n > 0); - - // Thread safe and idempotent. - BaseTree::Build(); - - // Result is a constant LIST with a fixed length - auto ldata = FlatVector::GetData(list); - auto &lentry = ldata[lidx]; - lentry.offset = ListVector::GetListSize(list); - lentry.length = bind_data.quantiles.size(); - - ListVector::Reserve(list, lentry.offset + lentry.length); - ListVector::SetListSize(list, lentry.offset + lentry.length); - auto &result = ListVector::GetEntry(list); - auto rdata = FlatVector::GetData(result); - - using ID = QuantileIndirect; - ID indirect(data); - for (const auto &q : bind_data.order) { - const auto &quantile = bind_data.quantiles[q]; - Interpolator interp(quantile, n, false); - - const auto lo_data = SelectNth(frames, interp.FRN); - auto hi_data = lo_data; - if (interp.CRN != interp.FRN) { - hi_data = SelectNth(frames, interp.CRN); - } - - // Interpolate indirectly - rdata[lentry.offset + q] = - interp.template Interpolate(lo_data, hi_data, result, indirect); - } - } -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_state.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_state.hpp deleted file mode 100644 index a46340955..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_state.hpp +++ /dev/null @@ -1,300 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/aggregate/quantile_state.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/core_functions/aggregate/quantile_sort_tree.hpp" -#include "SkipList.h" - -namespace duckdb { - -struct QuantileOperation { - template - static void Initialize(STATE &state) { - new (&state) STATE(); - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, - idx_t count) { - for (idx_t i = 0; i < count; i++) { - Operation(state, input, unary_input); - } - } - - template - static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &aggr_input) { - state.AddElement(input, aggr_input.input); - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - if (source.v.empty()) { - return; - } - target.v.insert(target.v.end(), source.v.begin(), source.v.end()); - } - - template - static void Destroy(STATE &state, AggregateInputData &) { - state.~STATE(); - } - - static bool IgnoreNull() { - return true; - } - - template - static void WindowInit(AggregateInputData &aggr_input_data, const WindowPartitionInput &partition, - data_ptr_t g_state) { - D_ASSERT(partition.input_count == 1); - - auto inputs = partition.inputs; - const auto count = partition.count; - const auto &filter_mask = partition.filter_mask; - const auto &stats = partition.stats; - - // If frames overlap significantly, then use local skip lists. - if (stats[0].end <= stats[1].begin) { - // Frames can overlap - const auto overlap = double(stats[1].begin - stats[0].end); - const auto cover = double(stats[1].end - stats[0].begin); - const auto ratio = overlap / cover; - if (ratio > .75) { - return; - } - } - - const auto data = FlatVector::GetData(inputs[0]); - const auto &data_mask = FlatVector::Validity(inputs[0]); - - // Build the tree - auto &state = *reinterpret_cast(g_state); - auto &window_state = state.GetOrCreateWindowState(); - if (count < std::numeric_limits::max()) { - window_state.qst32 = QuantileSortTree::WindowInit(data, aggr_input_data, data_mask, - filter_mask, count); - } else { - window_state.qst64 = QuantileSortTree::WindowInit(data, aggr_input_data, data_mask, - filter_mask, count); - } - } - - static idx_t FrameSize(const QuantileIncluded &included, const SubFrames &frames) { - // Count the number of valid values - idx_t n = 0; - if (included.AllValid()) { - for (const auto &frame : frames) { - n += frame.end - frame.start; - } - } else { - // NULLs or FILTERed values, - for (const auto &frame : frames) { - for (auto i = frame.start; i < frame.end; ++i) { - n += included(i); - } - } - } - - return n; - } -}; - -template -struct PointerLess { - inline bool operator()(const T &lhi, const T &rhi) const { - return *lhi < *rhi; - } -}; - -template -struct WindowQuantileState { - // Windowed Quantile merge sort trees - using QuantileSortTree32 = QuantileSortTree; - using QuantileSortTree64 = QuantileSortTree; - unique_ptr qst32; - unique_ptr qst64; - - // Windowed Quantile skip lists - using PointerType = const INPUT_TYPE *; - using SkipListType = duckdb_skiplistlib::skip_list::HeadNode>; - SubFrames prevs; - unique_ptr s; - mutable vector dest; - - // Windowed MAD indirection - idx_t count; - vector m; - - WindowQuantileState() : count(0) { - } - - inline void SetCount(size_t count_p) { - count = count_p; - if (count >= m.size()) { - m.resize(count); - } - } - - inline SkipListType &GetSkipList(bool reset = false) { - if (reset || !s) { - s.reset(); - s = make_uniq(); - } - return *s; - } - - struct SkipListUpdater { - SkipListType &skip; - const INPUT_TYPE *data; - const QuantileIncluded &included; - - inline SkipListUpdater(SkipListType &skip, const INPUT_TYPE *data, const QuantileIncluded &included) - : skip(skip), data(data), included(included) { - } - - inline void Neither(idx_t begin, idx_t end) { - } - - inline void Left(idx_t begin, idx_t end) { - for (; begin < end; ++begin) { - if (included(begin)) { - skip.remove(data + begin); - } - } - } - - inline void Right(idx_t begin, idx_t end) { - for (; begin < end; ++begin) { - if (included(begin)) { - skip.insert(data + begin); - } - } - } - - inline void Both(idx_t begin, idx_t end) { - } - }; - - void UpdateSkip(const INPUT_TYPE *data, const SubFrames &frames, const QuantileIncluded &included) { - // No overlap, or no data - if (!s || prevs.back().end <= frames.front().start || frames.back().end <= prevs.front().start) { - auto &skip = GetSkipList(true); - for (const auto &frame : frames) { - for (auto i = frame.start; i < frame.end; ++i) { - if (included(i)) { - skip.insert(data + i); - } - } - } - } else { - auto &skip = GetSkipList(); - SkipListUpdater updater(skip, data, included); - AggregateExecutor::IntersectFrames(prevs, frames, updater); - } - } - - bool HasTrees() const { - return qst32 || qst64; - } - - template - RESULT_TYPE WindowScalar(const INPUT_TYPE *data, const SubFrames &frames, const idx_t n, Vector &result, - const QuantileValue &q) const { - D_ASSERT(n > 0); - if (qst32) { - return qst32->WindowScalar(data, frames, n, result, q); - } else if (qst64) { - return qst64->WindowScalar(data, frames, n, result, q); - } else if (s) { - // Find the position(s) needed - try { - Interpolator interp(q, s->size(), false); - s->at(interp.FRN, interp.CRN - interp.FRN + 1, dest); - return interp.template Extract(dest.data(), result); - } catch (const duckdb_skiplistlib::skip_list::IndexError &idx_err) { - throw InternalException(idx_err.message()); - } - } else { - throw InternalException("No accelerator for scalar QUANTILE"); - } - } - - template - void WindowList(const INPUT_TYPE *data, const SubFrames &frames, const idx_t n, Vector &list, const idx_t lidx, - const QuantileBindData &bind_data) const { - D_ASSERT(n > 0); - // Result is a constant LIST with a fixed length - auto ldata = FlatVector::GetData(list); - auto &lentry = ldata[lidx]; - lentry.offset = ListVector::GetListSize(list); - lentry.length = bind_data.quantiles.size(); - - ListVector::Reserve(list, lentry.offset + lentry.length); - ListVector::SetListSize(list, lentry.offset + lentry.length); - auto &result = ListVector::GetEntry(list); - auto rdata = FlatVector::GetData(result); - - for (const auto &q : bind_data.order) { - const auto &quantile = bind_data.quantiles[q]; - rdata[lentry.offset + q] = WindowScalar(data, frames, n, result, quantile); - } - } -}; - -struct QuantileStandardType { - template - static T Operation(T input, AggregateInputData &) { - return input; - } -}; - -struct QuantileStringType { - template - static T Operation(T input, AggregateInputData &input_data) { - if (input.IsInlined()) { - return input; - } - auto string_data = input_data.allocator.Allocate(input.GetSize()); - memcpy(string_data, input.GetData(), input.GetSize()); - return string_t(char_ptr_cast(string_data), UnsafeNumericCast(input.GetSize())); - } -}; - -template -struct QuantileState { - using InputType = INPUT_TYPE; - - // Regular aggregation - vector v; - - // Window Quantile State - unique_ptr> window_state; - - void AddElement(INPUT_TYPE element, AggregateInputData &aggr_input) { - v.emplace_back(TYPE_OP::Operation(element, aggr_input)); - } - - bool HasTrees() const { - return window_state && window_state->HasTrees(); - } - WindowQuantileState &GetOrCreateWindowState() { - if (!window_state) { - window_state = make_uniq>(); - } - return *window_state; - } - WindowQuantileState &GetWindowState() { - return *window_state; - } - const WindowQuantileState &GetWindowState() const { - return *window_state; - } -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/regression/regr_count.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/regression/regr_count.hpp deleted file mode 100644 index 2b13a2abf..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/regression/regr_count.hpp +++ /dev/null @@ -1,42 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/aggregate/regression/regr_count.hpp -// -// -//===----------------------------------------------------------------------===// -// REGR_COUNT(y, x) - -#pragma once - -#include "duckdb/function/aggregate_function.hpp" -#include "duckdb/core_functions/aggregate/algebraic/covar.hpp" -#include "duckdb/core_functions/aggregate/algebraic/stddev.hpp" - -namespace duckdb { - -struct RegrCountFunction { - template - static void Initialize(STATE &state) { - state = 0; - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &) { - target += source; - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - target = static_cast(state); - } - static bool IgnoreNull() { - return true; - } - template - static void Operation(STATE &state, const A_TYPE &, const B_TYPE &, AggregateBinaryInput &) { - state += 1; - } -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/regression/regr_slope.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/regression/regr_slope.hpp deleted file mode 100644 index 701050419..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/regression/regr_slope.hpp +++ /dev/null @@ -1,61 +0,0 @@ -// REGR_SLOPE(y, x) -// Returns the slope of the linear regression line for non-null pairs in a group. -// It is computed for non-null pairs using the following formula: -// COVAR_POP(x,y) / VAR_POP(x) - -//! Input : Any numeric type -//! Output : Double - -#pragma once -#include "duckdb/core_functions/aggregate/algebraic/stddev.hpp" -#include "duckdb/core_functions/aggregate/algebraic/covar.hpp" - -namespace duckdb { - -struct RegrSlopeState { - CovarState cov_pop; - StddevState var_pop; -}; - -struct RegrSlopeOperation { - template - static void Initialize(STATE &state) { - CovarOperation::Initialize(state.cov_pop); - STDDevBaseOperation::Initialize(state.var_pop); - } - - template - static void Operation(STATE &state, const A_TYPE &y, const B_TYPE &x, AggregateBinaryInput &idata) { - CovarOperation::Operation(state.cov_pop, y, x, idata); - STDDevBaseOperation::Execute(state.var_pop, x); - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &aggr_input_data) { - CovarOperation::Combine(source.cov_pop, target.cov_pop, aggr_input_data); - STDDevBaseOperation::Combine(source.var_pop, target.var_pop, aggr_input_data); - } - - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - if (state.cov_pop.count == 0 || state.var_pop.count == 0) { - finalize_data.ReturnNull(); - } else { - auto cov = state.cov_pop.co_moment / state.cov_pop.count; - auto var_pop = state.var_pop.count > 1 ? (state.var_pop.dsquared / state.var_pop.count) : 0; - if (!Value::DoubleIsFinite(var_pop)) { - throw OutOfRangeException("VARPOP is out of range!"); - } - if (var_pop == 0) { - finalize_data.ReturnNull(); - return; - } - target = cov / var_pop; - } - } - - static bool IgnoreNull() { - return true; - } -}; -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/regression_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/regression_functions.hpp deleted file mode 100644 index 70cd5f07d..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/regression_functions.hpp +++ /dev/null @@ -1,99 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/aggregate/regression_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct RegrAvgxFun { - static constexpr const char *Name = "regr_avgx"; - static constexpr const char *Parameters = "y,x"; - static constexpr const char *Description = "Returns the average of the independent variable for non-null pairs in a group, where x is the independent variable and y is the dependent variable."; - static constexpr const char *Example = ""; - - static AggregateFunction GetFunction(); -}; - -struct RegrAvgyFun { - static constexpr const char *Name = "regr_avgy"; - static constexpr const char *Parameters = "y,x"; - static constexpr const char *Description = "Returns the average of the dependent variable for non-null pairs in a group, where x is the independent variable and y is the dependent variable."; - static constexpr const char *Example = ""; - - static AggregateFunction GetFunction(); -}; - -struct RegrCountFun { - static constexpr const char *Name = "regr_count"; - static constexpr const char *Parameters = "y,x"; - static constexpr const char *Description = "Returns the number of non-null number pairs in a group."; - static constexpr const char *Example = "(SUM(x*y) - SUM(x) * SUM(y) / COUNT(*)) / COUNT(*)"; - - static AggregateFunction GetFunction(); -}; - -struct RegrInterceptFun { - static constexpr const char *Name = "regr_intercept"; - static constexpr const char *Parameters = "y,x"; - static constexpr const char *Description = "Returns the intercept of the univariate linear regression line for non-null pairs in a group."; - static constexpr const char *Example = "AVG(y)-REGR_SLOPE(y,x)*AVG(x)"; - - static AggregateFunction GetFunction(); -}; - -struct RegrR2Fun { - static constexpr const char *Name = "regr_r2"; - static constexpr const char *Parameters = "y,x"; - static constexpr const char *Description = "Returns the coefficient of determination for non-null pairs in a group."; - static constexpr const char *Example = ""; - - static AggregateFunction GetFunction(); -}; - -struct RegrSlopeFun { - static constexpr const char *Name = "regr_slope"; - static constexpr const char *Parameters = "y,x"; - static constexpr const char *Description = "Returns the slope of the linear regression line for non-null pairs in a group."; - static constexpr const char *Example = "COVAR_POP(x,y) / VAR_POP(x)"; - - static AggregateFunction GetFunction(); -}; - -struct RegrSXXFun { - static constexpr const char *Name = "regr_sxx"; - static constexpr const char *Parameters = "y,x"; - static constexpr const char *Description = ""; - static constexpr const char *Example = "REGR_COUNT(y, x) * VAR_POP(x)"; - - static AggregateFunction GetFunction(); -}; - -struct RegrSXYFun { - static constexpr const char *Name = "regr_sxy"; - static constexpr const char *Parameters = "y,x"; - static constexpr const char *Description = "Returns the population covariance of input values"; - static constexpr const char *Example = "REGR_COUNT(y, x) * COVAR_POP(y, x)"; - - static AggregateFunction GetFunction(); -}; - -struct RegrSYYFun { - static constexpr const char *Name = "regr_syy"; - static constexpr const char *Parameters = "y,x"; - static constexpr const char *Description = ""; - static constexpr const char *Example = "REGR_COUNT(y, x) * VAR_POP(y)"; - - static AggregateFunction GetFunction(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/sum_helpers.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/sum_helpers.hpp deleted file mode 100644 index 562f61ade..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/sum_helpers.hpp +++ /dev/null @@ -1,175 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/aggregate/sum_helpers.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/common.hpp" -#include "duckdb/common/types.hpp" -#include "duckdb/common/types/vector.hpp" - -namespace duckdb { - -static inline void KahanAddInternal(double input, double &summed, double &err) { - double diff = input - err; - double newval = summed + diff; - err = (newval - summed) - diff; - summed = newval; -} - -template -struct SumState { - bool isset; - T value; - - void Initialize() { - this->isset = false; - } - - void Combine(const SumState &other) { - this->isset = other.isset || this->isset; - this->value += other.value; - } -}; - -struct KahanSumState { - bool isset; - double value; - double err; - - void Initialize() { - this->isset = false; - this->err = 0.0; - } - - void Combine(const KahanSumState &other) { - this->isset = other.isset || this->isset; - KahanAddInternal(other.value, this->value, this->err); - KahanAddInternal(other.err, this->value, this->err); - } -}; - -struct RegularAdd { - template - static void AddNumber(STATE &state, T input) { - state.value += input; - } - - template - static void AddConstant(STATE &state, T input, idx_t count) { - state.value += input * int64_t(count); - } -}; - -struct HugeintAdd { - template - static void AddNumber(STATE &state, T input) { - state.value = Hugeint::Add(state.value, input); - } - - template - static void AddConstant(STATE &state, T input, idx_t count) { - AddNumber(state, Hugeint::Multiply(input, UnsafeNumericCast(count))); - } -}; - -struct KahanAdd { - template - static void AddNumber(STATE &state, T input) { - KahanAddInternal(input, state.value, state.err); - } - - template - static void AddConstant(STATE &state, T input, idx_t count) { - KahanAddInternal(input * count, state.value, state.err); - } -}; - -struct AddToHugeint { - static void AddValue(hugeint_t &result, uint64_t value, int positive) { - // integer summation taken from Tim Gubner et al. - Efficient Query Processing - // with Optimistically Compressed Hash Tables & Strings in the USSR - - // add the value to the lower part of the hugeint - result.lower += value; - // now handle overflows - int overflow = result.lower < value; - // we consider two situations: - // (1) input[idx] is positive, and current value is lower than value: overflow - // (2) input[idx] is negative, and current value is higher than value: underflow - if (!(overflow ^ positive)) { - // in the case of an overflow or underflow we either increment or decrement the upper base - // positive: +1, negative: -1 - result.upper += -1 + 2 * positive; - } - } - - template - static void AddNumber(STATE &state, T input) { - AddValue(state.value, uint64_t(input), input >= 0); - } - - template - static void AddConstant(STATE &state, T input, idx_t count) { - // add a constant X number of times - // fast path: check if value * count fits into a uint64_t - // note that we check if value * VECTOR_SIZE fits in a uint64_t to avoid having to actually do a division - // this is still a pretty high number (18014398509481984) so most positive numbers will fit - if (input >= 0 && uint64_t(input) < (NumericLimits::Maximum() / STANDARD_VECTOR_SIZE)) { - // if it does just multiply it and add the value - uint64_t value = uint64_t(input) * count; - AddValue(state.value, value, 1); - } else { - // if it doesn't fit we have two choices - // either we loop over count and add the values individually - // or we convert to a hugeint and multiply the hugeint - // the problem is that hugeint multiplication is expensive - // hence we switch here: with a low count we do the loop - // with a high count we do the hugeint multiplication - if (count < 8) { - for (idx_t i = 0; i < count; i++) { - AddValue(state.value, uint64_t(input), input >= 0); - } - } else { - hugeint_t addition = hugeint_t(input) * Hugeint::Convert(count); - state.value += addition; - } - } - } -}; - -template -struct BaseSumOperation { - template - static void Initialize(STATE &state) { - state.value = 0; - STATEOP::template Initialize(state); - } - - template - static void Combine(const STATE &source, STATE &target, AggregateInputData &aggr_input_data) { - STATEOP::template Combine(source, target, aggr_input_data); - } - - template - static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &) { - STATEOP::template AddValues(state, 1); - ADDOP::template AddNumber(state, input); - } - - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &, idx_t count) { - STATEOP::template AddValues(state, count); - ADDOP::template AddConstant(state, input, count); - } - - static bool IgnoreNull() { - return true; - } -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/array_kernels.hpp b/src/duckdb/src/include/duckdb/core_functions/array_kernels.hpp deleted file mode 100644 index dd6e29153..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/array_kernels.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once -#include "duckdb/common/typedefs.hpp" -#include "duckdb/common/algorithm.hpp" -#include - -namespace duckdb { - -//------------------------------------------------------------------------- -// Folding Operations -//------------------------------------------------------------------------- -struct InnerProductOp { - static constexpr bool ALLOW_EMPTY = true; - - template - static TYPE Operation(const TYPE *lhs_data, const TYPE *rhs_data, const idx_t count) { - - TYPE result = 0; - - auto lhs_ptr = lhs_data; - auto rhs_ptr = rhs_data; - - for (idx_t i = 0; i < count; i++) { - const auto x = *lhs_ptr++; - const auto y = *rhs_ptr++; - result += x * y; - } - - return result; - } -}; - -struct NegativeInnerProductOp { - static constexpr bool ALLOW_EMPTY = true; - - template - static TYPE Operation(const TYPE *lhs_data, const TYPE *rhs_data, const idx_t count) { - return -InnerProductOp::Operation(lhs_data, rhs_data, count); - } -}; - -struct CosineSimilarityOp { - static constexpr bool ALLOW_EMPTY = false; - - template - static TYPE Operation(const TYPE *lhs_data, const TYPE *rhs_data, const idx_t count) { - - TYPE distance = 0; - TYPE norm_l = 0; - TYPE norm_r = 0; - - auto l_ptr = lhs_data; - auto r_ptr = rhs_data; - - for (idx_t i = 0; i < count; i++) { - const auto x = *l_ptr++; - const auto y = *r_ptr++; - distance += x * y; - norm_l += x * x; - norm_r += y * y; - } - - auto similarity = distance / std::sqrt(norm_l * norm_r); - return std::max(static_cast(-1.0), std::min(similarity, static_cast(1.0))); - } -}; - -struct CosineDistanceOp { - static constexpr bool ALLOW_EMPTY = false; - - template - static TYPE Operation(const TYPE *lhs_data, const TYPE *rhs_data, const idx_t count) { - return static_cast(1.0) - CosineSimilarityOp::Operation(lhs_data, rhs_data, count); - } -}; - -struct DistanceSquaredOp { - static constexpr bool ALLOW_EMPTY = true; - - template - static TYPE Operation(const TYPE *lhs_data, const TYPE *rhs_data, const idx_t count) { - - TYPE distance = 0; - - auto l_ptr = lhs_data; - auto r_ptr = rhs_data; - - for (idx_t i = 0; i < count; i++) { - const auto x = *l_ptr++; - const auto y = *r_ptr++; - const auto diff = x - y; - distance += diff * diff; - } - - return distance; - } -}; - -struct DistanceOp { - static constexpr bool ALLOW_EMPTY = true; - - template - static TYPE Operation(const TYPE *lhs_data, const TYPE *rhs_data, const idx_t count) { - return std::sqrt(DistanceSquaredOp::Operation(lhs_data, rhs_data, count)); - } -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/scalar/array_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/array_functions.hpp deleted file mode 100644 index 865d77bf6..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/scalar/array_functions.hpp +++ /dev/null @@ -1,93 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/scalar/array_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct ArrayValueFun { - static constexpr const char *Name = "array_value"; - static constexpr const char *Parameters = "any,..."; - static constexpr const char *Description = "Create an ARRAY containing the argument values."; - static constexpr const char *Example = "array_value(4, 5, 6)"; - - static ScalarFunction GetFunction(); -}; - -struct ArrayCrossProductFun { - static constexpr const char *Name = "array_cross_product"; - static constexpr const char *Parameters = "array, array"; - static constexpr const char *Description = "Compute the cross product of two arrays of size 3. The array elements can not be NULL."; - static constexpr const char *Example = "array_cross_product([1, 2, 3], [1, 2, 3])"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ArrayCosineSimilarityFun { - static constexpr const char *Name = "array_cosine_similarity"; - static constexpr const char *Parameters = "array1,array2"; - static constexpr const char *Description = "Compute the cosine similarity between two arrays of the same size. The array elements can not be NULL. The arrays can have any size as long as the size is the same for both arguments."; - static constexpr const char *Example = "array_cosine_similarity([1, 2, 3], [1, 2, 3])"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ArrayCosineDistanceFun { - static constexpr const char *Name = "array_cosine_distance"; - static constexpr const char *Parameters = "array1,array2"; - static constexpr const char *Description = "Compute the cosine distance between two arrays of the same size. The array elements can not be NULL. The arrays can have any size as long as the size is the same for both arguments."; - static constexpr const char *Example = "array_cosine_distance([1, 2, 3], [1, 2, 3])"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ArrayDistanceFun { - static constexpr const char *Name = "array_distance"; - static constexpr const char *Parameters = "array1,array2"; - static constexpr const char *Description = "Compute the distance between two arrays of the same size. The array elements can not be NULL. The arrays can have any size as long as the size is the same for both arguments."; - static constexpr const char *Example = "array_distance([1, 2, 3], [1, 2, 3])"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ArrayInnerProductFun { - static constexpr const char *Name = "array_inner_product"; - static constexpr const char *Parameters = "array1,array2"; - static constexpr const char *Description = "Compute the inner product between two arrays of the same size. The array elements can not be NULL. The arrays can have any size as long as the size is the same for both arguments."; - static constexpr const char *Example = "array_inner_product([1, 2, 3], [1, 2, 3])"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ArrayDotProductFun { - using ALIAS = ArrayInnerProductFun; - - static constexpr const char *Name = "array_dot_product"; -}; - -struct ArrayNegativeInnerProductFun { - static constexpr const char *Name = "array_negative_inner_product"; - static constexpr const char *Parameters = "array1,array2"; - static constexpr const char *Description = "Compute the negative inner product between two arrays of the same size. The array elements can not be NULL. The arrays can have any size as long as the size is the same for both arguments."; - static constexpr const char *Example = "array_negative_inner_product([1, 2, 3], [1, 2, 3])"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ArrayNegativeDotProductFun { - using ALIAS = ArrayNegativeInnerProductFun; - - static constexpr const char *Name = "array_negative_dot_product"; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/scalar/bit_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/bit_functions.hpp deleted file mode 100644 index f66427b6d..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/scalar/bit_functions.hpp +++ /dev/null @@ -1,54 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/scalar/bit_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct GetBitFun { - static constexpr const char *Name = "get_bit"; - static constexpr const char *Parameters = "bitstring,index"; - static constexpr const char *Description = "Extracts the nth bit from bitstring; the first (leftmost) bit is indexed 0"; - static constexpr const char *Example = "get_bit('0110010'::BIT, 2)"; - - static ScalarFunction GetFunction(); -}; - -struct SetBitFun { - static constexpr const char *Name = "set_bit"; - static constexpr const char *Parameters = "bitstring,index,new_value"; - static constexpr const char *Description = "Sets the nth bit in bitstring to newvalue; the first (leftmost) bit is indexed 0. Returns a new bitstring"; - static constexpr const char *Example = "set_bit('0110010'::BIT, 2, 0)"; - - static ScalarFunction GetFunction(); -}; - -struct BitPositionFun { - static constexpr const char *Name = "bit_position"; - static constexpr const char *Parameters = "substring,bitstring"; - static constexpr const char *Description = "Returns first starting index of the specified substring within bits, or zero if it is not present. The first (leftmost) bit is indexed 1"; - static constexpr const char *Example = "bit_position('010'::BIT, '1110101'::BIT)"; - - static ScalarFunction GetFunction(); -}; - -struct BitStringFun { - static constexpr const char *Name = "bitstring"; - static constexpr const char *Parameters = "bitstring,length"; - static constexpr const char *Description = "Pads the bitstring until the specified length"; - static constexpr const char *Example = "bitstring('1010'::BIT, 7)"; - - static ScalarFunctionSet GetFunctions(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/scalar/blob_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/blob_functions.hpp deleted file mode 100644 index 29c4034f4..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/scalar/blob_functions.hpp +++ /dev/null @@ -1,69 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/scalar/blob_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct DecodeFun { - static constexpr const char *Name = "decode"; - static constexpr const char *Parameters = "blob"; - static constexpr const char *Description = "Convert blob to varchar. Fails if blob is not valid utf-8"; - static constexpr const char *Example = "decode('\\xC3\\xBC'::BLOB)"; - - static ScalarFunction GetFunction(); -}; - -struct EncodeFun { - static constexpr const char *Name = "encode"; - static constexpr const char *Parameters = "string"; - static constexpr const char *Description = "Convert varchar to blob. Converts utf-8 characters into literal encoding"; - static constexpr const char *Example = "encode('my_string_with_ü')"; - - static ScalarFunction GetFunction(); -}; - -struct FromBase64Fun { - static constexpr const char *Name = "from_base64"; - static constexpr const char *Parameters = "string"; - static constexpr const char *Description = "Convert a base64 encoded string to a character string"; - static constexpr const char *Example = "from_base64('QQ==')"; - - static ScalarFunction GetFunction(); -}; - -struct ToBase64Fun { - static constexpr const char *Name = "to_base64"; - static constexpr const char *Parameters = "blob"; - static constexpr const char *Description = "Convert a blob to a base64 encoded string"; - static constexpr const char *Example = "base64('A'::blob)"; - - static ScalarFunction GetFunction(); -}; - -struct Base64Fun { - using ALIAS = ToBase64Fun; - - static constexpr const char *Name = "base64"; -}; - -struct CreateSortKeyFun { - static constexpr const char *Name = "create_sort_key"; - static constexpr const char *Parameters = "parameters..."; - static constexpr const char *Description = "Constructs a binary-comparable sort key based on a set of input parameters and sort qualifiers"; - static constexpr const char *Example = "create_sort_key('A', 'DESC')"; - - static ScalarFunction GetFunction(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/scalar/date_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/date_functions.hpp deleted file mode 100644 index 1d0723009..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/scalar/date_functions.hpp +++ /dev/null @@ -1,636 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/scalar/date_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct AgeFun { - static constexpr const char *Name = "age"; - static constexpr const char *Parameters = "timestamp,timestamp"; - static constexpr const char *Description = "Subtract arguments, resulting in the time difference between the two timestamps"; - static constexpr const char *Example = "age(TIMESTAMP '2001-04-10', TIMESTAMP '1992-09-20')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct CenturyFun { - static constexpr const char *Name = "century"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the century component from a date or timestamp"; - static constexpr const char *Example = "century(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct CurrentDateFun { - static constexpr const char *Name = "current_date"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = "Returns the current date"; - static constexpr const char *Example = "current_date()"; - - static ScalarFunction GetFunction(); -}; - -struct TodayFun { - using ALIAS = CurrentDateFun; - - static constexpr const char *Name = "today"; -}; - -struct DateDiffFun { - static constexpr const char *Name = "date_diff"; - static constexpr const char *Parameters = "part,startdate,enddate"; - static constexpr const char *Description = "The number of partition boundaries between the timestamps"; - static constexpr const char *Example = "date_diff('hour', TIMESTAMPTZ '1992-09-30 23:59:59', TIMESTAMPTZ '1992-10-01 01:58:00')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct DatediffFun { - using ALIAS = DateDiffFun; - - static constexpr const char *Name = "datediff"; -}; - -struct DatePartFun { - static constexpr const char *Name = "date_part"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Get subfield (equivalent to extract)"; - static constexpr const char *Example = "date_part('minute', TIMESTAMP '1992-09-20 20:38:40')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct DatepartFun { - using ALIAS = DatePartFun; - - static constexpr const char *Name = "datepart"; -}; - -struct DateSubFun { - static constexpr const char *Name = "date_sub"; - static constexpr const char *Parameters = "part,startdate,enddate"; - static constexpr const char *Description = "The number of complete partitions between the timestamps"; - static constexpr const char *Example = "date_sub('hour', TIMESTAMPTZ '1992-09-30 23:59:59', TIMESTAMPTZ '1992-10-01 01:58:00')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct DatesubFun { - using ALIAS = DateSubFun; - - static constexpr const char *Name = "datesub"; -}; - -struct DateTruncFun { - static constexpr const char *Name = "date_trunc"; - static constexpr const char *Parameters = "part,timestamp"; - static constexpr const char *Description = "Truncate to specified precision"; - static constexpr const char *Example = "date_trunc('hour', TIMESTAMPTZ '1992-09-20 20:38:40')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct DatetruncFun { - using ALIAS = DateTruncFun; - - static constexpr const char *Name = "datetrunc"; -}; - -struct DayFun { - static constexpr const char *Name = "day"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the day component from a date or timestamp"; - static constexpr const char *Example = "day(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct DayNameFun { - static constexpr const char *Name = "dayname"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "The (English) name of the weekday"; - static constexpr const char *Example = "dayname(TIMESTAMP '1992-03-22')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct DayOfMonthFun { - static constexpr const char *Name = "dayofmonth"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the dayofmonth component from a date or timestamp"; - static constexpr const char *Example = "dayofmonth(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct DayOfWeekFun { - static constexpr const char *Name = "dayofweek"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the dayofweek component from a date or timestamp"; - static constexpr const char *Example = "dayofweek(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct DayOfYearFun { - static constexpr const char *Name = "dayofyear"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the dayofyear component from a date or timestamp"; - static constexpr const char *Example = "dayofyear(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct DecadeFun { - static constexpr const char *Name = "decade"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the decade component from a date or timestamp"; - static constexpr const char *Example = "decade(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct EpochFun { - static constexpr const char *Name = "epoch"; - static constexpr const char *Parameters = "temporal"; - static constexpr const char *Description = "Extract the epoch component from a temporal type"; - static constexpr const char *Example = "epoch(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct EpochMsFun { - static constexpr const char *Name = "epoch_ms"; - static constexpr const char *Parameters = "temporal"; - static constexpr const char *Description = "Extract the epoch component in milliseconds from a temporal type"; - static constexpr const char *Example = "epoch_ms(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct EpochUsFun { - static constexpr const char *Name = "epoch_us"; - static constexpr const char *Parameters = "temporal"; - static constexpr const char *Description = "Extract the epoch component in microseconds from a temporal type"; - static constexpr const char *Example = "epoch_us(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct EpochNsFun { - static constexpr const char *Name = "epoch_ns"; - static constexpr const char *Parameters = "temporal"; - static constexpr const char *Description = "Extract the epoch component in nanoseconds from a temporal type"; - static constexpr const char *Example = "epoch_ns(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct EraFun { - static constexpr const char *Name = "era"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the era component from a date or timestamp"; - static constexpr const char *Example = "era(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct CurrentTimeFun { - static constexpr const char *Name = "get_current_time"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = "Returns the current time"; - static constexpr const char *Example = "get_current_time()"; - - static ScalarFunction GetFunction(); -}; - -struct GetCurrentTimestampFun { - static constexpr const char *Name = "get_current_timestamp"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = "Returns the current timestamp"; - static constexpr const char *Example = "get_current_timestamp()"; - - static ScalarFunction GetFunction(); -}; - -struct NowFun { - using ALIAS = GetCurrentTimestampFun; - - static constexpr const char *Name = "now"; -}; - -struct TransactionTimestampFun { - using ALIAS = GetCurrentTimestampFun; - - static constexpr const char *Name = "transaction_timestamp"; -}; - -struct HoursFun { - static constexpr const char *Name = "hour"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the hour component from a date or timestamp"; - static constexpr const char *Example = "hour(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ISODayOfWeekFun { - static constexpr const char *Name = "isodow"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the isodow component from a date or timestamp"; - static constexpr const char *Example = "isodow(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ISOYearFun { - static constexpr const char *Name = "isoyear"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the isoyear component from a date or timestamp"; - static constexpr const char *Example = "isoyear(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct JulianDayFun { - static constexpr const char *Name = "julian"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the Julian Day number from a date or timestamp"; - static constexpr const char *Example = "julian(timestamp '2006-01-01 12:00')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct LastDayFun { - static constexpr const char *Name = "last_day"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Returns the last day of the month"; - static constexpr const char *Example = "last_day(TIMESTAMP '1992-03-22 01:02:03.1234')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct MakeDateFun { - static constexpr const char *Name = "make_date"; - static constexpr const char *Parameters = "year,month,day"; - static constexpr const char *Description = "The date for the given parts"; - static constexpr const char *Example = "make_date(1992, 9, 20)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct MakeTimeFun { - static constexpr const char *Name = "make_time"; - static constexpr const char *Parameters = "hour,minute,seconds"; - static constexpr const char *Description = "The time for the given parts"; - static constexpr const char *Example = "make_time(13, 34, 27.123456)"; - - static ScalarFunction GetFunction(); -}; - -struct MakeTimestampFun { - static constexpr const char *Name = "make_timestamp"; - static constexpr const char *Parameters = "year,month,day,hour,minute,seconds"; - static constexpr const char *Description = "The timestamp for the given parts"; - static constexpr const char *Example = "make_timestamp(1992, 9, 20, 13, 34, 27.123456)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct MicrosecondsFun { - static constexpr const char *Name = "microsecond"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the microsecond component from a date or timestamp"; - static constexpr const char *Example = "microsecond(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct MillenniumFun { - static constexpr const char *Name = "millennium"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the millennium component from a date or timestamp"; - static constexpr const char *Example = "millennium(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct MillisecondsFun { - static constexpr const char *Name = "millisecond"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the millisecond component from a date or timestamp"; - static constexpr const char *Example = "millisecond(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct MinutesFun { - static constexpr const char *Name = "minute"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the minute component from a date or timestamp"; - static constexpr const char *Example = "minute(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct MonthFun { - static constexpr const char *Name = "month"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the month component from a date or timestamp"; - static constexpr const char *Example = "month(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct MonthNameFun { - static constexpr const char *Name = "monthname"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "The (English) name of the month"; - static constexpr const char *Example = "monthname(TIMESTAMP '1992-09-20')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct NanosecondsFun { - static constexpr const char *Name = "nanosecond"; - static constexpr const char *Parameters = "tsns"; - static constexpr const char *Description = "Extract the nanosecond component from a date or timestamp"; - static constexpr const char *Example = "nanosecond(timestamp_ns '2021-08-03 11:59:44.123456789') => 44123456789"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct QuarterFun { - static constexpr const char *Name = "quarter"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the quarter component from a date or timestamp"; - static constexpr const char *Example = "quarter(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct SecondsFun { - static constexpr const char *Name = "second"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the second component from a date or timestamp"; - static constexpr const char *Example = "second(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct StrfTimeFun { - static constexpr const char *Name = "strftime"; - static constexpr const char *Parameters = "text,format"; - static constexpr const char *Description = "Converts timestamp to string according to the format string"; - static constexpr const char *Example = "strftime(timestamp '1992-01-01 20:38:40', '%a, %-d %B %Y - %I:%M:%S %p')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct StrpTimeFun { - static constexpr const char *Name = "strptime"; - static constexpr const char *Parameters = "text,format"; - static constexpr const char *Description = "Converts string to timestamp with time zone according to the format string if %Z is specified"; - static constexpr const char *Example = "strptime('Wed, 1 January 1992 - 08:38:40 PST', '%a, %-d %B %Y - %H:%M:%S %Z')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct TimeBucketFun { - static constexpr const char *Name = "time_bucket"; - static constexpr const char *Parameters = "bucket_width,timestamp,origin"; - static constexpr const char *Description = "Truncate TIMESTAMPTZ by the specified interval bucket_width. Buckets are aligned relative to origin TIMESTAMPTZ. The origin defaults to 2000-01-03 00:00:00+00 for buckets that do not include a month or year interval, and to 2000-01-01 00:00:00+00 for month and year buckets"; - static constexpr const char *Example = "time_bucket(INTERVAL '2 weeks', TIMESTAMP '1992-04-20 15:26:00-07', TIMESTAMP '1992-04-01 00:00:00-07')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct TimezoneFun { - static constexpr const char *Name = "timezone"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the timezone component from a date or timestamp"; - static constexpr const char *Example = "timezone(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct TimezoneHourFun { - static constexpr const char *Name = "timezone_hour"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the timezone_hour component from a date or timestamp"; - static constexpr const char *Example = "timezone_hour(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct TimezoneMinuteFun { - static constexpr const char *Name = "timezone_minute"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the timezone_minute component from a date or timestamp"; - static constexpr const char *Example = "timezone_minute(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct TimeTZSortKeyFun { - static constexpr const char *Name = "timetz_byte_comparable"; - static constexpr const char *Parameters = "time_tz"; - static constexpr const char *Description = "Converts a TIME WITH TIME ZONE to an integer sort key"; - static constexpr const char *Example = "timetz_byte_comparable('18:18:16.21-07:00'::TIME_TZ)"; - - static ScalarFunction GetFunction(); -}; - -struct ToCenturiesFun { - static constexpr const char *Name = "to_centuries"; - static constexpr const char *Parameters = "integer"; - static constexpr const char *Description = "Construct a century interval"; - static constexpr const char *Example = "to_centuries(5)"; - - static ScalarFunction GetFunction(); -}; - -struct ToDaysFun { - static constexpr const char *Name = "to_days"; - static constexpr const char *Parameters = "integer"; - static constexpr const char *Description = "Construct a day interval"; - static constexpr const char *Example = "to_days(5)"; - - static ScalarFunction GetFunction(); -}; - -struct ToDecadesFun { - static constexpr const char *Name = "to_decades"; - static constexpr const char *Parameters = "integer"; - static constexpr const char *Description = "Construct a decade interval"; - static constexpr const char *Example = "to_decades(5)"; - - static ScalarFunction GetFunction(); -}; - -struct ToHoursFun { - static constexpr const char *Name = "to_hours"; - static constexpr const char *Parameters = "integer"; - static constexpr const char *Description = "Construct a hour interval"; - static constexpr const char *Example = "to_hours(5)"; - - static ScalarFunction GetFunction(); -}; - -struct ToMicrosecondsFun { - static constexpr const char *Name = "to_microseconds"; - static constexpr const char *Parameters = "integer"; - static constexpr const char *Description = "Construct a microsecond interval"; - static constexpr const char *Example = "to_microseconds(5)"; - - static ScalarFunction GetFunction(); -}; - -struct ToMillenniaFun { - static constexpr const char *Name = "to_millennia"; - static constexpr const char *Parameters = "integer"; - static constexpr const char *Description = "Construct a millenium interval"; - static constexpr const char *Example = "to_millennia(1)"; - - static ScalarFunction GetFunction(); -}; - -struct ToMillisecondsFun { - static constexpr const char *Name = "to_milliseconds"; - static constexpr const char *Parameters = "double"; - static constexpr const char *Description = "Construct a millisecond interval"; - static constexpr const char *Example = "to_milliseconds(5.5)"; - - static ScalarFunction GetFunction(); -}; - -struct ToMinutesFun { - static constexpr const char *Name = "to_minutes"; - static constexpr const char *Parameters = "integer"; - static constexpr const char *Description = "Construct a minute interval"; - static constexpr const char *Example = "to_minutes(5)"; - - static ScalarFunction GetFunction(); -}; - -struct ToMonthsFun { - static constexpr const char *Name = "to_months"; - static constexpr const char *Parameters = "integer"; - static constexpr const char *Description = "Construct a month interval"; - static constexpr const char *Example = "to_months(5)"; - - static ScalarFunction GetFunction(); -}; - -struct ToQuartersFun { - static constexpr const char *Name = "to_quarters"; - static constexpr const char *Parameters = "integer"; - static constexpr const char *Description = "Construct a quarter interval"; - static constexpr const char *Example = "to_quarters(5)"; - - static ScalarFunction GetFunction(); -}; - -struct ToSecondsFun { - static constexpr const char *Name = "to_seconds"; - static constexpr const char *Parameters = "double"; - static constexpr const char *Description = "Construct a second interval"; - static constexpr const char *Example = "to_seconds(5.5)"; - - static ScalarFunction GetFunction(); -}; - -struct ToTimestampFun { - static constexpr const char *Name = "to_timestamp"; - static constexpr const char *Parameters = "sec"; - static constexpr const char *Description = "Converts secs since epoch to a timestamp with time zone"; - static constexpr const char *Example = "to_timestamp(1284352323.5)"; - - static ScalarFunction GetFunction(); -}; - -struct ToWeeksFun { - static constexpr const char *Name = "to_weeks"; - static constexpr const char *Parameters = "integer"; - static constexpr const char *Description = "Construct a week interval"; - static constexpr const char *Example = "to_weeks(5)"; - - static ScalarFunction GetFunction(); -}; - -struct ToYearsFun { - static constexpr const char *Name = "to_years"; - static constexpr const char *Parameters = "integer"; - static constexpr const char *Description = "Construct a year interval"; - static constexpr const char *Example = "to_years(5)"; - - static ScalarFunction GetFunction(); -}; - -struct TryStrpTimeFun { - static constexpr const char *Name = "try_strptime"; - static constexpr const char *Parameters = "text,format"; - static constexpr const char *Description = "Converts string to timestamp using the format string (timestamp with time zone if %Z is specified). Returns NULL on failure"; - static constexpr const char *Example = "try_strptime('Wed, 1 January 1992 - 08:38:40 PM', '%a, %-d %B %Y - %I:%M:%S %p')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct WeekFun { - static constexpr const char *Name = "week"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the week component from a date or timestamp"; - static constexpr const char *Example = "week(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct WeekDayFun { - static constexpr const char *Name = "weekday"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the weekday component from a date or timestamp"; - static constexpr const char *Example = "weekday(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct WeekOfYearFun { - static constexpr const char *Name = "weekofyear"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the weekofyear component from a date or timestamp"; - static constexpr const char *Example = "weekofyear(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct YearFun { - static constexpr const char *Name = "year"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the year component from a date or timestamp"; - static constexpr const char *Example = "year(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct YearWeekFun { - static constexpr const char *Name = "yearweek"; - static constexpr const char *Parameters = "ts"; - static constexpr const char *Description = "Extract the yearweek component from a date or timestamp"; - static constexpr const char *Example = "yearweek(timestamp '2021-08-03 11:59:44.123456')"; - - static ScalarFunctionSet GetFunctions(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/scalar/enum_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/enum_functions.hpp deleted file mode 100644 index 66c7d6814..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/scalar/enum_functions.hpp +++ /dev/null @@ -1,63 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/scalar/enum_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct EnumFirstFun { - static constexpr const char *Name = "enum_first"; - static constexpr const char *Parameters = "enum"; - static constexpr const char *Description = "Returns the first value of the input enum type"; - static constexpr const char *Example = "enum_first(NULL::mood)"; - - static ScalarFunction GetFunction(); -}; - -struct EnumLastFun { - static constexpr const char *Name = "enum_last"; - static constexpr const char *Parameters = "enum"; - static constexpr const char *Description = "Returns the last value of the input enum type"; - static constexpr const char *Example = "enum_last(NULL::mood)"; - - static ScalarFunction GetFunction(); -}; - -struct EnumCodeFun { - static constexpr const char *Name = "enum_code"; - static constexpr const char *Parameters = "enum"; - static constexpr const char *Description = "Returns the numeric value backing the given enum value"; - static constexpr const char *Example = "enum_code('happy'::mood)"; - - static ScalarFunction GetFunction(); -}; - -struct EnumRangeFun { - static constexpr const char *Name = "enum_range"; - static constexpr const char *Parameters = "enum"; - static constexpr const char *Description = "Returns all values of the input enum type as an array"; - static constexpr const char *Example = "enum_range(NULL::mood)"; - - static ScalarFunction GetFunction(); -}; - -struct EnumRangeBoundaryFun { - static constexpr const char *Name = "enum_range_boundary"; - static constexpr const char *Parameters = "start,end"; - static constexpr const char *Description = "Returns the range between the two given enum values as an array. The values must be of the same enum type. When the first parameter is NULL, the result starts with the first value of the enum type. When the second parameter is NULL, the result ends with the last value of the enum type"; - static constexpr const char *Example = "enum_range_boundary(NULL, 'happy'::mood)"; - - static ScalarFunction GetFunction(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/scalar/generic_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/generic_functions.hpp deleted file mode 100644 index c7c72387e..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/scalar/generic_functions.hpp +++ /dev/null @@ -1,180 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/scalar/generic_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct AliasFun { - static constexpr const char *Name = "alias"; - static constexpr const char *Parameters = "expr"; - static constexpr const char *Description = "Returns the name of a given expression"; - static constexpr const char *Example = "alias(42 + 1)"; - - static ScalarFunction GetFunction(); -}; - -struct CurrentSettingFun { - static constexpr const char *Name = "current_setting"; - static constexpr const char *Parameters = "setting_name"; - static constexpr const char *Description = "Returns the current value of the configuration setting"; - static constexpr const char *Example = "current_setting('access_mode')"; - - static ScalarFunction GetFunction(); -}; - -struct ErrorFun { - static constexpr const char *Name = "error"; - static constexpr const char *Parameters = "message"; - static constexpr const char *Description = "Throws the given error message"; - static constexpr const char *Example = "error('access_mode')"; - - static ScalarFunction GetFunction(); -}; - -struct HashFun { - static constexpr const char *Name = "hash"; - static constexpr const char *Parameters = "param"; - static constexpr const char *Description = "Returns an integer with the hash of the value. Note that this is not a cryptographic hash"; - static constexpr const char *Example = "hash('🦆')"; - - static ScalarFunction GetFunction(); -}; - -struct LeastFun { - static constexpr const char *Name = "least"; - static constexpr const char *Parameters = "arg1, arg2, ..."; - static constexpr const char *Description = "Returns the lowest value of the set of input parameters"; - static constexpr const char *Example = "least(42, 84)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct GreatestFun { - static constexpr const char *Name = "greatest"; - static constexpr const char *Parameters = "arg1, arg2, ..."; - static constexpr const char *Description = "Returns the highest value of the set of input parameters"; - static constexpr const char *Example = "greatest(42, 84)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct StatsFun { - static constexpr const char *Name = "stats"; - static constexpr const char *Parameters = "expression"; - static constexpr const char *Description = "Returns a string with statistics about the expression. Expression can be a column, constant, or SQL expression"; - static constexpr const char *Example = "stats(5)"; - - static ScalarFunction GetFunction(); -}; - -struct TypeOfFun { - static constexpr const char *Name = "typeof"; - static constexpr const char *Parameters = "expression"; - static constexpr const char *Description = "Returns the name of the data type of the result of the expression"; - static constexpr const char *Example = "typeof('abc')"; - - static ScalarFunction GetFunction(); -}; - -struct CanCastImplicitlyFun { - static constexpr const char *Name = "can_cast_implicitly"; - static constexpr const char *Parameters = "source_type,target_type"; - static constexpr const char *Description = "Whether or not we can implicitly cast from the source type to the other type"; - static constexpr const char *Example = "can_implicitly_cast(NULL::INTEGER, NULL::BIGINT)"; - - static ScalarFunction GetFunction(); -}; - -struct CurrentQueryFun { - static constexpr const char *Name = "current_query"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = "Returns the current query as a string"; - static constexpr const char *Example = "current_query()"; - - static ScalarFunction GetFunction(); -}; - -struct CurrentSchemaFun { - static constexpr const char *Name = "current_schema"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = "Returns the name of the currently active schema. Default is main"; - static constexpr const char *Example = "current_schema()"; - - static ScalarFunction GetFunction(); -}; - -struct CurrentSchemasFun { - static constexpr const char *Name = "current_schemas"; - static constexpr const char *Parameters = "include_implicit"; - static constexpr const char *Description = "Returns list of schemas. Pass a parameter of True to include implicit schemas"; - static constexpr const char *Example = "current_schemas(true)"; - - static ScalarFunction GetFunction(); -}; - -struct CurrentDatabaseFun { - static constexpr const char *Name = "current_database"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = "Returns the name of the currently active database"; - static constexpr const char *Example = "current_database()"; - - static ScalarFunction GetFunction(); -}; - -struct InSearchPathFun { - static constexpr const char *Name = "in_search_path"; - static constexpr const char *Parameters = "database_name,schema_name"; - static constexpr const char *Description = "Returns whether or not the database/schema are in the search path"; - static constexpr const char *Example = "in_search_path('memory', 'main')"; - - static ScalarFunction GetFunction(); -}; - -struct CurrentTransactionIdFun { - static constexpr const char *Name = "txid_current"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = "Returns the current transaction’s ID (a BIGINT). It will assign a new one if the current transaction does not have one already"; - static constexpr const char *Example = "txid_current()"; - - static ScalarFunction GetFunction(); -}; - -struct VersionFun { - static constexpr const char *Name = "version"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = "Returns the currently active version of DuckDB in this format: v0.3.2 "; - static constexpr const char *Example = "version()"; - - static ScalarFunction GetFunction(); -}; - -struct EquiWidthBinsFun { - static constexpr const char *Name = "equi_width_bins"; - static constexpr const char *Parameters = "min,max,bin_count,nice_rounding"; - static constexpr const char *Description = "Generates bin_count equi-width bins between the min and max. If enabled nice_rounding makes the numbers more readable/less jagged"; - static constexpr const char *Example = "equi_width_bins(0, 10, 2, true)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct IsHistogramOtherBinFun { - static constexpr const char *Name = "is_histogram_other_bin"; - static constexpr const char *Parameters = "val"; - static constexpr const char *Description = "Whether or not the provided value is the histogram \"other\" bin (used for values not belonging to any provided bin)"; - static constexpr const char *Example = "is_histogram_other_bin(v)"; - - static ScalarFunction GetFunction(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/scalar/list_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/list_functions.hpp deleted file mode 100644 index a5fbfdfe0..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/scalar/list_functions.hpp +++ /dev/null @@ -1,390 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/scalar/list_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct ListFlattenFun { - static constexpr const char *Name = "flatten"; - static constexpr const char *Parameters = "nested_list"; - static constexpr const char *Description = "Flatten a nested list by one level"; - static constexpr const char *Example = "flatten([[1, 2, 3], [4, 5]])"; - - static ScalarFunction GetFunction(); -}; - -struct ListAggregateFun { - static constexpr const char *Name = "list_aggregate"; - static constexpr const char *Parameters = "list,name"; - static constexpr const char *Description = "Executes the aggregate function name on the elements of list"; - static constexpr const char *Example = "list_aggregate([1, 2, NULL], 'min')"; - - static ScalarFunction GetFunction(); -}; - -struct ArrayAggregateFun { - using ALIAS = ListAggregateFun; - - static constexpr const char *Name = "array_aggregate"; -}; - -struct ListAggrFun { - using ALIAS = ListAggregateFun; - - static constexpr const char *Name = "list_aggr"; -}; - -struct ArrayAggrFun { - using ALIAS = ListAggregateFun; - - static constexpr const char *Name = "array_aggr"; -}; - -struct AggregateFun { - using ALIAS = ListAggregateFun; - - static constexpr const char *Name = "aggregate"; -}; - -struct ListDistinctFun { - static constexpr const char *Name = "list_distinct"; - static constexpr const char *Parameters = "list"; - static constexpr const char *Description = "Removes all duplicates and NULLs from a list. Does not preserve the original order"; - static constexpr const char *Example = "list_distinct([1, 1, NULL, -3, 1, 5])"; - - static ScalarFunction GetFunction(); -}; - -struct ArrayDistinctFun { - using ALIAS = ListDistinctFun; - - static constexpr const char *Name = "array_distinct"; -}; - -struct ListUniqueFun { - static constexpr const char *Name = "list_unique"; - static constexpr const char *Parameters = "list"; - static constexpr const char *Description = "Counts the unique elements of a list"; - static constexpr const char *Example = "list_unique([1, 1, NULL, -3, 1, 5])"; - - static ScalarFunction GetFunction(); -}; - -struct ArrayUniqueFun { - using ALIAS = ListUniqueFun; - - static constexpr const char *Name = "array_unique"; -}; - -struct ListValueFun { - static constexpr const char *Name = "list_value"; - static constexpr const char *Parameters = "any,..."; - static constexpr const char *Description = "Create a LIST containing the argument values"; - static constexpr const char *Example = "list_value(4, 5, 6)"; - - static ScalarFunction GetFunction(); -}; - -struct ListPackFun { - using ALIAS = ListValueFun; - - static constexpr const char *Name = "list_pack"; -}; - -struct ListSliceFun { - static constexpr const char *Name = "list_slice"; - static constexpr const char *Parameters = "list,begin,end[,step]"; - static constexpr const char *Description = "Extract a sublist using slice conventions. Negative values are accepted"; - static constexpr const char *Example = "list_slice(l, 2, 4)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ArraySliceFun { - using ALIAS = ListSliceFun; - - static constexpr const char *Name = "array_slice"; -}; - -struct ListSortFun { - static constexpr const char *Name = "list_sort"; - static constexpr const char *Parameters = "list"; - static constexpr const char *Description = "Sorts the elements of the list"; - static constexpr const char *Example = "list_sort([3, 6, 1, 2])"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ArraySortFun { - using ALIAS = ListSortFun; - - static constexpr const char *Name = "array_sort"; -}; - -struct ListGradeUpFun { - static constexpr const char *Name = "list_grade_up"; - static constexpr const char *Parameters = "list"; - static constexpr const char *Description = "Returns the index of their sorted position."; - static constexpr const char *Example = "list_grade_up([3, 6, 1, 2])"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ArrayGradeUpFun { - using ALIAS = ListGradeUpFun; - - static constexpr const char *Name = "array_grade_up"; -}; - -struct GradeUpFun { - using ALIAS = ListGradeUpFun; - - static constexpr const char *Name = "grade_up"; -}; - -struct ListReverseSortFun { - static constexpr const char *Name = "list_reverse_sort"; - static constexpr const char *Parameters = "list"; - static constexpr const char *Description = "Sorts the elements of the list in reverse order"; - static constexpr const char *Example = "list_reverse_sort([3, 6, 1, 2])"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ArrayReverseSortFun { - using ALIAS = ListReverseSortFun; - - static constexpr const char *Name = "array_reverse_sort"; -}; - -struct ListTransformFun { - static constexpr const char *Name = "list_transform"; - static constexpr const char *Parameters = "list,lambda"; - static constexpr const char *Description = "Returns a list that is the result of applying the lambda function to each element of the input list. See the Lambda Functions section for more details"; - static constexpr const char *Example = "list_transform([1, 2, 3], x -> x + 1)"; - - static ScalarFunction GetFunction(); -}; - -struct ArrayTransformFun { - using ALIAS = ListTransformFun; - - static constexpr const char *Name = "array_transform"; -}; - -struct ListApplyFun { - using ALIAS = ListTransformFun; - - static constexpr const char *Name = "list_apply"; -}; - -struct ArrayApplyFun { - using ALIAS = ListTransformFun; - - static constexpr const char *Name = "array_apply"; -}; - -struct ApplyFun { - using ALIAS = ListTransformFun; - - static constexpr const char *Name = "apply"; -}; - -struct ListFilterFun { - static constexpr const char *Name = "list_filter"; - static constexpr const char *Parameters = "list,lambda"; - static constexpr const char *Description = "Constructs a list from those elements of the input list for which the lambda function returns true"; - static constexpr const char *Example = "list_filter([3, 4, 5], x -> x > 4)"; - - static ScalarFunction GetFunction(); -}; - -struct ArrayFilterFun { - using ALIAS = ListFilterFun; - - static constexpr const char *Name = "array_filter"; -}; - -struct FilterFun { - using ALIAS = ListFilterFun; - - static constexpr const char *Name = "filter"; -}; - -struct ListReduceFun { - static constexpr const char *Name = "list_reduce"; - static constexpr const char *Parameters = "list,lambda"; - static constexpr const char *Description = "Returns a single value that is the result of applying the lambda function to each element of the input list, starting with the first element and then repeatedly applying the lambda function to the result of the previous application and the next element of the list."; - static constexpr const char *Example = "list_reduce([1, 2, 3], (x, y) -> x + y)"; - - static ScalarFunction GetFunction(); -}; - -struct ArrayReduceFun { - using ALIAS = ListReduceFun; - - static constexpr const char *Name = "array_reduce"; -}; - -struct ReduceFun { - using ALIAS = ListReduceFun; - - static constexpr const char *Name = "reduce"; -}; - -struct GenerateSeriesFun { - static constexpr const char *Name = "generate_series"; - static constexpr const char *Parameters = "start,stop,step"; - static constexpr const char *Description = "Create a list of values between start and stop - the stop parameter is inclusive"; - static constexpr const char *Example = "generate_series(2, 5, 3)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ListRangeFun { - static constexpr const char *Name = "range"; - static constexpr const char *Parameters = "start,stop,step"; - static constexpr const char *Description = "Create a list of values between start and stop - the stop parameter is exclusive"; - static constexpr const char *Example = "range(2, 5, 3)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ListCosineDistanceFun { - static constexpr const char *Name = "list_cosine_distance"; - static constexpr const char *Parameters = "list1,list2"; - static constexpr const char *Description = "Compute the cosine distance between two lists"; - static constexpr const char *Example = "list_cosine_distance([1, 2, 3], [1, 2, 3])"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ListCosineDistanceFunAlias { - using ALIAS = ListCosineDistanceFun; - - static constexpr const char *Name = "<=>"; -}; - -struct ListCosineSimilarityFun { - static constexpr const char *Name = "list_cosine_similarity"; - static constexpr const char *Parameters = "list1,list2"; - static constexpr const char *Description = "Compute the cosine similarity between two lists"; - static constexpr const char *Example = "list_cosine_similarity([1, 2, 3], [1, 2, 3])"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ListDistanceFun { - static constexpr const char *Name = "list_distance"; - static constexpr const char *Parameters = "list1,list2"; - static constexpr const char *Description = "Compute the distance between two lists"; - static constexpr const char *Example = "list_distance([1, 2, 3], [1, 2, 3])"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ListDistanceFunAlias { - using ALIAS = ListDistanceFun; - - static constexpr const char *Name = "<->"; -}; - -struct ListInnerProductFun { - static constexpr const char *Name = "list_inner_product"; - static constexpr const char *Parameters = "list1,list2"; - static constexpr const char *Description = "Compute the inner product between two lists"; - static constexpr const char *Example = "list_inner_product([1, 2, 3], [1, 2, 3])"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ListDotProductFun { - using ALIAS = ListInnerProductFun; - - static constexpr const char *Name = "list_dot_product"; -}; - -struct ListNegativeInnerProductFun { - static constexpr const char *Name = "list_negative_inner_product"; - static constexpr const char *Parameters = "list1,list2"; - static constexpr const char *Description = "Compute the negative inner product between two lists"; - static constexpr const char *Example = "list_negative_inner_product([1, 2, 3], [1, 2, 3])"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ListNegativeDotProductFun { - using ALIAS = ListNegativeInnerProductFun; - - static constexpr const char *Name = "list_negative_dot_product"; -}; - -struct UnpivotListFun { - static constexpr const char *Name = "unpivot_list"; - static constexpr const char *Parameters = "any,..."; - static constexpr const char *Description = "Identical to list_value, but generated as part of unpivot for better error messages"; - static constexpr const char *Example = "unpivot_list(4, 5, 6)"; - - static ScalarFunction GetFunction(); -}; - -struct ListHasAnyFun { - static constexpr const char *Name = "list_has_any"; - static constexpr const char *Parameters = "l1, l2"; - static constexpr const char *Description = "Returns true if the lists have any element in common. NULLs are ignored."; - static constexpr const char *Example = "list_has_any([1, 2, 3], [2, 3, 4])"; - - static ScalarFunction GetFunction(); -}; - -struct ArrayHasAnyFun { - using ALIAS = ListHasAnyFun; - - static constexpr const char *Name = "array_has_any"; -}; - -struct ListHasAnyFunAlias { - using ALIAS = ListHasAnyFun; - - static constexpr const char *Name = "&&"; -}; - -struct ListHasAllFun { - static constexpr const char *Name = "list_has_all"; - static constexpr const char *Parameters = "l1, l2"; - static constexpr const char *Description = "Returns true if all elements of l2 are in l1. NULLs are ignored."; - static constexpr const char *Example = "list_has_all([1, 2, 3], [2, 3])"; - - static ScalarFunction GetFunction(); -}; - -struct ArrayHasAllFun { - using ALIAS = ListHasAllFun; - - static constexpr const char *Name = "array_has_all"; -}; - -struct ListHasAllFunAlias { - using ALIAS = ListHasAllFun; - - static constexpr const char *Name = "@>"; -}; - -struct ListHasAllFunAlias2 { - using ALIAS = ListHasAllFun; - - static constexpr const char *Name = "<@"; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/scalar/map_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/map_functions.hpp deleted file mode 100644 index eb9aae54e..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/scalar/map_functions.hpp +++ /dev/null @@ -1,105 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/scalar/map_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct CardinalityFun { - static constexpr const char *Name = "cardinality"; - static constexpr const char *Parameters = "map"; - static constexpr const char *Description = "Returns the size of the map (or the number of entries in the map)"; - static constexpr const char *Example = "cardinality( map([4, 2], ['a', 'b']) );"; - - static ScalarFunction GetFunction(); -}; - -struct MapFun { - static constexpr const char *Name = "map"; - static constexpr const char *Parameters = "keys,values"; - static constexpr const char *Description = "Creates a map from a set of keys and values"; - static constexpr const char *Example = "map(['key1', 'key2'], ['val1', 'val2'])"; - - static ScalarFunction GetFunction(); -}; - -struct MapEntriesFun { - static constexpr const char *Name = "map_entries"; - static constexpr const char *Parameters = "map"; - static constexpr const char *Description = "Returns the map entries as a list of keys/values"; - static constexpr const char *Example = "map_entries(map(['key'], ['val']))"; - - static ScalarFunction GetFunction(); -}; - -struct MapExtractFun { - static constexpr const char *Name = "map_extract"; - static constexpr const char *Parameters = "map,key"; - static constexpr const char *Description = "Returns a list containing the value for a given key or an empty list if the key is not contained in the map. The type of the key provided in the second parameter must match the type of the map’s keys else an error is returned"; - static constexpr const char *Example = "map_extract(map(['key'], ['val']), 'key')"; - - static ScalarFunction GetFunction(); -}; - -struct ElementAtFun { - using ALIAS = MapExtractFun; - - static constexpr const char *Name = "element_at"; -}; - -struct MapFromEntriesFun { - static constexpr const char *Name = "map_from_entries"; - static constexpr const char *Parameters = "map"; - static constexpr const char *Description = "Returns a map created from the entries of the array"; - static constexpr const char *Example = "map_from_entries([{k: 5, v: 'val1'}, {k: 3, v: 'val2'}]);"; - - static ScalarFunction GetFunction(); -}; - -struct MapConcatFun { - static constexpr const char *Name = "map_concat"; - static constexpr const char *Parameters = "any,..."; - static constexpr const char *Description = "Returns a map created from merging the input maps, on key collision the value is taken from the last map with that key"; - static constexpr const char *Example = "map_concat(map([1,2], ['a', 'b']), map([2,3], ['c', 'd']));"; - - static ScalarFunction GetFunction(); -}; - -struct MapKeysFun { - static constexpr const char *Name = "map_keys"; - static constexpr const char *Parameters = "map"; - static constexpr const char *Description = "Returns the keys of a map as a list"; - static constexpr const char *Example = "map_keys(map(['key'], ['val']))"; - - static ScalarFunction GetFunction(); -}; - -struct MapValuesFun { - static constexpr const char *Name = "map_values"; - static constexpr const char *Parameters = "map"; - static constexpr const char *Description = "Returns the values of a map as a list"; - static constexpr const char *Example = "map_values(map(['key'], ['val']))"; - - static ScalarFunction GetFunction(); -}; - -struct MapContainsFun { - static constexpr const char *Name = "map_contains"; - static constexpr const char *Parameters = "map,key"; - static constexpr const char *Description = "Returns true if the map contains the key, false otherwise"; - static constexpr const char *Example = "map_contains(map(['key'], ['val']), 'key')"; - - static ScalarFunction GetFunction(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/scalar/math_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/math_functions.hpp deleted file mode 100644 index cb1125a10..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/scalar/math_functions.hpp +++ /dev/null @@ -1,453 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/scalar/math_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct AbsOperatorFun { - static constexpr const char *Name = "@"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Absolute value"; - static constexpr const char *Example = "abs(-17.4)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct AbsFun { - using ALIAS = AbsOperatorFun; - - static constexpr const char *Name = "abs"; -}; - -struct PowOperatorFun { - static constexpr const char *Name = "**"; - static constexpr const char *Parameters = "x,y"; - static constexpr const char *Description = "Computes x to the power of y"; - static constexpr const char *Example = "pow(2, 3)"; - - static ScalarFunction GetFunction(); -}; - -struct PowFun { - using ALIAS = PowOperatorFun; - - static constexpr const char *Name = "pow"; -}; - -struct PowerFun { - using ALIAS = PowOperatorFun; - - static constexpr const char *Name = "power"; -}; - -struct PowOperatorFunAlias { - using ALIAS = PowOperatorFun; - - static constexpr const char *Name = "^"; -}; - -struct FactorialOperatorFun { - static constexpr const char *Name = "!__postfix"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Factorial of x. Computes the product of the current integer and all integers below it"; - static constexpr const char *Example = "4!"; - - static ScalarFunction GetFunction(); -}; - -struct FactorialFun { - using ALIAS = FactorialOperatorFun; - - static constexpr const char *Name = "factorial"; -}; - -struct AcosFun { - static constexpr const char *Name = "acos"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the arccosine of x"; - static constexpr const char *Example = "acos(0.5)"; - - static ScalarFunction GetFunction(); -}; - -struct AsinFun { - static constexpr const char *Name = "asin"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the arcsine of x"; - static constexpr const char *Example = "asin(0.5)"; - - static ScalarFunction GetFunction(); -}; - -struct AtanFun { - static constexpr const char *Name = "atan"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the arctangent of x"; - static constexpr const char *Example = "atan(0.5)"; - - static ScalarFunction GetFunction(); -}; - -struct Atan2Fun { - static constexpr const char *Name = "atan2"; - static constexpr const char *Parameters = "y,x"; - static constexpr const char *Description = "Computes the arctangent (y, x)"; - static constexpr const char *Example = "atan2(1.0, 0.0)"; - - static ScalarFunction GetFunction(); -}; - -struct BitCountFun { - static constexpr const char *Name = "bit_count"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns the number of bits that are set"; - static constexpr const char *Example = "bit_count(31)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct CbrtFun { - static constexpr const char *Name = "cbrt"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns the cube root of x"; - static constexpr const char *Example = "cbrt(8)"; - - static ScalarFunction GetFunction(); -}; - -struct CeilFun { - static constexpr const char *Name = "ceil"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Rounds the number up"; - static constexpr const char *Example = "ceil(17.4)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct CeilingFun { - using ALIAS = CeilFun; - - static constexpr const char *Name = "ceiling"; -}; - -struct CosFun { - static constexpr const char *Name = "cos"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the cos of x"; - static constexpr const char *Example = "cos(90)"; - - static ScalarFunction GetFunction(); -}; - -struct CotFun { - static constexpr const char *Name = "cot"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the cotangent of x"; - static constexpr const char *Example = "cot(0.5)"; - - static ScalarFunction GetFunction(); -}; - -struct DegreesFun { - static constexpr const char *Name = "degrees"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Converts radians to degrees"; - static constexpr const char *Example = "degrees(pi())"; - - static ScalarFunction GetFunction(); -}; - -struct EvenFun { - static constexpr const char *Name = "even"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Rounds x to next even number by rounding away from zero"; - static constexpr const char *Example = "even(2.9)"; - - static ScalarFunction GetFunction(); -}; - -struct ExpFun { - static constexpr const char *Name = "exp"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes e to the power of x"; - static constexpr const char *Example = "exp(1)"; - - static ScalarFunction GetFunction(); -}; - -struct FloorFun { - static constexpr const char *Name = "floor"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Rounds the number down"; - static constexpr const char *Example = "floor(17.4)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct IsFiniteFun { - static constexpr const char *Name = "isfinite"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns true if the floating point value is finite, false otherwise"; - static constexpr const char *Example = "isfinite(5.5)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct IsInfiniteFun { - static constexpr const char *Name = "isinf"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns true if the floating point value is infinite, false otherwise"; - static constexpr const char *Example = "isinf('Infinity'::float)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct IsNanFun { - static constexpr const char *Name = "isnan"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns true if the floating point value is not a number, false otherwise"; - static constexpr const char *Example = "isnan('NaN'::FLOAT)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct GammaFun { - static constexpr const char *Name = "gamma"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Interpolation of (x-1) factorial (so decimal inputs are allowed)"; - static constexpr const char *Example = "gamma(5.5)"; - - static ScalarFunction GetFunction(); -}; - -struct GreatestCommonDivisorFun { - static constexpr const char *Name = "greatest_common_divisor"; - static constexpr const char *Parameters = "x,y"; - static constexpr const char *Description = "Computes the greatest common divisor of x and y"; - static constexpr const char *Example = "greatest_common_divisor(42, 57)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct GcdFun { - using ALIAS = GreatestCommonDivisorFun; - - static constexpr const char *Name = "gcd"; -}; - -struct LeastCommonMultipleFun { - static constexpr const char *Name = "least_common_multiple"; - static constexpr const char *Parameters = "x,y"; - static constexpr const char *Description = "Computes the least common multiple of x and y"; - static constexpr const char *Example = "least_common_multiple(42, 57)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct LcmFun { - using ALIAS = LeastCommonMultipleFun; - - static constexpr const char *Name = "lcm"; -}; - -struct LogGammaFun { - static constexpr const char *Name = "lgamma"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the log of the gamma function"; - static constexpr const char *Example = "lgamma(2)"; - - static ScalarFunction GetFunction(); -}; - -struct LnFun { - static constexpr const char *Name = "ln"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the natural logarithm of x"; - static constexpr const char *Example = "ln(2)"; - - static ScalarFunction GetFunction(); -}; - -struct Log2Fun { - static constexpr const char *Name = "log2"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the 2-log of x"; - static constexpr const char *Example = "log2(8)"; - - static ScalarFunction GetFunction(); -}; - -struct Log10Fun { - static constexpr const char *Name = "log10"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the 10-log of x"; - static constexpr const char *Example = "log10(1000)"; - - static ScalarFunction GetFunction(); -}; - -struct LogFun { - static constexpr const char *Name = "log"; - static constexpr const char *Parameters = "b, x"; - static constexpr const char *Description = "Computes the logarithm of x to base b. b may be omitted, in which case the default 10"; - static constexpr const char *Example = "log(2, 64)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct NextAfterFun { - static constexpr const char *Name = "nextafter"; - static constexpr const char *Parameters = "x, y"; - static constexpr const char *Description = "Returns the next floating point value after x in the direction of y"; - static constexpr const char *Example = "nextafter(1::float, 2::float)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct PiFun { - static constexpr const char *Name = "pi"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = "Returns the value of pi"; - static constexpr const char *Example = "pi()"; - - static ScalarFunction GetFunction(); -}; - -struct RadiansFun { - static constexpr const char *Name = "radians"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Converts degrees to radians"; - static constexpr const char *Example = "radians(90)"; - - static ScalarFunction GetFunction(); -}; - -struct RoundFun { - static constexpr const char *Name = "round"; - static constexpr const char *Parameters = "x,precision"; - static constexpr const char *Description = "Rounds x to s decimal places"; - static constexpr const char *Example = "round(42.4332, 2)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct SignFun { - static constexpr const char *Name = "sign"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns the sign of x as -1, 0 or 1"; - static constexpr const char *Example = "sign(-349)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct SignBitFun { - static constexpr const char *Name = "signbit"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns whether the signbit is set or not"; - static constexpr const char *Example = "signbit(-0.0)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct SinFun { - static constexpr const char *Name = "sin"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the sin of x"; - static constexpr const char *Example = "sin(90)"; - - static ScalarFunction GetFunction(); -}; - -struct SqrtFun { - static constexpr const char *Name = "sqrt"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Returns the square root of x"; - static constexpr const char *Example = "sqrt(4)"; - - static ScalarFunction GetFunction(); -}; - -struct TanFun { - static constexpr const char *Name = "tan"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the tan of x"; - static constexpr const char *Example = "tan(90)"; - - static ScalarFunction GetFunction(); -}; - -struct TruncFun { - static constexpr const char *Name = "trunc"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Truncates the number"; - static constexpr const char *Example = "trunc(17.4)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct CoshFun { - static constexpr const char *Name = "cosh"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the hyperbolic cos of x"; - static constexpr const char *Example = "cosh(1)"; - - static ScalarFunction GetFunction(); -}; - -struct SinhFun { - static constexpr const char *Name = "sinh"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the hyperbolic sin of x"; - static constexpr const char *Example = "sinh(1)"; - - static ScalarFunction GetFunction(); -}; - -struct TanhFun { - static constexpr const char *Name = "tanh"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the hyperbolic tan of x"; - static constexpr const char *Example = "tanh(1)"; - - static ScalarFunction GetFunction(); -}; - -struct AcoshFun { - static constexpr const char *Name = "acosh"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the inverse hyperbolic cos of x"; - static constexpr const char *Example = "acosh(2.3)"; - - static ScalarFunction GetFunction(); -}; - -struct AsinhFun { - static constexpr const char *Name = "asinh"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the inverse hyperbolic sin of x"; - static constexpr const char *Example = "asinh(0.5)"; - - static ScalarFunction GetFunction(); -}; - -struct AtanhFun { - static constexpr const char *Name = "atanh"; - static constexpr const char *Parameters = "x"; - static constexpr const char *Description = "Computes the inverse hyperbolic tan of x"; - static constexpr const char *Example = "atanh(0.5)"; - - static ScalarFunction GetFunction(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/scalar/operators_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/operators_functions.hpp deleted file mode 100644 index 908ec939b..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/scalar/operators_functions.hpp +++ /dev/null @@ -1,72 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/scalar/operators_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct BitwiseAndFun { - static constexpr const char *Name = "&"; - static constexpr const char *Parameters = "left,right"; - static constexpr const char *Description = "Bitwise AND"; - static constexpr const char *Example = "91 & 15"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct BitwiseOrFun { - static constexpr const char *Name = "|"; - static constexpr const char *Parameters = "left,right"; - static constexpr const char *Description = "Bitwise OR"; - static constexpr const char *Example = "32 | 3"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct BitwiseNotFun { - static constexpr const char *Name = "~"; - static constexpr const char *Parameters = "input"; - static constexpr const char *Description = "Bitwise NOT"; - static constexpr const char *Example = "~15"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct LeftShiftFun { - static constexpr const char *Name = "<<"; - static constexpr const char *Parameters = "input"; - static constexpr const char *Description = "Bitwise shift left"; - static constexpr const char *Example = "1 << 4"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct RightShiftFun { - static constexpr const char *Name = ">>"; - static constexpr const char *Parameters = "input"; - static constexpr const char *Description = "Bitwise shift right"; - static constexpr const char *Example = "8 >> 2"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct BitwiseXorFun { - static constexpr const char *Name = "xor"; - static constexpr const char *Parameters = "left,right"; - static constexpr const char *Description = "Bitwise XOR"; - static constexpr const char *Example = "xor(17, 5)"; - - static ScalarFunctionSet GetFunctions(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/scalar/random_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/random_functions.hpp deleted file mode 100644 index 995c3df66..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/scalar/random_functions.hpp +++ /dev/null @@ -1,51 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/scalar/random_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct RandomFun { - static constexpr const char *Name = "random"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = "Returns a random number between 0 and 1"; - static constexpr const char *Example = "random()"; - - static ScalarFunction GetFunction(); -}; - -struct SetseedFun { - static constexpr const char *Name = "setseed"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = "Sets the seed to be used for the random function"; - static constexpr const char *Example = "setseed(0.42)"; - - static ScalarFunction GetFunction(); -}; - -struct UUIDFun { - static constexpr const char *Name = "uuid"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = "Returns a random UUID similar to this: eeccb8c5-9943-b2bb-bb5e-222f4e14b687"; - static constexpr const char *Example = "uuid()"; - - static ScalarFunction GetFunction(); -}; - -struct GenRandomUuidFun { - using ALIAS = UUIDFun; - - static constexpr const char *Name = "gen_random_uuid"; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/scalar/string_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/string_functions.hpp deleted file mode 100644 index 7f3181b0b..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/scalar/string_functions.hpp +++ /dev/null @@ -1,537 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/scalar/string_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct StartsWithOperatorFun { - static constexpr const char *Name = "^@"; - static constexpr const char *Parameters = "string,search_string"; - static constexpr const char *Description = "Returns true if string begins with search_string"; - static constexpr const char *Example = "starts_with('abc','a')"; - - static ScalarFunction GetFunction(); -}; - -struct StartsWithFun { - using ALIAS = StartsWithOperatorFun; - - static constexpr const char *Name = "starts_with"; -}; - -struct ASCIIFun { - static constexpr const char *Name = "ascii"; - static constexpr const char *Parameters = "string"; - static constexpr const char *Description = "Returns an integer that represents the Unicode code point of the first character of the string"; - static constexpr const char *Example = "ascii('Ω')"; - - static ScalarFunction GetFunction(); -}; - -struct BarFun { - static constexpr const char *Name = "bar"; - static constexpr const char *Parameters = "x,min,max,width"; - static constexpr const char *Description = "Draws a band whose width is proportional to (x - min) and equal to width characters when x = max. width defaults to 80"; - static constexpr const char *Example = "bar(5, 0, 20, 10)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct BinFun { - static constexpr const char *Name = "bin"; - static constexpr const char *Parameters = "value"; - static constexpr const char *Description = "Converts the value to binary representation"; - static constexpr const char *Example = "bin(42)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ToBinaryFun { - using ALIAS = BinFun; - - static constexpr const char *Name = "to_binary"; -}; - -struct ChrFun { - static constexpr const char *Name = "chr"; - static constexpr const char *Parameters = "code_point"; - static constexpr const char *Description = "Returns a character which is corresponding the ASCII code value or Unicode code point"; - static constexpr const char *Example = "chr(65)"; - - static ScalarFunction GetFunction(); -}; - -struct DamerauLevenshteinFun { - static constexpr const char *Name = "damerau_levenshtein"; - static constexpr const char *Parameters = "str1,str2"; - static constexpr const char *Description = "Extension of Levenshtein distance to also include transposition of adjacent characters as an allowed edit operation. In other words, the minimum number of edit operations (insertions, deletions, substitutions or transpositions) required to change one string to another. Different case is considered different"; - static constexpr const char *Example = "damerau_levenshtein('hello', 'world')"; - - static ScalarFunction GetFunction(); -}; - -struct FormatFun { - static constexpr const char *Name = "format"; - static constexpr const char *Parameters = "format,parameters..."; - static constexpr const char *Description = "Formats a string using fmt syntax"; - static constexpr const char *Example = "format('Benchmark \"{}\" took {} seconds', 'CSV', 42)"; - - static ScalarFunction GetFunction(); -}; - -struct FormatBytesFun { - static constexpr const char *Name = "format_bytes"; - static constexpr const char *Parameters = "bytes"; - static constexpr const char *Description = "Converts bytes to a human-readable presentation (e.g. 16000 -> 15.6 KiB)"; - static constexpr const char *Example = "format_bytes(1000 * 16)"; - - static ScalarFunction GetFunction(); -}; - -struct FormatreadablesizeFun { - using ALIAS = FormatBytesFun; - - static constexpr const char *Name = "formatReadableSize"; -}; - -struct FormatreadabledecimalsizeFun { - static constexpr const char *Name = "formatReadableDecimalSize"; - static constexpr const char *Parameters = "bytes"; - static constexpr const char *Description = "Converts bytes to a human-readable presentation (e.g. 16000 -> 16.0 KB)"; - static constexpr const char *Example = "format_bytes(1000 * 16)"; - - static ScalarFunction GetFunction(); -}; - -struct HammingFun { - static constexpr const char *Name = "hamming"; - static constexpr const char *Parameters = "str1,str2"; - static constexpr const char *Description = "The number of positions with different characters for 2 strings of equal length. Different case is considered different"; - static constexpr const char *Example = "hamming('duck','luck')"; - - static ScalarFunction GetFunction(); -}; - -struct MismatchesFun { - using ALIAS = HammingFun; - - static constexpr const char *Name = "mismatches"; -}; - -struct HexFun { - static constexpr const char *Name = "hex"; - static constexpr const char *Parameters = "value"; - static constexpr const char *Description = "Converts the value to hexadecimal representation"; - static constexpr const char *Example = "hex(42)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ToHexFun { - using ALIAS = HexFun; - - static constexpr const char *Name = "to_hex"; -}; - -struct InstrFun { - static constexpr const char *Name = "instr"; - static constexpr const char *Parameters = "haystack,needle"; - static constexpr const char *Description = "Returns location of first occurrence of needle in haystack, counting from 1. Returns 0 if no match found"; - static constexpr const char *Example = "instr('test test','es')"; - - static ScalarFunction GetFunction(); -}; - -struct StrposFun { - using ALIAS = InstrFun; - - static constexpr const char *Name = "strpos"; -}; - -struct PositionFun { - using ALIAS = InstrFun; - - static constexpr const char *Name = "position"; -}; - -struct JaccardFun { - static constexpr const char *Name = "jaccard"; - static constexpr const char *Parameters = "str1,str2"; - static constexpr const char *Description = "The Jaccard similarity between two strings. Different case is considered different. Returns a number between 0 and 1"; - static constexpr const char *Example = "jaccard('duck','luck')"; - - static ScalarFunction GetFunction(); -}; - -struct JaroSimilarityFun { - static constexpr const char *Name = "jaro_similarity"; - static constexpr const char *Parameters = "str1,str2"; - static constexpr const char *Description = "The Jaro similarity between two strings. Different case is considered different. Returns a number between 0 and 1"; - static constexpr const char *Example = "jaro_similarity('duck','duckdb')"; - - static ScalarFunction GetFunction(); -}; - -struct JaroWinklerSimilarityFun { - static constexpr const char *Name = "jaro_winkler_similarity"; - static constexpr const char *Parameters = "str1,str2"; - static constexpr const char *Description = "The Jaro-Winkler similarity between two strings. Different case is considered different. Returns a number between 0 and 1"; - static constexpr const char *Example = "jaro_winkler_similarity('duck','duckdb')"; - - static ScalarFunction GetFunction(); -}; - -struct LeftFun { - static constexpr const char *Name = "left"; - static constexpr const char *Parameters = "string,count"; - static constexpr const char *Description = "Extract the left-most count characters"; - static constexpr const char *Example = "left('Hello🦆', 2)"; - - static ScalarFunction GetFunction(); -}; - -struct LeftGraphemeFun { - static constexpr const char *Name = "left_grapheme"; - static constexpr const char *Parameters = "string,count"; - static constexpr const char *Description = "Extract the left-most count grapheme clusters"; - static constexpr const char *Example = "left_grapheme('🤦🏼‍♂️🤦🏽‍♀️', 1)"; - - static ScalarFunction GetFunction(); -}; - -struct LevenshteinFun { - static constexpr const char *Name = "levenshtein"; - static constexpr const char *Parameters = "str1,str2"; - static constexpr const char *Description = "The minimum number of single-character edits (insertions, deletions or substitutions) required to change one string to the other. Different case is considered different"; - static constexpr const char *Example = "levenshtein('duck','db')"; - - static ScalarFunction GetFunction(); -}; - -struct Editdist3Fun { - using ALIAS = LevenshteinFun; - - static constexpr const char *Name = "editdist3"; -}; - -struct LpadFun { - static constexpr const char *Name = "lpad"; - static constexpr const char *Parameters = "string,count,character"; - static constexpr const char *Description = "Pads the string with the character from the left until it has count characters"; - static constexpr const char *Example = "lpad('hello', 10, '>')"; - - static ScalarFunction GetFunction(); -}; - -struct LtrimFun { - static constexpr const char *Name = "ltrim"; - static constexpr const char *Parameters = "string,characters"; - static constexpr const char *Description = "Removes any occurrences of any of the characters from the left side of the string"; - static constexpr const char *Example = "ltrim('>>>>test<<', '><')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct MD5Fun { - static constexpr const char *Name = "md5"; - static constexpr const char *Parameters = "value"; - static constexpr const char *Description = "Returns the MD5 hash of the value as a string"; - static constexpr const char *Example = "md5('123')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct MD5NumberFun { - static constexpr const char *Name = "md5_number"; - static constexpr const char *Parameters = "value"; - static constexpr const char *Description = "Returns the MD5 hash of the value as an INT128"; - static constexpr const char *Example = "md5_number('123')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ParseDirnameFun { - static constexpr const char *Name = "parse_dirname"; - static constexpr const char *Parameters = "string,separator"; - static constexpr const char *Description = "Returns the top-level directory name. separator options: system, both_slash (default), forward_slash, backslash"; - static constexpr const char *Example = "parse_dirname('path/to/file.csv', 'system')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ParseDirpathFun { - static constexpr const char *Name = "parse_dirpath"; - static constexpr const char *Parameters = "string,separator"; - static constexpr const char *Description = "Returns the head of the path similarly to Python's os.path.dirname. separator options: system, both_slash (default), forward_slash, backslash"; - static constexpr const char *Example = "parse_dirpath('path/to/file.csv', 'system')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ParseFilenameFun { - static constexpr const char *Name = "parse_filename"; - static constexpr const char *Parameters = "string,trim_extension,separator"; - static constexpr const char *Description = "Returns the last component of the path similarly to Python's os.path.basename. If trim_extension is true, the file extension will be removed (it defaults to false). separator options: system, both_slash (default), forward_slash, backslash"; - static constexpr const char *Example = "parse_filename('path/to/file.csv', true, 'forward_slash')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ParsePathFun { - static constexpr const char *Name = "parse_path"; - static constexpr const char *Parameters = "string,separator"; - static constexpr const char *Description = "Returns a list of the components (directories and filename) in the path similarly to Python's pathlib.PurePath::parts. separator options: system, both_slash (default), forward_slash, backslash"; - static constexpr const char *Example = "parse_path('path/to/file.csv', 'system')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct PrintfFun { - static constexpr const char *Name = "printf"; - static constexpr const char *Parameters = "format,parameters..."; - static constexpr const char *Description = "Formats a string using printf syntax"; - static constexpr const char *Example = "printf('Benchmark \"%s\" took %d seconds', 'CSV', 42)"; - - static ScalarFunction GetFunction(); -}; - -struct RepeatFun { - static constexpr const char *Name = "repeat"; - static constexpr const char *Parameters = "string,count"; - static constexpr const char *Description = "Repeats the string count number of times"; - static constexpr const char *Example = "repeat('A', 5)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ReplaceFun { - static constexpr const char *Name = "replace"; - static constexpr const char *Parameters = "string,source,target"; - static constexpr const char *Description = "Replaces any occurrences of the source with target in string"; - static constexpr const char *Example = "replace('hello', 'l', '-')"; - - static ScalarFunction GetFunction(); -}; - -struct ReverseFun { - static constexpr const char *Name = "reverse"; - static constexpr const char *Parameters = "string"; - static constexpr const char *Description = "Reverses the string"; - static constexpr const char *Example = "reverse('hello')"; - - static ScalarFunction GetFunction(); -}; - -struct RightFun { - static constexpr const char *Name = "right"; - static constexpr const char *Parameters = "string,count"; - static constexpr const char *Description = "Extract the right-most count characters"; - static constexpr const char *Example = "right('Hello🦆', 3)"; - - static ScalarFunction GetFunction(); -}; - -struct RightGraphemeFun { - static constexpr const char *Name = "right_grapheme"; - static constexpr const char *Parameters = "string,count"; - static constexpr const char *Description = "Extract the right-most count grapheme clusters"; - static constexpr const char *Example = "right_grapheme('🤦🏼‍♂️🤦🏽‍♀️', 1)"; - - static ScalarFunction GetFunction(); -}; - -struct RpadFun { - static constexpr const char *Name = "rpad"; - static constexpr const char *Parameters = "string,count,character"; - static constexpr const char *Description = "Pads the string with the character from the right until it has count characters"; - static constexpr const char *Example = "rpad('hello', 10, '<')"; - - static ScalarFunction GetFunction(); -}; - -struct RtrimFun { - static constexpr const char *Name = "rtrim"; - static constexpr const char *Parameters = "string,characters"; - static constexpr const char *Description = "Removes any occurrences of any of the characters from the right side of the string"; - static constexpr const char *Example = "rtrim('>>>>test<<', '><')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct SHA1Fun { - static constexpr const char *Name = "sha1"; - static constexpr const char *Parameters = "value"; - static constexpr const char *Description = "Returns the SHA1 hash of the value"; - static constexpr const char *Example = "sha1('hello')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct SHA256Fun { - static constexpr const char *Name = "sha256"; - static constexpr const char *Parameters = "value"; - static constexpr const char *Description = "Returns the SHA256 hash of the value"; - static constexpr const char *Example = "sha256('hello')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct StringSplitFun { - static constexpr const char *Name = "string_split"; - static constexpr const char *Parameters = "string,separator"; - static constexpr const char *Description = "Splits the string along the separator"; - static constexpr const char *Example = "string_split('hello-world', '-')"; - - static ScalarFunction GetFunction(); -}; - -struct StrSplitFun { - using ALIAS = StringSplitFun; - - static constexpr const char *Name = "str_split"; -}; - -struct StringToArrayFun { - using ALIAS = StringSplitFun; - - static constexpr const char *Name = "string_to_array"; -}; - -struct SplitFun { - using ALIAS = StringSplitFun; - - static constexpr const char *Name = "split"; -}; - -struct StringSplitRegexFun { - static constexpr const char *Name = "string_split_regex"; - static constexpr const char *Parameters = "string,separator"; - static constexpr const char *Description = "Splits the string along the regex"; - static constexpr const char *Example = "string_split_regex('hello␣world; 42', ';?␣')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct StrSplitRegexFun { - using ALIAS = StringSplitRegexFun; - - static constexpr const char *Name = "str_split_regex"; -}; - -struct RegexpSplitToArrayFun { - using ALIAS = StringSplitRegexFun; - - static constexpr const char *Name = "regexp_split_to_array"; -}; - -struct TranslateFun { - static constexpr const char *Name = "translate"; - static constexpr const char *Parameters = "string,from,to"; - static constexpr const char *Description = "Replaces each character in string that matches a character in the from set with the corresponding character in the to set. If from is longer than to, occurrences of the extra characters in from are deleted"; - static constexpr const char *Example = "translate('12345', '143', 'ax')"; - - static ScalarFunction GetFunction(); -}; - -struct TrimFun { - static constexpr const char *Name = "trim"; - static constexpr const char *Parameters = "string,characters"; - static constexpr const char *Description = "Removes any occurrences of any of the characters from either side of the string"; - static constexpr const char *Example = "trim('>>>>test<<', '><')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct UnbinFun { - static constexpr const char *Name = "unbin"; - static constexpr const char *Parameters = "value"; - static constexpr const char *Description = "Converts a value from binary representation to a blob"; - static constexpr const char *Example = "unbin('0110')"; - - static ScalarFunction GetFunction(); -}; - -struct FromBinaryFun { - using ALIAS = UnbinFun; - - static constexpr const char *Name = "from_binary"; -}; - -struct UnhexFun { - static constexpr const char *Name = "unhex"; - static constexpr const char *Parameters = "value"; - static constexpr const char *Description = "Converts a value from hexadecimal representation to a blob"; - static constexpr const char *Example = "unhex('2A')"; - - static ScalarFunction GetFunction(); -}; - -struct FromHexFun { - using ALIAS = UnhexFun; - - static constexpr const char *Name = "from_hex"; -}; - -struct UnicodeFun { - static constexpr const char *Name = "unicode"; - static constexpr const char *Parameters = "str"; - static constexpr const char *Description = "Returns the unicode codepoint of the first character of the string"; - static constexpr const char *Example = "unicode('ü')"; - - static ScalarFunction GetFunction(); -}; - -struct OrdFun { - using ALIAS = UnicodeFun; - - static constexpr const char *Name = "ord"; -}; - -struct ToBaseFun { - static constexpr const char *Name = "to_base"; - static constexpr const char *Parameters = "number,radix,min_length"; - static constexpr const char *Description = "Converts a value to a string in the given base radix, optionally padding with leading zeros to the minimum length"; - static constexpr const char *Example = "to_base(42, 16)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct RegexpEscapeFun { - static constexpr const char *Name = "regexp_escape"; - static constexpr const char *Parameters = "string"; - static constexpr const char *Description = "Escapes all potentially meaningful regexp characters in the input string"; - static constexpr const char *Example = "regexp_escape('https://duckdb.org')"; - - static ScalarFunction GetFunction(); -}; - -struct UrlEncodeFun { - static constexpr const char *Name = "url_encode"; - static constexpr const char *Parameters = "input"; - static constexpr const char *Description = "Escapes the input string by encoding it so that it can be included in a URL query parameter."; - static constexpr const char *Example = "url_encode('this string has/ special+ characters>')"; - - static ScalarFunction GetFunction(); -}; - -struct UrlDecodeFun { - static constexpr const char *Name = "url_decode"; - static constexpr const char *Parameters = "input"; - static constexpr const char *Description = "Unescapes the URL encoded input."; - static constexpr const char *Example = "url_decode('this%20string%20is%2BFencoded')"; - - static ScalarFunction GetFunction(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/scalar/union_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/union_functions.hpp deleted file mode 100644 index 8b8694602..000000000 --- a/src/duckdb/src/include/duckdb/core_functions/scalar/union_functions.hpp +++ /dev/null @@ -1,45 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/core_functions/scalar/union_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct UnionExtractFun { - static constexpr const char *Name = "union_extract"; - static constexpr const char *Parameters = "union,tag"; - static constexpr const char *Description = "Extract the value with the named tags from the union. NULL if the tag is not currently selected"; - static constexpr const char *Example = "union_extract(s, 'k')"; - - static ScalarFunction GetFunction(); -}; - -struct UnionTagFun { - static constexpr const char *Name = "union_tag"; - static constexpr const char *Parameters = "union"; - static constexpr const char *Description = "Retrieve the currently selected tag of the union as an ENUM"; - static constexpr const char *Example = "union_tag(union_value(k := 'foo'))"; - - static ScalarFunction GetFunction(); -}; - -struct UnionValueFun { - static constexpr const char *Name = "union_value"; - static constexpr const char *Parameters = "tag"; - static constexpr const char *Description = "Create a single member UNION containing the argument value. The tag of the value will be the bound variable name"; - static constexpr const char *Example = "union_value(k := 'hello')"; - - static ScalarFunction GetFunction(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/aggregate_hashtable.hpp b/src/duckdb/src/include/duckdb/execution/aggregate_hashtable.hpp index 2b424152f..ac3c4a00a 100644 --- a/src/duckdb/src/include/duckdb/execution/aggregate_hashtable.hpp +++ b/src/duckdb/src/include/duckdb/execution/aggregate_hashtable.hpp @@ -57,6 +57,7 @@ class GroupedAggregateHashTable : public BaseAggregateHashTable { idx_t Capacity() const; //! Threshold at which to resize the HT idx_t ResizeThreshold() const; + static idx_t ResizeThreshold(idx_t capacity); //! Add the given data to the HT, computing the aggregates grouped by the //! data in the group chunk. When resize = true, aggregates will not be diff --git a/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_partitioned_aggregate.hpp b/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_partitioned_aggregate.hpp new file mode 100644 index 000000000..071a82ed1 --- /dev/null +++ b/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_partitioned_aggregate.hpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/execution/operator/aggregate/physical_partitioned_aggregate.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/execution/physical_operator.hpp" +#include "duckdb/planner/expression.hpp" +#include "duckdb/execution/operator/aggregate/grouped_aggregate_data.hpp" +#include "duckdb/parser/group_by_node.hpp" +#include "duckdb/execution/radix_partitioned_hashtable.hpp" +#include "duckdb/common/unordered_map.hpp" + +namespace duckdb { + +//! PhysicalPartitionedAggregate is an aggregate operator that can only perform aggregates on data that is partitioned +// by the grouping columns +class PhysicalPartitionedAggregate : public PhysicalOperator { +public: + static constexpr const PhysicalOperatorType TYPE = PhysicalOperatorType::PARTITIONED_AGGREGATE; + +public: + PhysicalPartitionedAggregate(ClientContext &context, vector types, + vector> expressions, vector> groups, + vector partitions, idx_t estimated_cardinality); + + //! The partitions over which this is grouped + vector partitions; + //! The groups over which the aggregate is partitioned - note that this is only + vector> groups; + //! The aggregates that have to be computed + vector> aggregates; + +public: + // Source interface + SourceResultType GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const override; + unique_ptr GetGlobalSourceState(ClientContext &context) const override; + + bool IsSource() const override { + return true; + } + +public: + // Sink interface + SinkResultType Sink(ExecutionContext &context, DataChunk &chunk, OperatorSinkInput &input) const override; + SinkCombineResultType Combine(ExecutionContext &context, OperatorSinkCombineInput &input) const override; + SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context, + OperatorSinkFinalizeInput &input) const override; + SinkNextBatchType NextBatch(ExecutionContext &context, OperatorSinkNextBatchInput &input) const override; + + unique_ptr GetLocalSinkState(ExecutionContext &context) const override; + unique_ptr GetGlobalSinkState(ClientContext &context) const override; + + InsertionOrderPreservingMap ParamsToString() const override; + + OperatorPartitionInfo RequiredPartitionInfo() const override; + bool IsSink() const override { + return true; + } + + bool ParallelSink() const override { + return true; + } +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_ungrouped_aggregate.hpp b/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_ungrouped_aggregate.hpp index 0f3937566..cd7d2a64a 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_ungrouped_aggregate.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_ungrouped_aggregate.hpp @@ -18,8 +18,7 @@ namespace duckdb { -//! PhysicalUngroupedAggregate is an aggregate operator that can only perform aggregates (1) without any groups, (2) -//! without any DISTINCT aggregates, and (3) when all aggregates are combineable +//! PhysicalUngroupedAggregate is an aggregate operator that can only perform aggregates without any groups class PhysicalUngroupedAggregate : public PhysicalOperator { public: static constexpr const PhysicalOperatorType TYPE = PhysicalOperatorType::UNGROUPED_AGGREGATE; diff --git a/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_window.hpp b/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_window.hpp index b1fb6e9ae..5b648f2f2 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_window.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_window.hpp @@ -37,8 +37,9 @@ class PhysicalWindow : public PhysicalOperator { GlobalSourceState &gstate) const override; unique_ptr GetGlobalSourceState(ClientContext &context) const override; SourceResultType GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const override; - idx_t GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate, - LocalSourceState &lstate) const override; + OperatorPartitionData GetPartitionData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate, + LocalSourceState &lstate, + const OperatorPartitionInfo &partition_info) const override; bool IsSource() const override { return true; @@ -47,7 +48,7 @@ class PhysicalWindow : public PhysicalOperator { return true; } - bool SupportsBatchIndex() const override; + bool SupportsPartitioning(const OperatorPartitionInfo &partition_info) const override; OrderPreservationType SourceOrder() const override; double GetProgress(ClientContext &context, GlobalSourceState &gstate_p) const override; diff --git a/src/duckdb/src/include/duckdb/execution/operator/aggregate/ungrouped_aggregate_state.hpp b/src/duckdb/src/include/duckdb/execution/operator/aggregate/ungrouped_aggregate_state.hpp index 0f18a169e..cf1b13c55 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/aggregate/ungrouped_aggregate_state.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/aggregate/ungrouped_aggregate_state.hpp @@ -11,6 +11,7 @@ #include "duckdb/execution/expression_executor.hpp" #include "duckdb/function/aggregate_function.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" +#include "duckdb/execution/operator/aggregate/aggregate_object.hpp" namespace duckdb { struct DistinctAggregateData; @@ -56,7 +57,7 @@ struct GlobalUngroupedAggregateState { ArenaAllocator &CreateAllocator() const; void Combine(LocalUngroupedAggregateState &other); void CombineDistinct(LocalUngroupedAggregateState &other, DistinctAggregateData &distinct_data); - void Finalize(DataChunk &result); + void Finalize(DataChunk &result, idx_t column_offset = 0); }; struct LocalUngroupedAggregateState { @@ -72,4 +73,23 @@ struct LocalUngroupedAggregateState { void Sink(DataChunk &payload_chunk, idx_t payload_idx, idx_t aggr_idx); }; +struct UngroupedAggregateExecuteState { +public: + UngroupedAggregateExecuteState(ClientContext &context, const vector> &aggregates, + const vector &child_types); + + //! The set of aggregates + const vector> &aggregates; + //! The executor + ExpressionExecutor child_executor; + //! The payload chunk, containing all the Vectors for the aggregates + DataChunk aggregate_input_chunk; + //! Aggregate filter data set + AggregateFilterDataSet filter_set; + +public: + void Sink(LocalUngroupedAggregateState &state, DataChunk &input); + void Reset(); +}; + } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/base_scanner.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/base_scanner.hpp index 8a10868d7..7436fa957 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/base_scanner.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/base_scanner.hpp @@ -114,6 +114,8 @@ class BaseScanner { bool ever_quoted = false; + bool ever_escaped = false; + //! Shared pointer to the buffer_manager, this is shared across multiple scanners shared_ptr buffer_manager; @@ -122,6 +124,10 @@ class BaseScanner { static CSVIterator SkipCSVRows(shared_ptr buffer_manager, const shared_ptr &state_machine, idx_t rows_to_skip); + inline static bool ContainsZeroByte(uint64_t v) { + return (v - UINT64_C(0x0101010101010101)) & ~(v)&UINT64_C(0x8080808080808080); + } + protected: //! Boundaries of this scanner CSVIterator iterator; @@ -142,10 +148,6 @@ class BaseScanner { //! Initializes the scanner virtual void Initialize(); - inline static bool ContainsZeroByte(uint64_t v) { - return (v - UINT64_C(0x0101010101010101)) & ~(v)&UINT64_C(0x8080808080808080); - } - //! Process one chunk template void Process(T &result) { @@ -254,6 +256,7 @@ class BaseScanner { } break; case CSVState::ESCAPE: T::SetEscaped(result); + ever_escaped = true; iterator.pos.buffer_pos++; break; case CSVState::STANDARD: { 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 7b86f238f..039c06abe 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,6 +72,9 @@ class CSVBuffer { char *Ptr() { return char_ptr_cast(handle.Ptr()); } + bool IsUnloaded() { + return block->IsUnloaded(); + } //! By default, we use CSV_BUFFER_SIZE to allocate each buffer //! TODO: Should benchmarks other values diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_buffer_manager.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_buffer_manager.hpp index 5bcf0af65..67d187d9e 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_buffer_manager.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_buffer_manager.hpp @@ -45,6 +45,8 @@ class CSVBufferManager { void ResetBufferManager(); string GetFilePath() const; + bool IsBlockUnloaded(idx_t block_idx); + ClientContext &context; idx_t skip_rows = 0; bool sniffing = false; diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_reader_options.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_reader_options.hpp index fe05ff653..88726cb9b 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_reader_options.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_reader_options.hpp @@ -98,7 +98,7 @@ struct CSVReaderOptions { idx_t sample_size_chunks = 20480 / sniff_size; //! Consider all columns to be of type varchar bool all_varchar = false; - //! Whether or not to automatically detect dialect and datatypes + //! Whether to automatically detect dialect and datatypes bool auto_detect = true; //! The file path of the CSV file to read string file_path; @@ -108,7 +108,7 @@ struct CSVReaderOptions { idx_t buffer_size = CSVBuffer::CSV_BUFFER_SIZE; //! Decimal separator when reading as numeric string decimal_separator = "."; - //! Whether or not to pad rows that do not have enough columns with NULL values + //! Whether to pad rows that do not have enough columns with NULL values bool null_padding = false; //! If we should attempt to run parallel scanning over one file bool parallel = true; @@ -128,7 +128,7 @@ struct CSVReaderOptions { //! The date format to use for writing (if any is specified) map write_date_format = {{LogicalTypeId::DATE, Value()}, {LogicalTypeId::TIMESTAMP, Value()}}; - //! Whether or not a type format is specified + //! Whether a type format is specified map has_format = {{LogicalTypeId::DATE, false}, {LogicalTypeId::TIMESTAMP, false}}; void Serialize(Serializer &serializer) const; diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state.hpp index ecb40e440..926c3a9e7 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state.hpp @@ -14,18 +14,19 @@ namespace duckdb { //! All States of CSV Parsing enum class CSVState : uint8_t { - STANDARD = 0, //! Regular unquoted field state - DELIMITER = 1, //! State after encountering a field separator (e.g., ;) - RECORD_SEPARATOR = 2, //! State after encountering a record separator (i.e., \n) - CARRIAGE_RETURN = 3, //! State after encountering a carriage return(i.e., \r) - QUOTED = 4, //! State when inside a quoted field - UNQUOTED = 5, //! State when leaving a quoted field - ESCAPE = 6, //! State when encountering an escape character (e.g., \) - INVALID = 7, //! Got to an Invalid State, this should error. - NOT_SET = 8, //! If the state is not set, usually the first state before getting the first character - QUOTED_NEW_LINE = 9, //! If we have a quoted newline - EMPTY_SPACE = 10, //! If we have empty spaces in the beginning and end of value - COMMENT = 11 //! If we are in a comment state, and hence have to skip the whole line + STANDARD = 0, //! Regular unquoted field state + DELIMITER = 1, //! State after encountering a field separator (e.g., ;) + RECORD_SEPARATOR = 2, //! State after encountering a record separator (i.e., \n) + CARRIAGE_RETURN = 3, //! State after encountering a carriage return(i.e., \r) + QUOTED = 4, //! State when inside a quoted field + UNQUOTED = 5, //! State when leaving a quoted field + ESCAPE = 6, //! State when encountering an escape character (e.g., \) + INVALID = 7, //! Got to an Invalid State, this should error. + NOT_SET = 8, //! If the state is not set, usually the first state before getting the first character + QUOTED_NEW_LINE = 9, //! If we have a quoted newline + EMPTY_SPACE = 10, //! If we have empty spaces in the beginning and end of value + COMMENT = 11, //! If we are in a comment state, and hence have to skip the whole line + STANDARD_NEWLINE = 12, //! State used for figuring out a new line. }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state_machine.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state_machine.hpp index 13933a180..1b83fbbea 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state_machine.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state_machine.hpp @@ -17,65 +17,72 @@ namespace duckdb { //! State of necessary CSV States to parse file //! Current, previous, and state before the previous struct CSVStates { - void Initialize() { - states[0] = CSVState::NOT_SET; - states[1] = CSVState::NOT_SET; + void Initialize(CSVState initial_state = CSVState::NOT_SET) { + states[0] = initial_state; + states[1] = initial_state; } - inline bool NewValue() { + inline bool NewValue() const { return states[1] == CSVState::DELIMITER; } - inline bool NewRow() { + inline bool NewRow() const { // It is a new row, if the previous state is not a record separator, and the current one is return states[0] != CSVState::RECORD_SEPARATOR && states[0] != CSVState::CARRIAGE_RETURN && (states[1] == CSVState::RECORD_SEPARATOR || states[1] == CSVState::CARRIAGE_RETURN); } - inline bool WasStandard() { + inline bool WasStandard() const { return states[0] == CSVState::STANDARD; } - inline bool EmptyLastValue() { + inline bool EmptyLastValue() const { // It is a new row, if the previous state is not a record separator, and the current one is - return states[0] == CSVState::DELIMITER && - (states[1] == CSVState::RECORD_SEPARATOR || states[1] == CSVState::CARRIAGE_RETURN || - states[1] == CSVState::DELIMITER); + return (states[0] == CSVState::DELIMITER && + (states[1] == CSVState::RECORD_SEPARATOR || states[1] == CSVState::CARRIAGE_RETURN || + states[1] == CSVState::DELIMITER)) || + (states[0] == CSVState::STANDARD && states[1] == CSVState::DELIMITER); } - inline bool EmptyLine() { + inline bool EmptyLine() const { return (states[1] == CSVState::CARRIAGE_RETURN || states[1] == CSVState::RECORD_SEPARATOR) && (states[0] == CSVState::RECORD_SEPARATOR || states[0] == CSVState::NOT_SET); } - inline bool IsNotSet() { + inline bool IsNotSet() const { return states[1] == CSVState::NOT_SET; } - inline bool IsComment() { + inline bool IsComment() const { return states[1] == CSVState::COMMENT; } - inline bool IsCurrentNewRow() { + inline bool IsCurrentNewRow() const { return states[1] == CSVState::RECORD_SEPARATOR || states[1] == CSVState::CARRIAGE_RETURN; } - inline bool IsCarriageReturn() { + inline bool IsCarriageReturn() const { return states[1] == CSVState::CARRIAGE_RETURN; } - inline bool IsInvalid() { + inline bool IsInvalid() const { return states[1] == CSVState::INVALID; } - inline bool IsQuoted() { + inline bool IsQuoted() const { return states[0] == CSVState::QUOTED; } - inline bool IsEscaped() { + inline bool IsEscaped() const { return states[1] == CSVState::ESCAPE || (states[0] == CSVState::UNQUOTED && states[1] == CSVState::QUOTED); } - inline bool IsQuotedCurrent() { + inline bool IsQuotedCurrent() const { return states[1] == CSVState::QUOTED || states[1] == CSVState::QUOTED_NEW_LINE; } + inline bool IsState(const CSVState state) const { + return states[1] == state; + } + inline bool WasState(const CSVState state) const { + return states[0] == state; + } CSVState states[2]; }; @@ -98,7 +105,7 @@ class CSVStateMachine { states.states[1] = transition_array[static_cast(current_char)][static_cast(states.states[1])]; } - void Print() { + void Print() const { std::cout << "State Machine Options" << '\n'; std::cout << "Delim: " << state_machine_options.delimiter.GetValue() << '\n'; std::cout << "Quote: " << state_machine_options.quote.GetValue() << '\n'; diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state_machine_cache.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state_machine_cache.hpp index decf46d46..4ad705282 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state_machine_cache.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state_machine_cache.hpp @@ -37,11 +37,11 @@ class StateMachine { uint64_t escape = 0; uint64_t comment = 0; - const CSVState *operator[](idx_t i) const { + const CSVState *operator[](const idx_t i) const { return state_machine[i]; } - CSVState *operator[](idx_t i) { + CSVState *operator[](const idx_t i) { return state_machine[i]; } }; @@ -60,7 +60,7 @@ struct HashCSVStateMachineConfig { //! The CSVStateMachineCache caches state machines, although small ~2kb, the actual creation of multiple State Machines //! can become a bottleneck on sniffing, when reading very small csv files. -//! Hence the cache stores State Machines based on their different delimiter|quote|escape options. +//! Hence, the cache stores State Machines based on their different delimiter|quote|escape options. class CSVStateMachineCache : public ObjectCacheEntry { public: CSVStateMachineCache(); @@ -85,7 +85,7 @@ class CSVStateMachineCache : public ObjectCacheEntry { void Insert(const CSVStateMachineOptions &state_machine_options); //! Cache on delimiter|quote|escape|newline unordered_map state_machine_cache; - //! Default value for options used to intialize CSV State Machine Cache + //! Default value for options used to initialize CSV State Machine Cache //! Because the state machine cache can be accessed in Parallel we need a mutex. mutex main_mutex; diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_validator.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_validator.hpp new file mode 100644 index 000000000..20d031707 --- /dev/null +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_validator.hpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/execution/operator/csv_scanner/csv_validator.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/map.hpp" +#include "duckdb/common/typedefs.hpp" +#include "duckdb/common/string.hpp" +#include "duckdb/common/vector.hpp" + +namespace duckdb { + +//! Information used to validate +struct ValidatorLine { + ValidatorLine(idx_t start_pos_p, idx_t end_pos_p) : start_pos(start_pos_p), end_pos(end_pos_p) { + } + const idx_t start_pos; + const idx_t end_pos; +}; + +struct ThreadLines { + ThreadLines() {}; + //! Validate everything is as it should be, returns true if it's all good, false o.w. + void Verify() const; + + void Insert(idx_t thread, ValidatorLine line_info); + + string Print() const; + +private: + map thread_lines; + //! We allow up to 2 bytes of error margin (basically \r\n) + static constexpr idx_t error_margin = 2; +}; + +//! The validator works by double-checking that threads started and ended in the right positions +struct CSVValidator { + CSVValidator() { + } + //! Validate that all files are good + void Verify() const; + + //! Inserts line_info to a given thread index of a given file. + void Insert(idx_t file_idx, idx_t thread, ValidatorLine line_info); + + string Print(idx_t file_idx) const; + +private: + //! Per file thread lines. + vector per_file_thread_lines; +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/global_csv_state.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/global_csv_state.hpp index de2448d52..4316d9e16 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/global_csv_state.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/global_csv_state.hpp @@ -15,6 +15,7 @@ #include "duckdb/function/table/read_csv.hpp" #include "duckdb/execution/operator/csv_scanner/csv_file_scanner.hpp" #include "duckdb/execution/operator/csv_scanner/string_value_scanner.hpp" +#include "duckdb/execution/operator/csv_scanner/csv_validator.hpp" namespace duckdb { @@ -78,6 +79,8 @@ struct CSVGlobalState : public GlobalTableFunctionState { unordered_map threads_per_file; //! We hold information on the current scanner boundary CSVIterator current_boundary; + + CSVValidator validator; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/scanner_boundary.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/scanner_boundary.hpp index 9e38f9bed..9f0d97820 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/scanner_boundary.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/scanner_boundary.hpp @@ -70,6 +70,10 @@ struct CSVIterator { void SetCurrentBoundaryToPosition(bool single_threaded); void SetStart(idx_t pos); + void SetEnd(idx_t pos); + + // Gets the current position for the file + idx_t GetGlobalCurrentPos(); //! 8 MB TODO: Should benchmarks other values static constexpr idx_t BYTES_PER_THREAD = 8000000; @@ -80,6 +84,8 @@ struct CSVIterator { bool first_one = true; + idx_t buffer_size; + private: //! The original setting CSVBoundary boundary; diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/string_value_scanner.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/string_value_scanner.hpp index e0047a66a..b27daf1b2 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/string_value_scanner.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/string_value_scanner.hpp @@ -12,7 +12,7 @@ #include "duckdb/execution/operator/csv_scanner/csv_state_machine.hpp" #include "duckdb/execution/operator/csv_scanner/scanner_boundary.hpp" #include "duckdb/execution/operator/csv_scanner/base_scanner.hpp" - +#include "duckdb/execution/operator/csv_scanner/csv_validator.hpp" namespace duckdb { struct CSVBufferUsage { @@ -132,6 +132,10 @@ class LineError { bool HandleErrors(StringValueResult &result); + bool HasError() const { + return !current_errors.empty(); + } + private: vector current_errors; bool is_error_in_line; @@ -267,6 +271,18 @@ class StringValueResult : public ScannerResult { void RemoveLastLine(); }; +struct ValidRowInfo { + ValidRowInfo(bool is_valid_p, idx_t start_pos_p, idx_t end_buffer_idx_p, idx_t end_pos_p, bool last_state_quote_p) + : is_valid(is_valid_p), start_pos(start_pos_p), end_buffer_idx(end_buffer_idx_p), end_pos(end_pos_p), + last_state_quote(last_state_quote_p) {}; + ValidRowInfo() : is_valid(false), start_pos(0), end_buffer_idx(0), end_pos(0) {}; + + bool is_valid; + idx_t start_pos; + idx_t end_buffer_idx; + idx_t end_pos; + bool last_state_quote = false; +}; //! Our dialect scanner basically goes over the CSV and actually parses the values to a DuckDB vector of string_t class StringValueScanner : public BaseScanner { public: @@ -297,6 +313,9 @@ class StringValueScanner : public BaseScanner { //! If we can directly cast the type when consuming the CSV file, or we have to do it later static bool CanDirectlyCast(const LogicalType &type, bool icu_loaded); + //! Gets validation line information + ValidatorLine GetValidationLine(); + const idx_t scanner_idx; //! Variable that manages buffer tracking @@ -308,20 +327,28 @@ class StringValueScanner : public BaseScanner { void FinalizeChunkProcess() override; //! Function used to process values that go over the first buffer, extra allocation might be necessary - void ProcessOverbufferValue(); + void ProcessOverBufferValue(); void ProcessExtraRow(); //! Function used to move from one buffer to the other, if necessary bool MoveToNextBuffer(); - void SkipUntilNewLine(); - + //! -------- Functions used to figure out where lines start ---------!// + //! Main function, sets the correct start void SetStart(); + //! From a given initial state, it skips until we reach the until_state + bool SkipUntilState(CSVState initial_state, CSVState until_state, CSVIterator ¤t_iterator, + bool "ed) const; + //! If the current row we found is valid + bool IsRowValid(CSVIterator ¤t_iterator) const; + ValidRowInfo TryRow(CSVState state, idx_t start_pos, idx_t end_pos) const; + bool FirstValueEndsOnQuote(CSVIterator iterator) const; StringValueResult result; vector types; - - //! Pointer to the previous buffer handle, necessary for overbuffer values + //! True Position where this scanner started scanning(i.e., after figuring out where the first line starts) + idx_t start_pos; + //! Pointer to the previous buffer handle, necessary for over-buffer values shared_ptr previous_buffer_handle; }; diff --git a/src/duckdb/src/include/duckdb/execution/operator/helper/physical_batch_collector.hpp b/src/duckdb/src/include/duckdb/execution/operator/helper/physical_batch_collector.hpp index f630187f8..29a58c7a6 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/helper/physical_batch_collector.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/helper/physical_batch_collector.hpp @@ -30,8 +30,8 @@ class PhysicalBatchCollector : public PhysicalResultCollector { unique_ptr GetLocalSinkState(ExecutionContext &context) const override; unique_ptr GetGlobalSinkState(ClientContext &context) const override; - bool RequiresBatchIndex() const override { - return true; + OperatorPartitionInfo RequiredPartitionInfo() const override { + return OperatorPartitionInfo::BatchIndex(); } bool ParallelSink() const override { diff --git a/src/duckdb/src/include/duckdb/execution/operator/helper/physical_buffered_batch_collector.hpp b/src/duckdb/src/include/duckdb/execution/operator/helper/physical_buffered_batch_collector.hpp index 6e2661c8b..1ab923968 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/helper/physical_buffered_batch_collector.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/helper/physical_buffered_batch_collector.hpp @@ -37,8 +37,8 @@ class PhysicalBufferedBatchCollector : public PhysicalResultCollector { unique_ptr GetLocalSinkState(ExecutionContext &context) const override; unique_ptr GetGlobalSinkState(ClientContext &context) const override; - bool RequiresBatchIndex() const override { - return true; + OperatorPartitionInfo RequiredPartitionInfo() const override { + return OperatorPartitionInfo::BatchIndex(); } bool ParallelSink() const override { diff --git a/src/duckdb/src/include/duckdb/execution/operator/helper/physical_limit.hpp b/src/duckdb/src/include/duckdb/execution/operator/helper/physical_limit.hpp index 2734066bb..47f01b2b5 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/helper/physical_limit.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/helper/physical_limit.hpp @@ -57,8 +57,8 @@ class PhysicalLimit : public PhysicalOperator { return true; } - bool RequiresBatchIndex() const override { - return true; + OperatorPartitionInfo RequiredPartitionInfo() const override { + return OperatorPartitionInfo::BatchIndex(); } public: diff --git a/src/duckdb/src/include/duckdb/execution/operator/join/join_filter_pushdown.hpp b/src/duckdb/src/include/duckdb/execution/operator/join/join_filter_pushdown.hpp index 0a270b545..2dbe14543 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/join/join_filter_pushdown.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/join/join_filter_pushdown.hpp @@ -19,8 +19,6 @@ struct GlobalUngroupedAggregateState; struct LocalUngroupedAggregateState; struct JoinFilterPushdownColumn { - //! The join condition from which this filter pushdown is generated - idx_t join_condition; //! The probe column index to which this filter should be applied ColumnBinding probe_column_index; }; @@ -39,11 +37,18 @@ struct JoinFilterLocalState { unique_ptr local_aggregate_state; }; -struct JoinFilterPushdownInfo { +struct JoinFilterPushdownFilter { //! The dynamic table filter set where to push filters into shared_ptr dynamic_filters; - //! The filters that we should generate - vector filters; + //! The columns for which we should generate filters + vector columns; +}; + +struct JoinFilterPushdownInfo { + //! The join condition indexes for which we compute the min/max aggregates + vector join_condition; + //! The probes to push the filter into + vector probe_info; //! Min/Max aggregates vector> min_max_aggregates; diff --git a/src/duckdb/src/include/duckdb/execution/operator/join/perfect_hash_join_executor.hpp b/src/duckdb/src/include/duckdb/execution/operator/join/perfect_hash_join_executor.hpp index d5dd3e4aa..0d481d003 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/join/perfect_hash_join_executor.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/join/perfect_hash_join_executor.hpp @@ -41,8 +41,8 @@ class PerfectHashJoinExecutor { bool CanDoPerfectHashJoin(); unique_ptr GetOperatorState(ExecutionContext &context); - OperatorResultType ProbePerfectHashTable(ExecutionContext &context, DataChunk &input, DataChunk &chunk, - OperatorState &state); + OperatorResultType ProbePerfectHashTable(ExecutionContext &context, DataChunk &input, DataChunk &lhs_output_columns, + DataChunk &chunk, OperatorState &state); bool BuildPerfectHashTable(LogicalType &type); private: diff --git a/src/duckdb/src/include/duckdb/execution/operator/join/physical_hash_join.hpp b/src/duckdb/src/include/duckdb/execution/operator/join/physical_hash_join.hpp index 5b8d9c081..84a0c3882 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/join/physical_hash_join.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/join/physical_hash_join.hpp @@ -22,6 +22,11 @@ class PhysicalHashJoin : public PhysicalComparisonJoin { public: static constexpr const PhysicalOperatorType TYPE = PhysicalOperatorType::HASH_JOIN; + struct JoinProjectionColumns { + vector col_idxs; + vector col_types; + }; + public: PhysicalHashJoin(LogicalOperator &op, unique_ptr left, unique_ptr right, vector cond, JoinType join_type, const vector &left_projection_map, @@ -38,15 +43,12 @@ class PhysicalHashJoin : public PhysicalComparisonJoin { //! The types of the join keys vector condition_types; - //! The indices for getting the payload columns - vector payload_column_idxs; - //! The types of the payload columns - vector payload_types; - - //! Positions of the RHS columns that need to output - vector rhs_output_columns; - //! The types of the output - vector rhs_output_types; + //! The indices/types of the payload columns + JoinProjectionColumns payload_columns; + //! The indices/types of the lhs columns that need to be output + JoinProjectionColumns lhs_output_columns; + //! The indices/types of the rhs columns that need to be output + JoinProjectionColumns rhs_output_columns; //! Duplicate eliminated types; only used for delim_joins (i.e. correlated subqueries) vector delim_types; diff --git a/src/duckdb/src/include/duckdb/execution/operator/order/physical_order.hpp b/src/duckdb/src/include/duckdb/execution/operator/order/physical_order.hpp index b3b28992d..b62fea5dd 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/order/physical_order.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/order/physical_order.hpp @@ -35,8 +35,9 @@ class PhysicalOrder : public PhysicalOperator { GlobalSourceState &gstate) const override; unique_ptr GetGlobalSourceState(ClientContext &context) const override; SourceResultType GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const override; - idx_t GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate, - LocalSourceState &lstate) const override; + OperatorPartitionData GetPartitionData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate, + LocalSourceState &lstate, + const OperatorPartitionInfo &partition_info) const override; bool IsSource() const override { return true; @@ -46,7 +47,10 @@ class PhysicalOrder : public PhysicalOperator { return true; } - bool SupportsBatchIndex() const override { + bool SupportsPartitioning(const OperatorPartitionInfo &partition_info) const override { + if (partition_info.RequiresPartitionColumns()) { + return false; + } return true; } diff --git a/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_copy_to_file.hpp b/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_copy_to_file.hpp index 4f01747d4..56f8a43a5 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_copy_to_file.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_copy_to_file.hpp @@ -49,8 +49,8 @@ class PhysicalBatchCopyToFile : public PhysicalOperator { unique_ptr GetGlobalSinkState(ClientContext &context) const override; SinkNextBatchType NextBatch(ExecutionContext &context, OperatorSinkNextBatchInput &input) const override; - bool RequiresBatchIndex() const override { - return true; + OperatorPartitionInfo RequiredPartitionInfo() const override { + return OperatorPartitionInfo::BatchIndex(); } bool IsSink() const override { diff --git a/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_insert.hpp b/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_insert.hpp index bce3ac633..57c349280 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_insert.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_insert.hpp @@ -60,8 +60,8 @@ class PhysicalBatchInsert : public PhysicalOperator { SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context, OperatorSinkFinalizeInput &input) const override; - bool RequiresBatchIndex() const override { - return true; + OperatorPartitionInfo RequiredPartitionInfo() const override { + return OperatorPartitionInfo::BatchIndex(); } bool IsSink() const override { diff --git a/src/duckdb/src/include/duckdb/execution/operator/scan/physical_positional_scan.hpp b/src/duckdb/src/include/duckdb/execution/operator/scan/physical_positional_scan.hpp index c142009d2..00a450237 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/scan/physical_positional_scan.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/scan/physical_positional_scan.hpp @@ -30,6 +30,7 @@ class PhysicalPositionalScan : public PhysicalOperator { public: bool Equals(const PhysicalOperator &other) const override; + vector> GetChildren() const override; public: unique_ptr GetLocalSourceState(ExecutionContext &context, diff --git a/src/duckdb/src/include/duckdb/execution/operator/scan/physical_table_scan.hpp b/src/duckdb/src/include/duckdb/execution/operator/scan/physical_table_scan.hpp index 621282e2d..530592121 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/scan/physical_table_scan.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/scan/physical_table_scan.hpp @@ -42,7 +42,8 @@ class PhysicalTableScan : public PhysicalOperator { vector names; //! The table filters unique_ptr table_filters; - //! Currently stores info related to filters pushed down into MultiFileLists + //! Currently stores info related to filters pushed down into MultiFileLists and sample rate pushed down into the + //! table scan ExtraOperatorInfo extra_info; //! Parameters vector parameters; @@ -60,17 +61,16 @@ class PhysicalTableScan : public PhysicalOperator { GlobalSourceState &gstate) const override; unique_ptr GetGlobalSourceState(ClientContext &context) const override; SourceResultType GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const override; - idx_t GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate, - LocalSourceState &lstate) const override; + OperatorPartitionData GetPartitionData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate, + LocalSourceState &lstate, + const OperatorPartitionInfo &partition_info) const override; bool IsSource() const override { return true; } bool ParallelSource() const override; - bool SupportsBatchIndex() const override { - return function.get_batch_index != nullptr; - } + bool SupportsPartitioning(const OperatorPartitionInfo &partition_info) const override; double GetProgress(ClientContext &context, GlobalSourceState &gstate) const override; }; diff --git a/src/duckdb/src/include/duckdb/execution/operator/schema/physical_create_art_index.hpp b/src/duckdb/src/include/duckdb/execution/operator/schema/physical_create_art_index.hpp index edd949fb7..cc3178386 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/schema/physical_create_art_index.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/schema/physical_create_art_index.hpp @@ -8,18 +8,18 @@ #pragma once -#include "duckdb/execution/physical_operator.hpp" #include "duckdb/execution/index/art/art.hpp" +#include "duckdb/execution/physical_operator.hpp" #include "duckdb/parser/parsed_data/create_index_info.hpp" - #include "duckdb/storage/data_table.hpp" #include namespace duckdb { + class DuckTableEntry; -//! Physical CREATE (UNIQUE) INDEX statement +//! Physical index creation operator. class PhysicalCreateARTIndex : public PhysicalOperator { public: static constexpr const PhysicalOperatorType TYPE = PhysicalOperatorType::CREATE_INDEX; @@ -27,18 +27,21 @@ class PhysicalCreateARTIndex : public PhysicalOperator { public: PhysicalCreateARTIndex(LogicalOperator &op, TableCatalogEntry &table, const vector &column_ids, unique_ptr info, vector> unbound_expressions, - idx_t estimated_cardinality, const bool sorted); + idx_t estimated_cardinality, const bool sorted, + unique_ptr alter_table_info = nullptr); - //! The table to create the index for + //! The table to create the index for. DuckTableEntry &table; - //! The list of column IDs required for the index + //! The list of column IDs of the index. vector storage_ids; - //! Info for index creation + //! Index creation information. unique_ptr info; - //! Unbound expressions to be used in the optimizer + //! Unbound expressions of the indexed columns. vector> unbound_expressions; - //! Whether the pipeline sorts the data prior to index creation + //! True, if the pipeline sorts the index data prior to index creation. const bool sorted; + //! Alter table information for adding indexes. + unique_ptr alter_table_info; public: //! Source interface, NOP for this operator @@ -49,14 +52,14 @@ class PhysicalCreateARTIndex : public PhysicalOperator { } public: - //! Sink interface, thread-local sink states + //! Sink interface, thread-local sink states. Contains an index for each state. unique_ptr GetLocalSinkState(ExecutionContext &context) const override; - //! Sink interface, global sink state + //! Sink interface, global sink state. Contains the global index. unique_ptr GetGlobalSinkState(ClientContext &context) const override; - //! Sink for unsorted data: insert iteratively + //! Sink for unsorted data: insert iteratively. SinkResultType SinkUnsorted(OperatorSinkInput &input) const; - //! Sink for sorted data: build + merge + //! Sink for sorted data: build + merge. SinkResultType SinkSorted(OperatorSinkInput &input) const; SinkResultType Sink(ExecutionContext &context, DataChunk &chunk, OperatorSinkInput &input) const override; diff --git a/src/duckdb/src/include/duckdb/execution/operator/set/physical_cte.hpp b/src/duckdb/src/include/duckdb/execution/operator/set/physical_cte.hpp index 5416c8fd3..3ce30ce67 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/set/physical_cte.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/set/physical_cte.hpp @@ -52,10 +52,6 @@ class PhysicalCTE : public PhysicalOperator { return false; } - bool RequiresBatchIndex() const override { - return false; - } - InsertionOrderPreservingMap ParamsToString() const override; public: diff --git a/src/duckdb/src/include/duckdb/execution/partition_info.hpp b/src/duckdb/src/include/duckdb/execution/partition_info.hpp new file mode 100644 index 000000000..8a56f77fb --- /dev/null +++ b/src/duckdb/src/include/duckdb/execution/partition_info.hpp @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/execution/partition_info.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/common.hpp" +#include "duckdb/common/types/value.hpp" +#include "duckdb/common/optional_idx.hpp" + +namespace duckdb { + +enum class PartitionInfo { NONE, REQUIRES_BATCH_INDEX }; + +struct ColumnPartitionData { + explicit ColumnPartitionData(Value partition_val) : min_val(partition_val), max_val(std::move(partition_val)) { + } + + Value min_val; + Value max_val; +}; + +struct SourcePartitionInfo { + //! The current batch index + //! This is only set in case RequiresBatchIndex() is true, and the source has support for it (SupportsBatchIndex()) + //! Otherwise this is left on INVALID_INDEX + //! The batch index is a globally unique, increasing index that should be used to maintain insertion order + //! //! in conjunction with parallelism + optional_idx batch_index; + //! The minimum batch index that any thread is currently actively reading + optional_idx min_batch_index; + //! Column partition data + vector partition_data; +}; + +struct OperatorPartitionInfo { + OperatorPartitionInfo() = default; + explicit OperatorPartitionInfo(bool batch_index) : batch_index(batch_index) { + } + explicit OperatorPartitionInfo(vector partition_columns_p) + : partition_columns(std::move(partition_columns_p)) { + } + + bool batch_index = false; + vector partition_columns; + + static OperatorPartitionInfo NoPartitionInfo() { + return OperatorPartitionInfo(false); + } + static OperatorPartitionInfo BatchIndex() { + return OperatorPartitionInfo(true); + } + static OperatorPartitionInfo PartitionColumns(vector columns) { + return OperatorPartitionInfo(std::move(columns)); + } + bool RequiresPartitionColumns() const { + return !partition_columns.empty(); + } + bool RequiresBatchIndex() const { + return batch_index; + } + bool AnyRequired() const { + return RequiresPartitionColumns() || RequiresBatchIndex(); + } +}; + +struct OperatorPartitionData { + explicit OperatorPartitionData(idx_t batch_index) : batch_index(batch_index) { + } + + idx_t batch_index; + vector partition_data; +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/physical_operator.hpp b/src/duckdb/src/include/duckdb/execution/physical_operator.hpp index be63efb25..91f81a6de 100644 --- a/src/duckdb/src/include/duckdb/execution/physical_operator.hpp +++ b/src/duckdb/src/include/duckdb/execution/physical_operator.hpp @@ -20,6 +20,7 @@ #include "duckdb/execution/physical_operator_states.hpp" #include "duckdb/common/enums/order_preservation_type.hpp" #include "duckdb/common/case_insensitive_map.hpp" +#include "duckdb/execution/partition_info.hpp" namespace duckdb { class Event; @@ -113,8 +114,9 @@ class PhysicalOperator { virtual unique_ptr GetGlobalSourceState(ClientContext &context) const; virtual SourceResultType GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const; - virtual idx_t GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate, - LocalSourceState &lstate) const; + virtual OperatorPartitionData GetPartitionData(ExecutionContext &context, DataChunk &chunk, + GlobalSourceState &gstate, LocalSourceState &lstate, + const OperatorPartitionInfo &partition_info) const; virtual bool IsSource() const { return false; @@ -124,8 +126,11 @@ class PhysicalOperator { return false; } - virtual bool SupportsBatchIndex() const { - return false; + virtual bool SupportsPartitioning(const OperatorPartitionInfo &partition_info) const { + if (partition_info.AnyRequired()) { + return false; + } + return true; } //! The type of order emitted by the operator (as a source) @@ -181,8 +186,8 @@ class PhysicalOperator { return false; } - virtual bool RequiresBatchIndex() const { - return false; + virtual OperatorPartitionInfo RequiredPartitionInfo() const { + return OperatorPartitionInfo::NoPartitionInfo(); } //! Whether or not the sink operator depends on the order of the input chunks @@ -241,8 +246,12 @@ class CachingPhysicalOperator : public PhysicalOperator { bool caching_supported; public: + //! This Execute will prevent small chunks from entering the pipeline, buffering them until a bigger chunk is + //! created. OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk, GlobalOperatorState &gstate, OperatorState &state) const final; + //! FinalExecute is used here to send out the remainder of the chunk (< STANDARD_VECTOR_SIZE) that we still had + //! cached. OperatorFinalizeResultType FinalExecute(ExecutionContext &context, DataChunk &chunk, GlobalOperatorState &gstate, OperatorState &state) const final; diff --git a/src/duckdb/src/include/duckdb/execution/physical_operator_states.hpp b/src/duckdb/src/include/duckdb/execution/physical_operator_states.hpp index 6c6717c49..9c0d6df1f 100644 --- a/src/duckdb/src/include/duckdb/execution/physical_operator_states.hpp +++ b/src/duckdb/src/include/duckdb/execution/physical_operator_states.hpp @@ -16,6 +16,7 @@ #include "duckdb/execution/execution_context.hpp" #include "duckdb/optimizer/join_order/join_node.hpp" #include "duckdb/parallel/interrupt.hpp" +#include "duckdb/execution/partition_info.hpp" namespace duckdb { class Event; @@ -26,17 +27,6 @@ class PipelineBuildState; class MetaPipeline; class InterruptState; -struct SourcePartitionInfo { - //! The current batch index - //! This is only set in case RequiresBatchIndex() is true, and the source has support for it (SupportsBatchIndex()) - //! Otherwise this is left on INVALID_INDEX - //! The batch index is a globally unique, increasing index that should be used to maintain insertion order - //! //! in conjunction with parallelism - optional_idx batch_index; - //! The minimum batch index that any thread is currently actively reading - optional_idx min_batch_index; -}; - // LCOV_EXCL_START class OperatorState { public: diff --git a/src/duckdb/src/include/duckdb/execution/physical_plan_generator.hpp b/src/duckdb/src/include/duckdb/execution/physical_plan_generator.hpp index 0b09b3494..51797f589 100644 --- a/src/duckdb/src/include/duckdb/execution/physical_plan_generator.hpp +++ b/src/duckdb/src/include/duckdb/execution/physical_plan_generator.hpp @@ -45,8 +45,6 @@ class PhysicalPlanGenerator { //! Whether or not we should preserve insertion order for executing the given sink static bool PreserveInsertionOrder(ClientContext &context, PhysicalOperator &plan); - static bool HasEquality(vector &conds, idx_t &range_count); - protected: unique_ptr CreatePlan(LogicalOperator &op); diff --git a/src/duckdb/src/include/duckdb/execution/window_executor.hpp b/src/duckdb/src/include/duckdb/execution/window_executor.hpp index 0c9a7c340..139b2fc9b 100644 --- a/src/duckdb/src/include/duckdb/execution/window_executor.hpp +++ b/src/duckdb/src/include/duckdb/execution/window_executor.hpp @@ -15,120 +15,213 @@ namespace duckdb { -// A wrapper for building DataChunks in parallel -class WindowDataChunk { +// A wrapper for building ColumnDataCollections in parallel +class WindowCollection { public: - // True if the vector data can just be copied to - static bool IsSimple(const Vector &v); + using ColumnDataCollectionPtr = unique_ptr; + using ColumnDataCollectionSpec = pair>; + using ColumnSet = unordered_set; - static inline bool IsMaskAligned(idx_t begin, idx_t end, idx_t count) { - return ValidityMask::IsAligned(begin) && (ValidityMask::IsAligned(end) || (end == count)); + WindowCollection(BufferManager &buffer_manager, idx_t count, const vector &types); + + idx_t ColumnCount() const { + return types.size(); } - explicit WindowDataChunk(DataChunk &chunk); + idx_t size() const { // NOLINT + return count; + } - void Initialize(Allocator &allocator, const vector &types, idx_t capacity); + const vector &GetTypes() const { + return types; + } - void Copy(DataChunk &src, idx_t begin); + //! Update a thread-local collection for appending data to a given row + void GetCollection(idx_t row_idx, ColumnDataCollectionSpec &spec); + //! Single-threaded, idempotent ordered combining of all the appended data. + void Combine(const ColumnSet &build_validity); + + //! The collection data. May be null if the column count is 0. + ColumnDataCollectionPtr inputs; + //! Global validity mask + vector> all_valids; + //! Optional validity mask for the entire collection + vector validities; + + //! The collection columns + const vector types; + //! The collection rows + const idx_t count; - //! The wrapped chunk - DataChunk &chunk; + //! Guard for range updates + mutex lock; + //! The paging buffer manager to use + BufferManager &buffer_manager; + //! The component column data collections + vector collections; + //! The (sorted) collection ranges + using Range = pair; + vector ranges; +}; -private: - //! True if the column is a scalar only value - vector is_simple; - //! Exclusive lock for each column - vector locks; +class WindowBuilder { +public: + explicit WindowBuilder(WindowCollection &collection); + + //! Add a new chunk at the given index + void Sink(DataChunk &chunk, idx_t input_idx); + + //! The collection we are helping to build + WindowCollection &collection; + //! The thread's current input collection + using ColumnDataCollectionSpec = WindowCollection::ColumnDataCollectionSpec; + ColumnDataCollectionSpec sink; + //! The state used for appending to the collection + ColumnDataAppendState appender; + //! Are all the sunk rows valid? + bool all_valid = true; }; -struct WindowInputExpression { - static void PrepareInputExpression(Expression &expr, ExpressionExecutor &executor, DataChunk &chunk) { - vector types; - types.push_back(expr.return_type); - executor.AddExpression(expr); +class WindowCursor { +public: + WindowCursor(const WindowCollection &paged, column_t col_idx); + WindowCursor(const WindowCollection &paged, vector column_ids); - auto &allocator = executor.GetAllocator(); - chunk.Initialize(allocator, types); + //! Is the scan in range? + inline bool RowIsVisible(idx_t row_idx) const { + return (row_idx < state.next_row_index && state.current_row_index <= row_idx); } - - WindowInputExpression(optional_ptr expr_p, ClientContext &context) - : expr(expr_p), ptype(PhysicalType::INVALID), scalar(true), executor(context) { - if (expr) { - PrepareInputExpression(*expr, executor, chunk); - ptype = expr->return_type.InternalType(); - scalar = expr->IsScalar(); - } + //! The offset of the row in the given state + inline sel_t RowOffset(idx_t row_idx) const { + D_ASSERT(RowIsVisible(row_idx)); + return UnsafeNumericCast(row_idx - state.current_row_index); } - - void Execute(DataChunk &input_chunk) { - if (expr) { - chunk.Reset(); - executor.Execute(input_chunk, chunk); - chunk.Verify(); - chunk.Flatten(); + //! Scan the next chunk + inline bool Scan() { + return paged.inputs->Scan(state, chunk); + } + //! Seek to the given row + inline idx_t Seek(idx_t row_idx) { + if (!RowIsVisible(row_idx)) { + D_ASSERT(paged.inputs.get()); + paged.inputs->Seek(row_idx, state, chunk); } + return RowOffset(row_idx); } - + //! Check a collection cell for nullity + bool CellIsNull(idx_t col_idx, idx_t row_idx) { + D_ASSERT(chunk.ColumnCount() > col_idx); + auto index = Seek(row_idx); + auto &source = chunk.data[col_idx]; + return FlatVector::IsNull(source, index); + } + //! Read a typed cell template - inline T GetCell(idx_t i) const { - D_ASSERT(!chunk.data.empty()); - const auto data = FlatVector::GetData(chunk.data[0]); - return data[scalar ? 0 : i]; + T GetCell(idx_t col_idx, idx_t row_idx) { + D_ASSERT(chunk.ColumnCount() > col_idx); + auto index = Seek(row_idx); + auto &source = chunk.data[col_idx]; + const auto data = FlatVector::GetData(source); + return data[index]; } - - inline bool CellIsNull(idx_t i) const { - D_ASSERT(!chunk.data.empty()); - if (chunk.data[0].GetVectorType() == VectorType::CONSTANT_VECTOR) { - return ConstantVector::IsNull(chunk.data[0]); - } - return FlatVector::IsNull(chunk.data[0], i); + //! Copy a single value + void CopyCell(idx_t col_idx, idx_t row_idx, Vector &target, idx_t target_offset) { + D_ASSERT(chunk.ColumnCount() > col_idx); + auto index = Seek(row_idx); + auto &source = chunk.data[col_idx]; + VectorOperations::Copy(source, target, index + 1, index, target_offset); } - inline void CopyCell(Vector &target, idx_t target_offset, idx_t width = 1) const { - D_ASSERT(!chunk.data.empty()); - auto &source = chunk.data[0]; - auto source_offset = scalar ? 0 : target_offset; - VectorOperations::Copy(source, target, source_offset + width, source_offset, target_offset); + unique_ptr Copy() const { + return make_uniq(paged, state.column_ids); } - optional_ptr expr; - PhysicalType ptype; - bool scalar; - ExpressionExecutor executor; + //! The pageable data + const WindowCollection &paged; + //! The state used for reading the collection + ColumnDataScanState state; + //! The data chunk read into DataChunk chunk; }; -struct WindowInputColumn { - WindowInputColumn(optional_ptr expr_p, ClientContext &context, idx_t count); +// Column indexes of the bounds chunk +enum WindowBounds : uint8_t { + PARTITION_BEGIN, + PARTITION_END, + PEER_BEGIN, + PEER_END, + VALID_BEGIN, + VALID_END, + FRAME_BEGIN, + FRAME_END +}; + +// C++ 11 won't do this automatically... +struct WindowBoundsHash { + inline uint64_t operator()(const WindowBounds &value) const { + return value; + } +}; + +using WindowBoundsSet = unordered_set; + +//! A shared set of expressions +struct WindowSharedExpressions { + struct Shared { + column_t size = 0; + expression_map_t> columns; + }; - void Copy(DataChunk &input_chunk, idx_t input_idx); + //! Register a shared expression in a shared set + static column_t RegisterExpr(const unique_ptr &expr, Shared &shared); - inline bool CellIsNull(idx_t i) const { - D_ASSERT(!target.data.empty()); - D_ASSERT(i < count); - return FlatVector::IsNull((target.data[0]), scalar ? 0 : i); + //! Register a shared collection expression + column_t RegisterCollection(const unique_ptr &expr, bool build_validity) { + auto result = RegisterExpr(expr, coll_shared); + if (build_validity) { + coll_validity.insert(result); + } + return result; + } + //! Register a shared collection expression + inline column_t RegisterSink(const unique_ptr &expr) { + return RegisterExpr(expr, sink_shared); + } + //! Register a shared evaluation expression + inline column_t RegisterEvaluate(const unique_ptr &expr) { + return RegisterExpr(expr, eval_shared); } - template - inline T GetCell(idx_t i) const { - D_ASSERT(!target.data.empty()); - D_ASSERT(i < count); - const auto data = FlatVector::GetData(target.data[0]); - return data[scalar ? 0 : i]; + //! Expression layout + static vector GetSortedExpressions(Shared &shared); + + //! Expression execution utility + static void PrepareExecutors(Shared &shared, ExpressionExecutor &exec, DataChunk &chunk); + + //! Prepare collection expressions + inline void PrepareCollection(ExpressionExecutor &exec, DataChunk &chunk) { + PrepareExecutors(coll_shared, exec, chunk); } - optional_ptr expr; - PhysicalType ptype; - const bool scalar; - const idx_t count; + //! Prepare collection expressions + inline void PrepareSink(ExpressionExecutor &exec, DataChunk &chunk) { + PrepareExecutors(sink_shared, exec, chunk); + } -private: - DataChunk target; - WindowDataChunk wtarget; -}; + //! Prepare collection expressions + inline void PrepareEvaluate(ExpressionExecutor &exec, DataChunk &chunk) { + PrepareExecutors(eval_shared, exec, chunk); + } -// Column indexes of the bounds chunk -enum WindowBounds : uint8_t { PARTITION_BEGIN, PARTITION_END, PEER_BEGIN, PEER_END, WINDOW_BEGIN, WINDOW_END }; + //! Fully materialised shared expressions + Shared coll_shared; + //! Sink shared expressions + Shared sink_shared; + //! Evaluate shared expressions + Shared eval_shared; + //! Requested collection validity masks + unordered_set coll_validity; +}; class WindowExecutorState { public: @@ -152,6 +245,8 @@ class WindowExecutor; class WindowExecutorGlobalState : public WindowExecutorState { public: + using CollectionPtr = optional_ptr; + WindowExecutorGlobalState(const WindowExecutor &executor, const idx_t payload_count, const ValidityMask &partition_mask, const ValidityMask &order_mask); @@ -161,29 +256,26 @@ class WindowExecutorGlobalState : public WindowExecutorState { const ValidityMask &partition_mask; const ValidityMask &order_mask; vector arg_types; - - // evaluate RANGE expressions, if needed - WindowInputColumn range; }; class WindowExecutorLocalState : public WindowExecutorState { public: - explicit WindowExecutorLocalState(const WindowExecutorGlobalState &gstate); + using CollectionPtr = optional_ptr; - void Sink(WindowExecutorGlobalState &gstate, DataChunk &input_chunk, idx_t input_idx); + explicit WindowExecutorLocalState(const WindowExecutorGlobalState &gstate); - // Argument evaluation - ExpressionExecutor payload_executor; - DataChunk payload_chunk; + void Sink(WindowExecutorGlobalState &gstate, DataChunk &sink_chunk, DataChunk &coll_chunk, idx_t input_idx); + virtual void Finalize(WindowExecutorGlobalState &gstate, CollectionPtr collection); - //! Range evaluation - ExpressionExecutor range_executor; - DataChunk range_chunk; + //! The state used for reading the range collection + unique_ptr range_cursor; }; class WindowExecutor { public: - WindowExecutor(BoundWindowExpression &wexpr, ClientContext &context); + using CollectionPtr = optional_ptr; + + WindowExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); virtual ~WindowExecutor() { } @@ -191,31 +283,45 @@ class WindowExecutor { GetGlobalState(const idx_t payload_count, const ValidityMask &partition_mask, const ValidityMask &order_mask) const; virtual unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const; - virtual void Sink(DataChunk &input_chunk, const idx_t input_idx, const idx_t total_count, + virtual void Sink(DataChunk &sink_chunk, DataChunk &coll_chunk, const idx_t input_idx, WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const; - virtual void Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const { - } + virtual void Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + CollectionPtr collection) const; - void Evaluate(idx_t row_idx, DataChunk &input_chunk, Vector &result, WindowExecutorLocalState &lstate, + void Evaluate(idx_t row_idx, DataChunk &eval_chunk, Vector &result, WindowExecutorLocalState &lstate, WindowExecutorGlobalState &gstate) const; // The function const BoundWindowExpression &wexpr; ClientContext &context; + // evaluate frame expressions, if needed + column_t boundary_start_idx = DConstants::INVALID_INDEX; + column_t boundary_end_idx = DConstants::INVALID_INDEX; + + // evaluate RANGE expressions, if needed + optional_ptr range_expr; + column_t range_idx = DConstants::INVALID_INDEX; + protected: - virtual void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, - idx_t count, idx_t row_idx) const = 0; + virtual void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + DataChunk &eval_chunk, Vector &result, idx_t count, idx_t row_idx) const = 0; }; class WindowAggregateExecutor : public WindowExecutor { public: - WindowAggregateExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowAggregationMode mode); + WindowAggregateExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared, + WindowAggregationMode mode); + + bool IsConstantAggregate(); + bool IsCustomAggregate(); + bool IsDistinctAggregate(); - void Sink(DataChunk &input_chunk, const idx_t input_idx, const idx_t total_count, WindowExecutorGlobalState &gstate, + void Sink(DataChunk &sink_chunk, DataChunk &coll_chunk, const idx_t input_idx, WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const override; - void Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const override; + void Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + CollectionPtr collection) const override; unique_ptr GetGlobalState(const idx_t payload_count, const ValidityMask &partition_mask, const ValidityMask &order_mask) const override; @@ -223,121 +329,136 @@ class WindowAggregateExecutor : public WindowExecutor { const WindowAggregationMode mode; + // aggregate computation algorithm + unique_ptr aggregator; + + // FILTER reference expression in sink_chunk + unique_ptr filter_ref; + protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, - idx_t count, idx_t row_idx) const override; + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, + Vector &result, idx_t count, idx_t row_idx) const override; }; class WindowRowNumberExecutor : public WindowExecutor { public: - WindowRowNumberExecutor(BoundWindowExpression &wexpr, ClientContext &context); + WindowRowNumberExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, - idx_t count, idx_t row_idx) const override; + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, + Vector &result, idx_t count, idx_t row_idx) const override; }; // Base class for non-aggregate functions that use peer boundaries class WindowRankExecutor : public WindowExecutor { public: - WindowRankExecutor(BoundWindowExpression &wexpr, ClientContext &context); + WindowRankExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const override; protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, - idx_t count, idx_t row_idx) const override; + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, + Vector &result, idx_t count, idx_t row_idx) const override; }; class WindowDenseRankExecutor : public WindowExecutor { public: - WindowDenseRankExecutor(BoundWindowExpression &wexpr, ClientContext &context); + WindowDenseRankExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const override; protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, - idx_t count, idx_t row_idx) const override; + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, + Vector &result, idx_t count, idx_t row_idx) const override; }; class WindowPercentRankExecutor : public WindowExecutor { public: - WindowPercentRankExecutor(BoundWindowExpression &wexpr, ClientContext &context); + WindowPercentRankExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const override; protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, - idx_t count, idx_t row_idx) const override; + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, + Vector &result, idx_t count, idx_t row_idx) const override; }; class WindowCumeDistExecutor : public WindowExecutor { public: - WindowCumeDistExecutor(BoundWindowExpression &wexpr, ClientContext &context); + WindowCumeDistExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, - idx_t count, idx_t row_idx) const override; + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, + Vector &result, idx_t count, idx_t row_idx) const override; }; // Base class for non-aggregate functions that have a payload class WindowValueExecutor : public WindowExecutor { public: - WindowValueExecutor(BoundWindowExpression &wexpr, ClientContext &context); + WindowValueExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); - void Sink(DataChunk &input_chunk, const idx_t input_idx, const idx_t total_count, WindowExecutorGlobalState &gstate, - WindowExecutorLocalState &lstate) const override; + void Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + CollectionPtr collection) const override; unique_ptr GetGlobalState(const idx_t payload_count, const ValidityMask &partition_mask, const ValidityMask &order_mask) const override; unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const override; + + //! The column index of the value column + column_t child_idx = DConstants::INVALID_INDEX; + //! The column index of the Nth column + column_t nth_idx = DConstants::INVALID_INDEX; + //! The column index of the offset column + column_t offset_idx = DConstants::INVALID_INDEX; + //! The column index of the default value column + column_t default_idx = DConstants::INVALID_INDEX; }; // class WindowNtileExecutor : public WindowValueExecutor { public: - WindowNtileExecutor(BoundWindowExpression &wexpr, ClientContext &context); + WindowNtileExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, - idx_t count, idx_t row_idx) const override; + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, + Vector &result, idx_t count, idx_t row_idx) const override; }; class WindowLeadLagExecutor : public WindowValueExecutor { public: - WindowLeadLagExecutor(BoundWindowExpression &wexpr, ClientContext &context); + WindowLeadLagExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const override; protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, - idx_t count, idx_t row_idx) const override; + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, + Vector &result, idx_t count, idx_t row_idx) const override; }; class WindowFirstValueExecutor : public WindowValueExecutor { public: - WindowFirstValueExecutor(BoundWindowExpression &wexpr, ClientContext &context); + WindowFirstValueExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, - idx_t count, idx_t row_idx) const override; + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, + Vector &result, idx_t count, idx_t row_idx) const override; }; class WindowLastValueExecutor : public WindowValueExecutor { public: - WindowLastValueExecutor(BoundWindowExpression &wexpr, ClientContext &context); + WindowLastValueExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, - idx_t count, idx_t row_idx) const override; + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, + Vector &result, idx_t count, idx_t row_idx) const override; }; class WindowNthValueExecutor : public WindowValueExecutor { public: - WindowNthValueExecutor(BoundWindowExpression &wexpr, ClientContext &context); + WindowNthValueExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, - idx_t count, idx_t row_idx) const override; + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, + Vector &result, idx_t count, idx_t row_idx) const override; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/window_segment_tree.hpp b/src/duckdb/src/include/duckdb/execution/window_segment_tree.hpp index d70b47898..7df2a7734 100644 --- a/src/duckdb/src/include/duckdb/execution/window_segment_tree.hpp +++ b/src/duckdb/src/include/duckdb/execution/window_segment_tree.hpp @@ -18,6 +18,9 @@ namespace duckdb { +struct WindowSharedExpressions; +class WindowCollection; + class WindowAggregatorState { public: WindowAggregatorState(); @@ -41,41 +44,49 @@ class WindowAggregatorState { class WindowAggregator { public: - WindowAggregator(AggregateObject aggr, const vector &arg_types_p, const LogicalType &result_type_p, - const WindowExcludeMode exclude_mode_p); + using CollectionPtr = optional_ptr; + + WindowAggregator(const BoundWindowExpression &wexpr, const WindowExcludeMode exclude_mode_p); + WindowAggregator(const BoundWindowExpression &wexpr, const WindowExcludeMode exclude_mode_p, + WindowSharedExpressions &shared); virtual ~WindowAggregator(); // Threading states - virtual unique_ptr GetGlobalState(idx_t group_count, + virtual unique_ptr GetGlobalState(ClientContext &context, idx_t group_count, const ValidityMask &partition_mask) const; virtual unique_ptr GetLocalState(const WindowAggregatorState &gstate) const = 0; // Build - virtual void Sink(WindowAggregatorState &gstate, WindowAggregatorState &lstate, DataChunk &arg_chunk, - idx_t input_idx, optional_ptr filter_sel, idx_t filtered); - virtual void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, const FrameStats &stats); + virtual void Sink(WindowAggregatorState &gstate, WindowAggregatorState &lstate, DataChunk &sink_chunk, + DataChunk &coll_chunk, idx_t input_idx, optional_ptr filter_sel, idx_t filtered); + virtual void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, CollectionPtr collection, + const FrameStats &stats); // Probe virtual void Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx) const = 0; + //! The window function + const BoundWindowExpression &wexpr; //! A description of the aggregator const AggregateObject aggr; //! The argument types for the function - const vector arg_types; + vector arg_types; //! The result type of the window function const LogicalType result_type; //! The size of a single aggregate state const idx_t state_size; //! The window exclusion clause const WindowExcludeMode exclude_mode; + //! Partition collection column indicies + vector child_idx; }; // Used for validation class WindowNaiveAggregator : public WindowAggregator { public: - WindowNaiveAggregator(AggregateObject aggr, const vector &arg_types_p, - const LogicalType &result_type_p, const WindowExcludeMode exclude_mode); + WindowNaiveAggregator(const BoundWindowExpression &wexpr, const WindowExcludeMode exclude_mode, + WindowSharedExpressions &shared); ~WindowNaiveAggregator() override; unique_ptr GetLocalState(const WindowAggregatorState &gstate) const override; @@ -85,16 +96,18 @@ class WindowNaiveAggregator : public WindowAggregator { class WindowConstantAggregator : public WindowAggregator { public: - WindowConstantAggregator(AggregateObject aggr, const vector &arg_types_p, - const LogicalType &result_type_p, WindowExcludeMode exclude_mode_p); + WindowConstantAggregator(const BoundWindowExpression &wexpr, WindowExcludeMode exclude_mode_p, + WindowSharedExpressions &shared); ~WindowConstantAggregator() override { } - unique_ptr GetGlobalState(idx_t group_count, + unique_ptr GetGlobalState(ClientContext &context, idx_t group_count, const ValidityMask &partition_mask) const override; - void Sink(WindowAggregatorState &gstate, WindowAggregatorState &lstate, DataChunk &arg_chunk, idx_t input_idx, - optional_ptr filter_sel, idx_t filtered) override; - void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, const FrameStats &stats) override; + void Sink(WindowAggregatorState &gstate, WindowAggregatorState &lstate, DataChunk &sink_chunk, + DataChunk &coll_chunk, idx_t input_idx, optional_ptr filter_sel, + idx_t filtered) override; + void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, CollectionPtr collection, + const FrameStats &stats) override; unique_ptr GetLocalState(const WindowAggregatorState &gstate) const override; void Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, const DataChunk &bounds, @@ -103,13 +116,14 @@ class WindowConstantAggregator : public WindowAggregator { class WindowCustomAggregator : public WindowAggregator { public: - WindowCustomAggregator(AggregateObject aggr, const vector &arg_types_p, - const LogicalType &result_type_p, const WindowExcludeMode exclude_mode); + WindowCustomAggregator(const BoundWindowExpression &wexpr, const WindowExcludeMode exclude_mode, + WindowSharedExpressions &shared); ~WindowCustomAggregator() override; - unique_ptr GetGlobalState(idx_t group_count, + unique_ptr GetGlobalState(ClientContext &context, idx_t group_count, const ValidityMask &partition_mask) const override; - void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, const FrameStats &stats) override; + void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, CollectionPtr collection, + const FrameStats &stats) override; unique_ptr GetLocalState(const WindowAggregatorState &gstate) const override; void Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, const DataChunk &bounds, @@ -119,13 +133,14 @@ class WindowCustomAggregator : public WindowAggregator { class WindowSegmentTree : public WindowAggregator { public: - WindowSegmentTree(AggregateObject aggr, const vector &arg_types_p, const LogicalType &result_type_p, - WindowAggregationMode mode_p, const WindowExcludeMode exclude_mode); + WindowSegmentTree(const BoundWindowExpression &wexpr, WindowAggregationMode mode_p, + const WindowExcludeMode exclude_mode, WindowSharedExpressions &shared); - unique_ptr GetGlobalState(idx_t group_count, + unique_ptr GetGlobalState(ClientContext &context, idx_t group_count, const ValidityMask &partition_mask) const override; unique_ptr GetLocalState(const WindowAggregatorState &gstate) const override; - void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, const FrameStats &stats) override; + void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, CollectionPtr collection, + const FrameStats &stats) override; void Evaluate(const WindowAggregatorState &gstate, WindowAggregatorState &lstate, const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx) const override; @@ -142,16 +157,16 @@ class WindowSegmentTree : public WindowAggregator { class WindowDistinctAggregator : public WindowAggregator { public: - WindowDistinctAggregator(AggregateObject aggr, const vector &arg_types_p, - const LogicalType &result_type_p, const WindowExcludeMode exclude_mode_p, - ClientContext &context); + WindowDistinctAggregator(const BoundWindowExpression &wexpr, const WindowExcludeMode exclude_mode_p, + WindowSharedExpressions &shared, ClientContext &context); // Build - unique_ptr GetGlobalState(idx_t group_count, + unique_ptr GetGlobalState(ClientContext &context, idx_t group_count, const ValidityMask &partition_mask) const override; - void Sink(WindowAggregatorState &gsink, WindowAggregatorState &lstate, DataChunk &arg_chunk, idx_t input_idx, - optional_ptr filter_sel, idx_t filtered) override; - void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, const FrameStats &stats) override; + void Sink(WindowAggregatorState &gsink, WindowAggregatorState &lstate, DataChunk &sink_chunk, DataChunk &coll_chunk, + idx_t input_idx, optional_ptr filter_sel, idx_t filtered) override; + void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, CollectionPtr collection, + const FrameStats &stats) override; // Evaluate unique_ptr GetLocalState(const WindowAggregatorState &gstate) const override; diff --git a/src/duckdb/src/include/duckdb/function/aggregate/distributive_function_utils.hpp b/src/duckdb/src/include/duckdb/function/aggregate/distributive_function_utils.hpp new file mode 100644 index 000000000..cdaed691c --- /dev/null +++ b/src/duckdb/src/include/duckdb/function/aggregate/distributive_function_utils.hpp @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/function/aggregate/distributive_functions.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/function/function_set.hpp" + +namespace duckdb { + +struct CountFunctionBase { + static AggregateFunction GetFunction(); +}; + +struct FirstFunctionGetter { + static AggregateFunction GetFunction(const LogicalType &type); +}; + +struct MinFunction { + static AggregateFunction GetFunction(); +}; + +struct MaxFunction { + static AggregateFunction GetFunction(); +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/aggregate/distributive_functions.hpp b/src/duckdb/src/include/duckdb/function/aggregate/distributive_functions.hpp index cba1a7dec..7d6eb3274 100644 --- a/src/duckdb/src/include/duckdb/function/aggregate/distributive_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/aggregate/distributive_functions.hpp @@ -1,36 +1,87 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/function/aggregate/distributive_functions.hpp +// function/aggregate/distributive_functions.hpp // // //===----------------------------------------------------------------------===// +// This file is automatically generated by scripts/generate_functions.py +// Do not edit this file manually, your changes will be overwritten +//===----------------------------------------------------------------------===// #pragma once -#include "duckdb/function/aggregate_function.hpp" #include "duckdb/function/function_set.hpp" -#include "duckdb/common/types/null_value.hpp" -#include "duckdb/function/built_in_functions.hpp" namespace duckdb { struct CountStarFun { - static AggregateFunction GetFunction(); + static constexpr const char *Name = "count_star"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; - static void RegisterFunction(BuiltinFunctions &set); + static AggregateFunction GetFunction(); }; struct CountFun { - static AggregateFunction GetFunction(); + static constexpr const char *Name = "count"; + static constexpr const char *Parameters = "arg"; + static constexpr const char *Description = "Returns the number of non-null values in arg."; + static constexpr const char *Example = "count(A)"; - static void RegisterFunction(BuiltinFunctions &set); + static AggregateFunctionSet GetFunctions(); }; struct FirstFun { - static AggregateFunction GetFunction(const LogicalType &type); + static constexpr const char *Name = "first"; + static constexpr const char *Parameters = "arg"; + static constexpr const char *Description = "Returns the first value (null or non-null) from arg. This function is affected by ordering."; + static constexpr const char *Example = "first(A)"; + + static AggregateFunctionSet GetFunctions(); +}; + +struct ArbitraryFun { + using ALIAS = FirstFun; + + static constexpr const char *Name = "arbitrary"; +}; + +struct LastFun { + static constexpr const char *Name = "last"; + static constexpr const char *Parameters = "arg"; + static constexpr const char *Description = "Returns the last value of a column. This function is affected by ordering."; + static constexpr const char *Example = "last(A)"; + + static AggregateFunctionSet GetFunctions(); +}; + +struct AnyValueFun { + static constexpr const char *Name = "any_value"; + static constexpr const char *Parameters = "arg"; + static constexpr const char *Description = "Returns the first non-null value from arg. This function is affected by ordering."; + static constexpr const char *Example = ""; + + static AggregateFunctionSet GetFunctions(); +}; + +struct MinFun { + static constexpr const char *Name = "min"; + static constexpr const char *Parameters = "arg"; + static constexpr const char *Description = "Returns the minimum value present in arg."; + static constexpr const char *Example = "min(A)"; + + static AggregateFunctionSet GetFunctions(); +}; + +struct MaxFun { + static constexpr const char *Name = "max"; + static constexpr const char *Parameters = "arg"; + static constexpr const char *Description = "Returns the maximum value present in arg."; + static constexpr const char *Example = "max(A)"; - static void RegisterFunction(BuiltinFunctions &set); + static AggregateFunctionSet GetFunctions(); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/minmax_n_helpers.hpp b/src/duckdb/src/include/duckdb/function/aggregate/minmax_n_helpers.hpp similarity index 99% rename from src/duckdb/src/include/duckdb/core_functions/aggregate/minmax_n_helpers.hpp rename to src/duckdb/src/include/duckdb/function/aggregate/minmax_n_helpers.hpp index 55a7a1507..9c59d11cb 100644 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/minmax_n_helpers.hpp +++ b/src/duckdb/src/include/duckdb/function/aggregate/minmax_n_helpers.hpp @@ -8,7 +8,7 @@ #include "duckdb/common/types/vector.hpp" #include "duckdb/common/enums/order_type.hpp" #include "duckdb/function/aggregate_function.hpp" -#include "duckdb/core_functions/create_sort_key.hpp" +#include "duckdb/function/create_sort_key.hpp" namespace duckdb { diff --git a/src/duckdb/src/include/duckdb/core_functions/aggregate/sort_key_helpers.hpp b/src/duckdb/src/include/duckdb/function/aggregate/sort_key_helpers.hpp similarity index 93% rename from src/duckdb/src/include/duckdb/core_functions/aggregate/sort_key_helpers.hpp rename to src/duckdb/src/include/duckdb/function/aggregate/sort_key_helpers.hpp index 12798ae3d..f1ecb86f9 100644 --- a/src/duckdb/src/include/duckdb/core_functions/aggregate/sort_key_helpers.hpp +++ b/src/duckdb/src/include/duckdb/function/aggregate/sort_key_helpers.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/core_functions/aggregate/sort_key_helpers.hpp +// duckdb/function/aggregate/sort_key_helpers.hpp // // //===----------------------------------------------------------------------===// @@ -9,7 +9,7 @@ #pragma once #include "duckdb/common/common.hpp" -#include "duckdb/core_functions/create_sort_key.hpp" +#include "duckdb/function/create_sort_key.hpp" namespace duckdb { diff --git a/src/duckdb/src/include/duckdb/function/aggregate_function.hpp b/src/duckdb/src/include/duckdb/function/aggregate_function.hpp index 4d4ef63ff..d31962413 100644 --- a/src/duckdb/src/include/duckdb/function/aggregate_function.hpp +++ b/src/duckdb/src/include/duckdb/function/aggregate_function.hpp @@ -16,6 +16,8 @@ namespace duckdb { +class BufferManager; + //! A half-open range of frame boundary values _relative to the current row_ //! This is why they are signed values. struct FrameDelta { @@ -29,14 +31,21 @@ struct FrameDelta { using FrameStats = array; //! The partition data for custom window functions +//! Note that if the inputs is nullptr then the column count is 0, +//! but the row count will still be valid +class ColumnDataCollection; struct WindowPartitionInput { - WindowPartitionInput(const Vector inputs[], idx_t input_count, idx_t count, const ValidityMask &filter_mask, + WindowPartitionInput(ClientContext &context, const ColumnDataCollection *inputs, idx_t count, + vector &column_ids, vector &all_valid, const ValidityMask &filter_mask, const FrameStats &stats) - : inputs(inputs), input_count(input_count), count(count), filter_mask(filter_mask), stats(stats) { + : context(context), inputs(inputs), count(count), column_ids(column_ids), all_valid(all_valid), + filter_mask(filter_mask), stats(stats) { } - const Vector *inputs; - idx_t input_count; + ClientContext &context; + const ColumnDataCollection *inputs; idx_t count; + vector column_ids; + vector all_valid; const ValidityMask &filter_mask; const FrameStats stats; }; @@ -94,6 +103,13 @@ struct AggregateFunctionInfo { } }; +enum class AggregateDestructorType { + STANDARD, + // legacy destructors allow non-trivial destructors in aggregate states + // these might not be trivial to off-load to disk + LEGACY +}; + class AggregateFunction : public BaseScalarFunction { // NOLINT: work-around bug in clang-tidy public: AggregateFunction(const string &name, const vector &arguments, const LogicalType &return_type, @@ -197,29 +213,33 @@ class AggregateFunction : public BaseScalarFunction { // NOLINT: work-around bug AggregateFunction::StateFinalize, AggregateFunction::NullaryUpdate); } - template + template static AggregateFunction UnaryAggregate(const LogicalType &input_type, LogicalType return_type, FunctionNullHandling null_handling = FunctionNullHandling::DEFAULT_NULL_HANDLING) { - return AggregateFunction( - {input_type}, return_type, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, AggregateFunction::UnaryScatterUpdate, - AggregateFunction::StateCombine, AggregateFunction::StateFinalize, - null_handling, AggregateFunction::UnaryUpdate); + return AggregateFunction({input_type}, return_type, AggregateFunction::StateSize, + AggregateFunction::StateInitialize, + AggregateFunction::UnaryScatterUpdate, + AggregateFunction::StateCombine, + AggregateFunction::StateFinalize, null_handling, + AggregateFunction::UnaryUpdate); } - template + template static AggregateFunction UnaryAggregateDestructor(LogicalType input_type, LogicalType return_type) { - auto aggregate = UnaryAggregate(input_type, return_type); + auto aggregate = UnaryAggregate(input_type, return_type); aggregate.destructor = AggregateFunction::StateDestroy; return aggregate; } - template + template static AggregateFunction BinaryAggregate(const LogicalType &a_type, const LogicalType &b_type, LogicalType return_type) { return AggregateFunction({a_type, b_type}, return_type, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, + AggregateFunction::StateInitialize, AggregateFunction::BinaryScatterUpdate, AggregateFunction::StateCombine, AggregateFunction::StateFinalize, @@ -232,8 +252,14 @@ class AggregateFunction : public BaseScalarFunction { // NOLINT: work-around bug return sizeof(STATE); } - template + template static void StateInitialize(const AggregateFunction &, data_ptr_t state) { + // FIXME: we should remove the "destructor_type" option in the future +#if !defined(__GNUC__) || (__GNUC__ >= 5) + static_assert(std::is_trivially_move_constructible::value || + destructor_type == AggregateDestructorType::LEGACY, + "Aggregate state must be trivially move constructible"); +#endif OP::Initialize(*reinterpret_cast(state)); } @@ -265,16 +291,6 @@ class AggregateFunction : public BaseScalarFunction { // NOLINT: work-around bug AggregateExecutor::UnaryUpdate(inputs[0], aggr_input_data, state, count); } - template - static void UnaryWindow(AggregateInputData &aggr_input_data, const WindowPartitionInput &partition, - const_data_ptr_t g_state, data_ptr_t l_state, const SubFrames &subframes, Vector &result, - idx_t rid) { - - D_ASSERT(partition.input_count == 1); - AggregateExecutor::UnaryWindow( - partition.inputs[0], partition.filter_mask, aggr_input_data, l_state, subframes, result, rid, g_state); - } - template static void BinaryScatterUpdate(Vector inputs[], AggregateInputData &aggr_input_data, idx_t input_count, Vector &states, idx_t count) { diff --git a/src/duckdb/src/include/duckdb/function/built_in_functions.hpp b/src/duckdb/src/include/duckdb/function/built_in_functions.hpp index 3e665afeb..fb8ef3166 100644 --- a/src/duckdb/src/include/duckdb/function/built_in_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/built_in_functions.hpp @@ -54,19 +54,12 @@ class BuiltinFunctions { void RegisterArrowFunctions(); void RegisterSnifferFunction(); - // aggregates - void RegisterDistributiveAggregates(); - - // scalar functions - void RegisterCompressedMaterializationFunctions(); - void RegisterGenericFunctions(); - void RegisterOperators(); - void RegisterStringFunctions(); - void RegisterNestedFunctions(); - void RegisterSequenceFunctions(); + void RegisterExtensionOverloads(); // pragmas void RegisterPragmaFunctions(); + + void AddExtensionFunction(ScalarFunctionSet set); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/create_sort_key.hpp b/src/duckdb/src/include/duckdb/function/create_sort_key.hpp similarity index 92% rename from src/duckdb/src/include/duckdb/core_functions/create_sort_key.hpp rename to src/duckdb/src/include/duckdb/function/create_sort_key.hpp index 1f464945f..15ddc0d89 100644 --- a/src/duckdb/src/include/duckdb/core_functions/create_sort_key.hpp +++ b/src/duckdb/src/include/duckdb/function/create_sort_key.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/core_functions/create_sort_key.hpp +// duckdb/function/create_sort_key.hpp // // //===----------------------------------------------------------------------===// @@ -46,6 +46,7 @@ struct OrderModifiers { }; struct CreateSortKeyHelpers { + static void CreateSortKey(DataChunk &input, const vector &modifiers, Vector &result); static void CreateSortKey(Vector &input, idx_t input_count, OrderModifiers modifiers, Vector &result); static void DecodeSortKey(string_t sort_key, Vector &result, idx_t result_idx, OrderModifiers modifiers); static void CreateSortKeyWithValidity(Vector &input, Vector &result, const OrderModifiers &modifiers, diff --git a/src/duckdb/src/include/duckdb/core_functions/function_list.hpp b/src/duckdb/src/include/duckdb/function/function_list.hpp similarity index 80% rename from src/duckdb/src/include/duckdb/core_functions/function_list.hpp rename to src/duckdb/src/include/duckdb/function/function_list.hpp index 024ca49f8..a36b1d902 100644 --- a/src/duckdb/src/include/duckdb/core_functions/function_list.hpp +++ b/src/duckdb/src/include/duckdb/function/function_list.hpp @@ -26,8 +26,14 @@ struct StaticFunctionDefinition { get_scalar_function_set_t get_function_set; get_aggregate_function_t get_aggregate_function; get_aggregate_function_set_t get_aggregate_function_set; +}; + +class Catalog; +struct CatalogTransaction; - static const StaticFunctionDefinition *GetFunctionList(); +struct FunctionList { + static const StaticFunctionDefinition *GetInternalFunctionList(); + static void RegisterFunctions(Catalog &catalog, CatalogTransaction transaction); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/function_set.hpp b/src/duckdb/src/include/duckdb/function/function_set.hpp index d20a52737..3a0a223b1 100644 --- a/src/duckdb/src/include/duckdb/function/function_set.hpp +++ b/src/duckdb/src/include/duckdb/function/function_set.hpp @@ -41,23 +41,29 @@ class FunctionSet { D_ASSERT(offset < functions.size()); return functions[offset]; } - bool MergeFunctionSet(FunctionSet new_functions) { + bool MergeFunctionSet(FunctionSet new_functions, bool override = false) { D_ASSERT(!new_functions.functions.empty()); - bool need_rewrite_entry = false; for (auto &new_func : new_functions.functions) { - bool can_add = true; + bool overwritten = false; for (auto &func : functions) { if (new_func.Equal(func)) { - can_add = false; + // function overload already exists + if (override) { + // override it + overwritten = true; + func = new_func; + } else { + // throw an error + return false; + } break; } } - if (can_add) { + if (!overwritten) { functions.push_back(new_func); - need_rewrite_entry = true; } } - return need_rewrite_entry; + return true; } }; diff --git a/src/duckdb/src/include/duckdb/core_functions/lambda_functions.hpp b/src/duckdb/src/include/duckdb/function/lambda_functions.hpp similarity index 99% rename from src/duckdb/src/include/duckdb/core_functions/lambda_functions.hpp rename to src/duckdb/src/include/duckdb/function/lambda_functions.hpp index ea4db5acf..a47894a39 100644 --- a/src/duckdb/src/include/duckdb/core_functions/lambda_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/lambda_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/core_functions/lambda_functions.hpp +// duckdb/function/lambda_functions.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/src/include/duckdb/function/scalar/compressed_materialization_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/compressed_materialization_functions.hpp index aab5dede1..f9e4fe930 100644 --- a/src/duckdb/src/include/duckdb/function/scalar/compressed_materialization_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/compressed_materialization_functions.hpp @@ -1,49 +1,180 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/function/scalar/compressed_materialization_functions.hpp +// function/scalar/compressed_materialization_functions.hpp // // //===----------------------------------------------------------------------===// +// This file is automatically generated by scripts/generate_functions.py +// Do not edit this file manually, your changes will be overwritten +//===----------------------------------------------------------------------===// #pragma once -#include "duckdb/function/built_in_functions.hpp" #include "duckdb/function/function_set.hpp" namespace duckdb { -struct CompressedMaterializationFunctions { - //! The types we compress integral types to - static const vector IntegralTypes(); - //! The types we compress strings to - static const vector StringTypes(); +struct InternalCompressIntegralUtinyintFun { + static constexpr const char *Name = "__internal_compress_integral_utinyint"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct InternalCompressIntegralUsmallintFun { + static constexpr const char *Name = "__internal_compress_integral_usmallint"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct InternalCompressIntegralUintegerFun { + static constexpr const char *Name = "__internal_compress_integral_uinteger"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct InternalCompressIntegralUbigintFun { + static constexpr const char *Name = "__internal_compress_integral_ubigint"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct InternalCompressStringUtinyintFun { + static constexpr const char *Name = "__internal_compress_string_utinyint"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; - static unique_ptr Bind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments); + static ScalarFunction GetFunction(); }; -//! Needed for (de)serialization without binding -enum class CompressedMaterializationDirection : uint8_t { INVALID = 0, COMPRESS = 1, DECOMPRESS = 2 }; +struct InternalCompressStringUsmallintFun { + static constexpr const char *Name = "__internal_compress_string_usmallint"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; -struct CMIntegralCompressFun { - static ScalarFunction GetFunction(const LogicalType &input_type, const LogicalType &result_type); - static void RegisterFunction(BuiltinFunctions &set); + static ScalarFunction GetFunction(); }; -struct CMIntegralDecompressFun { - static ScalarFunction GetFunction(const LogicalType &input_type, const LogicalType &result_type); - static void RegisterFunction(BuiltinFunctions &set); +struct InternalCompressStringUintegerFun { + static constexpr const char *Name = "__internal_compress_string_uinteger"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunction GetFunction(); }; -struct CMStringCompressFun { - static ScalarFunction GetFunction(const LogicalType &result_type); - static void RegisterFunction(BuiltinFunctions &set); +struct InternalCompressStringUbigintFun { + static constexpr const char *Name = "__internal_compress_string_ubigint"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunction GetFunction(); }; -struct CMStringDecompressFun { - static ScalarFunction GetFunction(const LogicalType &input_type); - static void RegisterFunction(BuiltinFunctions &set); +struct InternalCompressStringHugeintFun { + static constexpr const char *Name = "__internal_compress_string_hugeint"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunction GetFunction(); +}; + +struct InternalDecompressIntegralSmallintFun { + static constexpr const char *Name = "__internal_decompress_integral_smallint"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct InternalDecompressIntegralIntegerFun { + static constexpr const char *Name = "__internal_decompress_integral_integer"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct InternalDecompressIntegralBigintFun { + static constexpr const char *Name = "__internal_decompress_integral_bigint"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct InternalDecompressIntegralHugeintFun { + static constexpr const char *Name = "__internal_decompress_integral_hugeint"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct InternalDecompressIntegralUsmallintFun { + static constexpr const char *Name = "__internal_decompress_integral_usmallint"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct InternalDecompressIntegralUintegerFun { + static constexpr const char *Name = "__internal_decompress_integral_uinteger"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct InternalDecompressIntegralUbigintFun { + static constexpr const char *Name = "__internal_decompress_integral_ubigint"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct InternalDecompressIntegralUhugeintFun { + static constexpr const char *Name = "__internal_decompress_integral_uhugeint"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct InternalDecompressStringFun { + static constexpr const char *Name = "__internal_decompress_string"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/compressed_materialization_utils.hpp b/src/duckdb/src/include/duckdb/function/scalar/compressed_materialization_utils.hpp new file mode 100644 index 000000000..8609999a9 --- /dev/null +++ b/src/duckdb/src/include/duckdb/function/scalar/compressed_materialization_utils.hpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/function/scalar/compressed_materialization_utils.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/function/built_in_functions.hpp" +#include "duckdb/function/function_set.hpp" + +namespace duckdb { + +struct CMUtils { + //! The types we compress integral types to + static const vector IntegralTypes(); + //! The types we compress strings to + static const vector StringTypes(); + + static unique_ptr Bind(ClientContext &context, ScalarFunction &bound_function, + vector> &arguments); +}; + +//! Needed for (de)serialization without binding +enum class CompressedMaterializationDirection : uint8_t { INVALID = 0, COMPRESS = 1, DECOMPRESS = 2 }; + +struct CMIntegralCompressFun { + static ScalarFunction GetFunction(const LogicalType &input_type, const LogicalType &result_type); +}; + +struct CMIntegralDecompressFun { + static ScalarFunction GetFunction(const LogicalType &input_type, const LogicalType &result_type); +}; + +struct CMStringCompressFun { + static ScalarFunction GetFunction(const LogicalType &result_type); +}; + +struct CMStringDecompressFun { + static ScalarFunction GetFunction(const LogicalType &input_type); +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/date_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/date_functions.hpp new file mode 100644 index 000000000..66cf9502c --- /dev/null +++ b/src/duckdb/src/include/duckdb/function/scalar/date_functions.hpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// function/scalar/date_functions.hpp +// +// +//===----------------------------------------------------------------------===// +// This file is automatically generated by scripts/generate_functions.py +// Do not edit this file manually, your changes will be overwritten +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/function/function_set.hpp" + +namespace duckdb { + +struct StrfTimeFun { + static constexpr const char *Name = "strftime"; + static constexpr const char *Parameters = "data,format"; + static constexpr const char *Description = "Converts a date to a string according to the format string."; + static constexpr const char *Example = "strftime(date '1992-01-01', '%a, %-d %B %Y')"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct StrpTimeFun { + static constexpr const char *Name = "strptime"; + static constexpr const char *Parameters = "text,format"; + static constexpr const char *Description = "Converts the string text to timestamp according to the format string. Throws an error on failure. To return NULL on failure, use try_strptime."; + static constexpr const char *Example = "strptime('Wed, 1 January 1992 - 08:38:40 PM', '%a, %-d %B %Y - %I:%M:%S %p')"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct TryStrpTimeFun { + static constexpr const char *Name = "try_strptime"; + static constexpr const char *Parameters = "text,format"; + static constexpr const char *Description = "Converts the string text to timestamp according to the format string. Returns NULL on failure."; + static constexpr const char *Example = "try_strptime('Wed, 1 January 1992 - 08:38:40 PM', '%a, %-d %B %Y - %I:%M:%S %p')"; + + static ScalarFunctionSet GetFunctions(); +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/generic_common.hpp b/src/duckdb/src/include/duckdb/function/scalar/generic_common.hpp new file mode 100644 index 000000000..f4a4089e6 --- /dev/null +++ b/src/duckdb/src/include/duckdb/function/scalar/generic_common.hpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/function/scalar/generic_common.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/function/scalar_function.hpp" +#include "duckdb/function/function_set.hpp" +#include "duckdb/function/built_in_functions.hpp" +#include "duckdb/common/serializer/serializer.hpp" +#include "duckdb/common/serializer/deserializer.hpp" + +namespace duckdb { +class BoundFunctionExpression; + +struct ConstantOrNull { + static unique_ptr Bind(Value value); + static bool IsConstantOrNull(BoundFunctionExpression &expr, const Value &val); +}; + +struct ExportAggregateFunctionBindData : public FunctionData { + unique_ptr aggregate; + explicit ExportAggregateFunctionBindData(unique_ptr aggregate_p); + unique_ptr Copy() const override; + bool Equals(const FunctionData &other_p) const override; +}; + +struct ExportAggregateFunction { + static unique_ptr Bind(unique_ptr child_aggregate); +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/generic_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/generic_functions.hpp index abd1713ed..fd2865e6c 100644 --- a/src/duckdb/src/include/duckdb/function/scalar/generic_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/generic_functions.hpp @@ -1,45 +1,54 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/function/scalar/generic_functions.hpp +// function/scalar/generic_functions.hpp // // //===----------------------------------------------------------------------===// +// This file is automatically generated by scripts/generate_functions.py +// Do not edit this file manually, your changes will be overwritten +//===----------------------------------------------------------------------===// #pragma once -#include "duckdb/function/scalar_function.hpp" #include "duckdb/function/function_set.hpp" -#include "duckdb/function/built_in_functions.hpp" -#include "duckdb/common/serializer/serializer.hpp" -#include "duckdb/common/serializer/deserializer.hpp" namespace duckdb { -class BoundFunctionExpression; -struct ConstantOrNull { - static ScalarFunction GetFunction(const LogicalType &return_type); - static unique_ptr Bind(Value value); - static bool IsConstantOrNull(BoundFunctionExpression &expr, const Value &val); - static void RegisterFunction(BuiltinFunctions &set); +struct ConstantOrNullFun { + static constexpr const char *Name = "constant_or_null"; + static constexpr const char *Parameters = "arg1,arg2"; + static constexpr const char *Description = "If arg2 is NULL, return NULL. Otherwise, return arg1."; + static constexpr const char *Example = "constant_or_null(42, NULL)"; + + static ScalarFunction GetFunction(); }; -struct ExportAggregateFunctionBindData : public FunctionData { - unique_ptr aggregate; - explicit ExportAggregateFunctionBindData(unique_ptr aggregate_p); - unique_ptr Copy() const override; - bool Equals(const FunctionData &other_p) const override; +struct GetVariableFun { + static constexpr const char *Name = "getvariable"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunction GetFunction(); }; -struct ExportAggregateFunction { - static unique_ptr Bind(unique_ptr child_aggregate); - static ScalarFunction GetCombine(); - static ScalarFunction GetFinalize(); - static void RegisterFunction(BuiltinFunctions &set); +struct ErrorFun { + static constexpr const char *Name = "error"; + static constexpr const char *Parameters = "message"; + static constexpr const char *Description = "Throws the given error message"; + static constexpr const char *Example = "error('access_mode')"; + + static ScalarFunction GetFunction(); }; -struct GetVariableFun { - static void RegisterFunction(BuiltinFunctions &set); +struct CreateSortKeyFun { + static constexpr const char *Name = "create_sort_key"; + static constexpr const char *Parameters = "parameters..."; + static constexpr const char *Description = "Constructs a binary-comparable sort key based on a set of input parameters and sort qualifiers"; + static constexpr const char *Example = "create_sort_key('A', 'DESC')"; + + static ScalarFunction GetFunction(); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/list/contains_or_position.hpp b/src/duckdb/src/include/duckdb/function/scalar/list/contains_or_position.hpp index 2af4b12d7..1c091e7da 100644 --- a/src/duckdb/src/include/duckdb/function/scalar/list/contains_or_position.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/list/contains_or_position.hpp @@ -1,5 +1,5 @@ #pragma once -#include "duckdb/core_functions/create_sort_key.hpp" +#include "duckdb/function/create_sort_key.hpp" #include "duckdb/common/operator/comparison_operators.hpp" namespace duckdb { diff --git a/src/duckdb/src/include/duckdb/function/scalar/list_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/list_functions.hpp new file mode 100644 index 000000000..577b643f6 --- /dev/null +++ b/src/duckdb/src/include/duckdb/function/scalar/list_functions.hpp @@ -0,0 +1,156 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// function/scalar/list_functions.hpp +// +// +//===----------------------------------------------------------------------===// +// This file is automatically generated by scripts/generate_functions.py +// Do not edit this file manually, your changes will be overwritten +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/function/function_set.hpp" + +namespace duckdb { + +struct ListSelectFun { + static constexpr const char *Name = "list_select"; + static constexpr const char *Parameters = "value_list,index_list"; + static constexpr const char *Description = "Returns a list based on the elements selected by the index_list."; + static constexpr const char *Example = "list_select([10, 20, 30, 40], [1, 4])"; + + static ScalarFunction GetFunction(); +}; + +struct ArraySelectFun { + using ALIAS = ListSelectFun; + + static constexpr const char *Name = "array_select"; +}; + +struct ListWhereFun { + static constexpr const char *Name = "list_where"; + static constexpr const char *Parameters = "value_list,mask_list"; + static constexpr const char *Description = "Returns a list with the BOOLEANs in mask_list applied as a mask to the value_list."; + static constexpr const char *Example = "list_where([10, 20, 30, 40], [true, false, false, true])"; + + static ScalarFunction GetFunction(); +}; + +struct ArrayWhereFun { + using ALIAS = ListWhereFun; + + static constexpr const char *Name = "array_where"; +}; + +struct ListContainsFun { + static constexpr const char *Name = "list_contains"; + static constexpr const char *Parameters = "list,element"; + static constexpr const char *Description = "Returns true if the list contains the element."; + static constexpr const char *Example = "list_contains([1, 2, NULL], 1)"; + + static ScalarFunction GetFunction(); +}; + +struct ArrayContainsFun { + using ALIAS = ListContainsFun; + + static constexpr const char *Name = "array_contains"; +}; + +struct ListHasFun { + using ALIAS = ListContainsFun; + + static constexpr const char *Name = "list_has"; +}; + +struct ArrayHasFun { + using ALIAS = ListContainsFun; + + static constexpr const char *Name = "array_has"; +}; + +struct ListPositionFun { + static constexpr const char *Name = "list_position"; + static constexpr const char *Parameters = "list,element"; + static constexpr const char *Description = "Returns the index of the element if the list contains the element. If the element is not found, it returns NULL."; + static constexpr const char *Example = "list_position([1, 2, NULL], 2)"; + + static ScalarFunction GetFunction(); +}; + +struct ListIndexofFun { + using ALIAS = ListPositionFun; + + static constexpr const char *Name = "list_indexof"; +}; + +struct ArrayPositionFun { + using ALIAS = ListPositionFun; + + static constexpr const char *Name = "array_position"; +}; + +struct ArrayIndexofFun { + using ALIAS = ListPositionFun; + + static constexpr const char *Name = "array_indexof"; +}; + +struct ListZipFun { + static constexpr const char *Name = "list_zip"; + static constexpr const char *Parameters = "list1,list2,..."; + static constexpr const char *Description = "Zips k LISTs to a new LIST whose length will be that of the longest list. Its elements are structs of k elements from each list list_1, …, list_k, missing elements are replaced with NULL. If truncate is set, all lists are truncated to the smallest list length."; + static constexpr const char *Example = "list_zip([1, 2], [3, 4], [5, 6])"; + + static ScalarFunction GetFunction(); +}; + +struct ArrayZipFun { + using ALIAS = ListZipFun; + + static constexpr const char *Name = "array_zip"; +}; + +struct ListExtractFun { + static constexpr const char *Name = "list_extract"; + static constexpr const char *Parameters = "list,index"; + static constexpr const char *Description = "Extract the indexth (1-based) value from the list."; + static constexpr const char *Example = "list_extract([4, 5, 6], 3)"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct ListElementFun { + using ALIAS = ListExtractFun; + + static constexpr const char *Name = "list_element"; +}; + +struct ListResizeFun { + static constexpr const char *Name = "list_resize"; + static constexpr const char *Parameters = "list,size[,value]"; + static constexpr const char *Description = "Resizes the list to contain size elements. Initializes new elements with value or NULL if value is not set."; + static constexpr const char *Example = "list_resize([1, 2, 3], 5, 0)"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct ArrayResizeFun { + using ALIAS = ListResizeFun; + + static constexpr const char *Name = "array_resize"; +}; + +struct ArrayExtractFun { + static constexpr const char *Name = "array_extract"; + static constexpr const char *Parameters = "list,index"; + static constexpr const char *Description = "Extract the indexth (1-based) value from the array."; + static constexpr const char *Example = "array_extract('DuckDB', 2)"; + + static ScalarFunctionSet GetFunctions(); +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/scalar/debug_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/map_functions.hpp similarity index 61% rename from src/duckdb/src/include/duckdb/core_functions/scalar/debug_functions.hpp rename to src/duckdb/src/include/duckdb/function/scalar/map_functions.hpp index 5c83d51c8..5814a00e3 100644 --- a/src/duckdb/src/include/duckdb/core_functions/scalar/debug_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/map_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/core_functions/scalar/debug_functions.hpp +// function/scalar/map_functions.hpp // // //===----------------------------------------------------------------------===// @@ -15,11 +15,11 @@ namespace duckdb { -struct VectorTypeFun { - static constexpr const char *Name = "vector_type"; - static constexpr const char *Parameters = "col"; - static constexpr const char *Description = "Returns the VectorType of a given column"; - static constexpr const char *Example = "vector_type(col)"; +struct MapContainsFun { + static constexpr const char *Name = "map_contains"; + static constexpr const char *Parameters = "map,key"; + static constexpr const char *Description = "Checks if a map contains a given key."; + static constexpr const char *Example = "map_contains(MAP {'key1': 10, 'key2': 20, 'key3': 30}, 'key2')"; static ScalarFunction GetFunction(); }; diff --git a/src/duckdb/src/include/duckdb/function/scalar/nested_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/nested_functions.hpp index e7b2f55ca..bbad8b75c 100644 --- a/src/duckdb/src/include/duckdb/function/scalar/nested_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/nested_functions.hpp @@ -82,50 +82,8 @@ struct HistogramAggState { MAP_TYPE *hist; }; -struct ListExtractFun { - static void RegisterFunction(BuiltinFunctions &set); -}; - -struct ListConcatFun { - static ScalarFunction GetFunction(); - static void RegisterFunction(BuiltinFunctions &set); -}; - -struct ListContainsFun { - static ScalarFunction GetFunction(); - static void RegisterFunction(BuiltinFunctions &set); -}; - -struct ListPositionFun { - static ScalarFunction GetFunction(); - static void RegisterFunction(BuiltinFunctions &set); -}; - -struct ListResizeFun { - static void RegisterFunction(BuiltinFunctions &set); -}; - -struct ListZipFun { - static ScalarFunction GetFunction(); - static void RegisterFunction(BuiltinFunctions &set); -}; - -struct ListSelectFun { - static ScalarFunction GetFunction(); - static void RegisterFunction(BuiltinFunctions &set); -}; - -struct ListWhereFun { - static ScalarFunction GetFunction(); - static void RegisterFunction(BuiltinFunctions &set); -}; - -struct StructExtractFun { - static ScalarFunction KeyExtractFunction(); - static ScalarFunction IndexExtractFunction(); - static ScalarFunctionSet GetFunctions(); - static unique_ptr GetBindData(idx_t index); - static void RegisterFunction(BuiltinFunctions &set); -}; +unique_ptr GetBindData(idx_t index); +ScalarFunction GetKeyExtractFunction(); +ScalarFunction GetIndexExtractFunction(); } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/operator_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/operator_functions.hpp new file mode 100644 index 000000000..dbb7a1461 --- /dev/null +++ b/src/duckdb/src/include/duckdb/function/scalar/operator_functions.hpp @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// function/scalar/operator_functions.hpp +// +// +//===----------------------------------------------------------------------===// +// This file is automatically generated by scripts/generate_functions.py +// Do not edit this file manually, your changes will be overwritten +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/function/function_set.hpp" + +namespace duckdb { + +struct OperatorAddFun { + static constexpr const char *Name = "+"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct AddFun { + using ALIAS = OperatorAddFun; + + static constexpr const char *Name = "add"; +}; + +struct OperatorSubtractFun { + static constexpr const char *Name = "-"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct SubtractFun { + using ALIAS = OperatorSubtractFun; + + static constexpr const char *Name = "subtract"; +}; + +struct OperatorMultiplyFun { + static constexpr const char *Name = "*"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct MultiplyFun { + using ALIAS = OperatorMultiplyFun; + + static constexpr const char *Name = "multiply"; +}; + +struct OperatorFloatDivideFun { + static constexpr const char *Name = "/"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct OperatorIntegerDivideFun { + static constexpr const char *Name = "//"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct DivideFun { + using ALIAS = OperatorIntegerDivideFun; + + static constexpr const char *Name = "divide"; +}; + +struct OperatorModuloFun { + static constexpr const char *Name = "%"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct ModFun { + using ALIAS = OperatorModuloFun; + + static constexpr const char *Name = "mod"; +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/operators.hpp b/src/duckdb/src/include/duckdb/function/scalar/operators.hpp index 90689a335..f23c5c3bc 100644 --- a/src/duckdb/src/include/duckdb/function/scalar/operators.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/operators.hpp @@ -14,28 +14,14 @@ namespace duckdb { -struct AddFun { +struct AddFunction { static ScalarFunction GetFunction(const LogicalType &type); static ScalarFunction GetFunction(const LogicalType &left_type, const LogicalType &right_type); - static void RegisterFunction(BuiltinFunctions &set); }; -struct SubtractFun { +struct SubtractFunction { static ScalarFunction GetFunction(const LogicalType &type); static ScalarFunction GetFunction(const LogicalType &left_type, const LogicalType &right_type); - static void RegisterFunction(BuiltinFunctions &set); -}; - -struct MultiplyFun { - static void RegisterFunction(BuiltinFunctions &set); -}; - -struct DivideFun { - static void RegisterFunction(BuiltinFunctions &set); -}; - -struct ModFun { - static void RegisterFunction(BuiltinFunctions &set); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/sequence_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/sequence_functions.hpp index 34103bfc1..d7f6eb01a 100644 --- a/src/duckdb/src/include/duckdb/function/scalar/sequence_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/sequence_functions.hpp @@ -1,45 +1,36 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/function/scalar/sequence_functions.hpp +// function/scalar/sequence_functions.hpp // // //===----------------------------------------------------------------------===// +// This file is automatically generated by scripts/generate_functions.py +// Do not edit this file manually, your changes will be overwritten +//===----------------------------------------------------------------------===// #pragma once -#include "duckdb/catalog/catalog_entry/sequence_catalog_entry.hpp" -#include "duckdb/function/scalar_function.hpp" #include "duckdb/function/function_set.hpp" -#include "duckdb/function/built_in_functions.hpp" namespace duckdb { -struct NextvalBindData : public FunctionData { - explicit NextvalBindData(SequenceCatalogEntry &sequence) : sequence(sequence), create_info(sequence.GetInfo()) { - } - - //! The sequence to use for the nextval computation; only if the sequence is a constant - SequenceCatalogEntry &sequence; - - //! The CreateInfo for the above sequence, if it exists - unique_ptr create_info; - - unique_ptr Copy() const override { - return make_uniq(sequence); - } +struct CurrvalFun { + static constexpr const char *Name = "currval"; + static constexpr const char *Parameters = "'sequence_name'"; + static constexpr const char *Description = "Return the current value of the sequence. Note that nextval must be called at least once prior to calling currval."; + static constexpr const char *Example = "currval('my_sequence_name')"; - bool Equals(const FunctionData &other_p) const override { - auto &other = other_p.Cast(); - return RefersToSameObject(sequence, other.sequence); - } + static ScalarFunction GetFunction(); }; struct NextvalFun { - static void RegisterFunction(BuiltinFunctions &set); -}; + static constexpr const char *Name = "nextval"; + static constexpr const char *Parameters = "'sequence_name'"; + static constexpr const char *Description = "Return the following value of the sequence."; + static constexpr const char *Example = "nextval('my_sequence_name')"; -struct CurrvalFun { - static void RegisterFunction(BuiltinFunctions &set); + static ScalarFunction GetFunction(); }; + } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/sequence_utils.hpp b/src/duckdb/src/include/duckdb/function/scalar/sequence_utils.hpp new file mode 100644 index 000000000..642e53f9c --- /dev/null +++ b/src/duckdb/src/include/duckdb/function/scalar/sequence_utils.hpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/function/scalar/sequence_functions.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/catalog/catalog_entry/sequence_catalog_entry.hpp" +#include "duckdb/function/scalar_function.hpp" +#include "duckdb/function/function_set.hpp" +#include "duckdb/function/built_in_functions.hpp" + +namespace duckdb { + +struct NextvalBindData : public FunctionData { + explicit NextvalBindData(SequenceCatalogEntry &sequence) : sequence(sequence), create_info(sequence.GetInfo()) { + } + + //! The sequence to use for the nextval computation; only if the sequence is a constant + SequenceCatalogEntry &sequence; + + //! The CreateInfo for the above sequence, if it exists + unique_ptr create_info; + + unique_ptr Copy() const override { + return make_uniq(sequence); + } + + bool Equals(const FunctionData &other_p) const override { + auto &other = other_p.Cast(); + return RefersToSameObject(sequence, other.sequence); + } +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/string_common.hpp b/src/duckdb/src/include/duckdb/function/scalar/string_common.hpp new file mode 100644 index 000000000..4cf00d8c4 --- /dev/null +++ b/src/duckdb/src/include/duckdb/function/scalar/string_common.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include "duckdb/common/typedefs.hpp" +#include "duckdb/function/scalar_function.hpp" +#include "utf8proc_wrapper.hpp" + +namespace duckdb { + +bool IsAscii(const char *input, idx_t n); +idx_t LowerLength(const char *input_data, idx_t input_length); +void LowerCase(const char *input_data, idx_t input_length, char *result_data); +idx_t FindStrInStr(const string_t &haystack_s, const string_t &needle_s); +idx_t FindStrInStr(const unsigned char *haystack, idx_t haystack_size, const unsigned char *needle, idx_t needle_size); +string_t SubstringASCII(Vector &result, string_t input, int64_t offset, int64_t length); +string_t SubstringUnicode(Vector &result, string_t input, int64_t offset, int64_t length); +string_t SubstringGrapheme(Vector &result, string_t input, int64_t offset, int64_t length); + +ScalarFunction GetStringContains(); +DUCKDB_API bool Glob(const char *s, idx_t slen, const char *pattern, idx_t plen, bool allow_question_mark = true); + +static inline bool IsCharacter(char c) { + return (c & 0xc0) != 0x80; +} + +template +static inline TR Length(TA input) { + auto input_data = input.GetData(); + auto input_length = input.GetSize(); + TR length = 0; + for (idx_t i = 0; i < input_length; i++) { + length += IsCharacter(input_data[i]); + } + return length; +} + +template +static inline TR GraphemeCount(TA input) { + auto input_data = input.GetData(); + auto input_length = input.GetSize(); + for (idx_t i = 0; i < input_length; i++) { + if (input_data[i] & 0x80) { + // non-ascii character: use grapheme iterator on remainder of string + return UnsafeNumericCast(Utf8Proc::GraphemeCount(input_data, input_length)); + } + } + return UnsafeNumericCast(input_length); +} + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/string_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/string_functions.hpp index 76dda0878..6c6c0d1ff 100644 --- a/src/duckdb/src/include/duckdb/function/scalar/string_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/string_functions.hpp @@ -1,131 +1,450 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/function/scalar/string_functions.hpp +// function/scalar/string_functions.hpp // // //===----------------------------------------------------------------------===// +// This file is automatically generated by scripts/generate_functions.py +// Do not edit this file manually, your changes will be overwritten +//===----------------------------------------------------------------------===// #pragma once #include "duckdb/function/function_set.hpp" -#include "utf8proc_wrapper.hpp" -#include "duckdb/function/built_in_functions.hpp" - -namespace duckdb_re2 { -class RE2; -} namespace duckdb { -struct LowerFun { - static const uint8_t ASCII_TO_LOWER_MAP[]; +struct UpperFun { + static constexpr const char *Name = "upper"; + static constexpr const char *Parameters = "string"; + static constexpr const char *Description = "Convert string to upper case."; + static constexpr const char *Example = "upper('Hello')"; + + static ScalarFunction GetFunction(); +}; + +struct UcaseFun { + using ALIAS = UpperFun; + + static constexpr const char *Name = "ucase"; +}; - //! Returns the length of the result string obtained from lowercasing the given input (in bytes) - static idx_t LowerLength(const char *input_data, idx_t input_length); - //! Lowercases the string to the target output location, result_data must have space for at least LowerLength bytes - static void LowerCase(const char *input_data, idx_t input_length, char *result_data); +struct LowerFun { + static constexpr const char *Name = "lower"; + static constexpr const char *Parameters = "string"; + static constexpr const char *Description = "Convert string to lower case"; + static constexpr const char *Example = "lower('Hello')"; static ScalarFunction GetFunction(); - static void RegisterFunction(BuiltinFunctions &set); }; -struct UpperFun { - static const uint8_t ASCII_TO_UPPER_MAP[]; +struct LcaseFun { + using ALIAS = LowerFun; - static void RegisterFunction(BuiltinFunctions &set); + static constexpr const char *Name = "lcase"; }; -struct StripAccentsFun { - static bool IsAscii(const char *input, idx_t n); +struct ConcatWsFun { + static constexpr const char *Name = "concat_ws"; + static constexpr const char *Parameters = "separator,string,..."; + static constexpr const char *Description = "Concatenate strings together separated by the specified separator."; + static constexpr const char *Example = "concat_ws(', ', 'Banana', 'Apple', 'Melon')"; + static ScalarFunction GetFunction(); - static void RegisterFunction(BuiltinFunctions &set); }; struct ConcatFun { - static void RegisterFunction(BuiltinFunctions &set); + static constexpr const char *Name = "concat"; + static constexpr const char *Parameters = "string,..."; + static constexpr const char *Description = "Concatenate many strings together."; + static constexpr const char *Example = "concat('Hello', ' ', 'World')"; + static ScalarFunction GetFunction(); }; -struct ConcatWSFun { - static void RegisterFunction(BuiltinFunctions &set); -}; +struct ListConcatFun { + static constexpr const char *Name = "list_concat"; + static constexpr const char *Parameters = "list1,list2"; + static constexpr const char *Description = "Concatenates two lists."; + static constexpr const char *Example = "list_concat([2, 3], [4, 5, 6])"; -struct LengthFun { - static void RegisterFunction(BuiltinFunctions &set); - static inline bool IsCharacter(char c) { - return (c & 0xc0) != 0x80; - } - - template - static inline TR Length(TA input) { - auto input_data = input.GetData(); - auto input_length = input.GetSize(); - TR length = 0; - for (idx_t i = 0; i < input_length; i++) { - length += IsCharacter(input_data[i]); - } - return length; - } - - template - static inline TR GraphemeCount(TA input) { - auto input_data = input.GetData(); - auto input_length = input.GetSize(); - for (idx_t i = 0; i < input_length; i++) { - if (input_data[i] & 0x80) { - // non-ascii character: use grapheme iterator on remainder of string - return UnsafeNumericCast(Utf8Proc::GraphemeCount(input_data, input_length)); - } - } - return UnsafeNumericCast(input_length); - } + static ScalarFunction GetFunction(); }; -struct LikeFun { - static ScalarFunction GetLikeFunction(); - static void RegisterFunction(BuiltinFunctions &set); - DUCKDB_API static bool Glob(const char *s, idx_t slen, const char *pattern, idx_t plen, - bool allow_question_mark = true); +struct ListCatFun { + using ALIAS = ListConcatFun; + + static constexpr const char *Name = "list_cat"; }; -struct LikeEscapeFun { - static ScalarFunction GetLikeEscapeFun(); - static void RegisterFunction(BuiltinFunctions &set); +struct ArrayConcatFun { + using ALIAS = ListConcatFun; + + static constexpr const char *Name = "array_concat"; }; -struct NFCNormalizeFun { - static ScalarFunction GetFunction(); - static void RegisterFunction(BuiltinFunctions &set); +struct ArrayCatFun { + using ALIAS = ListConcatFun; + + static constexpr const char *Name = "array_cat"; }; -struct SubstringFun { - static void RegisterFunction(BuiltinFunctions &set); - static string_t SubstringUnicode(Vector &result, string_t input, int64_t offset, int64_t length); - static string_t SubstringGrapheme(Vector &result, string_t input, int64_t offset, int64_t length); +struct ConcatOperatorFun { + static constexpr const char *Name = "||"; + static constexpr const char *Parameters = "list1,list2"; + static constexpr const char *Description = "Concatenates two lists."; + static constexpr const char *Example = "list_concat([2, 3], [4, 5, 6])"; + + static ScalarFunction GetFunction(); }; struct PrefixFun { + static constexpr const char *Name = "prefix"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + static ScalarFunction GetFunction(); - static void RegisterFunction(BuiltinFunctions &set); }; struct SuffixFun { + static constexpr const char *Name = "suffix"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + static ScalarFunction GetFunction(); - static void RegisterFunction(BuiltinFunctions &set); }; struct ContainsFun { + static constexpr const char *Name = "contains"; + static constexpr const char *Parameters = "string,search_string"; + static constexpr const char *Description = "Return true if search_string is found within string."; + static constexpr const char *Example = "contains('abc', 'a')"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct StripAccentsFun { + static constexpr const char *Name = "strip_accents"; + static constexpr const char *Parameters = "string"; + static constexpr const char *Description = "Strips accents from string."; + static constexpr const char *Example = "strip_accents('mühleisen')"; + + static ScalarFunction GetFunction(); +}; + +struct NFCNormalizeFun { + static constexpr const char *Name = "nfc_normalize"; + static constexpr const char *Parameters = "string"; + static constexpr const char *Description = "Convert string to Unicode NFC normalized string. Useful for comparisons and ordering if text data is mixed between NFC normalized and not."; + static constexpr const char *Example = "nfc_normalize('ardèch')"; + + static ScalarFunction GetFunction(); +}; + +struct LengthFun { + static constexpr const char *Name = "length"; + static constexpr const char *Parameters = "string"; + static constexpr const char *Description = "Number of characters in string."; + static constexpr const char *Example = "length('Hello🦆')"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct LenFun { + using ALIAS = LengthFun; + + static constexpr const char *Name = "len"; +}; + +struct StrlenFun { + static constexpr const char *Name = "strlen"; + static constexpr const char *Parameters = "string"; + static constexpr const char *Description = "Number of bytes in string."; + static constexpr const char *Example = "strlen('🦆')"; + + static ScalarFunction GetFunction(); +}; + +struct BitLengthFun { + static constexpr const char *Name = "bit_length"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunctionSet GetFunctions(); +}; + +struct OctetLengthFun { + static constexpr const char *Name = "octet_length"; + static constexpr const char *Parameters = "blob"; + static constexpr const char *Description = "Number of bytes in blob."; + static constexpr const char *Example = "octet_length('\\xAA\\xBB'::BLOB)"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct LengthGraphemeFun { + static constexpr const char *Name = "length_grapheme"; + static constexpr const char *Parameters = "string"; + static constexpr const char *Description = "Number of grapheme clusters in string."; + static constexpr const char *Example = "length_grapheme('🤦🏼‍♂️🤦🏽‍♀️')"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct ArrayLengthFun { + static constexpr const char *Name = "array_length"; + static constexpr const char *Parameters = "list"; + static constexpr const char *Description = "Returns the length of the list."; + static constexpr const char *Example = "array_length([1,2,3])"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct SubstringFun { + static constexpr const char *Name = "substring"; + static constexpr const char *Parameters = "string,start,length"; + static constexpr const char *Description = "Extract substring of length characters starting from character start. Note that a start value of 1 refers to the first character of the string."; + static constexpr const char *Example = "substring('Hello', 2, 2)"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct SubstrFun { + using ALIAS = SubstringFun; + + static constexpr const char *Name = "substr"; +}; + +struct SubstringGraphemeFun { + static constexpr const char *Name = "substring_grapheme"; + static constexpr const char *Parameters = "string,start,length"; + static constexpr const char *Description = "Extract substring of length grapheme clusters starting from character start. Note that a start value of 1 refers to the first character of the string."; + static constexpr const char *Example = "substring_grapheme('🦆🤦🏼‍♂️🤦🏽‍♀️🦆', 3, 2)"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct StringSplitFun { + static constexpr const char *Name = "string_split"; + static constexpr const char *Parameters = "string,separator"; + static constexpr const char *Description = "Splits the string along the separator"; + static constexpr const char *Example = "string_split('hello-world', '-')"; + + static ScalarFunction GetFunction(); +}; + +struct StrSplitFun { + using ALIAS = StringSplitFun; + + static constexpr const char *Name = "str_split"; +}; + +struct StringToArrayFun { + using ALIAS = StringSplitFun; + + static constexpr const char *Name = "string_to_array"; +}; + +struct SplitFun { + using ALIAS = StringSplitFun; + + static constexpr const char *Name = "split"; +}; + +struct StringSplitRegexFun { + static constexpr const char *Name = "string_split_regex"; + static constexpr const char *Parameters = "string,separator"; + static constexpr const char *Description = "Splits the string along the regex"; + static constexpr const char *Example = "string_split_regex('hello␣world; 42', ';?␣')"; + static ScalarFunctionSet GetFunctions(); - static ScalarFunction GetStringContains(); - static void RegisterFunction(BuiltinFunctions &set); - static idx_t Find(const string_t &haystack, const string_t &needle); - static idx_t Find(const unsigned char *haystack, idx_t haystack_size, const unsigned char *needle, - idx_t needle_size); +}; + +struct StrSplitRegexFun { + using ALIAS = StringSplitRegexFun; + + static constexpr const char *Name = "str_split_regex"; +}; + +struct RegexpSplitToArrayFun { + using ALIAS = StringSplitRegexFun; + + static constexpr const char *Name = "regexp_split_to_array"; }; struct RegexpFun { - static void RegisterFunction(BuiltinFunctions &set); + static constexpr const char *Name = "regexp_full_match"; + static constexpr const char *Parameters = "string,regex[,options]"; + static constexpr const char *Description = "Returns true if the entire string matches the regex. A set of optional options can be set."; + static constexpr const char *Example = "regexp_full_match('anabanana', '(an)*')"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct RegexpMatchesFun { + static constexpr const char *Name = "regexp_matches"; + static constexpr const char *Parameters = "string,pattern[,options]"; + static constexpr const char *Description = "Returns true if string contains the regexp pattern, false otherwise. A set of optional options can be set."; + static constexpr const char *Example = "regexp_matches('anabanana', '(an)*')"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct RegexpReplaceFun { + static constexpr const char *Name = "regexp_replace"; + static constexpr const char *Parameters = "string,pattern,replacement[,options]"; + static constexpr const char *Description = "If string contains the regexp pattern, replaces the matching part with replacement. A set of optional options can be set."; + static constexpr const char *Example = "regexp_replace('hello', '[lo]', '-')"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct RegexpExtractFun { + static constexpr const char *Name = "regexp_extract"; + static constexpr const char *Parameters = "string,pattern[,group = 0][,options]"; + static constexpr const char *Description = "If string contains the regexp pattern, returns the capturing group specified by optional parameter group. The group must be a constant value. If no group is given, it defaults to 0. A set of optional options can be set."; + static constexpr const char *Example = "regexp_extract('abc', '([a-z])(b)', 1)"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct RegexpExtractAllFun { + static constexpr const char *Name = "regexp_extract_all"; + static constexpr const char *Parameters = "string, regex[, group = 0][, options]"; + static constexpr const char *Description = "Split the string along the regex and extract all occurrences of group. A set of optional options can be set."; + static constexpr const char *Example = "regexp_extract_all('hello_world', '([a-z ]+)_?', 1)"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct RegexpEscapeFun { + static constexpr const char *Name = "regexp_escape"; + static constexpr const char *Parameters = "string"; + static constexpr const char *Description = "Escapes all potentially meaningful regexp characters in the input string"; + static constexpr const char *Example = "regexp_escape('https://duckdb.org')"; + + static ScalarFunction GetFunction(); +}; + +struct LikeFun { + static constexpr const char *Name = "~~"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunction GetFunction(); +}; + +struct NotLikeFun { + static constexpr const char *Name = "!~~"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunction GetFunction(); +}; + +struct GlobPatternFun { + static constexpr const char *Name = "~~~"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunction GetFunction(); +}; + +struct ILikeFun { + static constexpr const char *Name = "~~*"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunction GetFunction(); +}; + +struct NotILikeFun { + static constexpr const char *Name = "!~~*"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunction GetFunction(); +}; + +struct LikeEscapeFun { + static constexpr const char *Name = "like_escape"; + static constexpr const char *Parameters = "string,like_specifier,escape_character"; + static constexpr const char *Description = "Returns true if the string matches the like_specifier (see Pattern Matching) using case-sensitive matching. escape_character is used to search for wildcard characters in the string."; + static constexpr const char *Example = "like_escape('a%c', 'a$%c', '$')"; + + static ScalarFunction GetFunction(); +}; + +struct NotLikeEscapeFun { + static constexpr const char *Name = "not_like_escape"; + static constexpr const char *Parameters = "string,like_specifier,escape_character"; + static constexpr const char *Description = "Returns false if the string matches the like_specifier (see Pattern Matching) using case-sensitive matching. escape_character is used to search for wildcard characters in the string."; + static constexpr const char *Example = "not_like_escape('a%c', 'a$%c', '$')"; + + static ScalarFunction GetFunction(); +}; + +struct IlikeEscapeFun { + static constexpr const char *Name = "ilike_escape"; + static constexpr const char *Parameters = "string,like_specifier,escape_character"; + static constexpr const char *Description = "Returns true if the string matches the like_specifier (see Pattern Matching) using case-insensitive matching. escape_character is used to search for wildcard characters in the string."; + static constexpr const char *Example = "ilike_escape('A%c', 'a$%C', '$')"; + + static ScalarFunction GetFunction(); +}; + +struct NotIlikeEscapeFun { + static constexpr const char *Name = "not_ilike_escape"; + static constexpr const char *Parameters = "string,like_specifier,escape_character"; + static constexpr const char *Description = "Returns false if the string matches the like_specifier (see Pattern Matching) using case-insensitive matching. escape_character is used to search for wildcard characters in the string."; + static constexpr const char *Example = "not_ilike_escape('A%c', 'a$%C', '$')"; + + static ScalarFunction GetFunction(); +}; + +struct MD5Fun { + static constexpr const char *Name = "md5"; + static constexpr const char *Parameters = "value"; + static constexpr const char *Description = "Returns the MD5 hash of the value as a string"; + static constexpr const char *Example = "md5('123')"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct MD5NumberFun { + static constexpr const char *Name = "md5_number"; + static constexpr const char *Parameters = "value"; + static constexpr const char *Description = "Returns the MD5 hash of the value as an INT128"; + static constexpr const char *Example = "md5_number('123')"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct SHA1Fun { + static constexpr const char *Name = "sha1"; + static constexpr const char *Parameters = "value"; + static constexpr const char *Description = "Returns the SHA1 hash of the value"; + static constexpr const char *Example = "sha1('hello')"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct SHA256Fun { + static constexpr const char *Name = "sha256"; + static constexpr const char *Parameters = "value"; + static constexpr const char *Description = "Returns the SHA256 hash of the value"; + static constexpr const char *Example = "sha256('hello')"; + + static ScalarFunctionSet GetFunctions(); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/scalar/struct_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/struct_functions.hpp similarity index 50% rename from src/duckdb/src/include/duckdb/core_functions/scalar/struct_functions.hpp rename to src/duckdb/src/include/duckdb/function/scalar/struct_functions.hpp index b83c5e953..881ad99d2 100644 --- a/src/duckdb/src/include/duckdb/core_functions/scalar/struct_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/struct_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/core_functions/scalar/struct_functions.hpp +// function/scalar/struct_functions.hpp // // //===----------------------------------------------------------------------===// @@ -15,19 +15,19 @@ namespace duckdb { -struct StructInsertFun { - static constexpr const char *Name = "struct_insert"; - static constexpr const char *Parameters = "struct,any"; - static constexpr const char *Description = "Adds field(s)/value(s) to an existing STRUCT with the argument values. The entry name(s) will be the bound variable name(s)"; - static constexpr const char *Example = "struct_insert({'a': 1}, b := 2)"; +struct StructExtractFun { + static constexpr const char *Name = "struct_extract"; + static constexpr const char *Parameters = "struct,'entry'"; + static constexpr const char *Description = "Extract the named entry from the STRUCT."; + static constexpr const char *Example = "struct_extract({'i': 3, 'v2': 3, 'v3': 0}, 'i')"; - static ScalarFunction GetFunction(); + static ScalarFunctionSet GetFunctions(); }; struct StructPackFun { static constexpr const char *Name = "struct_pack"; - static constexpr const char *Parameters = "any"; - static constexpr const char *Description = "Creates a STRUCT containing the argument values. The entry name will be the bound variable name"; + static constexpr const char *Parameters = "name:=any,...)"; + static constexpr const char *Description = "Create a STRUCT containing the argument values. The entry name will be the bound variable name."; static constexpr const char *Example = "struct_pack(i := 4, s := 'string')"; static ScalarFunction GetFunction(); @@ -35,9 +35,9 @@ struct StructPackFun { struct RowFun { static constexpr const char *Name = "row"; - static constexpr const char *Parameters = "any"; - static constexpr const char *Description = "Creates an unnamed STRUCT containing the argument values."; - static constexpr const char *Example = "row(4, 'hello')"; + static constexpr const char *Parameters = "any,..."; + static constexpr const char *Description = "Create an unnamed STRUCT (tuple) containing the argument values."; + static constexpr const char *Example = "row(i, i % 4, i / 4)"; static ScalarFunction GetFunction(); }; diff --git a/src/duckdb/src/include/duckdb/core_functions/scalar/secret_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/system_functions.hpp similarity index 52% rename from src/duckdb/src/include/duckdb/core_functions/scalar/secret_functions.hpp rename to src/duckdb/src/include/duckdb/function/scalar/system_functions.hpp index 17e5614e0..c7a2fe269 100644 --- a/src/duckdb/src/include/duckdb/core_functions/scalar/secret_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/system_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/core_functions/scalar/secret_functions.hpp +// function/scalar/system_functions.hpp // // //===----------------------------------------------------------------------===// @@ -15,11 +15,20 @@ namespace duckdb { -struct WhichSecretFun { - static constexpr const char *Name = "which_secret"; - static constexpr const char *Parameters = "path,type"; - static constexpr const char *Description = "Print out the name of the secret that will be used for reading a path"; - static constexpr const char *Example = "which_secret('s3://some/authenticated/path.csv', 's3')"; +struct FinalizeFun { + static constexpr const char *Name = "finalize"; + static constexpr const char *Parameters = "col0"; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; + + static ScalarFunction GetFunction(); +}; + +struct CombineFun { + static constexpr const char *Name = "combine"; + static constexpr const char *Parameters = "col0,col1"; + static constexpr const char *Description = ""; + static constexpr const char *Example = ""; static ScalarFunction GetFunction(); }; diff --git a/src/duckdb/src/include/duckdb/function/scalar_function.hpp b/src/duckdb/src/include/duckdb/function/scalar_function.hpp index ff658383e..2a8b15330 100644 --- a/src/duckdb/src/include/duckdb/function/scalar_function.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar_function.hpp @@ -53,6 +53,7 @@ class Binder; class BoundFunctionExpression; class LogicalDependencyList; class ScalarFunctionCatalogEntry; + struct StatementProperties; struct FunctionStatisticsInput { diff --git a/src/duckdb/src/include/duckdb/function/table/arrow.hpp b/src/duckdb/src/include/duckdb/function/table/arrow.hpp index bc88fed02..d9930f466 100644 --- a/src/duckdb/src/include/duckdb/function/table/arrow.hpp +++ b/src/duckdb/src/include/duckdb/function/table/arrow.hpp @@ -214,8 +214,7 @@ struct ArrowTableFunction { static idx_t ArrowScanMaxThreads(ClientContext &context, const FunctionData *bind_data); //! Allows parallel Create Table / Insertion - static idx_t ArrowGetBatchIndex(ClientContext &context, const FunctionData *bind_data_p, - LocalTableFunctionState *local_state, GlobalTableFunctionState *global_state); + static OperatorPartitionData ArrowGetPartitionData(ClientContext &context, TableFunctionGetPartitionInput &input); //! Specify if a given type can be pushed-down by the arrow engine static bool ArrowPushdownType(const LogicalType &type); 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 fae4b5100..f74dc466e 100644 --- a/src/duckdb/src/include/duckdb/function/table/system_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/table/system_functions.hpp @@ -18,6 +18,8 @@ struct PragmaCollations { }; struct PragmaTableInfo { + static void GetColumnInfo(TableCatalogEntry &table, const ColumnDefinition &column, DataChunk &output, idx_t index); + 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 d15990d07..1f5ee44b0 100644 --- a/src/duckdb/src/include/duckdb/function/table_function.hpp +++ b/src/duckdb/src/include/duckdb/function/table_function.hpp @@ -23,9 +23,12 @@ namespace duckdb { class BaseStatistics; class LogicalDependencyList; class LogicalGet; +class TableFunction; class TableFilterSet; class TableCatalogEntry; struct MultiFileReader; +struct OperatorPartitionData; +struct OperatorPartitionInfo; struct TableFunctionInfo { DUCKDB_API virtual ~TableFunctionInfo(); @@ -102,14 +105,17 @@ struct TableFunctionBindInput { struct TableFunctionInitInput { TableFunctionInitInput(optional_ptr bind_data_p, const vector &column_ids_p, - const vector &projection_ids_p, optional_ptr filters_p) - : bind_data(bind_data_p), column_ids(column_ids_p), projection_ids(projection_ids_p), filters(filters_p) { + const vector &projection_ids_p, optional_ptr filters_p, + optional_ptr sample_options_p = nullptr) + : bind_data(bind_data_p), column_ids(column_ids_p), projection_ids(projection_ids_p), filters(filters_p), + sample_options(sample_options_p) { } optional_ptr bind_data; const vector &column_ids; const vector projection_ids; optional_ptr filters; + optional_ptr sample_options; bool CanRemoveFilterColumns() const { if (projection_ids.empty()) { @@ -139,7 +145,33 @@ struct TableFunctionInput { optional_ptr global_state; }; -enum class ScanType : uint8_t { TABLE, PARQUET }; +struct TableFunctionPartitionInput { + TableFunctionPartitionInput(optional_ptr bind_data_p, const vector &partition_ids) + : bind_data(bind_data_p), partition_ids(partition_ids) { + } + + optional_ptr bind_data; + const vector &partition_ids; +}; + +struct TableFunctionGetPartitionInput { +public: + TableFunctionGetPartitionInput(optional_ptr bind_data_p, + optional_ptr local_state_p, + optional_ptr global_state_p, + const OperatorPartitionInfo &partition_info_p) + : bind_data(bind_data_p), local_state(local_state_p), global_state(global_state_p), + partition_info(partition_info_p) { + } + +public: + optional_ptr bind_data; + optional_ptr local_state; + optional_ptr global_state; + const OperatorPartitionInfo &partition_info; +}; + +enum class ScanType : uint8_t { TABLE, PARQUET, EXTERNAL }; struct BindInfo { public: @@ -181,6 +213,14 @@ struct BindInfo { } }; +//! How a table is partitioned by a given set of columns +enum class TablePartitionInfo : uint8_t { + NOT_PARTITIONED, // the table is not partitioned by the given set of columns + SINGLE_VALUE_PARTITIONS, // each partition has exactly one unique value (e.g. bounds = [1,1][2,2][3,3]) + OVERLAPPING_PARTITIONS, // the partitions overlap **only** at the boundaries (e.g. bounds = [1,2][2,3][3,4] + DISJOINT_PARTITIONS // the partitions are disjoint (e.g. bounds = [1,2][3,4][5,6]) +}; + typedef unique_ptr (*table_function_bind_t)(ClientContext &context, TableFunctionBindInput &input, vector &return_types, vector &names); typedef unique_ptr (*table_function_bind_replace_t)(ClientContext &context, TableFunctionBindInput &input); @@ -196,13 +236,12 @@ typedef OperatorResultType (*table_in_out_function_t)(ExecutionContext &context, DataChunk &input, DataChunk &output); typedef OperatorFinalizeResultType (*table_in_out_function_final_t)(ExecutionContext &context, TableFunctionInput &data, DataChunk &output); -typedef idx_t (*table_function_get_batch_index_t)(ClientContext &context, const FunctionData *bind_data, - LocalTableFunctionState *local_state, - GlobalTableFunctionState *global_state); +typedef OperatorPartitionData (*table_function_get_partition_data_t)(ClientContext &context, + TableFunctionGetPartitionInput &input); typedef BindInfo (*table_function_get_bind_info_t)(const optional_ptr bind_data); -typedef unique_ptr (*table_function_get_multi_file_reader_t)(); +typedef unique_ptr (*table_function_get_multi_file_reader_t)(const TableFunction &); typedef bool (*table_function_supports_pushdown_type_t)(const LogicalType &type); @@ -223,6 +262,9 @@ typedef unique_ptr (*table_function_deserialize_t)(Deserializer &d typedef void (*table_function_type_pushdown_t)(ClientContext &context, optional_ptr bind_data, const unordered_map &new_column_types); +typedef TablePartitionInfo (*table_function_get_partition_info_t)(ClientContext &context, + TableFunctionPartitionInput &input); + //! When to call init_global to initialize the table function enum class TableFunctionInitialization { INITIALIZE_ON_EXECUTE, INITIALIZE_ON_SCHEDULE }; @@ -277,8 +319,8 @@ class TableFunction : public SimpleNamedParameterFunction { // NOLINT: work-arou table_function_to_string_t to_string; //! (Optional) return how much of the table we have scanned up to this point (% of the data) table_function_progress_t table_scan_progress; - //! (Optional) returns the current batch index of the current scan operator - table_function_get_batch_index_t get_batch_index; + //! (Optional) returns the partition info of the current scan operator + table_function_get_partition_data_t get_partition_data; //! (Optional) returns extra bind info table_function_get_bind_info_t get_bind_info; //! (Optional) pushes down type information to scanner, returns true if pushdown was successful @@ -287,6 +329,8 @@ class TableFunction : public SimpleNamedParameterFunction { // NOLINT: work-arou table_function_get_multi_file_reader_t get_multi_file_reader; //! (Optional) If this scanner supports filter pushdown, but not to all data types table_function_supports_pushdown_type_t supports_pushdown_type; + //! Get partition info of the table + table_function_get_partition_info_t get_partition_info; table_function_serialize_t serialize; table_function_deserialize_t deserialize; @@ -301,6 +345,9 @@ class TableFunction : public SimpleNamedParameterFunction { // NOLINT: work-arou //! Whether or not the table function can immediately prune out filter columns that are unused in the remainder of //! the query plan, e.g., "SELECT i FROM tbl WHERE j = 42;" - j does not need to leave the table function at all bool filter_prune; + //! Whether or not the table function supports sampling pushdown. If not supported a sample will be taken after the + //! table function. + bool sampling_pushdown; //! Additional function info, passed to the bind shared_ptr function_info; diff --git a/src/duckdb/src/include/duckdb/core_functions/to_interval.hpp b/src/duckdb/src/include/duckdb/function/to_interval.hpp similarity index 94% rename from src/duckdb/src/include/duckdb/core_functions/to_interval.hpp rename to src/duckdb/src/include/duckdb/function/to_interval.hpp index a0f6bf8f6..3ef1e82c1 100644 --- a/src/duckdb/src/include/duckdb/core_functions/to_interval.hpp +++ b/src/duckdb/src/include/duckdb/function/to_interval.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/core_functions/to_interval.hpp +// duckdb/function/to_interval.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/src/include/duckdb/main/appender.hpp b/src/duckdb/src/include/duckdb/main/appender.hpp index 9662e2744..47be7eafe 100644 --- a/src/duckdb/src/include/duckdb/main/appender.hpp +++ b/src/duckdb/src/include/duckdb/main/appender.hpp @@ -122,6 +122,8 @@ class Appender : public BaseAppender { unordered_map default_values; public: + DUCKDB_API Appender(Connection &con, const string &database_name, const string &schema_name, + const string &table_name); DUCKDB_API Appender(Connection &con, const string &schema_name, const string &table_name); DUCKDB_API Appender(Connection &con, const string &table_name); DUCKDB_API ~Appender() override; diff --git a/src/duckdb/src/include/duckdb/main/attached_database.hpp b/src/duckdb/src/include/duckdb/main/attached_database.hpp index db2e8ef53..098edf9f7 100644 --- a/src/duckdb/src/include/duckdb/main/attached_database.hpp +++ b/src/duckdb/src/include/duckdb/main/attached_database.hpp @@ -13,6 +13,7 @@ #include "duckdb/common/mutex.hpp" #include "duckdb/main/config.hpp" #include "duckdb/catalog/catalog_entry.hpp" +#include "duckdb/storage/storage_options.hpp" namespace duckdb { class Catalog; @@ -43,8 +44,10 @@ struct AttachOptions { AccessMode access_mode; //! The file format type. The default type is a duckdb database file, but other file formats are possible. string db_type; - //! We only set this, if we detect any unrecognized option. - string unrecognized_option; + //! Set of remaining (key, value) options + unordered_map options; + //! (optionally) a catalog can be provided with a default table + QualifiedName default_table; }; //! The AttachedDatabase represents an attached database instance. @@ -61,7 +64,7 @@ class AttachedDatabase : public CatalogEntry { ~AttachedDatabase() override; //! Initializes the catalog and storage of the attached database. - void Initialize(const optional_idx block_alloc_size = optional_idx()); + void Initialize(StorageOptions options = StorageOptions()); void Close(); Catalog &ParentCatalog() override; 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 932730c0e..8d91edd60 100644 --- a/src/duckdb/src/include/duckdb/main/capi/extension_api.hpp +++ b/src/duckdb/src/include/duckdb/main/capi/extension_api.hpp @@ -422,6 +422,16 @@ typedef struct { duckdb_arrow_schema arrow_schema, duckdb_arrow_array arrow_array, duckdb_arrow_stream *out_stream); duckdb_data_chunk (*duckdb_stream_fetch_chunk)(duckdb_result result); + // dev + // WARNING! the functions below are not (yet) stable + + duckdb_state (*duckdb_appender_create_ext)(duckdb_connection connection, const char *catalog, const char *schema, + const char *table, duckdb_appender *out_appender); + duckdb_state (*duckdb_table_description_create_ext)(duckdb_connection connection, const char *catalog, + const char *schema, const char *table, + duckdb_table_description *out); + char *(*duckdb_table_description_get_column_name)(duckdb_table_description table_description, idx_t index); + duckdb_logical_type (*duckdb_param_logical_type)(duckdb_prepared_statement prepared_statement, idx_t param_idx); } duckdb_ext_api_v0; //===--------------------------------------------------------------------===// @@ -800,6 +810,10 @@ inline duckdb_ext_api_v0 CreateAPIv0() { result.duckdb_arrow_scan = duckdb_arrow_scan; result.duckdb_arrow_array_scan = duckdb_arrow_array_scan; result.duckdb_stream_fetch_chunk = duckdb_stream_fetch_chunk; + result.duckdb_appender_create_ext = duckdb_appender_create_ext; + result.duckdb_table_description_create_ext = duckdb_table_description_create_ext; + result.duckdb_table_description_get_column_name = duckdb_table_description_get_column_name; + result.duckdb_param_logical_type = duckdb_param_logical_type; 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 306aa0a62..029fbab38 100644 --- a/src/duckdb/src/include/duckdb/main/client_config.hpp +++ b/src/duckdb/src/include/duckdb/main/client_config.hpp @@ -170,6 +170,16 @@ struct ClientConfig { user_variables.erase(name); } + template + typename OP::RETURN_TYPE GetSetting(const ClientContext &context) { + return OP::GetSetting(context).template GetValue(); + } + + template + 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 c03e38ae0..cd22bbc79 100644 --- a/src/duckdb/src/include/duckdb/main/client_context.hpp +++ b/src/duckdb/src/include/duckdb/main/client_context.hpp @@ -117,14 +117,21 @@ class ClientContext : public enable_shared_from_this { //! Destroy the client context DUCKDB_API void Destroy(); - //! Get the table info of a specific table, or nullptr if it cannot be found + //! Get the table info of a specific table, or nullptr if it cannot be found. + DUCKDB_API unique_ptr TableInfo(const string &database_name, const string &schema_name, + 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); //! Appends a DataChunk to the specified table. Returns whether or not the append was successful. DUCKDB_API void Append(TableDescription &description, ColumnDataCollection &collection); + //! Try to bind a relation in the current client context; either throws an exception or fills the result_columns //! list with the set of returned columns DUCKDB_API void TryBindRelation(Relation &relation, vector &result_columns); + //! Internal function for try bind relation. It does not require a client-context lock. + DUCKDB_API void InternalTryBindRelation(Relation &relation, vector &result_columns); + //! Execute a relation DUCKDB_API unique_ptr PendingQuery(const shared_ptr &relation, bool allow_stream_result); diff --git a/src/duckdb/src/include/duckdb/main/client_context_wrapper.hpp b/src/duckdb/src/include/duckdb/main/client_context_wrapper.hpp index 2ee703458..41c102255 100644 --- a/src/duckdb/src/include/duckdb/main/client_context_wrapper.hpp +++ b/src/duckdb/src/include/duckdb/main/client_context_wrapper.hpp @@ -9,16 +9,21 @@ #pragma once #include "duckdb/common/shared_ptr.hpp" +#include "duckdb/parser/column_definition.hpp" namespace duckdb { class ClientContext; +class Relation; + class ClientContextWrapper { public: + virtual ~ClientContextWrapper() = default; explicit ClientContextWrapper(const shared_ptr &context); shared_ptr GetContext(); shared_ptr TryGetContext(); + virtual void TryBindRelation(Relation &relation, vector &columns); private: weak_ptr client_context; diff --git a/src/duckdb/src/include/duckdb/main/config.hpp b/src/duckdb/src/include/duckdb/main/config.hpp index 162109bad..e52b1ab53 100644 --- a/src/duckdb/src/include/duckdb/main/config.hpp +++ b/src/duckdb/src/include/duckdb/main/config.hpp @@ -70,7 +70,7 @@ typedef Value (*get_setting_function_t)(const ClientContext &context); struct ConfigurationOption { const char *name; const char *description; - LogicalTypeId parameter_type; + const char *parameter_type; set_global_function_t set_global; set_local_function_t set_local; reset_global_function_t reset_global; @@ -209,7 +209,7 @@ struct DBConfigOptions { bool arrow_use_list_view = false; //! Whenever a DuckDB type does not have a clear native or canonical extension match in Arrow, export the types //! with a duckdb.type_name extension name - bool arrow_arrow_lossless_conversion = false; + bool arrow_lossless_conversion = false; //! Whether when producing arrow objects we produce string_views or regular strings bool produce_arrow_string_views = false; //! Database configuration variables as controlled by SET @@ -272,6 +272,10 @@ struct DBConfigOptions { bool debug_skip_checkpoint_on_commit = false; //! The maximum amount of vacuum tasks to schedule during a checkpoint idx_t max_vacuum_tasks = 100; + //! Paths that are explicitly allowed, even if enable_external_access is false + unordered_set allowed_paths; + //! Directories that are explicitly allowed, even if enable_external_access is false + set allowed_directories; bool operator==(const DBConfigOptions &other) const; }; @@ -346,6 +350,7 @@ struct DBConfig { DUCKDB_API void ResetOption(DatabaseInstance *db, const ConfigurationOption &option); DUCKDB_API void SetOption(const string &name, Value value); DUCKDB_API void ResetOption(const string &name); + static LogicalType ParseLogicalType(const string &type); DUCKDB_API void CheckLock(const string &name); @@ -373,6 +378,23 @@ struct DBConfig { OrderByNullType ResolveNullOrder(OrderType order_type, OrderByNullType null_type) const; const string UserAgent() const; + template + typename OP::RETURN_TYPE GetSetting(const ClientContext &context) { + std::lock_guard lock(config_lock); + return OP::GetSetting(context).template GetValue(); + } + + template + Value GetSettingValue(const ClientContext &context) { + std::lock_guard lock(config_lock); + return OP::GetSetting(context); + } + + bool CanAccessFile(const string &path, FileType type); + void AddAllowedDirectory(const string &path); + void AddAllowedPath(const string &path); + string SanitizeAllowedPath(const string &path) const; + private: unique_ptr compression_functions; unique_ptr cast_functions; diff --git a/src/duckdb/src/include/duckdb/main/connection.hpp b/src/duckdb/src/include/duckdb/main/connection.hpp index aec41c7d5..54499c6b0 100644 --- a/src/duckdb/src/include/duckdb/main/connection.hpp +++ b/src/duckdb/src/include/duckdb/main/connection.hpp @@ -103,10 +103,14 @@ class Connection { //! Prepare the specified statement, returning a prepared statement object DUCKDB_API unique_ptr Prepare(unique_ptr statement); - //! Get the table info of a specific table (in the default schema), or nullptr if it cannot be found - DUCKDB_API unique_ptr TableInfo(const string &table_name); - //! Get the table info of a specific table, or nullptr if it cannot be found + //! Get the table info of a specific table, or nullptr if it cannot be found. + DUCKDB_API unique_ptr TableInfo(const string &database_name, const string &schema_name, + 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); + //! Get the table info of a specific table, or nullptr if it cannot be found. Uses INVALID_CATALOG and + //! DEFAULT_SCHEMA. + DUCKDB_API unique_ptr TableInfo(const string &table_name); //! Extract a set of SQL statements from a specific query DUCKDB_API vector> ExtractStatements(const string &query); diff --git a/src/duckdb/src/include/duckdb/main/database_file_opener.hpp b/src/duckdb/src/include/duckdb/main/database_file_opener.hpp index 6cf210867..024956aaa 100644 --- a/src/duckdb/src/include/duckdb/main/database_file_opener.hpp +++ b/src/duckdb/src/include/duckdb/main/database_file_opener.hpp @@ -22,7 +22,7 @@ class DatabaseFileOpener : public FileOpener { } SettingLookupResult TryGetCurrentSetting(const string &key, Value &result) override { - return SettingLookupResult(); + return db.TryGetCurrentSetting(key, result); } optional_ptr TryGetClientContext() override { diff --git a/src/duckdb/src/include/duckdb/main/database_manager.hpp b/src/duckdb/src/include/duckdb/main/database_manager.hpp index c06b5505a..c193c979f 100644 --- a/src/duckdb/src/include/duckdb/main/database_manager.hpp +++ b/src/duckdb/src/include/duckdb/main/database_manager.hpp @@ -21,6 +21,7 @@ namespace duckdb { class AttachedDatabase; class Catalog; +class CatalogEntryRetriever; class CatalogSet; class ClientContext; class DatabaseInstance; @@ -83,6 +84,8 @@ class DatabaseManager { bool HasDefaultDatabase() { return !default_database.empty(); } + //! Gets a list of all attached database paths + vector GetAttachedDatabasePaths(); private: //! Returns a database with a specified path diff --git a/src/duckdb/src/include/duckdb/main/extension_entries.hpp b/src/duckdb/src/include/duckdb/main/extension_entries.hpp index ae31c576d..f30af0b16 100644 --- a/src/duckdb/src/include/duckdb/main/extension_entries.hpp +++ b/src/duckdb/src/include/duckdb/main/extension_entries.hpp @@ -11,8 +11,13 @@ #include "duckdb/common/unordered_map.hpp" #include "duckdb/common/enums/catalog_type.hpp" -// NOTE: this file is generated by scripts/generate_extensions_function.py. Check out the check-load-install-extensions -// job in .github/workflows/LinuxRelease.yml on how to use it +// NOTE: this file is generated by scripts/generate_extensions_function.py. +// Example usage to refresh one extension (replace "icu" with the desired extension): +// GENERATE_EXTENSION_ENTRIES=1 make debug +// python3 scripts/generate_extensions_function.py --extensions icu --shell build/debug/duckdb --extension_dir +// build/debug + +// Check out the check-load-install-extensions job in .github/workflows/LinuxRelease.yml for more details namespace duckdb { @@ -27,31 +32,173 @@ struct ExtensionFunctionEntry { CatalogType type; }; +struct ExtensionFunctionOverloadEntry { + char name[48]; + char extension[48]; + CatalogType type; + char signature[96]; +}; + static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { + {"!__postfix", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"&", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"&&", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"**", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"->>", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"<->", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"<<", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"<<=", "inet", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"<=>", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"<@", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {">>", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {">>=", "inet", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"@", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"@>", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"^", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"^@", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"abs", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"acos", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"acosh", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"add_numbers_together", "demo_capi", CatalogType::SCALAR_FUNCTION_ENTRY}, {"add_parquet_key", "parquet", CatalogType::PRAGMA_FUNCTION_ENTRY}, + {"aggregate", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"alias", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"apply", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"approx_count_distinct", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"approx_quantile", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"approx_top_k", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"arg_max", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"arg_max_null", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"arg_min", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"arg_min_null", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"argmax", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"argmin", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"array_agg", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"array_aggr", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_aggregate", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_apply", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_cosine_distance", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_cosine_similarity", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_cross_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_distance", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_distinct", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_dot_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_filter", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_grade_up", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_has_all", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_has_any", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_inner_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_negative_dot_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_negative_inner_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_reduce", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_reverse_sort", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_slice", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_sort", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"array_to_json", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_transform", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_unique", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"array_value", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"ascii", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"asin", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"asinh", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"atan", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"atan2", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"atanh", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"avg", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"bar", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"base64", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"bin", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"bit_and", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"bit_count", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"bit_or", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"bit_position", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"bit_xor", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"bitstring", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"bitstring_agg", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"bool_and", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"bool_or", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"broadcast", "inet", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"can_cast_implicitly", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"cardinality", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"cbrt", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"ceil", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"ceiling", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"chr", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"corr", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"cos", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"cosh", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"cot", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"covar_pop", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"covar_samp", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"create_fts_index", "fts", CatalogType::PRAGMA_FUNCTION_ENTRY}, + {"current_database", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"current_date", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"current_localtime", "icu", CatalogType::SCALAR_FUNCTION_ENTRY}, {"current_localtimestamp", "icu", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"current_query", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"current_schema", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"current_schemas", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"current_setting", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"damerau_levenshtein", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"dbgen", "tpch", CatalogType::TABLE_FUNCTION_ENTRY}, + {"decode", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"degrees", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"delta_scan", "delta", CatalogType::TABLE_FUNCTION_ENTRY}, {"drop_fts_index", "fts", CatalogType::PRAGMA_FUNCTION_ENTRY}, {"dsdgen", "tpcds", CatalogType::TABLE_FUNCTION_ENTRY}, + {"editdist3", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"element_at", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"encode", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"entropy", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"enum_code", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"enum_first", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"enum_last", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"enum_range", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"enum_range_boundary", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"epoch_ms", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"epoch_ns", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"epoch_us", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"equi_width_bins", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"even", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"excel_text", "excel", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"exp", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"factorial", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"family", "inet", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"favg", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"filter", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"flatten", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"floor", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"format", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"format_bytes", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"formatreadabledecimalsize", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"formatreadablesize", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"from_base64", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"from_binary", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"from_hex", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"from_json", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, {"from_json_strict", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, {"from_substrait", "substrait", CatalogType::TABLE_FUNCTION_ENTRY}, {"from_substrait_json", "substrait", CatalogType::TABLE_FUNCTION_ENTRY}, + {"fsum", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"fuzz_all_functions", "sqlsmith", CatalogType::TABLE_FUNCTION_ENTRY}, {"fuzzyduck", "sqlsmith", CatalogType::TABLE_FUNCTION_ENTRY}, + {"gamma", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"gcd", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"gen_random_uuid", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"get_bit", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"get_current_time", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"get_current_timestamp", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"get_substrait", "substrait", CatalogType::TABLE_FUNCTION_ENTRY}, {"get_substrait_json", "substrait", CatalogType::TABLE_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}, + {"group_concat", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"hamming", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"hash", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"hex", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"histogram", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"histogram_exact", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"hnsw_compact_index", "vss", CatalogType::PRAGMA_FUNCTION_ENTRY}, {"hnsw_index_scan", "vss", CatalogType::TABLE_FUNCTION_ENTRY}, {"host", "inet", CatalogType::SCALAR_FUNCTION_ENTRY}, @@ -193,6 +340,15 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"icu_collate_zh_tw", "icu", CatalogType::SCALAR_FUNCTION_ENTRY}, {"icu_collate_zu", "icu", CatalogType::SCALAR_FUNCTION_ENTRY}, {"icu_sort_key", "icu", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"in_search_path", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"instr", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"is_histogram_other_bin", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"isfinite", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"isinf", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"isnan", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"jaccard", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"jaro_similarity", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"jaro_winkler_similarity", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"json", "json", CatalogType::MACRO_ENTRY}, {"json_array", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, {"json_array_length", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, @@ -221,27 +377,104 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"json_type", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, {"json_valid", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, {"json_value", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"kahan_sum", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"kurtosis", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"kurtosis_pop", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"lcm", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"least", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"least_common_multiple", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"left", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"left_grapheme", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"levenshtein", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"lgamma", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"list_aggr", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_aggregate", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_apply", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_cosine_distance", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_cosine_similarity", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_distance", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_distinct", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_dot_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_filter", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_grade_up", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_has_all", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_has_any", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_inner_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_negative_dot_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_negative_inner_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_pack", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_reduce", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_reverse_sort", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_slice", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_sort", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_transform", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_unique", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"list_value", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"listagg", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"ln", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"load_aws_credentials", "aws", CatalogType::TABLE_FUNCTION_ENTRY}, + {"log", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"log10", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"log2", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"lpad", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"ltrim", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"mad", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"make_date", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"make_time", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"make_timestamp", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"make_timestamptz", "icu", 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}, + {"map_extract", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"map_from_entries", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"map_keys", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"map_values", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"max_by", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"mean", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"median", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"min_by", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"mismatches", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"mode", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"mysql_clear_cache", "mysql_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"mysql_execute", "mysql_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"mysql_query", "mysql_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, + {"nanosecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"netmask", "inet", CatalogType::SCALAR_FUNCTION_ENTRY}, {"network", "inet", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"nextafter", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"now", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"ord", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"parquet_file_metadata", "parquet", CatalogType::TABLE_FUNCTION_ENTRY}, {"parquet_kv_metadata", "parquet", CatalogType::TABLE_FUNCTION_ENTRY}, {"parquet_metadata", "parquet", CatalogType::TABLE_FUNCTION_ENTRY}, {"parquet_scan", "parquet", CatalogType::TABLE_FUNCTION_ENTRY}, {"parquet_schema", "parquet", CatalogType::TABLE_FUNCTION_ENTRY}, + {"parse_dirname", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"parse_dirpath", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"parse_filename", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"parse_path", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"pg_clear_cache", "postgres_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"pg_timezone_names", "icu", CatalogType::TABLE_FUNCTION_ENTRY}, + {"pi", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"position", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"postgres_attach", "postgres_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"postgres_execute", "postgres_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"postgres_query", "postgres_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"postgres_scan", "postgres_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"postgres_scan_pushdown", "postgres_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, + {"pow", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"power", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"pragma_hnsw_index_info", "vss", CatalogType::TABLE_FUNCTION_ENTRY}, {"pragma_rtree_index_info", "spatial", CatalogType::TABLE_FUNCTION_ENTRY}, + {"printf", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"product", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"quantile", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"quantile_cont", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"quantile_disc", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"radians", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"random", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"read_json", "json", CatalogType::TABLE_FUNCTION_ENTRY}, {"read_json_auto", "json", CatalogType::TABLE_FUNCTION_ENTRY}, {"read_json_objects", "json", CatalogType::TABLE_FUNCTION_ENTRY}, @@ -250,16 +483,44 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"read_ndjson_auto", "json", CatalogType::TABLE_FUNCTION_ENTRY}, {"read_ndjson_objects", "json", CatalogType::TABLE_FUNCTION_ENTRY}, {"read_parquet", "parquet", CatalogType::TABLE_FUNCTION_ENTRY}, + {"reduce", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"reduce_sql_statement", "sqlsmith", 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}, + {"regr_intercept", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"regr_r2", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"regr_slope", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"regr_sxx", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"regr_sxy", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"regr_syy", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"repeat", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"replace", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"reservoir_quantile", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"reverse", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"right", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"right_grapheme", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"round", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"row_to_json", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"rpad", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"rtree_index_dump", "spatial", CatalogType::TABLE_FUNCTION_ENTRY}, {"rtree_index_scan", "spatial", CatalogType::TABLE_FUNCTION_ENTRY}, + {"rtrim", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"scan_arrow_ipc", "arrow", CatalogType::TABLE_FUNCTION_ENTRY}, + {"sem", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"set_bit", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"setseed", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"shapefile_meta", "spatial", CatalogType::TABLE_FUNCTION_ENTRY}, + {"sign", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"signbit", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"sin", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"sinh", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"skewness", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"sql_auto_complete", "autocomplete", CatalogType::TABLE_FUNCTION_ENTRY}, {"sqlite_attach", "sqlite_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"sqlite_scan", "sqlite_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"sqlsmith", "sqlsmith", CatalogType::TABLE_FUNCTION_ENTRY}, + {"sqrt", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_area", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_area_spheroid", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_asgeojson", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, @@ -379,20 +640,285 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"st_zmax", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_zmflag", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_zmin", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"starts_with", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"stats", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"stddev", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"stddev_pop", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"stddev_samp", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"stem", "fts", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"string_agg", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"strpos", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"struct_insert", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"sum", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"sum_no_overflow", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"sumkahan", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"tan", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"tanh", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"text", "excel", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"timetz_byte_comparable", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"to_arrow_ipc", "arrow", CatalogType::TABLE_FUNCTION_ENTRY}, + {"to_base", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_base64", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_binary", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_centuries", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_days", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_decades", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_hex", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_hours", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"to_json", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_microseconds", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_millennia", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_milliseconds", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_minutes", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_months", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_quarters", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_seconds", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_timestamp", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_weeks", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"to_years", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"today", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"tpcds", "tpcds", CatalogType::PRAGMA_FUNCTION_ENTRY}, {"tpcds_answers", "tpcds", CatalogType::TABLE_FUNCTION_ENTRY}, {"tpcds_queries", "tpcds", CatalogType::TABLE_FUNCTION_ENTRY}, {"tpch", "tpch", CatalogType::PRAGMA_FUNCTION_ENTRY}, {"tpch_answers", "tpch", CatalogType::TABLE_FUNCTION_ENTRY}, {"tpch_queries", "tpch", CatalogType::TABLE_FUNCTION_ENTRY}, + {"transaction_timestamp", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"translate", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"trim", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"trunc", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"txid_current", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"typeof", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"unbin", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"unhex", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"unicode", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"union_extract", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"union_tag", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"union_value", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"unpivot_list", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"url_decode", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"url_encode", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"uuid", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"var_pop", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"var_samp", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"variance", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, + {"vector_type", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"version", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"vss_join", "vss", CatalogType::TABLE_MACRO_ENTRY}, {"vss_match", "vss", CatalogType::TABLE_MACRO_ENTRY}, + {"xor", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"|", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, + {"~", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, }; // END_OF_EXTENSION_FUNCTIONS +static constexpr ExtensionFunctionOverloadEntry EXTENSION_FUNCTION_OVERLOADS[] = { + {"age", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>INTERVAL"}, + {"age", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP,TIMESTAMP>INTERVAL"}, + {"age", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>INTERVAL"}, + {"age", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ,TIMESTAMPTZ>INTERVAL"}, + {"century", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"century", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"century", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"century", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"date_diff", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,DATE,DATE>BIGINT"}, + {"date_diff", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIME,TIME>BIGINT"}, + {"date_diff", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP,TIMESTAMP>BIGINT"}, + {"date_diff", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ,TIMESTAMPTZ>BIGINT"}, + {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,DATE>BIGINT"}, + {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,INTERVAL>BIGINT"}, + {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIME>BIGINT"}, + {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP>BIGINT"}, + {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMETZ>BIGINT"}, + {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],DATE>STRUCT()"}, + {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],INTERVAL>STRUCT()"}, + {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],TIME>STRUCT()"}, + {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],TIMESTAMP>STRUCT()"}, + {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],TIMETZ>STRUCT()"}, + {"date_part", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ>BIGINT"}, + {"date_part", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],TIMESTAMPTZ>STRUCT()"}, + {"date_sub", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,DATE,DATE>BIGINT"}, + {"date_sub", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIME,TIME>BIGINT"}, + {"date_sub", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP,TIMESTAMP>BIGINT"}, + {"date_sub", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ,TIMESTAMPTZ>BIGINT"}, + {"date_trunc", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,DATE>TIMESTAMP"}, + {"date_trunc", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,INTERVAL>INTERVAL"}, + {"date_trunc", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP>TIMESTAMP"}, + {"date_trunc", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ>TIMESTAMPTZ"}, + {"datediff", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,DATE,DATE>BIGINT"}, + {"datediff", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIME,TIME>BIGINT"}, + {"datediff", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP,TIMESTAMP>BIGINT"}, + {"datediff", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ,TIMESTAMPTZ>BIGINT"}, + {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,DATE>BIGINT"}, + {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,INTERVAL>BIGINT"}, + {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIME>BIGINT"}, + {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP>BIGINT"}, + {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMETZ>BIGINT"}, + {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],DATE>STRUCT()"}, + {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],INTERVAL>STRUCT()"}, + {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],TIME>STRUCT()"}, + {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],TIMESTAMP>STRUCT()"}, + {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],TIMETZ>STRUCT()"}, + {"datepart", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ>BIGINT"}, + {"datepart", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],TIMESTAMPTZ>STRUCT()"}, + {"datesub", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,DATE,DATE>BIGINT"}, + {"datesub", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIME,TIME>BIGINT"}, + {"datesub", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP,TIMESTAMP>BIGINT"}, + {"datesub", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ,TIMESTAMPTZ>BIGINT"}, + {"datetrunc", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,DATE>TIMESTAMP"}, + {"datetrunc", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,INTERVAL>INTERVAL"}, + {"datetrunc", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP>TIMESTAMP"}, + {"datetrunc", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ>TIMESTAMPTZ"}, + {"day", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"day", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"day", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"day", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"dayname", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>VARCHAR"}, + {"dayname", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>VARCHAR"}, + {"dayname", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>VARCHAR"}, + {"dayofmonth", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"dayofmonth", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"dayofmonth", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"dayofmonth", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"dayofweek", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"dayofweek", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"dayofweek", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"dayofweek", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"dayofyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"dayofyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"dayofyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"dayofyear", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"decade", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"decade", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"decade", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"decade", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"epoch", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>DOUBLE"}, + {"epoch", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>DOUBLE"}, + {"epoch", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIME>DOUBLE"}, + {"epoch", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>DOUBLE"}, + {"epoch", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMETZ>DOUBLE"}, + {"epoch", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>DOUBLE"}, + {"era", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"era", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"era", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"era", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"generate_series", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "BIGINT>BIGINT[]"}, + {"generate_series", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "BIGINT,BIGINT>BIGINT[]"}, + {"generate_series", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "BIGINT,BIGINT,BIGINT>BIGINT[]"}, + {"generate_series", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, + "TIMESTAMP,TIMESTAMP,INTERVAL>TIMESTAMP[]"}, + {"generate_series", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ,TIMESTAMPTZ,INTERVAL>TIMESTAMPTZ[]"}, + {"hour", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"hour", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"hour", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIME>BIGINT"}, + {"hour", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"hour", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMETZ>BIGINT"}, + {"hour", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"isodow", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"isodow", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"isodow", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"isodow", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"isoyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"isoyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"isoyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"isoyear", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"julian", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>DOUBLE"}, + {"julian", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>DOUBLE"}, + {"julian", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>DOUBLE"}, + {"last_day", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>DATE"}, + {"last_day", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>DATE"}, + {"last_day", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>DATE"}, + {"microsecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"microsecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"microsecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIME>BIGINT"}, + {"microsecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"microsecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMETZ>BIGINT"}, + {"microsecond", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"millennium", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"millennium", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"millennium", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"millennium", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"millisecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"millisecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"millisecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIME>BIGINT"}, + {"millisecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"millisecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMETZ>BIGINT"}, + {"millisecond", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"minute", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"minute", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"minute", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIME>BIGINT"}, + {"minute", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"minute", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMETZ>BIGINT"}, + {"minute", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"month", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"month", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"month", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"month", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"monthname", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>VARCHAR"}, + {"monthname", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>VARCHAR"}, + {"monthname", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>VARCHAR"}, + {"quarter", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"quarter", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"quarter", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"quarter", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"range", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "BIGINT>BIGINT[]"}, + {"range", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "BIGINT,BIGINT>BIGINT[]"}, + {"range", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "BIGINT,BIGINT,BIGINT>BIGINT[]"}, + {"range", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP,TIMESTAMP,INTERVAL>TIMESTAMP[]"}, + {"range", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ,TIMESTAMPTZ,INTERVAL>TIMESTAMPTZ[]"}, + {"second", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"second", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"second", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIME>BIGINT"}, + {"second", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"second", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMETZ>BIGINT"}, + {"second", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"time_bucket", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,DATE>DATE"}, + {"time_bucket", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,DATE,DATE>DATE"}, + {"time_bucket", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,DATE,INTERVAL>DATE"}, + {"time_bucket", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,TIMESTAMP>TIMESTAMP"}, + {"time_bucket", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,TIMESTAMP,INTERVAL>TIMESTAMP"}, + {"time_bucket", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,TIMESTAMP,TIMESTAMP>TIMESTAMP"}, + {"time_bucket", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,TIMESTAMPTZ>TIMESTAMPTZ"}, + {"time_bucket", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,TIMESTAMPTZ,INTERVAL>TIMESTAMPTZ"}, + {"time_bucket", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,TIMESTAMPTZ,TIMESTAMPTZ>TIMESTAMPTZ"}, + {"time_bucket", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,TIMESTAMPTZ,VARCHAR>TIMESTAMPTZ"}, + {"timezone", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"timezone", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"timezone", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,TIMETZ>TIMETZ"}, + {"timezone", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"timezone", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"timezone", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP>TIMESTAMPTZ"}, + {"timezone", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ>TIMESTAMP"}, + {"timezone", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMETZ>TIMETZ"}, + {"timezone_hour", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"timezone_hour", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"timezone_hour", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"timezone_hour", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"timezone_minute", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"timezone_minute", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"timezone_minute", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"timezone_minute", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"week", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"week", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"week", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"week", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"weekday", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"weekday", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"weekday", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"weekday", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"weekofyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"weekofyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"weekofyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"weekofyear", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"year", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"year", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"year", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"year", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, + {"yearweek", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, + {"yearweek", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, + {"yearweek", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, + {"yearweek", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, +}; // END_OF_EXTENSION_FUNCTION_OVERLOADS + static constexpr ExtensionEntry EXTENSION_SETTINGS[] = { {"azure_account_name", "azure"}, {"azure_context_caching", "azure"}, @@ -410,6 +936,7 @@ static constexpr ExtensionEntry EXTENSION_SETTINGS[] = { {"binary_as_string", "parquet"}, {"ca_cert_file", "httpfs"}, {"calendar", "icu"}, + {"disable_parquet_prefetching", "parquet"}, {"enable_geoparquet_conversion", "parquet"}, {"enable_server_cert_verification", "httpfs"}, {"force_download", "httpfs"}, @@ -434,6 +961,7 @@ static constexpr ExtensionEntry EXTENSION_SETTINGS[] = { {"pg_pages_per_task", "postgres_scanner"}, {"pg_use_binary_copy", "postgres_scanner"}, {"pg_use_ctid_scan", "postgres_scanner"}, + {"prefetch_all_parquet_files", "parquet"}, {"s3_access_key_id", "httpfs"}, {"s3_endpoint", "httpfs"}, {"s3_region", "httpfs"}, @@ -508,8 +1036,10 @@ static constexpr ExtensionEntry EXTENSION_FILE_CONTAINS[] = {{".parquet?", "parq // Note: these are currently hardcoded in scripts/generate_extensions_function.py // TODO: automate by passing though to script via duckdb static constexpr ExtensionEntry EXTENSION_SECRET_TYPES[] = { - {"s3", "httpfs"}, {"r2", "httpfs"}, {"gcs", "httpfs"}, - {"azure", "azure"}, {"huggingface", "httpfs"}, {"bearer", "httpfs"}}; // EXTENSION_SECRET_TYPES + {"s3", "httpfs"}, {"r2", "httpfs"}, + {"gcs", "httpfs"}, {"azure", "azure"}, + {"huggingface", "httpfs"}, {"bearer", "httpfs"}, + {"mysql", "mysql_scanner"}, {"postgres", "postgres_scanner"}}; // EXTENSION_SECRET_TYPES // Note: these are currently hardcoded in scripts/generate_extensions_function.py // TODO: automate by passing though to script via duckdb @@ -526,11 +1056,13 @@ static constexpr ExtensionEntry EXTENSION_SECRET_PROVIDERS[] = { {"azure/service_principal", "azure"}, {"huggingface/config", "httfps"}, {"huggingface/credential_chain", "httpfs"}, - {"bearer/config", "httpfs"}}; // EXTENSION_SECRET_PROVIDERS + {"bearer/config", "httpfs"}, + {"mysql/config", "mysql_scanner"}, + {"postgres/config", "postgres_scanner"}}; // EXTENSION_SECRET_PROVIDERS static constexpr const char *AUTOLOADABLE_EXTENSIONS[] = { - "aws", "azure", "autocomplete", "delta", "excel", "fts", "httpfs", - "inet", "icu", "json", "parquet", "sqlite_scanner", "sqlsmith", "postgres_scanner", + "aws", "azure", "autocomplete", "core_functions", "delta", "excel", "fts", "httpfs", + "inet", "icu", "json", "mysql_scanner", "parquet", "sqlite_scanner", "sqlsmith", "postgres_scanner", "tpcds", "tpch"}; // 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 22b0e1b25..e1f3f7f33 100644 --- a/src/duckdb/src/include/duckdb/main/extension_helper.hpp +++ b/src/duckdb/src/include/duckdb/main/extension_helper.hpp @@ -173,6 +173,19 @@ class ExtensionHelper { return result; } + template + static idx_t ArraySize(const ExtensionEntry (&entries)[N]) { + return N; + } + + template + static const ExtensionEntry *GetArrayEntry(const ExtensionEntry (&entries)[N], idx_t entry) { + if (entry >= N) { + return nullptr; + } + return entries + entry; + } + //! Lookup a name in an ExtensionEntry list template static string FindExtensionInEntries(const string &name, const ExtensionEntry (&entries)[N]) { diff --git a/src/duckdb/src/include/duckdb/main/extension_util.hpp b/src/duckdb/src/include/duckdb/main/extension_util.hpp index f91ad2277..6bdd7fa6d 100644 --- a/src/duckdb/src/include/duckdb/main/extension_util.hpp +++ b/src/duckdb/src/include/duckdb/main/extension_util.hpp @@ -18,6 +18,9 @@ namespace duckdb { struct CreateMacroInfo; struct CreateCollationInfo; +struct CreateAggregateFunctionInfo; +struct CreateScalarFunctionInfo; +struct CreateTableFunctionInfo; class DatabaseInstance; //! The ExtensionUtil class contains methods that are useful for extensions @@ -25,18 +28,18 @@ class ExtensionUtil { public: //! Register a new DuckDB extension DUCKDB_API static void RegisterExtension(DatabaseInstance &db, const string &name, const ExtensionLoadedInfo &info); - //! Register a new scalar function - throw an exception if the function already exists + //! Register a new scalar function - merge overloads if the function already exists DUCKDB_API static void RegisterFunction(DatabaseInstance &db, ScalarFunction function); - //! Register a new scalar function set - throw an exception if the function already exists DUCKDB_API static void RegisterFunction(DatabaseInstance &db, ScalarFunctionSet function); - //! Register a new aggregate function - throw an exception if the function already exists + DUCKDB_API static void RegisterFunction(DatabaseInstance &db, CreateScalarFunctionInfo info); + //! Register a new aggregate function - merge overloads if the function already exists DUCKDB_API static void RegisterFunction(DatabaseInstance &db, AggregateFunction function); - //! Register a new aggregate function set - throw an exception if the function already exists DUCKDB_API static void RegisterFunction(DatabaseInstance &db, AggregateFunctionSet function); - //! Register a new table function - throw an exception if the function already exists + DUCKDB_API static void RegisterFunction(DatabaseInstance &db, CreateAggregateFunctionInfo info); + //! Register a new table function - merge overloads if the function already exists DUCKDB_API static void RegisterFunction(DatabaseInstance &db, TableFunction function); - //! Register a new table function set - throw an exception if the function already exists DUCKDB_API static void RegisterFunction(DatabaseInstance &db, TableFunctionSet function); + DUCKDB_API static void RegisterFunction(DatabaseInstance &db, CreateTableFunctionInfo info); //! Register a new pragma function - throw an exception if the function already exists DUCKDB_API static void RegisterFunction(DatabaseInstance &db, PragmaFunction function); //! Register a new pragma function set - throw an exception if the function already exists @@ -56,6 +59,8 @@ class ExtensionUtil { //! Returns a reference to the function in the catalog - throws an exception if it does not exist DUCKDB_API static ScalarFunctionCatalogEntry &GetFunction(DatabaseInstance &db, const string &name); DUCKDB_API static TableFunctionCatalogEntry &GetTableFunction(DatabaseInstance &db, const string &name); + DUCKDB_API static optional_ptr TryGetFunction(DatabaseInstance &db, const string &name); + DUCKDB_API static optional_ptr TryGetTableFunction(DatabaseInstance &db, const string &name); //! Add a function overload DUCKDB_API static void AddFunctionOverload(DatabaseInstance &db, ScalarFunction function); diff --git a/src/duckdb/src/include/duckdb/main/query_profiler.hpp b/src/duckdb/src/include/duckdb/main/query_profiler.hpp index 240729122..d8a0b6386 100644 --- a/src/duckdb/src/include/duckdb/main/query_profiler.hpp +++ b/src/duckdb/src/include/duckdb/main/query_profiler.hpp @@ -113,6 +113,7 @@ class QueryProfiler { unique_ptr CreateTree(const PhysicalOperator &root, const profiler_settings_t &settings, const idx_t depth = 0); void Render(const ProfilingNode &node, std::ostream &str) const; + string RenderDisabledMessage(ProfilerPrintFormat format) const; public: DUCKDB_API bool IsEnabled() const; @@ -145,6 +146,7 @@ class QueryProfiler { //! return the printed as a string. Unlike ToString, which is always formatted as a string, //! the return value is formatted based on the current print format (see GetPrintFormat()). DUCKDB_API string ToString(ExplainFormat format = ExplainFormat::DEFAULT) const; + DUCKDB_API string ToString(ProfilerPrintFormat format) const; static InsertionOrderPreservingMap JSONSanitize(const InsertionOrderPreservingMap &input); static string JSONSanitize(const string &text); @@ -207,6 +209,7 @@ class QueryProfiler { //! Check whether or not an operator type requires query profiling. If none of the ops in a query require profiling //! no profiling information is output. bool OperatorRequiresProfiling(PhysicalOperatorType op_type); + ExplainFormat GetExplainFormat(ProfilerPrintFormat format) const; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/main/relation.hpp b/src/duckdb/src/include/duckdb/main/relation.hpp index 18b125a32..cae8e0936 100644 --- a/src/duckdb/src/include/duckdb/main/relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation.hpp @@ -34,16 +34,35 @@ class LogicalOperator; class QueryNode; class TableRef; +class RelationContextWrapper : public ClientContextWrapper { +public: + ~RelationContextWrapper() override = default; + explicit RelationContextWrapper(const shared_ptr &context) : ClientContextWrapper(context) {}; + + explicit RelationContextWrapper(const ClientContextWrapper &context) : ClientContextWrapper(context) {}; + + void TryBindRelation(Relation &relation, vector &columns) override { + GetContext()->InternalTryBindRelation(relation, columns); + } + +private: + weak_ptr client_context; +}; + class Relation : public enable_shared_from_this { public: - Relation(const shared_ptr &context, RelationType type) : context(context), type(type) { + Relation(const shared_ptr &context_p, const RelationType type) : type(type) { + context = make_shared_ptr(context_p); } - Relation(ClientContextWrapper &context, RelationType type) : context(context.GetContext()), type(type) { + Relation(const shared_ptr &context, RelationType type) : context(context), type(type) { } - virtual ~Relation() { + + Relation(const shared_ptr &context, RelationType type) : context(context), type(type) { } - ClientContextWrapper context; + virtual ~Relation() = default; + + shared_ptr context; RelationType type; vector> external_dependencies; @@ -64,7 +83,7 @@ class Relation : public enable_shared_from_this { DUCKDB_API shared_ptr CreateView(const string &name, bool replace = true, bool temporary = false); DUCKDB_API shared_ptr CreateView(const string &schema_name, const string &name, bool replace = true, bool temporary = false); - DUCKDB_API unique_ptr Query(const string &sql); + DUCKDB_API unique_ptr Query(const string &sql) const; DUCKDB_API unique_ptr Query(const string &name, const string &sql); //! Explain the query plan of this relation @@ -75,6 +94,7 @@ class Relation : public enable_shared_from_this { virtual bool IsReadOnly() { return true; } + DUCKDB_API void TryBindRelation(vector &columns); public: // PROJECT @@ -177,7 +197,7 @@ class Relation : public enable_shared_from_this { DUCKDB_API vector> GetAllDependencies(); protected: - DUCKDB_API string RenderWhitespace(idx_t depth); + DUCKDB_API static string RenderWhitespace(idx_t depth); public: template diff --git a/src/duckdb/src/include/duckdb/main/relation/delete_relation.hpp b/src/duckdb/src/include/duckdb/main/relation/delete_relation.hpp index 2e0c6564c..d72a48bd4 100644 --- a/src/duckdb/src/include/duckdb/main/relation/delete_relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation/delete_relation.hpp @@ -15,8 +15,8 @@ namespace duckdb { class DeleteRelation : public Relation { public: - DeleteRelation(ClientContextWrapper &context, unique_ptr condition, string schema_name, - string table_name); + DeleteRelation(shared_ptr &context, unique_ptr condition, + string schema_name, string table_name); vector columns; unique_ptr condition; diff --git a/src/duckdb/src/include/duckdb/main/relation/table_function_relation.hpp b/src/duckdb/src/include/duckdb/main/relation/table_function_relation.hpp index 3a2208d03..8781d7125 100644 --- a/src/duckdb/src/include/duckdb/main/relation/table_function_relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation/table_function_relation.hpp @@ -17,7 +17,9 @@ class TableFunctionRelation : public Relation { TableFunctionRelation(const shared_ptr &context, string name, vector parameters, named_parameter_map_t named_parameters, shared_ptr input_relation_p = nullptr, bool auto_init = true); - + TableFunctionRelation(const shared_ptr &context, string name, vector parameters, + named_parameter_map_t named_parameters, shared_ptr input_relation_p = nullptr, + bool auto_init = true); TableFunctionRelation(const shared_ptr &context, string name, vector parameters, shared_ptr input_relation_p = nullptr, bool auto_init = true); ~TableFunctionRelation() override { diff --git a/src/duckdb/src/include/duckdb/main/relation/table_relation.hpp b/src/duckdb/src/include/duckdb/main/relation/table_relation.hpp index a14ce054b..37af419e3 100644 --- a/src/duckdb/src/include/duckdb/main/relation/table_relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation/table_relation.hpp @@ -16,6 +16,7 @@ namespace duckdb { class TableRelation : public Relation { public: TableRelation(const shared_ptr &context, unique_ptr description); + TableRelation(const shared_ptr &context, unique_ptr description); unique_ptr description; diff --git a/src/duckdb/src/include/duckdb/main/relation/update_relation.hpp b/src/duckdb/src/include/duckdb/main/relation/update_relation.hpp index 1cb142222..f46739dde 100644 --- a/src/duckdb/src/include/duckdb/main/relation/update_relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation/update_relation.hpp @@ -15,8 +15,9 @@ namespace duckdb { class UpdateRelation : public Relation { public: - UpdateRelation(ClientContextWrapper &context, unique_ptr condition, string schema_name, - string table_name, vector update_columns, vector> expressions); + UpdateRelation(shared_ptr &context, unique_ptr condition, + string schema_name, string table_name, vector update_columns, + vector> expressions); vector columns; unique_ptr condition; diff --git a/src/duckdb/src/include/duckdb/main/relation/value_relation.hpp b/src/duckdb/src/include/duckdb/main/relation/value_relation.hpp index 81fb8c4e1..b9165bc20 100644 --- a/src/duckdb/src/include/duckdb/main/relation/value_relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation/value_relation.hpp @@ -17,6 +17,8 @@ class ValueRelation : public Relation { public: ValueRelation(const shared_ptr &context, const vector> &values, vector names, string alias = "values"); + ValueRelation(const shared_ptr &context, const vector> &values, + vector names, string alias = "values"); ValueRelation(const shared_ptr &context, const string &values, vector names, string alias = "values"); diff --git a/src/duckdb/src/include/duckdb/main/relation/view_relation.hpp b/src/duckdb/src/include/duckdb/main/relation/view_relation.hpp index 78f72d786..529817d60 100644 --- a/src/duckdb/src/include/duckdb/main/relation/view_relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation/view_relation.hpp @@ -15,6 +15,7 @@ namespace duckdb { class ViewRelation : public Relation { public: ViewRelation(const shared_ptr &context, string schema_name, string view_name); + ViewRelation(const shared_ptr &context, string schema_name, string view_name); ViewRelation(const shared_ptr &context, unique_ptr ref, const string &view_name); string schema_name; diff --git a/src/duckdb/src/include/duckdb/main/settings.hpp b/src/duckdb/src/include/duckdb/main/settings.hpp index f3f7ab6df..ab33eab16 100644 --- a/src/duckdb/src/include/duckdb/main/settings.hpp +++ b/src/duckdb/src/include/duckdb/main/settings.hpp @@ -10,6 +10,7 @@ #include "duckdb/common/common.hpp" #include "duckdb/common/types/value.hpp" +#include "duckdb/main/config.hpp" namespace duckdb { class ClientContext; @@ -52,906 +53,1047 @@ struct SettingLookupResult { SettingScope scope = SettingScope::INVALID; }; +//===----------------------------------------------------------------------===// +// This code is autogenerated from 'update_settings_header_file.py'. +// Please do not make any changes directly here, as they will be overwritten. +// +// Start of the auto-generated list of settings structures +//===----------------------------------------------------------------------===// + struct AccessModeSetting { + using RETURN_TYPE = AccessMode; static constexpr const char *Name = "access_mode"; static constexpr const char *Description = "Access mode of the database (AUTOMATIC, READ_ONLY or READ_WRITE)"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static 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 Value GetSetting(const ClientContext &context); }; -struct AllowPersistentSecrets { - static constexpr const char *Name = "allow_persistent_secrets"; - static constexpr const char *Description = - "Allow the creation of persistent secrets, that are stored and loaded on restarts"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; +struct AllocatorBackgroundThreadsSetting { + using RETURN_TYPE = bool; + 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); }; -struct CatalogErrorMaxSchema { - static constexpr const char *Name = "catalog_error_max_schemas"; +struct AllocatorBulkDeallocationFlushThresholdSetting { + using RETURN_TYPE = string; + static constexpr const char *Name = "allocator_bulk_deallocation_flush_threshold"; static constexpr const char *Description = - "The maximum number of schemas the system will scan for \"did you mean...\" style errors in the catalog"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; + "If a bulk deallocation larger than this occurs, flush outstanding allocations."; + 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); }; -struct CheckpointThresholdSetting { - static constexpr const char *Name = "checkpoint_threshold"; +struct AllocatorFlushThresholdSetting { + using RETURN_TYPE = string; + static constexpr const char *Name = "allocator_flush_threshold"; static constexpr const char *Description = - "The WAL size threshold at which to automatically trigger a checkpoint (e.g. 1GB)"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + "Peak allocation threshold at which to flush the allocator after completing a task."; + 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); }; -struct DebugCheckpointAbort { - static constexpr const char *Name = "debug_checkpoint_abort"; - static constexpr const char *Description = - "DEBUG SETTING: trigger an abort while checkpointing for testing purposes"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct AllowCommunityExtensionsSetting { + using RETURN_TYPE = bool; + 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); }; -struct DebugForceExternal { - static constexpr const char *Name = "debug_force_external"; - static constexpr const char *Description = - "DEBUG SETTING: force out-of-core computation for operators that support it, used for testing"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); +struct AllowExtensionsMetadataMismatchSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "allow_extensions_metadata_mismatch"; + static constexpr const char *Description = "Allow to load extensions with not compatible metadata"; + static constexpr const 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); }; -struct DebugForceNoCrossProduct { - static constexpr const char *Name = "debug_force_no_cross_product"; +struct AllowPersistentSecretsSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "allow_persistent_secrets"; static constexpr const char *Description = - "DEBUG SETTING: Force disable cross product generation when hyper graph isn't connected, used for testing"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); + "Allow the creation of persistent secrets, that are stored and loaded on restarts"; + 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); }; -struct DebugSkipCheckpointOnCommit { - static constexpr const char *Name = "debug_skip_checkpoint_on_commit"; - static constexpr const char *Description = "DEBUG SETTING: skip checkpointing on commit"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; +struct AllowUnredactedSecretsSetting { + using RETURN_TYPE = bool; + 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); }; -struct OrderedAggregateThreshold { - static constexpr const char *Name = "ordered_aggregate_threshold"; // NOLINT - static constexpr const char *Description = // NOLINT - "The number of rows to accumulate before sorting, used for tuning"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; // NOLINT - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); +struct AllowUnsignedExtensionsSetting { + using RETURN_TYPE = bool; + 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); }; -struct DebugAsOfIEJoin { - static constexpr const char *Name = "debug_asof_iejoin"; // NOLINT - static constexpr const char *Description = "DEBUG SETTING: force use of IEJoin to implement AsOf joins"; // NOLINT - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; // NOLINT - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); +struct AllowedDirectoriesSetting { + using RETURN_TYPE = vector; + static constexpr const char *Name = "allowed_directories"; + static constexpr const char *Description = "List of directories/prefixes that are ALWAYS allowed to be queried - " + "even when enable_external_access is false"; + 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); }; -struct PreferRangeJoins { - static constexpr const char *Name = "prefer_range_joins"; // NOLINT - static constexpr const char *Description = "Force use of range joins with mixed predicates"; // NOLINT - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; // NOLINT - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); +struct AllowedPathsSetting { + using RETURN_TYPE = vector; + static constexpr const char *Name = "allowed_paths"; + static constexpr const char *Description = + "List of files that are ALWAYS allowed to be queried - even when enable_external_access is false"; + 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); }; -struct DebugWindowMode { - static constexpr const char *Name = "debug_window_mode"; - static constexpr const char *Description = "DEBUG SETTING: switch window mode to use"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct ArrowLargeBufferSizeSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "arrow_large_buffer_size"; + static constexpr const char *Description = + "If arrow buffers for strings, blobs, uuids and bits should be exported using large buffers"; + static constexpr const 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); }; -struct DefaultCollationSetting { - static constexpr const char *Name = "default_collation"; - static constexpr const char *Description = "The collation setting used when none is specified"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct ArrowLosslessConversionSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "arrow_lossless_conversion"; + static constexpr const char *Description = + "Whenever a DuckDB type does not have a clear native or canonical extension match in Arrow, export the types " + "with a duckdb.type_name extension name."; + static constexpr const char *InputType = "BOOLEAN"; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct DefaultOrderSetting { - static constexpr const char *Name = "default_order"; - static constexpr const char *Description = "The order type used when none is specified (ASC or DESC)"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct ArrowOutputListViewSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "arrow_output_list_view"; + static constexpr const char *Description = + "If export to arrow format should use ListView as the physical layout for LIST columns"; + static constexpr const 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); }; -struct DefaultNullOrderSetting { - static constexpr const char *Name = "default_null_order"; - static constexpr const char *Description = "Null ordering used when none is specified (NULLS_FIRST or NULLS_LAST)"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct AutoinstallExtensionRepositorySetting { + using RETURN_TYPE = string; + static constexpr const char *Name = "autoinstall_extension_repository"; + static constexpr const char *Description = + "Overrides the custom endpoint for extension installation on autoloading"; + static constexpr const 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); }; -struct DefaultSecretStorage { - static constexpr const char *Name = "default_secret_storage"; - static constexpr const char *Description = "Allows switching the default storage for secrets"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct AutoinstallKnownExtensionsSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "autoinstall_known_extensions"; + static constexpr const char *Description = + "Whether known extensions are allowed to be automatically installed when a query depends on them"; + static constexpr const 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); }; -struct DisabledFileSystemsSetting { - static constexpr const char *Name = "disabled_filesystems"; - static constexpr const char *Description = "Disable specific file systems preventing access (e.g. LocalFileSystem)"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct AutoloadKnownExtensionsSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "autoload_known_extensions"; + static constexpr const char *Description = + "Whether known extensions are allowed to be automatically loaded when a query depends on them"; + static constexpr const 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); }; -struct DisabledOptimizersSetting { - static constexpr const char *Name = "disabled_optimizers"; - static constexpr const char *Description = "DEBUG SETTING: disable a specific set of optimizers (comma separated)"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct CatalogErrorMaxSchemasSetting { + using RETURN_TYPE = idx_t; + static constexpr const char *Name = "catalog_error_max_schemas"; + static constexpr const char *Description = + "The maximum number of schemas the system will scan for \"did you mean...\" style errors in the catalog"; + static constexpr const 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); }; -struct EnableExternalAccessSetting { - static constexpr const char *Name = "enable_external_access"; +struct CheckpointThresholdSetting { + using RETURN_TYPE = string; + static constexpr const char *Name = "checkpoint_threshold"; static constexpr const char *Description = - "Allow the database to access external state (through e.g. loading/installing modules, COPY TO/FROM, CSV " - "readers, pandas replacement scans, etc)"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + "The WAL size threshold at which to automatically trigger a checkpoint (e.g. 1GB)"; + 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); }; -struct EnableMacrosDependencies { - static constexpr const char *Name = "enable_macro_dependencies"; - static constexpr const char *Description = - "Enable created MACROs to create dependencies on the referenced objects (such as tables)"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; +struct CustomExtensionRepositorySetting { + using RETURN_TYPE = string; + 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); }; -struct EnableViewDependencies { - static constexpr const char *Name = "enable_view_dependencies"; +struct CustomProfilingSettingsSetting { + using RETURN_TYPE = string; + static constexpr const char *Name = "custom_profiling_settings"; + static constexpr const char *Description = "Accepts a JSON enabling custom metrics"; + 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); +}; + +struct CustomUserAgentSetting { + using RETURN_TYPE = string; + static constexpr const char *Name = "custom_user_agent"; + static constexpr const char *Description = "Metadata from DuckDB callers"; + 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); +}; + +struct DebugAsofIejoinSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "debug_asof_iejoin"; + static constexpr const char *Description = "DEBUG SETTING: force use of IEJoin to implement AsOf joins"; + 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); +}; + +struct DebugCheckpointAbortSetting { + using RETURN_TYPE = CheckpointAbort; + static constexpr const char *Name = "debug_checkpoint_abort"; static constexpr const char *Description = - "Enable created VIEWs to create dependencies on the referenced objects (such as tables)"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + "DEBUG SETTING: trigger an abort while checkpointing for testing purposes"; + 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); }; -struct EnableFSSTVectors { - static constexpr const char *Name = "enable_fsst_vectors"; +struct DebugForceExternalSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "debug_force_external"; static constexpr const char *Description = - "Allow scans on FSST compressed segments to emit compressed vectors to utilize late decompression"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + "DEBUG SETTING: force out-of-core computation for operators that support it, used for testing"; + 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); +}; + +struct DebugForceNoCrossProductSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "debug_force_no_cross_product"; + static constexpr const char *Description = + "DEBUG SETTING: Force disable cross product generation when hyper graph isn't connected, used for testing"; + static constexpr const char *InputType = "BOOLEAN"; + static void SetLocal(ClientContext &context, const Value ¶meter); + static void ResetLocal(ClientContext &context); + static Value GetSetting(const ClientContext &context); +}; + +struct DebugSkipCheckpointOnCommitSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "debug_skip_checkpoint_on_commit"; + static constexpr const char *Description = "DEBUG SETTING: skip checkpointing on commit"; + 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); }; -struct AllowUnsignedExtensionsSetting { - static constexpr const char *Name = "allow_unsigned_extensions"; - static constexpr const char *Description = "Allow to load extensions with invalid or missing signatures"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; +struct DebugWindowModeSetting { + using RETURN_TYPE = WindowAggregationMode; + static constexpr const char *Name = "debug_window_mode"; + static constexpr const char *Description = "DEBUG SETTING: switch window mode to use"; + 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); }; -struct AllowCommunityExtensionsSetting { - static constexpr const char *Name = "allow_community_extensions"; - static constexpr const char *Description = "Allow to load community built extensions"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; +struct DefaultBlockSizeSetting { + using RETURN_TYPE = idx_t; + static constexpr const char *Name = "default_block_size"; + static constexpr const char *Description = + "The default block size for new duckdb database files (new as-in, they do not yet exist)."; + static constexpr const 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); }; -struct AllowExtensionsMetadataMismatchSetting { - static constexpr const char *Name = "allow_extensions_metadata_mismatch"; - static constexpr const char *Description = "Allow to load extensions with not compatible metadata"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; +struct DefaultCollationSetting { + using RETURN_TYPE = string; + static constexpr const char *Name = "default_collation"; + static constexpr const char *Description = "The collation setting used when none is specified"; + static constexpr const char *InputType = "VARCHAR"; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); + static void SetLocal(ClientContext &context, const Value ¶meter); + static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct AllowUnredactedSecretsSetting { - static constexpr const char *Name = "allow_unredacted_secrets"; - static constexpr const char *Description = "Allow printing unredacted secrets"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; +struct DefaultNullOrderSetting { + using RETURN_TYPE = DefaultOrderByNullType; + static constexpr const char *Name = "default_null_order"; + static constexpr const char *Description = "Null ordering used when none is specified (NULLS_FIRST or NULLS_LAST)"; + static constexpr const 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); }; -struct CustomExtensionRepository { - static constexpr const char *Name = "custom_extension_repository"; - static constexpr const char *Description = "Overrides the custom endpoint for remote extension installation"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct DefaultOrderSetting { + using RETURN_TYPE = string; + static constexpr const char *Name = "default_order"; + static constexpr const char *Description = "The order type used when none is specified (ASC or DESC)"; + static constexpr const 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); }; -struct AutoloadExtensionRepository { - static constexpr const char *Name = "autoinstall_extension_repository"; - static constexpr const char *Description = - "Overrides the custom endpoint for extension installation on autoloading"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct DefaultSecretStorageSetting { + using RETURN_TYPE = string; + static constexpr const char *Name = "default_secret_storage"; + static constexpr const char *Description = "Allows switching the default storage for secrets"; + 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); }; -struct AutoinstallKnownExtensions { - static constexpr const char *Name = "autoinstall_known_extensions"; - static constexpr const char *Description = - "Whether known extensions are allowed to be automatically installed when a query depends on them"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; +struct DisabledFilesystemsSetting { + using RETURN_TYPE = string; + static constexpr const char *Name = "disabled_filesystems"; + static constexpr const char *Description = "Disable specific file systems preventing access (e.g. LocalFileSystem)"; + 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); }; -struct AutoloadKnownExtensions { - static constexpr const char *Name = "autoload_known_extensions"; - static constexpr const char *Description = - "Whether known extensions are allowed to be automatically loaded when a query depends on them"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; +struct DisabledOptimizersSetting { + using RETURN_TYPE = string; + static constexpr const char *Name = "disabled_optimizers"; + static constexpr const char *Description = "DEBUG SETTING: disable a specific set of optimizers (comma separated)"; + static constexpr const 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); }; -struct EnableObjectCacheSetting { - static constexpr const char *Name = "enable_object_cache"; - static constexpr const char *Description = "Whether or not object cache is used to cache e.g. Parquet metadata"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; +struct DuckDBAPISetting { + using RETURN_TYPE = string; + 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); }; -struct StorageCompatibilityVersion { - static constexpr const char *Name = "storage_compatibility_version"; - static constexpr const char *Description = "Serialize on checkpoint with compatibility for a given duckdb version"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct EnableExternalAccessSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "enable_external_access"; + static constexpr const char *Description = + "Allow the database to access external state (through e.g. loading/installing modules, COPY TO/FROM, CSV " + "readers, pandas replacement scans, etc)"; + static constexpr const 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); +}; + +struct EnableFSSTVectorsSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "enable_fsst_vectors"; + static constexpr const char *Description = + "Allow scans on FSST compressed segments to emit compressed vectors to utilize late decompression"; + static constexpr const 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); +}; + +struct EnableHTTPLoggingSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "enable_http_logging"; + static constexpr const char *Description = "Enables HTTP logging"; + 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); }; struct EnableHTTPMetadataCacheSetting { + using RETURN_TYPE = bool; static constexpr const char *Name = "enable_http_metadata_cache"; static constexpr const char *Description = "Whether or not the global http metadata is used to cache HTTP metadata"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static 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); +}; + +struct EnableMacroDependenciesSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "enable_macro_dependencies"; + static constexpr const char *Description = + "Enable created MACROs to create dependencies on the referenced objects (such as tables)"; + static constexpr const 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); +}; + +struct EnableObjectCacheSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "enable_object_cache"; + static constexpr const char *Description = "Whether or not object cache is used to cache e.g. Parquet metadata"; + static constexpr const 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); }; struct EnableProfilingSetting { + using RETURN_TYPE = string; static constexpr const char *Name = "enable_profiling"; static constexpr const char *Description = "Enables profiling, and sets the output format (JSON, QUERY_TREE, QUERY_TREE_OPTIMIZER)"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); -}; - -struct CustomProfilingSettings { - static constexpr const char *Name = "custom_profiling_settings"; - static constexpr const char *Description = "Accepts a JSON enabling custom metrics"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static constexpr const char *InputType = "VARCHAR"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct EnableProgressBarSetting { + using RETURN_TYPE = bool; static constexpr const char *Name = "enable_progress_bar"; static constexpr const char *Description = "Enables the progress bar, printing progress to the terminal for long queries"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static constexpr const char *InputType = "BOOLEAN"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); + static bool OnLocalSet(ClientContext &context, const Value &input); + static bool OnLocalReset(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct EnableProgressBarPrintSetting { + using RETURN_TYPE = bool; static constexpr const char *Name = "enable_progress_bar_print"; static constexpr const char *Description = "Controls the printing of the progress bar, when 'enable_progress_bar' is true"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static constexpr const char *InputType = "BOOLEAN"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct ErrorsAsJsonSetting { +struct EnableViewDependenciesSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "enable_view_dependencies"; + static constexpr const char *Description = + "Enable created VIEWs to create dependencies on the referenced objects (such as tables)"; + static constexpr const 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); +}; + +struct ErrorsAsJSONSetting { + using RETURN_TYPE = bool; static constexpr const char *Name = "errors_as_json"; static constexpr const char *Description = "Output error messages as structured JSON instead of as a raw string"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static constexpr const char *InputType = "BOOLEAN"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct ExplainOutputSetting { + using RETURN_TYPE = ExplainOutputType; static constexpr const char *Name = "explain_output"; static constexpr const char *Description = "Output of EXPLAIN statements (ALL, OPTIMIZED_ONLY, PHYSICAL_ONLY)"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static constexpr const char *InputType = "VARCHAR"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct ExportLargeBufferArrow { - static constexpr const char *Name = "arrow_large_buffer_size"; - static constexpr const char *Description = - "If arrow buffers for strings, blobs, uuids and bits should be exported using large buffers"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - struct ExtensionDirectorySetting { + using RETURN_TYPE = string; static constexpr const char *Name = "extension_directory"; static constexpr const char *Description = "Set the directory to store extensions in"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static 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); }; struct ExternalThreadsSetting { + using RETURN_TYPE = idx_t; static constexpr const char *Name = "external_threads"; static constexpr const char *Description = "The number of external threads that work on DuckDB tasks."; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT; + static 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); }; struct FileSearchPathSetting { + using RETURN_TYPE = string; static constexpr const char *Name = "file_search_path"; static constexpr const char *Description = "A comma separated list of directories to search for input files"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static constexpr const char *InputType = "VARCHAR"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct ForceCompressionSetting { - static constexpr const char *Name = "force_compression"; - static constexpr const char *Description = "DEBUG SETTING: forces a specific compression method to be used"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct ForceBitpackingModeSetting { + using RETURN_TYPE = string; + 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); }; -struct ForceBitpackingModeSetting { - static constexpr const char *Name = "force_bitpacking_mode"; - static constexpr const char *Description = "DEBUG SETTING: forces a specific bitpacking mode"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct ForceCompressionSetting { + using RETURN_TYPE = string; + 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 void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; 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 LogicalTypeId InputType = LogicalTypeId::VARCHAR; + 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); +}; + +struct HTTPLoggingOutputSetting { + using RETURN_TYPE = string; + static constexpr const char *Name = "http_logging_output"; + static constexpr const char *Description = + "The file to which HTTP logging output should be saved, or empty to print to the terminal"; + static constexpr const char *InputType = "VARCHAR"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct HTTPProxy { +struct HTTPProxySetting { + using RETURN_TYPE = string; static constexpr const char *Name = "http_proxy"; static constexpr const char *Description = "HTTP proxy host"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + 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); }; -struct HTTPProxyUsername { - static constexpr const char *Name = "http_proxy_username"; - static constexpr const char *Description = "Username for HTTP proxy"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct HTTPProxyPasswordSetting { + using RETURN_TYPE = string; + 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); }; -struct HTTPProxyPassword { - static constexpr const char *Name = "http_proxy_password"; - static constexpr const char *Description = "Password for HTTP proxy"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct HTTPProxyUsernameSetting { + using RETURN_TYPE = string; + 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); }; -struct IntegerDivisionSetting { - static constexpr const char *Name = "integer_division"; +struct IEEEFloatingPointOpsSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "ieee_floating_point_ops"; static constexpr const char *Description = - "Whether or not the / operator defaults to integer division, or to floating point division"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + "Use IEE754-compliant floating point operations (returning NAN instead of errors/NULL)."; + 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); }; -struct LogQueryPathSetting { - static constexpr const char *Name = "log_query_path"; +struct ImmediateTransactionModeSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "immediate_transaction_mode"; static constexpr const char *Description = - "Specifies the path to which queries should be logged (default: NULL, queries are not logged)"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); + "Whether transactions should be started lazily when needed, or immediately when BEGIN TRANSACTION is called"; + 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); }; -struct LockConfigurationSetting { - static constexpr const char *Name = "lock_configuration"; - static constexpr const char *Description = "Whether or not the configuration can be altered"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; +struct IndexScanMaxCountSetting { + using RETURN_TYPE = idx_t; + static constexpr const char *Name = "index_scan_max_count"; + static constexpr const char *Description = + "The maximum index scan count sets a threshold for index scans. If fewer than MAX(index_scan_max_count, " + "index_scan_percentage * total_row_count) rows match, we perform an index scan instead of a table scan."; + static constexpr const 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); }; -struct IEEEFloatingPointOpsSetting { - static constexpr const char *Name = "ieee_floating_point_ops"; +struct IndexScanPercentageSetting { + using RETURN_TYPE = double; + static constexpr const char *Name = "index_scan_percentage"; static constexpr const char *Description = - "Use IEE754-compliant floating point operations (returning NAN instead of errors/NULL)"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + "The index scan percentage sets a threshold for index scans. If fewer than MAX(index_scan_max_count, " + "index_scan_percentage * total_row_count) rows match, we perform an index scan instead of a table scan."; + static constexpr const char *InputType = "DOUBLE"; + 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 Value GetSetting(const ClientContext &context); +}; + +struct IntegerDivisionSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "integer_division"; + static constexpr const char *Description = + "Whether or not the / operator defaults to integer division, or to floating point division"; + static constexpr const char *InputType = "BOOLEAN"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct ImmediateTransactionModeSetting { - static constexpr const char *Name = "immediate_transaction_mode"; - static constexpr const char *Description = - "Whether transactions should be started lazily when needed, or immediately when BEGIN TRANSACTION is called"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; +struct LockConfigurationSetting { + using RETURN_TYPE = bool; + 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); }; -struct MaximumExpressionDepthSetting { +struct LogQueryPathSetting { + using RETURN_TYPE = string; + static constexpr const char *Name = "log_query_path"; + static constexpr const char *Description = + "Specifies the path to which queries should be logged (default: NULL, queries are not logged)"; + static constexpr const char *InputType = "VARCHAR"; + static void SetLocal(ClientContext &context, const Value ¶meter); + static void ResetLocal(ClientContext &context); + static Value GetSetting(const ClientContext &context); +}; + +struct MaxExpressionDepthSetting { + using RETURN_TYPE = idx_t; static constexpr const char *Name = "max_expression_depth"; static constexpr const char *Description = "The maximum expression depth limit in the parser. WARNING: increasing this setting and using very deep " "expressions might lead to stack overflow errors."; - static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; + static constexpr const char *InputType = "UBIGINT"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct MaximumMemorySetting { +struct MaxMemorySetting { + using RETURN_TYPE = string; static constexpr const char *Name = "max_memory"; static constexpr const char *Description = "The maximum memory of the system (e.g. 1GB)"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static 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); }; -struct StreamingBufferSize { - static constexpr const char *Name = "streaming_buffer_size"; - static constexpr const char *Description = - "The maximum memory to buffer between fetching from a streaming result (e.g. 1GB)"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); -}; - -struct MaximumTempDirectorySize { +struct MaxTempDirectorySizeSetting { + using RETURN_TYPE = string; static constexpr const char *Name = "max_temp_directory_size"; static constexpr const char *Description = - "The maximum amount of data stored inside the 'temp_directory' (when set). If the `temp_directory` is set to " - "an existing directory, this option defaults to the available disk space on " - "that drive. Otherwise, it defaults to 0 (implying that the temporary directory is not used)."; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + "The maximum amount of data stored inside the 'temp_directory' (when set) (e.g. 1GB)"; + 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); }; -struct MaximumVacuumTasks { +struct MaxVacuumTasksSetting { + using RETURN_TYPE = idx_t; static constexpr const char *Name = "max_vacuum_tasks"; - static constexpr const char *Description = "The maximum vacuum tasks to schedule during a checkpoint"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; + static constexpr const char *Description = "The maximum vacuum tasks to schedule during a checkpoint."; + 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); }; -struct MergeJoinThreshold { +struct MergeJoinThresholdSetting { + using RETURN_TYPE = idx_t; static constexpr const char *Name = "merge_join_threshold"; static constexpr const char *Description = "The number of rows we need on either table to choose a merge join"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; + static constexpr const char *InputType = "UBIGINT"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct NestedLoopJoinThreshold { +struct NestedLoopJoinThresholdSetting { + using RETURN_TYPE = idx_t; static constexpr const char *Name = "nested_loop_join_threshold"; static constexpr const char *Description = "The number of rows we need on either table to choose a nested loop join"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; + static constexpr const char *InputType = "UBIGINT"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct OldImplicitCasting { +struct OldImplicitCastingSetting { + using RETURN_TYPE = bool; static constexpr const char *Name = "old_implicit_casting"; static constexpr const char *Description = "Allow implicit casting to/from VARCHAR"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static 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); }; -struct OrderByNonIntegerLiteral { +struct OrderByNonIntegerLiteralSetting { + using RETURN_TYPE = bool; static constexpr const char *Name = "order_by_non_integer_literal"; static constexpr const char *Description = - "Allow ordering by non-integer literals - ordering by such literals has no effect"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + "Allow ordering by non-integer literals - ordering by such literals has no effect."; + 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); }; -struct PartitionedWriteFlushThreshold { +struct OrderedAggregateThresholdSetting { + using RETURN_TYPE = idx_t; + static constexpr const char *Name = "ordered_aggregate_threshold"; + static constexpr const char *Description = "The number of rows to accumulate before sorting, used for tuning"; + static constexpr const char *InputType = "UBIGINT"; + static void SetLocal(ClientContext &context, const Value ¶meter); + static void ResetLocal(ClientContext &context); + static bool OnLocalSet(ClientContext &context, const Value &input); + static Value GetSetting(const ClientContext &context); +}; + +struct PartitionedWriteFlushThresholdSetting { + using RETURN_TYPE = idx_t; static constexpr const char *Name = "partitioned_write_flush_threshold"; static constexpr const char *Description = "The threshold in number of rows after which we flush a thread state when writing using PARTITION_BY"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; + static constexpr const char *InputType = "UBIGINT"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct PartitionedWriteMaxOpenFiles { +struct PartitionedWriteMaxOpenFilesSetting { + using RETURN_TYPE = idx_t; static constexpr const char *Name = "partitioned_write_max_open_files"; static constexpr const char *Description = "The maximum amount of files the system can keep open before flushing to disk when writing using PARTITION_BY"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; + static constexpr const char *InputType = "UBIGINT"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct DefaultBlockAllocSize { - static constexpr const char *Name = "default_block_size"; - static constexpr const char *Description = - "The default block size for new duckdb database files (new as-in, they do not yet exist)."; - static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - -struct IndexScanPercentage { - static constexpr const char *Name = "index_scan_percentage"; - static constexpr const char *Description = - "The index scan percentage sets a threshold for index scans. If fewer than MAX(index_scan_max_count, " - "index_scan_percentage * total_row_count) rows match, we perform an index scan instead of a table scan."; - static constexpr const LogicalTypeId InputType = LogicalTypeId::DOUBLE; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - -struct IndexScanMaxCount { - static constexpr const char *Name = "index_scan_max_count"; - static constexpr const char *Description = - "The maximum index scan count sets a threshold for index scans. If fewer than MAX(index_scan_max_count, " - "index_scan_percentage * total_row_count) rows match, we perform an index scan instead of a table scan."; - static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - struct PasswordSetting { + using RETURN_TYPE = string; static constexpr const char *Name = "password"; static constexpr const char *Description = "The password to use. Ignored for legacy compatibility."; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static 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); }; -struct PerfectHashThresholdSetting { +struct PerfectHtThresholdSetting { + using RETURN_TYPE = idx_t; static constexpr const char *Name = "perfect_ht_threshold"; static constexpr const char *Description = "Threshold in bytes for when to use a perfect hash table"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT; + static constexpr const char *InputType = "UBIGINT"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct PivotFilterThreshold { +struct PivotFilterThresholdSetting { + using RETURN_TYPE = idx_t; static constexpr const char *Name = "pivot_filter_threshold"; static constexpr const char *Description = "The threshold to switch from using filtered aggregates to LIST with a dedicated pivot operator"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT; + static constexpr const char *InputType = "UBIGINT"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct PivotLimitSetting { + using RETURN_TYPE = idx_t; static constexpr const char *Name = "pivot_limit"; static constexpr const char *Description = "The maximum number of pivot columns in a pivot statement"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT; + static constexpr const char *InputType = "UBIGINT"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct PreserveIdentifierCase { +struct PreferRangeJoinsSetting { + using RETURN_TYPE = bool; + static constexpr const char *Name = "prefer_range_joins"; + static constexpr const char *Description = "Force use of range joins with mixed predicates"; + 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); +}; + +struct PreserveIdentifierCaseSetting { + using RETURN_TYPE = bool; static constexpr const char *Name = "preserve_identifier_case"; static constexpr const char *Description = "Whether or not to preserve the identifier case, instead of always lowercasing all non-quoted identifiers"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static constexpr const char *InputType = "BOOLEAN"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct PreserveInsertionOrder { +struct PreserveInsertionOrderSetting { + using RETURN_TYPE = bool; static constexpr const char *Name = "preserve_insertion_order"; static constexpr const char *Description = "Whether or not to preserve insertion order. If set to false the system is allowed to re-order any results " "that do not contain ORDER BY clauses."; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - -struct ArrowOutputListView { - static constexpr const char *Name = "arrow_output_list_view"; - static constexpr const char *Description = - "If export to arrow format should use ListView as the physical layout for LIST columns"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - -struct LosslessConversionArrow { - static constexpr const char *Name = "arrow_lossless_conversion"; - static constexpr const char *Description = - "Whenever a DuckDB type does not have a clear native or canonical extension match in Arrow, export the types " - "with a duckdb.type_name extension name."; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static 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); }; -struct ProduceArrowStringView { +struct ProduceArrowStringViewSetting { + using RETURN_TYPE = bool; static constexpr const char *Name = "produce_arrow_string_view"; static constexpr const char *Description = "If strings should be produced by DuckDB in Utf8View format instead of Utf8"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static 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); }; struct ProfileOutputSetting { + using RETURN_TYPE = string; static constexpr const char *Name = "profile_output"; static constexpr const char *Description = "The file to which profile output should be saved, or empty to print to the terminal"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static constexpr const char *InputType = "VARCHAR"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct ProfilingModeSetting { + using RETURN_TYPE = string; static constexpr const char *Name = "profiling_mode"; static constexpr const char *Description = "The profiling mode (STANDARD or DETAILED)"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static constexpr const char *InputType = "VARCHAR"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct ProgressBarTimeSetting { + using RETURN_TYPE = int64_t; static constexpr const char *Name = "progress_bar_time"; static constexpr const char *Description = "Sets the time (in milliseconds) how long a query needs to take before we start printing a progress bar"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT; + static constexpr const char *InputType = "BIGINT"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct ScalarSubqueryErrorOnMultipleRows { +struct ScalarSubqueryErrorOnMultipleRowsSetting { + using RETURN_TYPE = bool; static constexpr const char *Name = "scalar_subquery_error_on_multiple_rows"; static constexpr const char *Description = - "When a scalar subquery returns multiple rows - return a random row instead of returning an error"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + "When a scalar subquery returns multiple rows - return a random row instead of returning an error."; + 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); }; struct SchemaSetting { + using RETURN_TYPE = string; static constexpr const char *Name = "schema"; static constexpr const char *Description = "Sets the default search schema. Equivalent to setting search_path to a single value."; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static constexpr const char *InputType = "VARCHAR"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct SearchPathSetting { + using RETURN_TYPE = string; static constexpr const char *Name = "search_path"; static constexpr const char *Description = "Sets the default catalog search path as a comma-separated list of values"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static constexpr const char *InputType = "VARCHAR"; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct SecretDirectorySetting { + using RETURN_TYPE = string; static constexpr const char *Name = "secret_directory"; static constexpr const char *Description = "Set the directory to which persistent secrets are stored"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static 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); }; -struct TempDirectorySetting { - static constexpr const char *Name = "temp_directory"; - static constexpr const char *Description = "Set the directory to which to write temp files"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - -struct ThreadsSetting { - static constexpr const char *Name = "threads"; - static constexpr const char *Description = "The number of total threads used by the system."; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - -struct UsernameSetting { - static constexpr const char *Name = "username"; - static constexpr const char *Description = "The username to use. Ignored for legacy compatibility."; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - -struct AllocatorFlushThreshold { - static constexpr const char *Name = "allocator_flush_threshold"; - static constexpr const char *Description = - "Peak allocation threshold at which to flush the allocator after completing a task."; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct StorageCompatibilityVersionSetting { + using RETURN_TYPE = string; + static constexpr const char *Name = "storage_compatibility_version"; + static constexpr const char *Description = "Serialize on checkpoint with compatibility for a given duckdb version"; + static constexpr const 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); }; -struct AllocatorBulkDeallocationFlushThreshold { - static constexpr const char *Name = "allocator_bulk_deallocation_flush_threshold"; +struct StreamingBufferSizeSetting { + using RETURN_TYPE = string; + static constexpr const char *Name = "streaming_buffer_size"; static constexpr const char *Description = - "If a bulk deallocation larger than this occurs, flush outstanding allocations."; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); + "The maximum memory to buffer between fetching from a streaming result (e.g. 1GB)"; + 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); }; -struct AllocatorBackgroundThreadsSetting { - static constexpr const char *Name = "allocator_background_threads"; - static constexpr const char *Description = "Whether to enable the allocator background thread."; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; +struct TempDirectorySetting { + using RETURN_TYPE = string; + static constexpr const char *Name = "temp_directory"; + static constexpr const char *Description = "Set the directory to which to write temp files"; + 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); }; -struct DuckDBApiSetting { - static constexpr const char *Name = "duckdb_api"; - static constexpr const char *Description = "DuckDB API surface"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct ThreadsSetting { + using RETURN_TYPE = int64_t; + static constexpr const char *Name = "threads"; + static constexpr const char *Description = "The number of total threads used by the system."; + 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); }; -struct CustomUserAgentSetting { - static constexpr const char *Name = "custom_user_agent"; - static constexpr const char *Description = "Metadata from DuckDB callers"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; +struct UsernameSetting { + using RETURN_TYPE = string; + 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); }; -struct EnableHTTPLoggingSetting { - static constexpr const char *Name = "enable_http_logging"; - static constexpr const char *Description = "Enables HTTP logging"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); -}; - -struct HTTPLoggingOutputSetting { - static constexpr const char *Name = "http_logging_output"; - static constexpr const char *Description = - "The file to which HTTP logging output should be saved, or empty to print to the terminal"; - static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); -}; +//===----------------------------------------------------------------------===// +// End of the auto-generated list of settings structures +//===--------------------------------------------------------------------===// } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/main/table_description.hpp b/src/duckdb/src/include/duckdb/main/table_description.hpp index 151592f49..d1b7f6561 100644 --- a/src/duckdb/src/include/duckdb/main/table_description.hpp +++ b/src/duckdb/src/include/duckdb/main/table_description.hpp @@ -12,13 +12,23 @@ namespace duckdb { -struct TableDescription { +class TableDescription { public: - //! The schema of the table + TableDescription(const string &database_name, const string &schema_name, const string &table_name) + : database(database_name), schema(schema_name), table(table_name) {}; + + TableDescription() = delete; + +public: + //! The database of the table. + string database; + //! The schema of the table. string schema; - //! The table name of the table + //! The name of the table. string table; - //! The columns of the table + //! True, if the catalog is readonly. + bool readonly; + //! The columns of the table. vector columns; public: diff --git a/src/duckdb/src/include/duckdb/optimizer/build_probe_side_optimizer.hpp b/src/duckdb/src/include/duckdb/optimizer/build_probe_side_optimizer.hpp index ccc4644a5..cdb7dbfda 100644 --- a/src/duckdb/src/include/duckdb/optimizer/build_probe_side_optimizer.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/build_probe_side_optimizer.hpp @@ -37,7 +37,7 @@ class BuildProbeSideOptimizer : LogicalOperatorVisitor { void VisitExpression(unique_ptr *expression) override {}; private: - void TryFlipJoinChildren(LogicalOperator &op); + void TryFlipJoinChildren(LogicalOperator &op) const; static idx_t ChildHasJoins(LogicalOperator &op); static BuildSize GetBuildSizes(const LogicalOperator &op, idx_t lhs_cardinality, idx_t rhs_cardinality); diff --git a/src/duckdb/src/include/duckdb/optimizer/column_lifetime_analyzer.hpp b/src/duckdb/src/include/duckdb/optimizer/column_lifetime_analyzer.hpp index 72848bc25..d6fe5b72b 100644 --- a/src/duckdb/src/include/duckdb/optimizer/column_lifetime_analyzer.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/column_lifetime_analyzer.hpp @@ -8,18 +8,21 @@ #pragma once -#include "duckdb/planner/logical_operator_visitor.hpp" -#include "duckdb/planner/column_binding_map.hpp" #include "duckdb/common/vector.hpp" +#include "duckdb/planner/column_binding_map.hpp" +#include "duckdb/planner/logical_operator_visitor.hpp" namespace duckdb { + +class Optimizer; class BoundColumnRefExpression; //! The ColumnLifetimeAnalyzer optimizer traverses the logical operator tree and ensures that columns are removed from //! the plan when no longer required class ColumnLifetimeAnalyzer : public LogicalOperatorVisitor { public: - explicit ColumnLifetimeAnalyzer(bool is_root = false) : everything_referenced(is_root) { + explicit ColumnLifetimeAnalyzer(Optimizer &optimizer_p, LogicalOperator &root_p, bool is_root = false) + : optimizer(optimizer_p), root(root_p), everything_referenced(is_root) { } void VisitOperator(LogicalOperator &op) override; @@ -29,6 +32,8 @@ class ColumnLifetimeAnalyzer : public LogicalOperatorVisitor { unique_ptr VisitReplace(BoundReferenceExpression &expr, unique_ptr *expr_ptr) override; private: + Optimizer &optimizer; + LogicalOperator &root; //! Whether or not all the columns are referenced. This happens in the case of the root expression (because the //! output implicitly refers all the columns below it) bool everything_referenced; @@ -36,10 +41,12 @@ class ColumnLifetimeAnalyzer : public LogicalOperatorVisitor { column_binding_set_t column_references; private: + void VisitOperatorInternal(LogicalOperator &op); void StandardVisitOperator(LogicalOperator &op); - - void ExtractUnusedColumnBindings(vector bindings, column_binding_set_t &unused_bindings); - void GenerateProjectionMap(vector bindings, column_binding_set_t &unused_bindings, - vector &map); + void ExtractUnusedColumnBindings(const vector &bindings, column_binding_set_t &unused_bindings); + static void GenerateProjectionMap(vector bindings, column_binding_set_t &unused_bindings, + vector &map); + void Verify(LogicalOperator &op); + void AddVerificationProjection(unique_ptr &child); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/optimizer/common_aggregate_optimizer.hpp b/src/duckdb/src/include/duckdb/optimizer/common_aggregate_optimizer.hpp index ff0215923..0728b2267 100644 --- a/src/duckdb/src/include/duckdb/optimizer/common_aggregate_optimizer.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/common_aggregate_optimizer.hpp @@ -8,8 +8,8 @@ #pragma once -#include "duckdb/planner/logical_operator_visitor.hpp" #include "duckdb/planner/column_binding_map.hpp" +#include "duckdb/planner/logical_operator_visitor.hpp" namespace duckdb { //! The CommonAggregateOptimizer optimizer eliminates duplicate aggregates from aggregate nodes @@ -18,8 +18,8 @@ class CommonAggregateOptimizer : public LogicalOperatorVisitor { void VisitOperator(LogicalOperator &op) override; private: + void StandardVisitOperator(LogicalOperator &op); unique_ptr VisitReplace(BoundColumnRefExpression &expr, unique_ptr *expr_ptr) override; - void ExtractCommonAggregates(LogicalAggregate &aggr); private: diff --git a/src/duckdb/src/include/duckdb/optimizer/empty_result_pullup.hpp b/src/duckdb/src/include/duckdb/optimizer/empty_result_pullup.hpp new file mode 100644 index 000000000..8959c0ecc --- /dev/null +++ b/src/duckdb/src/include/duckdb/optimizer/empty_result_pullup.hpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/optimizer/deliminator.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/optimizer/column_binding_replacer.hpp" + +namespace duckdb { + +//! The EmptyResultPullup Optimizer traverses the logical operator tree and Pulls up empty operators when possible +class EmptyResultPullup : LogicalOperatorVisitor { +public: + EmptyResultPullup() { + } + + unique_ptr Optimize(unique_ptr op); + +private: + unique_ptr PullUpEmptyJoinChildren(unique_ptr op); +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/optimizer/filter_pushdown.hpp b/src/duckdb/src/include/duckdb/optimizer/filter_pushdown.hpp index 1554e9a6f..94706d210 100644 --- a/src/duckdb/src/include/duckdb/optimizer/filter_pushdown.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/filter_pushdown.hpp @@ -57,6 +57,8 @@ class FilterPushdown { unique_ptr PushdownJoin(unique_ptr op); //! Push down a LogicalProjection op unique_ptr PushdownProjection(unique_ptr op); + //! Push down a LogicalProjection op + unique_ptr PushdownUnnest(unique_ptr op); //! Push down a LogicalSetOperation op unique_ptr PushdownSetOperation(unique_ptr op); //! Push down a LogicalGet op diff --git a/src/duckdb/src/include/duckdb/optimizer/sampling_pushdown.hpp b/src/duckdb/src/include/duckdb/optimizer/sampling_pushdown.hpp new file mode 100644 index 000000000..78c67a199 --- /dev/null +++ b/src/duckdb/src/include/duckdb/optimizer/sampling_pushdown.hpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/optimizer/sampling_pushdown.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/constants.hpp" +#include "duckdb/planner/logical_operator.hpp" +#include "duckdb/common/unique_ptr.hpp" + +namespace duckdb { +class LocigalOperator; +class Optimizer; + +class SamplingPushdown { +public: + //! Optimize SYSTEM SAMPLING + SCAN to SAMPLE SCAN + unique_ptr Optimize(unique_ptr op); +}; + +} // 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 618c07505..555cb7379 100644 --- a/src/duckdb/src/include/duckdb/optimizer/statistics_propagator.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/statistics_propagator.hpp @@ -87,7 +87,7 @@ class StatisticsPropagator { unique_ptr PropagateExpression(unique_ptr &expr); unique_ptr PropagateExpression(Expression &expr, unique_ptr &expr_ptr); - + //! Run a comparison between the statistics and the table filter; returns the prune result unique_ptr PropagateExpression(BoundAggregateExpression &expr, unique_ptr &expr_ptr); unique_ptr PropagateExpression(BoundBetweenExpression &expr, unique_ptr &expr_ptr); unique_ptr PropagateExpression(BoundCaseExpression &expr, unique_ptr &expr_ptr); diff --git a/src/duckdb/src/include/duckdb/parallel/pipeline_executor.hpp b/src/duckdb/src/include/duckdb/parallel/pipeline_executor.hpp index e19c4483d..9781e6fb8 100644 --- a/src/duckdb/src/include/duckdb/parallel/pipeline_executor.hpp +++ b/src/duckdb/src/include/duckdb/parallel/pipeline_executor.hpp @@ -32,6 +32,28 @@ enum class PipelineExecuteResult { INTERRUPTED }; +class ExecutionBudget { +public: + explicit ExecutionBudget(idx_t maximum) : processed(0), maximum_to_process(maximum) { + } + +public: + bool Next() { + if (IsDepleted()) { + return false; + } + processed++; + return true; + } + bool IsDepleted() const { + return processed >= maximum_to_process; + } + +private: + idx_t processed; + idx_t maximum_to_process; +}; + //! The Pipeline class represents an execution pipeline class PipelineExecutor { public: @@ -43,10 +65,6 @@ class PipelineExecutor { //! Returns true if execution is finished, false if Execute should be called again PipelineExecuteResult Execute(idx_t max_chunks); - //! Push a single input DataChunk into the pipeline. - //! Returns either OperatorResultType::NEED_MORE_INPUT or OperatorResultType::FINISHED - //! If OperatorResultType::FINISHED is returned, more input will not change the result anymore - OperatorResultType ExecutePush(DataChunk &input); //! Called after depleting the source: finalizes the execution of this pipeline executor //! This should only be called once per PipelineExecutor. PipelineExecuteResult PushFinalize(); @@ -91,8 +109,8 @@ class PipelineExecutor { bool finalized = false; //! Whether or not the pipeline has finished processing int32_t finished_processing_idx = -1; - //! Whether or not this pipeline requires keeping track of the batch index of the source - bool requires_batch_index = false; + //! Partition info that is used by this executor + OperatorPartitionInfo required_partition_info; //! Source has indicated it is exhausted bool exhausted_source = false; @@ -128,7 +146,7 @@ class PipelineExecutor { SourceResultType GetData(DataChunk &chunk, OperatorSourceInput &input); SinkResultType Sink(DataChunk &chunk, OperatorSinkInput &input); - OperatorResultType ExecutePushInternal(DataChunk &input, idx_t initial_idx = 0); + OperatorResultType ExecutePushInternal(DataChunk &input, ExecutionBudget &chunk_budget, idx_t initial_idx = 0); //! Pushes a chunk through the pipeline and returns a single result chunk //! Returns whether or not a new input chunk is needed, or whether or not we are finished OperatorResultType Execute(DataChunk &input, DataChunk &result, idx_t initial_index = 0); @@ -138,7 +156,7 @@ class PipelineExecutor { //! Tries to flush all state from intermediate operators. Will return true if all state is flushed, false in the //! case of a blocked sink. - bool TryFlushCachingOperators(); + bool TryFlushCachingOperators(ExecutionBudget &chunk_budget); static bool CanCacheType(const LogicalType &type); void CacheChunk(DataChunk &input, idx_t operator_idx); diff --git a/src/duckdb/src/include/duckdb/parser/constraints/unique_constraint.hpp b/src/duckdb/src/include/duckdb/parser/constraints/unique_constraint.hpp index 570a3e27c..a3811160a 100644 --- a/src/duckdb/src/include/duckdb/parser/constraints/unique_constraint.hpp +++ b/src/duckdb/src/include/duckdb/parser/constraints/unique_constraint.hpp @@ -8,8 +8,11 @@ #pragma once -#include "duckdb/parser/constraint.hpp" +#include "duckdb/common/enum_util.hpp" +#include "duckdb/common/enums/index_constraint_type.hpp" #include "duckdb/common/vector.hpp" +#include "duckdb/parser/column_list.hpp" +#include "duckdb/parser/constraint.hpp" namespace duckdb { @@ -18,52 +21,33 @@ class UniqueConstraint : public Constraint { static constexpr const ConstraintType TYPE = ConstraintType::UNIQUE; public: - DUCKDB_API UniqueConstraint(LogicalIndex index, bool is_primary_key); - DUCKDB_API UniqueConstraint(vector columns, bool is_primary_key); + DUCKDB_API UniqueConstraint(const LogicalIndex index, const bool is_primary_key); + DUCKDB_API UniqueConstraint(vector columns, const bool is_primary_key); public: DUCKDB_API string ToString() const override; - DUCKDB_API unique_ptr Copy() const override; - DUCKDB_API void Serialize(Serializer &serializer) const override; DUCKDB_API static unique_ptr Deserialize(Deserializer &deserializer); - bool IsPrimaryKey() const { - return is_primary_key; - } - - bool HasIndex() const { - return index.index != DConstants::INVALID_INDEX; - } - - LogicalIndex GetIndex() const { - if (!HasIndex()) { - throw InternalException("UniqueConstraint::GetIndex called on a unique constraint without a defined index"); - } - return index; - } - void SetIndex(LogicalIndex new_index) { - D_ASSERT(new_index.index != DConstants::INVALID_INDEX); - index = new_index; - } - - const vector &GetColumnNames() const { - D_ASSERT(columns.size() >= 1); - return columns; - } - vector &GetColumnNamesMutable() { - D_ASSERT(columns.size() >= 1); - return columns; - } - - void SetColumnName(string name) { - if (!columns.empty()) { - // name has already been set - return; - } - columns.push_back(std::move(name)); - } + //! Returns true, if the constraint is a PRIMARY KEY constraint. + bool IsPrimaryKey() const; + //! Returns true, if the constraint is defined on a single column. + bool HasIndex() const; + //! Returns the column index on which the constraint is defined. + LogicalIndex GetIndex() const; + //! Sets the column index of the constraint. + void SetIndex(const LogicalIndex new_index); + //! Returns a constant reference to the column names on which the constraint is defined. + const vector &GetColumnNames() const; + //! Returns a mutable reference to the column names on which the constraint is defined. + vector &GetColumnNamesMutable(); + //! Returns the column indexes on which the constraint is defined. + vector GetLogicalIndexes(const ColumnList &columns) const; + //! Get the name of the constraint. + string GetName(const string &table_name) const; + //! Sets a single column name. Does nothing, if the name is already set. + void SetColumnName(const string &name); private: UniqueConstraint(); @@ -73,12 +57,12 @@ class UniqueConstraint : public Constraint { #else public: #endif - //! The index of the column for which this constraint holds. Only used when the constraint relates to a single - //! column, equal to DConstants::INVALID_INDEX if not used + + //! The indexed column of the constraint. Only used for single-column constraints, invalid otherwise. LogicalIndex index; - //! The set of columns for which this constraint holds by name. Only used when the index field is not used. + //! The names of the columns on which this constraint is defined. Only set if the index field is not set. vector columns; - //! Whether or not this is a PRIMARY KEY constraint, or a UNIQUE constraint. + //! Whether this is a PRIMARY KEY constraint, or a UNIQUE constraint. bool is_primary_key; }; diff --git a/src/duckdb/src/include/duckdb/parser/expression/columnref_expression.hpp b/src/duckdb/src/include/duckdb/parser/expression/columnref_expression.hpp index f50717efd..408dcaab3 100644 --- a/src/duckdb/src/include/duckdb/parser/expression/columnref_expression.hpp +++ b/src/duckdb/src/include/duckdb/parser/expression/columnref_expression.hpp @@ -12,6 +12,7 @@ #include "duckdb/common/vector.hpp" namespace duckdb { +struct BindingAlias; //! Represents a reference to a column from either the FROM clause or from an //! alias @@ -22,6 +23,8 @@ class ColumnRefExpression : public ParsedExpression { public: //! Specify both the column and table name ColumnRefExpression(string column_name, string table_name); + //! Specify both the column and table alias + ColumnRefExpression(string column_name, const BindingAlias &alias); //! Only specify the column name, the table name will be derived later explicit ColumnRefExpression(string column_name); //! Specify a set of names diff --git a/src/duckdb/src/include/duckdb/parser/expression/star_expression.hpp b/src/duckdb/src/include/duckdb/parser/expression/star_expression.hpp index d95b683d2..c35ef2029 100644 --- a/src/duckdb/src/include/duckdb/parser/expression/star_expression.hpp +++ b/src/duckdb/src/include/duckdb/parser/expression/star_expression.hpp @@ -10,6 +10,7 @@ #include "duckdb/parser/parsed_expression.hpp" #include "duckdb/common/case_insensitive_map.hpp" +#include "duckdb/parser/qualified_name_set.hpp" namespace duckdb { @@ -24,9 +25,11 @@ class StarExpression : public ParsedExpression { //! The relation name in case of tbl.*, or empty if this is a normal * string relation_name; //! List of columns to exclude from the STAR expression - case_insensitive_set_t exclude_list; + qualified_column_set_t exclude_list; //! List of columns to replace with another expression case_insensitive_map_t> replace_list; + //! List of columns to rename + qualified_column_map_t rename_list; //! The expression to select the columns (regular expression or list) unique_ptr expr; //! Whether or not this is a COLUMNS expression @@ -46,5 +49,12 @@ class StarExpression : public ParsedExpression { void Serialize(Serializer &serializer) const override; static unique_ptr Deserialize(Deserializer &deserializer); + +public: + // these methods exist for backwards compatibility of (de)serialization + StarExpression(const case_insensitive_set_t &exclude_list, qualified_column_set_t qualified_set); + + case_insensitive_set_t SerializedExcludeList() const; + qualified_column_set_t SerializedQualifiedExcludeList() const; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/alter_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/alter_info.hpp index 88db356af..7e47a2e88 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/alter_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/alter_info.hpp @@ -74,6 +74,7 @@ struct AlterInfo : public ParseInfo { }; AlterEntryData GetAlterEntryData() const; + bool IsAddPrimaryKey() const; protected: explicit AlterInfo(AlterType type); diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/alter_scalar_function_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/alter_scalar_function_info.hpp index 625f25f31..f3a209462 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/alter_scalar_function_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/alter_scalar_function_info.hpp @@ -13,6 +13,7 @@ #include "duckdb/parser/parsed_data/alter_info.hpp" namespace duckdb { +struct CreateScalarFunctionInfo; //===--------------------------------------------------------------------===// // Alter Scalar Function @@ -33,10 +34,10 @@ struct AlterScalarFunctionInfo : public AlterInfo { // AddScalarFunctionOverloadInfo //===--------------------------------------------------------------------===// struct AddScalarFunctionOverloadInfo : public AlterScalarFunctionInfo { - AddScalarFunctionOverloadInfo(AlterEntryData data, ScalarFunctionSet new_overloads); + AddScalarFunctionOverloadInfo(AlterEntryData data, unique_ptr new_overloads); ~AddScalarFunctionOverloadInfo() override; - ScalarFunctionSet new_overloads; + unique_ptr new_overloads; public: unique_ptr Copy() const override; 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 73a685f73..9506b1519 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 @@ -78,7 +78,8 @@ enum class AlterTableType : uint8_t { FOREIGN_KEY_CONSTRAINT = 7, SET_NOT_NULL = 8, DROP_NOT_NULL = 9, - SET_COLUMN_COMMENT = 10 + SET_COLUMN_COMMENT = 10, + ADD_CONSTRAINT = 11 }; struct AlterTableInfo : public AlterInfo { @@ -346,4 +347,24 @@ struct RenameViewInfo : public AlterViewInfo { RenameViewInfo(); }; +//===--------------------------------------------------------------------===// +// AddConstraintInfo +//===--------------------------------------------------------------------===// +struct AddConstraintInfo : public AlterTableInfo { + AddConstraintInfo(AlterEntryData data, unique_ptr constraint); + ~AddConstraintInfo() override; + + //! The constraint to add. + unique_ptr constraint; + +public: + unique_ptr Copy() const override; + string ToString() const override; + void Serialize(Serializer &serializer) const override; + static unique_ptr Deserialize(Deserializer &deserializer); + +private: + AddConstraintInfo(); +}; + } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/attach_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/attach_info.hpp index 7906ac52f..835dd9a4c 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/attach_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/attach_info.hpp @@ -13,6 +13,7 @@ #include "duckdb/common/unordered_map.hpp" #include "duckdb/common/types/value.hpp" #include "duckdb/common/enums/on_create_conflict.hpp" +#include "duckdb/storage/storage_options.hpp" namespace duckdb { @@ -34,10 +35,8 @@ struct AttachInfo : public ParseInfo { OnCreateConflict on_conflict = OnCreateConflict::ERROR_ON_CONFLICT; public: - //! Returns the block allocation size, which is the allocation size of blocks for this attached database file. - //! Returns DConstants::INVALID_INDEX, if not provided. This is NOT the actual memory available on a block - //! (block_size), even though the corresponding option we expose to the user is called "block_size". - optional_idx GetBlockAllocSize() const; + //! Returns the storage options + StorageOptions GetStorageOptions() const; //! Copies this AttachInfo and returns an unique pointer to the new AttachInfo. unique_ptr Copy() const; string ToString() const; diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/comment_on_column_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/comment_on_column_info.hpp index c274ffb55..60aa36ef0 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/comment_on_column_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/comment_on_column_info.hpp @@ -12,9 +12,9 @@ #include "duckdb/common/types/value.hpp" #include "duckdb/parser/parsed_data/alter_info.hpp" #include "duckdb/parser/qualified_name.hpp" -#include "duckdb/catalog/catalog_entry_retriever.hpp" namespace duckdb { +class CatalogEntryRetriever; class ClientContext; class CatalogEntry; diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/create_function_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/create_function_info.hpp index 64018f3bf..0c403004a 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/create_function_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/create_function_info.hpp @@ -14,12 +14,7 @@ namespace duckdb { struct CreateFunctionInfo : public CreateInfo { - explicit CreateFunctionInfo(CatalogType type, string schema = DEFAULT_SCHEMA) - : CreateInfo(type, std::move(schema)) { - D_ASSERT(type == CatalogType::SCALAR_FUNCTION_ENTRY || type == CatalogType::AGGREGATE_FUNCTION_ENTRY || - type == CatalogType::TABLE_FUNCTION_ENTRY || type == CatalogType::PRAGMA_FUNCTION_ENTRY || - type == CatalogType::MACRO_ENTRY || type == CatalogType::TABLE_MACRO_ENTRY); - } + explicit CreateFunctionInfo(CatalogType type, string schema = DEFAULT_SCHEMA); //! Function name string name; @@ -29,6 +24,8 @@ struct CreateFunctionInfo : public CreateInfo { vector parameter_names; //! The example (if any) string example; + + DUCKDB_API void CopyFunctionProperties(CreateFunctionInfo &other) const; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/create_index_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/create_index_info.hpp index 08ff3826f..6cc6e84ce 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/create_index_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/create_index_info.hpp @@ -46,12 +46,12 @@ struct CreateIndexInfo : public CreateInfo { public: DUCKDB_API unique_ptr Copy() const override; - string ToString() const override; - vector ExpressionsToList() const; - string ExpressionsToString() const; void Serialize(Serializer &serializer) const override; static unique_ptr Deserialize(Deserializer &deserializer); + + vector ExpressionsToList() const; + string ExpressionsToString() const; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/sample_options.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/sample_options.hpp index 201469bcf..e6f8b571c 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/sample_options.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/sample_options.hpp @@ -15,21 +15,29 @@ namespace duckdb { -enum class SampleMethod : uint8_t { SYSTEM_SAMPLE = 0, BERNOULLI_SAMPLE = 1, RESERVOIR_SAMPLE = 2 }; +// Invalid is 255 because previously stored databases have SampleMethods according to the current ENUMS and we need to +// maintain that +enum class SampleMethod : uint8_t { SYSTEM_SAMPLE = 0, BERNOULLI_SAMPLE = 1, RESERVOIR_SAMPLE = 2, INVALID = 255 }; // **DEPRECATED**: Use EnumUtil directly instead. string SampleMethodToString(SampleMethod method); -struct SampleOptions { +class SampleOptions { + +public: + explicit SampleOptions(int64_t seed_ = -1); + Value sample_size; bool is_percentage; SampleMethod method; - int64_t seed = -1; + optional_idx seed = optional_idx::Invalid(); unique_ptr Copy(); + void SetSeed(idx_t new_seed); static bool Equals(SampleOptions *a, SampleOptions *b); void Serialize(Serializer &serializer) const; static unique_ptr Deserialize(Deserializer &deserializer); + int64_t GetSeed() const; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/qualified_name.hpp b/src/duckdb/src/include/duckdb/parser/qualified_name.hpp index ee5947806..e8e1e6715 100644 --- a/src/duckdb/src/include/duckdb/parser/qualified_name.hpp +++ b/src/duckdb/src/include/duckdb/parser/qualified_name.hpp @@ -12,6 +12,7 @@ #include "duckdb/common/exception/parser_exception.hpp" #include "duckdb/parser/keyword_helper.hpp" #include "duckdb/common/string_util.hpp" +#include "duckdb/planner/binding_alias.hpp" namespace duckdb { @@ -22,70 +23,28 @@ struct QualifiedName { //! Parse the (optional) schema and a name from a string in the format of e.g. "schema"."table"; if there is no dot //! the schema will be set to INVALID_SCHEMA - static QualifiedName Parse(const string &input) { - string catalog; - string schema; - string name; - idx_t idx = 0; - vector entries; - string entry; - normal: - //! quote - for (; idx < input.size(); idx++) { - if (input[idx] == '"') { - idx++; - goto quoted; - } else if (input[idx] == '.') { - goto separator; - } - entry += input[idx]; - } - goto end; - separator: - entries.push_back(entry); - entry = ""; - idx++; - goto normal; - quoted: - //! look for another quote - for (; idx < input.size(); idx++) { - if (input[idx] == '"') { - //! unquote - idx++; - goto normal; - } - entry += input[idx]; - } - throw ParserException("Unterminated quote in qualified name!"); - end: - if (entries.empty()) { - catalog = INVALID_CATALOG; - schema = INVALID_SCHEMA; - name = entry; - } else if (entries.size() == 1) { - catalog = INVALID_CATALOG; - schema = entries[0]; - name = entry; - } else if (entries.size() == 2) { - catalog = entries[0]; - schema = entries[1]; - name = entry; - } else { - throw ParserException("Expected catalog.entry, schema.entry or entry: too many entries found"); - } - return QualifiedName {catalog, schema, name}; - } + static QualifiedName Parse(const string &input); }; struct QualifiedColumnName { - QualifiedColumnName() { - } - QualifiedColumnName(string table_p, string column_p) : table(std::move(table_p)), column(std::move(column_p)) { - } + QualifiedColumnName(); + QualifiedColumnName(string column_p); // NOLINT: allow implicit conversion from string to column name + QualifiedColumnName(string table_p, string column_p); + QualifiedColumnName(const BindingAlias &alias, string column_p); + string catalog; string schema; string table; string column; + + string ToString() const; + + void Serialize(Serializer &serializer) const; + static QualifiedColumnName Deserialize(Deserializer &deserializer); + + bool IsQualified() const; + + bool operator==(const QualifiedColumnName &rhs) const; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/qualified_name_set.hpp b/src/duckdb/src/include/duckdb/parser/qualified_name_set.hpp index 1a1052095..c17cde85d 100644 --- a/src/duckdb/src/include/duckdb/parser/qualified_name_set.hpp +++ b/src/duckdb/src/include/duckdb/parser/qualified_name_set.hpp @@ -16,17 +16,33 @@ namespace duckdb { struct QualifiedColumnHashFunction { uint64_t operator()(const QualifiedColumnName &a) const { - std::hash str_hasher; - return str_hasher(a.schema) ^ str_hasher(a.table) ^ str_hasher(a.column); + // hash only on the column name - since we match based on the shortest possible match + return StringUtil::CIHash(a.column); } }; struct QualifiedColumnEquality { bool operator()(const QualifiedColumnName &a, const QualifiedColumnName &b) const { - return a.schema == b.schema && a.table == b.table && a.column == b.column; + // qualified column names follow a prefix comparison + // so "tbl.i" and "i" are equivalent, as are "schema.tbl.i" and "i" + // but "tbl.i" and "tbl2.i" are not equivalent + if (!a.catalog.empty() && !b.catalog.empty() && !StringUtil::CIEquals(a.catalog, b.catalog)) { + return false; + } + if (!a.schema.empty() && !b.schema.empty() && !StringUtil::CIEquals(a.schema, b.schema)) { + return false; + } + if (!a.table.empty() && !b.table.empty() && !StringUtil::CIEquals(a.table, b.table)) { + return false; + } + return StringUtil::CIEquals(a.column, b.column); } }; using qualified_column_set_t = unordered_set; +template +using qualified_column_map_t = + unordered_map; + } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/tableref/basetableref.hpp b/src/duckdb/src/include/duckdb/parser/tableref/basetableref.hpp index 16bc1bb86..b841559ea 100644 --- a/src/duckdb/src/include/duckdb/parser/tableref/basetableref.hpp +++ b/src/duckdb/src/include/duckdb/parser/tableref/basetableref.hpp @@ -8,11 +8,13 @@ #pragma once -#include "duckdb/parser/tableref.hpp" #include "duckdb/common/vector.hpp" +#include "duckdb/main/table_description.hpp" +#include "duckdb/parser/tableref.hpp" namespace duckdb { -//! Represents a TableReference to a base table in the schema + +//! Represents a TableReference to a base table in a catalog and schema. class BaseTableRef : public TableRef { public: static constexpr const TableReferenceType TYPE = TableReferenceType::BASE_TABLE; @@ -21,23 +23,24 @@ class BaseTableRef : public TableRef { BaseTableRef() : TableRef(TableReferenceType::BASE_TABLE), catalog_name(INVALID_CATALOG), schema_name(INVALID_SCHEMA) { } + explicit BaseTableRef(const TableDescription &description) + : TableRef(TableReferenceType::BASE_TABLE), catalog_name(description.database), schema_name(description.schema), + table_name(description.table) { + } - //! The catalog name + //! The catalog name. string catalog_name; - //! Schema name + //! The schema name. string schema_name; - //! Table name + //! The table name. string table_name; public: string ToString() const override; bool Equals(const TableRef &other_p) const override; - unique_ptr Copy() override; - - //! Deserializes a blob back into a BaseTableRef void Serialize(Serializer &serializer) const override; - static unique_ptr Deserialize(Deserializer &source); }; + } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/tokens.hpp b/src/duckdb/src/include/duckdb/parser/tokens.hpp index f5eeb2c0c..d18adfd44 100644 --- a/src/duckdb/src/include/duckdb/parser/tokens.hpp +++ b/src/duckdb/src/include/duckdb/parser/tokens.hpp @@ -104,6 +104,6 @@ class ShowRef; //===--------------------------------------------------------------------===// // Other //===--------------------------------------------------------------------===// -struct SampleOptions; +class SampleOptions; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/transformer.hpp b/src/duckdb/src/include/duckdb/parser/transformer.hpp index 0125f2f1f..00833a526 100644 --- a/src/duckdb/src/include/duckdb/parser/transformer.hpp +++ b/src/duckdb/src/include/duckdb/parser/transformer.hpp @@ -261,8 +261,8 @@ class Transformer { //===--------------------------------------------------------------------===// // Constraints transform //===--------------------------------------------------------------------===// - unique_ptr TransformConstraint(duckdb_libpgquery::PGListCell &cell); - unique_ptr TransformConstraint(duckdb_libpgquery::PGListCell &cell, ColumnDefinition &column, + unique_ptr TransformConstraint(duckdb_libpgquery::PGConstraint &constraint); + unique_ptr TransformConstraint(duckdb_libpgquery::PGConstraint &constraint, ColumnDefinition &column, idx_t index); //===--------------------------------------------------------------------===// diff --git a/src/duckdb/src/include/duckdb/planner/bind_context.hpp b/src/duckdb/src/include/duckdb/planner/bind_context.hpp index e4b63f830..dbad01397 100644 --- a/src/duckdb/src/include/duckdb/planner/bind_context.hpp +++ b/src/duckdb/src/include/duckdb/planner/bind_context.hpp @@ -30,10 +30,12 @@ class TableCatalogEntry; class TableFunctionCatalogEntry; struct UsingColumnSet { - string primary_binding; - unordered_set bindings; + BindingAlias primary_binding; + vector bindings; }; +enum class ColumnBindType { EXPAND_GENERATED_COLUMNS, DO_NOT_EXPAND_GENERATED_COLUMNS }; + //! The BindContext object keeps track of all the tables and columns that are //! encountered during the binding process. class BindContext { @@ -46,10 +48,10 @@ 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. - string GetMatchingBinding(const string &column_name); + optional_ptr GetMatchingBinding(const string &column_name); //! Like GetMatchingBinding, but instead of throwing an error if multiple tables have the same binding it will //! return a list of all the matching ones - unordered_set GetMatchingBindings(const string &column_name); + vector> GetMatchingBindings(const string &column_name); //! Like GetMatchingBindings, but returns the top 3 most similar bindings (in levenshtein distance) instead of the //! matching ones vector GetSimilarBindings(const string &column_name); @@ -61,38 +63,45 @@ class BindContext { string BindColumn(PositionalReferenceExpression &ref, string &table_name, string &column_name); unique_ptr PositionToColumn(PositionalReferenceExpression &ref); - unique_ptr ExpandGeneratedColumn(const string &table_name, const string &column_name); - - unique_ptr CreateColumnReference(const string &table_name, const string &column_name); - unique_ptr CreateColumnReference(const string &schema_name, const string &table_name, - const string &column_name); - unique_ptr CreateColumnReference(const string &catalog_name, const string &schema_name, - const string &table_name, const string &column_name); + unique_ptr ExpandGeneratedColumn(TableBinding &table_binding, const string &column_name); + + unique_ptr + CreateColumnReference(const string &table_name, const string &column_name, + ColumnBindType bind_type = ColumnBindType::EXPAND_GENERATED_COLUMNS); + unique_ptr + CreateColumnReference(const string &schema_name, const string &table_name, const string &column_name, + ColumnBindType bind_type = ColumnBindType::EXPAND_GENERATED_COLUMNS); + unique_ptr + CreateColumnReference(const string &catalog_name, const string &schema_name, const string &table_name, + const string &column_name, + ColumnBindType bind_type = ColumnBindType::EXPAND_GENERATED_COLUMNS); + unique_ptr + CreateColumnReference(const BindingAlias &table_alias, const string &column_name, + ColumnBindType bind_type = ColumnBindType::EXPAND_GENERATED_COLUMNS); //! Generate column expressions for all columns that are present in the //! referenced tables. This is used to resolve the * expression in a //! selection list. void GenerateAllColumnExpressions(StarExpression &expr, vector> &new_select_list); - //! Check if the given (binding, column_name) is in the exclusion/replacement lists. - //! Returns true if it is in one of these lists, and should therefore be skipped. - bool CheckExclusionList(StarExpression &expr, const string &column_name, - vector> &new_select_list, - case_insensitive_set_t &excluded_columns); - const vector> &GetBindingsList() { + const vector> &GetBindingsList() { return bindings_list; } + vector GetBindingAliases(); void GetTypesAndNames(vector &result_names, vector &result_types); //! Adds a base table with the given alias to the BindContext. void AddBaseTable(idx_t index, const string &alias, const vector &names, const vector &types, - vector &bound_column_ids, StandardEntry *entry, bool add_row_id = true); + vector &bound_column_ids, StandardEntry &entry, bool add_row_id = true); + void AddBaseTable(idx_t index, const string &alias, const vector &names, const vector &types, + vector &bound_column_ids, const string &table_name); //! Adds a call to a table function with the given alias to the BindContext. void AddTableFunction(idx_t index, const string &alias, const vector &names, - const vector &types, vector &bound_column_ids, StandardEntry *entry); + const vector &types, vector &bound_column_ids, + optional_ptr entry); //! Adds a table view with a given alias to the BindContext. - void AddView(idx_t index, const string &alias, SubqueryRef &ref, BoundQueryNode &subquery, ViewCatalogEntry *view); + void AddView(idx_t index, const string &alias, SubqueryRef &ref, BoundQueryNode &subquery, ViewCatalogEntry &view); //! Adds a subquery with a given alias to the BindContext. void AddSubquery(idx_t index, const string &alias, SubqueryRef &ref, BoundQueryNode &subquery); //! Adds a subquery with a given alias to the BindContext. @@ -117,17 +126,18 @@ class BindContext { //! column sets with the same name) throw an exception. optional_ptr GetUsingBinding(const string &column_name); //! Returns any using column set for the given column name, or nullptr if there is none - optional_ptr GetUsingBinding(const string &column_name, const string &binding_name); + optional_ptr GetUsingBinding(const string &column_name, const BindingAlias &binding); //! Erase a using binding from the set of using bindings void RemoveUsingBinding(const string &column_name, UsingColumnSet &set); //! Transfer a using binding from one bind context to this bind context void TransferUsingBinding(BindContext ¤t_context, optional_ptr current_set, - UsingColumnSet &new_set, const string &binding, const string &using_column); + UsingColumnSet &new_set, const string &using_column); //! Fetch the actual column name from the given binding, or throws if none exists //! This can be different from "column_name" because of case insensitivity //! (e.g. "column_name" might return "COLUMN_NAME") - string GetActualColumnName(const string &binding, const string &column_name); + string GetActualColumnName(const BindingAlias &binding_alias, const string &column_name); + string GetActualColumnName(Binding &binding, const string &column_name); case_insensitive_map_t> GetCTEBindings() { return cte_bindings; @@ -144,21 +154,27 @@ class BindContext { //! Add all the bindings from a BindContext to this BindContext. The other BindContext is destroyed in the process. void AddContext(BindContext other); //! For semi and anti joins we remove the binding context of the right table after binding the condition. - void RemoveContext(vector> &other_bindings_list); + void RemoveContext(const vector &aliases); //! Gets a binding of the specified name. Returns a nullptr and sets the out_error if the binding could not be //! found. optional_ptr GetBinding(const string &name, ErrorData &out_error); + optional_ptr GetBinding(const BindingAlias &alias, ErrorData &out_error); + + optional_ptr GetBinding(const BindingAlias &alias, const string &column_name, ErrorData &out_error); + + //! Get all bindings that match a specific binding alias - returns an error if none match + vector> GetBindings(const BindingAlias &alias, ErrorData &out_error); + private: - void AddBinding(const string &alias, unique_ptr binding); + void AddBinding(unique_ptr binding); + static string AmbiguityException(const BindingAlias &alias, const vector> &bindings); private: Binder &binder; - //! The set of bindings - case_insensitive_map_t> bindings; //! The list of bindings in insertion order - vector> bindings_list; + vector> bindings_list; //! The set of columns used in USING join conditions case_insensitive_map_t> using_columns; //! Using column sets diff --git a/src/duckdb/src/include/duckdb/planner/binder.hpp b/src/duckdb/src/include/duckdb/planner/binder.hpp index cdfc67d1b..ba6de071e 100644 --- a/src/duckdb/src/include/duckdb/planner/binder.hpp +++ b/src/duckdb/src/include/duckdb/planner/binder.hpp @@ -24,6 +24,7 @@ #include "duckdb/planner/bound_tokens.hpp" #include "duckdb/planner/expression/bound_columnref_expression.hpp" #include "duckdb/planner/joinside.hpp" +#include "duckdb/planner/bound_constraint.hpp" #include "duckdb/planner/logical_operator.hpp" #include "duckdb/planner/tableref/bound_delimgetref.hpp" @@ -49,7 +50,6 @@ class BoundConstraint; struct CreateInfo; struct BoundCreateTableInfo; -struct BoundCreateFunctionInfo; struct CommonTableExpressionInfo; struct BoundParameterMap; struct BoundPragmaInfo; @@ -125,6 +125,7 @@ class Binder : public enable_shared_from_this { vector> &bound_defaults); static unique_ptr BindCreateTableCheckpoint(unique_ptr info, SchemaCatalogEntry &schema); + static vector> BindConstraints(ClientContext &context, const vector> &constraints, const string &table_name, const ColumnList &columns); @@ -133,6 +134,11 @@ class Binder : public enable_shared_from_this { vector> BindConstraints(const TableCatalogEntry &table); vector> BindNewConstraints(vector> &constraints, const string &table_name, const ColumnList &columns); + unique_ptr BindConstraint(Constraint &constraint, const string &table, const ColumnList &columns); + unique_ptr BindUniqueConstraint(Constraint &constraint, const string &table, + const ColumnList &columns); + + BoundStatement BindAlterAddIndex(BoundStatement &result, CatalogEntry &entry, unique_ptr alter_info); void SetCatalogLookupCallback(catalog_entry_callback_t callback); void BindCreateViewInfo(CreateViewInfo &base); @@ -189,11 +195,11 @@ class Binder : public enable_shared_from_this { void BindLogicalType(LogicalType &type, optional_ptr catalog = nullptr, const string &schema = INVALID_SCHEMA); - bool HasMatchingBinding(const string &table_name, const string &column_name, ErrorData &error); - bool HasMatchingBinding(const string &schema_name, const string &table_name, const string &column_name, - ErrorData &error); - bool HasMatchingBinding(const string &catalog_name, const string &schema_name, const string &table_name, - const string &column_name, ErrorData &error); + optional_ptr GetMatchingBinding(const string &table_name, const string &column_name, ErrorData &error); + optional_ptr GetMatchingBinding(const string &schema_name, const string &table_name, + const string &column_name, ErrorData &error); + optional_ptr GetMatchingBinding(const string &catalog_name, const string &schema_name, + const string &table_name, const string &column_name, ErrorData &error); void SetBindingMode(BindingMode mode); BindingMode GetBindingMode(); @@ -384,12 +390,12 @@ class Binder : public enable_shared_from_this { vector &target_types, unique_ptr op); - string FindBinding(const string &using_column, const string &join_side); - bool TryFindBinding(const string &using_column, const string &join_side, string &result); + BindingAlias FindBinding(const string &using_column, const string &join_side); + bool TryFindBinding(const string &using_column, const string &join_side, BindingAlias &result); void AddUsingBindingSet(unique_ptr set); - string RetrieveUsingBinding(Binder ¤t_binder, optional_ptr current_set, - const string &column_name, const string &join_side); + BindingAlias RetrieveUsingBinding(Binder ¤t_binder, optional_ptr current_set, + const string &column_name, const string &join_side); void AddCTEMap(CommonTableExpressionMap &cte_map); diff --git a/src/duckdb/src/include/duckdb/planner/binding_alias.hpp b/src/duckdb/src/include/duckdb/planner/binding_alias.hpp new file mode 100644 index 000000000..2d85b521e --- /dev/null +++ b/src/duckdb/src/include/duckdb/planner/binding_alias.hpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/planner/binding_alias.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/common.hpp" +#include "duckdb/common/case_insensitive_map.hpp" + +namespace duckdb { +class StandardEntry; + +struct BindingAlias { + BindingAlias(); + explicit BindingAlias(string alias); + BindingAlias(string schema, string alias); + BindingAlias(string catalog, string schema, string alias); + explicit BindingAlias(const StandardEntry &entry); + + bool IsSet() const; + const string &GetAlias() const; + + const string &GetCatalog() const { + return catalog; + } + const string &GetSchema() const { + return schema; + } + + bool Matches(const BindingAlias &other) const; + bool operator==(const BindingAlias &other) const; + string ToString() const; + +private: + string catalog; + string schema; + string alias; +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/planner/constraints/bound_unique_constraint.hpp b/src/duckdb/src/include/duckdb/planner/constraints/bound_unique_constraint.hpp index 4c7468d60..b03f6ffef 100644 --- a/src/duckdb/src/include/duckdb/planner/constraints/bound_unique_constraint.hpp +++ b/src/duckdb/src/include/duckdb/planner/constraints/bound_unique_constraint.hpp @@ -19,22 +19,23 @@ class BoundUniqueConstraint : public BoundConstraint { static constexpr const ConstraintType TYPE = ConstraintType::UNIQUE; public: - BoundUniqueConstraint(vector keys, logical_index_set_t key_set, bool is_primary_key) - : BoundConstraint(ConstraintType::UNIQUE), keys(std::move(keys)), key_set(std::move(key_set)), + BoundUniqueConstraint(vector keys_p, physical_index_set_t key_set_p, const bool is_primary_key) + : BoundConstraint(ConstraintType::UNIQUE), keys(std::move(keys_p)), key_set(std::move(key_set_p)), is_primary_key(is_primary_key) { + #ifdef DEBUG - D_ASSERT(this->keys.size() == this->key_set.size()); - for (auto &key : this->keys) { - D_ASSERT(this->key_set.find(key) != this->key_set.end()); + D_ASSERT(keys.size() == key_set.size()); + for (auto &key : keys) { + D_ASSERT(key_set.find(key) != key_set.end()); } #endif } - //! The keys that define the unique constraint - vector keys; - //! The same keys but stored as an unordered set - logical_index_set_t key_set; - //! Whether or not the unique constraint is a primary key + //! The keys that define the unique constraint. + vector keys; + //! The same keys but stored as an unordered set. + physical_index_set_t key_set; + //! Whether this is a PRIMARY KEY constraint, or a UNIQUE constraint. bool is_primary_key; }; diff --git a/src/duckdb/src/include/duckdb/planner/expression.hpp b/src/duckdb/src/include/duckdb/planner/expression.hpp index a7f9045f9..97094bbde 100644 --- a/src/duckdb/src/include/duckdb/planner/expression.hpp +++ b/src/duckdb/src/include/duckdb/planner/expression.hpp @@ -32,10 +32,12 @@ class Expression : public BaseExpression { bool HasSubquery() const override; bool IsScalar() const override; bool HasParameter() const override; + virtual bool IsVolatile() const; virtual bool IsConsistent() const; virtual bool PropagatesNullValues() const; virtual bool IsFoldable() const; + virtual bool CanThrow() const; hash_t Hash() const override; diff --git a/src/duckdb/src/include/duckdb/planner/expression/bound_cast_expression.hpp b/src/duckdb/src/include/duckdb/planner/expression/bound_cast_expression.hpp index d45ac502f..c625fb4f9 100644 --- a/src/duckdb/src/include/duckdb/planner/expression/bound_cast_expression.hpp +++ b/src/duckdb/src/include/duckdb/planner/expression/bound_cast_expression.hpp @@ -54,6 +54,8 @@ class BoundCastExpression : public Expression { unique_ptr Copy() const override; + bool CanThrow() const override; + void Serialize(Serializer &serializer) const override; static unique_ptr Deserialize(Deserializer &deserializer); diff --git a/src/duckdb/src/include/duckdb/planner/expression_binder.hpp b/src/duckdb/src/include/duckdb/planner/expression_binder.hpp index 5206f8a8f..407b1eea0 100644 --- a/src/duckdb/src/include/duckdb/planner/expression_binder.hpp +++ b/src/duckdb/src/include/duckdb/planner/expression_binder.hpp @@ -107,7 +107,7 @@ class ExpressionBinder { //! 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 - unique_ptr QualifyColumnName(ColumnRefExpression &col_ref, ErrorData &error); + virtual unique_ptr QualifyColumnName(ColumnRefExpression &col_ref, ErrorData &error); //! Enables special-handling of lambda parameters by tracking them in the lambda_params vector void QualifyColumnNamesInLambda(FunctionExpression &function, vector> &lambda_params); //! Recursively qualifies the column references in the (children) of the expression. Passes on the @@ -116,6 +116,7 @@ class ExpressionBinder { const bool within_function_expression = false); //! Entry point for qualifying the column references of the expression static void QualifyColumnNames(Binder &binder, unique_ptr &expr); + static void QualifyColumnNames(ExpressionBinder &binder, unique_ptr &expr); static bool PushCollation(ClientContext &context, unique_ptr &source, const LogicalType &sql_type); static void TestCollation(ClientContext &context, const string &collation); @@ -220,6 +221,9 @@ class ExpressionBinder { //! Returns true if the function name is an alias for the UNNEST function static bool IsUnnestFunction(const string &function_name); BindResult TryBindLambdaOrJson(FunctionExpression &function, idx_t depth, CatalogEntry &func); + + unique_ptr QualifyColumnNameWithManyDotsInternal(ColumnRefExpression &col_ref, ErrorData &error, + idx_t &struct_extract_start); virtual void ThrowIfUnnestInLambda(const ColumnBinding &column_binding); }; 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 4cb65dab0..b111cc368 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 @@ -25,6 +25,8 @@ class HavingBinder : public BaseSelectBinder { BindResult BindWindow(WindowExpression &expr, idx_t depth) override; BindResult BindColumnRef(unique_ptr &expr_ptr, idx_t depth, bool root_expression) override; + unique_ptr QualifyColumnName(ColumnRefExpression &col_ref, ErrorData &error) override; + private: ColumnAliasBinder column_alias_binder; AggregateHandling aggregate_handling; diff --git a/src/duckdb/src/include/duckdb/planner/expression_binder/index_binder.hpp b/src/duckdb/src/include/duckdb/planner/expression_binder/index_binder.hpp index 0d2ac67f0..b15948b34 100644 --- a/src/duckdb/src/include/duckdb/planner/expression_binder/index_binder.hpp +++ b/src/duckdb/src/include/duckdb/planner/expression_binder/index_binder.hpp @@ -10,22 +10,25 @@ #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" #include "duckdb/common/unordered_map.hpp" -#include "duckdb/parser/parsed_data/create_index_info.hpp" -#include "duckdb/planner/expression_binder.hpp" #include "duckdb/execution/index/bound_index.hpp" #include "duckdb/execution/index/unbound_index.hpp" +#include "duckdb/parser/parsed_data/create_index_info.hpp" +#include "duckdb/planner/expression_binder.hpp" namespace duckdb { class BoundColumnRefExpression; -//! The IndexBinder is responsible for binding indexes, as well as expressions within an index statement +//! The IndexBinder binds indexes and expressions within index statements. class IndexBinder : public ExpressionBinder { public: IndexBinder(Binder &binder, ClientContext &context, optional_ptr table = nullptr, optional_ptr info = nullptr); unique_ptr BindIndex(const UnboundIndex &index); + unique_ptr BindCreateIndex(ClientContext &context, unique_ptr create_index_info, + TableCatalogEntry &table_entry, unique_ptr plan, + unique_ptr alter_table_info); protected: BindResult BindExpression(unique_ptr &expr_ptr, idx_t depth, @@ -33,7 +36,7 @@ class IndexBinder : public ExpressionBinder { string UnsupportedAggregateMessage() override; private: - // only for WAL replay + // Only for WAL replay. optional_ptr table; optional_ptr info; }; diff --git a/src/duckdb/src/include/duckdb/planner/filter/conjunction_filter.hpp b/src/duckdb/src/include/duckdb/planner/filter/conjunction_filter.hpp index 1713ad67f..49fcf6e95 100644 --- a/src/duckdb/src/include/duckdb/planner/filter/conjunction_filter.hpp +++ b/src/duckdb/src/include/duckdb/planner/filter/conjunction_filter.hpp @@ -12,6 +12,7 @@ #include "duckdb/common/vector.hpp" namespace duckdb { + class ConjunctionFilter : public TableFilter { public: explicit ConjunctionFilter(TableFilterType filter_type_p) : TableFilter(filter_type_p) { @@ -35,8 +36,6 @@ class ConjunctionOrFilter : public ConjunctionFilter { public: ConjunctionOrFilter(); - -public: FilterPropagateResult CheckStatistics(BaseStatistics &stats) override; string ToString(const string &column_name) override; bool Equals(const TableFilter &other) const override; diff --git a/src/duckdb/src/include/duckdb/planner/filter/optional_filter.hpp b/src/duckdb/src/include/duckdb/planner/filter/optional_filter.hpp new file mode 100644 index 000000000..9d18c87f9 --- /dev/null +++ b/src/duckdb/src/include/duckdb/planner/filter/optional_filter.hpp @@ -0,0 +1,35 @@ + +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/planner/filter/optional_filter.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/planner/table_filter.hpp" + +namespace duckdb { + +class OptionalFilter : public TableFilter { +public: + static constexpr const TableFilterType TYPE = TableFilterType::OPTIONAL_FILTER; + +public: + OptionalFilter(); + + string ToString(const string &column_name) override; + unique_ptr Copy() const override; + unique_ptr ToExpression(const Expression &column) const override; + FilterPropagateResult CheckStatistics(BaseStatistics &stats) override; + void Serialize(Serializer &serializer) const override; + static unique_ptr Deserialize(Deserializer &deserializer); + +public: + // optional child filters + unique_ptr child_filter; +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/planner/logical_operator.hpp b/src/duckdb/src/include/duckdb/planner/logical_operator.hpp index b0611f7e3..e7f533bdd 100644 --- a/src/duckdb/src/include/duckdb/planner/logical_operator.hpp +++ b/src/duckdb/src/include/duckdb/planner/logical_operator.hpp @@ -80,6 +80,10 @@ class LogicalOperator { return true; }; + virtual bool HasProjectionMap() const { + return false; + } + //! Returns the set of table indexes of this operator virtual vector GetTableIndex() const; diff --git a/src/duckdb/src/include/duckdb/planner/logical_operator_visitor.hpp b/src/duckdb/src/include/duckdb/planner/logical_operator_visitor.hpp index ff0fd75de..b11065f67 100644 --- a/src/duckdb/src/include/duckdb/planner/logical_operator_visitor.hpp +++ b/src/duckdb/src/include/duckdb/planner/logical_operator_visitor.hpp @@ -35,6 +35,9 @@ class LogicalOperatorVisitor { //! Automatically calls the Visit method for Expression children of the current operator. Can be overloaded to //! change this behavior. void VisitOperatorExpressions(LogicalOperator &op); + //! Alternatives for VisitOperatorChildren for operators that have a projection map + void VisitOperatorWithProjectionMapChildren(LogicalOperator &op); + void VisitChildOfOperatorWithProjectionMap(LogicalOperator &child, vector &projection_map); // The VisitExpressionChildren method is called at the end of every call to VisitExpression to recursively visit all // expressions in an expression tree. It can be overloaded to prevent automatically visiting the entire tree. diff --git a/src/duckdb/src/include/duckdb/planner/operator/logical_comparison_join.hpp b/src/duckdb/src/include/duckdb/planner/operator/logical_comparison_join.hpp index fd095f534..e361a2a6e 100644 --- a/src/duckdb/src/include/duckdb/planner/operator/logical_comparison_join.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator/logical_comparison_join.hpp @@ -70,6 +70,8 @@ class LogicalComparisonJoin : public LogicalJoin { const unordered_set &right_bindings, vector> &expressions, vector &conditions, vector> &arbitrary_expressions); + + bool HasEquality(idx_t &range_count) const; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/planner/operator/logical_create_index.hpp b/src/duckdb/src/include/duckdb/planner/operator/logical_create_index.hpp index e9925cb40..2f04c7ee4 100644 --- a/src/duckdb/src/include/duckdb/planner/operator/logical_create_index.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator/logical_create_index.hpp @@ -20,15 +20,15 @@ class LogicalCreateIndex : public LogicalOperator { public: LogicalCreateIndex(unique_ptr info_p, vector> expressions_p, - TableCatalogEntry &table_p); + TableCatalogEntry &table_p, unique_ptr alter_table_info = nullptr); - // Info for index creation + //! Index creation information. unique_ptr info; - - //! The table to create the index for + //! The table to create the index for. TableCatalogEntry &table; - - //! Unbound expressions to be used in the optimizer + // Alter table information. + unique_ptr alter_table_info; + //! Unbound expressions of the indexed columns. vector> unbound_expressions; public: @@ -39,8 +39,8 @@ class LogicalCreateIndex : public LogicalOperator { void ResolveTypes() override; private: - LogicalCreateIndex(ClientContext &context, unique_ptr info, vector> expressions); - - TableCatalogEntry &BindTable(ClientContext &context, CreateIndexInfo &info); + LogicalCreateIndex(ClientContext &context, unique_ptr info, vector> expressions, + unique_ptr alter_info); + TableCatalogEntry &BindTable(ClientContext &context, CreateIndexInfo &info_p); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/planner/operator/logical_filter.hpp b/src/duckdb/src/include/duckdb/planner/operator/logical_filter.hpp index acd5771b9..b6f8323a6 100644 --- a/src/duckdb/src/include/duckdb/planner/operator/logical_filter.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator/logical_filter.hpp @@ -26,6 +26,10 @@ class LogicalFilter : public LogicalOperator { public: vector GetColumnBindings() override; + bool HasProjectionMap() const override { + return !projection_map.empty(); + } + void Serialize(Serializer &serializer) const override; static unique_ptr Deserialize(Deserializer &deserializer); 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 07af9e2ea..273a83d45 100644 --- a/src/duckdb/src/include/duckdb/planner/operator/logical_get.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator/logical_get.hpp @@ -49,8 +49,9 @@ class LogicalGet : public LogicalOperator { vector input_table_names; //! For a table-in-out function, the set of projected input columns vector projected_input; - //! Currently stores File Filters (as strings) applied by hive partitioning/complex filter pushdown - //! Stored so they can be included in explain output + //! Currently stores File Filters (as strings) applied by hive partitioning/complex filter pushdown and sample rate + //! pushed down into the table scan + //! Stored so the can be included in explain output ExtraOperatorInfo extra_info; //! Contains a reference to dynamically generated table filters (through e.g. a join up in the tree) shared_ptr dynamic_filters; diff --git a/src/duckdb/src/include/duckdb/planner/operator/logical_join.hpp b/src/duckdb/src/include/duckdb/planner/operator/logical_join.hpp index a6a63de66..9e278886c 100644 --- a/src/duckdb/src/include/duckdb/planner/operator/logical_join.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator/logical_join.hpp @@ -27,6 +27,10 @@ class LogicalJoin : public LogicalOperator { static void GetTableReferences(LogicalOperator &op, unordered_set &bindings); static void GetExpressionBindings(Expression &expr, unordered_set &bindings); + bool HasProjectionMap() const override { + return !left_projection_map.empty() || !right_projection_map.empty(); + } + //! The type of the join (INNER, OUTER, etc...) JoinType join_type; //! Table index used to refer to the MARK column (in case of a MARK join) diff --git a/src/duckdb/src/include/duckdb/planner/operator/logical_order.hpp b/src/duckdb/src/include/duckdb/planner/operator/logical_order.hpp index c16193ff8..a7bdf50d8 100644 --- a/src/duckdb/src/include/duckdb/planner/operator/logical_order.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator/logical_order.hpp @@ -24,11 +24,15 @@ class LogicalOrder : public LogicalOperator { explicit LogicalOrder(vector orders); vector orders; - vector projections; + vector projection_map; public: vector GetColumnBindings() override; + bool HasProjectionMap() const override { + return !projection_map.empty(); + } + void Serialize(Serializer &serializer) const override; static unique_ptr Deserialize(Deserializer &deserializer); diff --git a/src/duckdb/src/include/duckdb/planner/table_binding.hpp b/src/duckdb/src/include/duckdb/planner/table_binding.hpp index 551ab9b00..6bf75cf06 100644 --- a/src/duckdb/src/include/duckdb/planner/table_binding.hpp +++ b/src/duckdb/src/include/duckdb/planner/table_binding.hpp @@ -14,6 +14,7 @@ #include "duckdb/parser/parsed_expression.hpp" #include "duckdb/planner/expression_binder.hpp" #include "duckdb/catalog/catalog_entry/table_column_type.hpp" +#include "duckdb/planner/binding_alias.hpp" namespace duckdb { class BindContext; @@ -31,14 +32,13 @@ enum class BindingType { BASE, TABLE, DUMMY, CATALOG_ENTRY }; //! A Binding represents a binding to a table, table-producing function or subquery with a specified table index. struct Binding { - Binding(BindingType binding_type, const string &alias, vector types, vector names, - idx_t index); + Binding(BindingType binding_type, BindingAlias alias, vector types, vector names, idx_t index); virtual ~Binding() = default; //! The type of Binding BindingType binding_type; //! The alias of the binding - string alias; + BindingAlias alias; //! The table index of the binding idx_t index; //! The types of the bound columns @@ -55,6 +55,10 @@ struct Binding { virtual ErrorData ColumnNotFoundError(const string &column_name) const; virtual BindResult Bind(ColumnRefExpression &colref, idx_t depth); virtual optional_ptr GetStandardEntry(); + string GetAlias() const; + + static BindingAlias GetAlias(const string &explicit_alias, const StandardEntry &entry); + static BindingAlias GetAlias(const string &explicit_alias, optional_ptr entry); public: template diff --git a/src/duckdb/src/include/duckdb/planner/table_filter.hpp b/src/duckdb/src/include/duckdb/planner/table_filter.hpp index edcb975cd..079d22a2d 100644 --- a/src/duckdb/src/include/duckdb/planner/table_filter.hpp +++ b/src/duckdb/src/include/duckdb/planner/table_filter.hpp @@ -28,7 +28,8 @@ enum class TableFilterType : uint8_t { IS_NOT_NULL = 2, CONJUNCTION_OR = 3, CONJUNCTION_AND = 4, - STRUCT_EXTRACT = 5 + STRUCT_EXTRACT = 5, + OPTIONAL_FILTER = 6 }; //! TableFilter represents a filter pushed down into the table scan. diff --git a/src/duckdb/src/include/duckdb/storage/arena_allocator.hpp b/src/duckdb/src/include/duckdb/storage/arena_allocator.hpp index dc778907d..d76aeccb6 100644 --- a/src/duckdb/src/include/duckdb/storage/arena_allocator.hpp +++ b/src/duckdb/src/include/duckdb/storage/arena_allocator.hpp @@ -25,6 +25,7 @@ struct ArenaChunk { }; class ArenaAllocator { +public: static constexpr const idx_t ARENA_ALLOCATOR_INITIAL_CAPACITY = 2048; static constexpr const idx_t ARENA_ALLOCATOR_MAX_CAPACITY = 1ULL << 24ULL; // 16MB 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 be1128fae..ee6b3ddf6 100644 --- a/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp +++ b/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp @@ -15,6 +15,7 @@ #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/storage_info.hpp" namespace duckdb { @@ -101,7 +102,6 @@ class BlockHandle : public enable_shared_from_this { } inline void SetDestroyBufferUpon(DestroyBufferUpon destroy_buffer_upon_p) { - lock_guard guard(lock); destroy_buffer_upon = destroy_buffer_upon_p; } @@ -116,10 +116,17 @@ class BlockHandle : public enable_shared_from_this { inline const idx_t &GetMemoryUsage() const { return memory_usage; } + bool IsUnloaded() { return state == BlockState::BLOCK_UNLOADED; } + void SetEvictionQueueIndex(const idx_t index) { + D_ASSERT(!eviction_queue_idx.IsValid()); // Cannot overwrite + D_ASSERT(buffer->type == FileBufferType::MANAGED_BUFFER); // MANAGED_BUFFER only (at least, for now) + eviction_queue_idx = index; + } + private: BufferHandle Load(unique_ptr buffer = nullptr); BufferHandle LoadFromBuffer(data_ptr_t data, unique_ptr reusable_buffer); @@ -144,7 +151,7 @@ class BlockHandle : public enable_shared_from_this { //! LRU timestamp (for age-based eviction) atomic lru_timestamp_msec; //! When to destroy the data buffer - DestroyBufferUpon destroy_buffer_upon; + 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. idx_t memory_usage; @@ -152,6 +159,8 @@ class BlockHandle : public enable_shared_from_this { BufferPoolReservation memory_charge; //! Does the block contain any memory pointers? const char *unswizzled; + //! Index for eviction queue (FileBufferType::MANAGED_BUFFER only, for now) + optional_idx eviction_queue_idx; }; } // 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 50166a51f..f4548e430 100644 --- a/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool.hpp +++ b/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool.hpp @@ -82,14 +82,21 @@ class BufferPool { 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(FileBufferType type); + 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 &GetEvictionQueueForType(FileBufferType type); + EvictionQueue &GetEvictionQueueForBlockHandle(const BlockHandle &handle); //! Increments the dead nodes for the queue with specified type - void IncrementDeadNodes(FileBufferType type); + void IncrementDeadNodes(const BlockHandle &handle); + + //! How many eviction queues we have for the different FileBufferTypes + static constexpr idx_t BLOCK_QUEUE_SIZE = 1; + static constexpr idx_t MANAGED_BUFFER_QUEUE_SIZE = 6; + static constexpr idx_t TINY_BUFFER_QUEUE_SIZE = 1; + //! Mapping and priority order for the eviction queues + const array eviction_queue_sizes; protected: enum class MemoryUsageCaches { diff --git a/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp b/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp index e2a3b95e0..f497aa1db 100644 --- a/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp @@ -59,6 +59,7 @@ class BufferManager { virtual shared_ptr RegisterTransientMemory(const idx_t size, const idx_t block_size); //! Returns a new block of memory that is smaller than the block size setting. virtual shared_ptr RegisterSmallMemory(const idx_t size); + virtual shared_ptr RegisterSmallMemory(MemoryTag tag, const idx_t size); virtual DUCKDB_API Allocator &GetBufferAllocator(); virtual DUCKDB_API void ReserveMemory(idx_t size); @@ -98,7 +99,7 @@ class BufferManager { virtual TemporaryMemoryManager &GetTemporaryMemoryManager(); protected: - virtual void PurgeQueue(FileBufferType type) = 0; + virtual void PurgeQueue(const BlockHandle &handle) = 0; virtual void AddToEvictionQueue(shared_ptr &handle); virtual void WriteTemporaryBuffer(MemoryTag tag, block_id_t block_id, FileBuffer &buffer); virtual unique_ptr ReadTemporaryBuffer(MemoryTag tag, BlockHandle &block, diff --git a/src/duckdb/src/include/duckdb/storage/compression/alp/alp_constants.hpp b/src/duckdb/src/include/duckdb/storage/compression/alp/alp_constants.hpp index e4763d762..cf9766177 100644 --- a/src/duckdb/src/include/duckdb/storage/compression/alp/alp_constants.hpp +++ b/src/duckdb/src/include/duckdb/storage/compression/alp/alp_constants.hpp @@ -19,7 +19,7 @@ class AlpConstants { static constexpr uint32_t RG_SAMPLES = 8; static constexpr uint16_t SAMPLES_PER_VECTOR = 32; // We calculate how many equidistant vector we must jump within a rowgroup - static constexpr uint32_t RG_SAMPLES_DUCKDB_JUMP = (STANDARD_ROW_GROUPS_SIZE / RG_SAMPLES) / STANDARD_VECTOR_SIZE; + static constexpr uint32_t RG_SAMPLES_DUCKDB_JUMP = (DEFAULT_ROW_GROUP_SIZE / RG_SAMPLES) / STANDARD_VECTOR_SIZE; static constexpr uint8_t HEADER_SIZE = sizeof(uint32_t); static constexpr uint8_t EXPONENT_SIZE = sizeof(uint8_t); diff --git a/src/duckdb/src/include/duckdb/storage/data_table.hpp b/src/duckdb/src/include/duckdb/storage/data_table.hpp index 313cb4b74..b3b6515bd 100644 --- a/src/duckdb/src/include/duckdb/storage/data_table.hpp +++ b/src/duckdb/src/include/duckdb/storage/data_table.hpp @@ -9,11 +9,8 @@ #pragma once #include "duckdb/common/enums/index_constraint_type.hpp" -#include "duckdb/common/enums/scan_options.hpp" -#include "duckdb/common/mutex.hpp" #include "duckdb/common/types/data_chunk.hpp" #include "duckdb/common/unique_ptr.hpp" -#include "duckdb/storage/block.hpp" #include "duckdb/storage/index.hpp" #include "duckdb/storage/statistics/column_statistics.hpp" #include "duckdb/storage/table/column_segment.hpp" @@ -25,6 +22,7 @@ #include "duckdb/transaction/local_storage.hpp" namespace duckdb { + class BoundForeignKeyConstraint; class ClientContext; class ColumnDataCollection; @@ -61,7 +59,7 @@ class DataTable { DataTable(ClientContext &context, DataTable &parent, idx_t changed_idx, const LogicalType &target_type, const vector &bound_columns, Expression &cast_expr); //! Constructs a DataTable as a delta on an existing data table but with one column added new constraint - explicit DataTable(ClientContext &context, DataTable &parent, unique_ptr constraint); + DataTable(ClientContext &context, DataTable &parent, BoundConstraint &constraint); //! A reference to the database instance AttachedDatabase &db; @@ -76,13 +74,11 @@ class DataTable { vector GetTypes(); const vector &Columns() const; - void InitializeScan(TableScanState &state, const vector &column_ids, - TableFilterSet *table_filter = nullptr); void InitializeScan(DuckTransaction &transaction, TableScanState &state, const vector &column_ids, TableFilterSet *table_filters = nullptr); //! Returns the maximum amount of threads that should be assigned to scan this data table - idx_t MaxThreads(ClientContext &context); + idx_t MaxThreads(ClientContext &context) const; void InitializeParallelScan(ClientContext &context, ParallelTableScanState &state); bool NextParallelScan(ClientContext &context, ParallelTableScanState &state, TableScanState &scan_state); @@ -149,13 +145,15 @@ class DataTable { //! Commit the append void CommitAppend(transaction_t commit_id, idx_t row_start, idx_t count); //! Write a segment of the table to the WAL - void WriteToLog(WriteAheadLog &log, idx_t row_start, idx_t count, optional_ptr commit_state); + void WriteToLog(DuckTransaction &transaction, WriteAheadLog &log, idx_t row_start, idx_t count, + optional_ptr commit_state); //! Revert a set of appends made by the given AppendState, used to revert appends in the event of an error during //! commit (e.g. because of an I/O exception) - void RevertAppend(idx_t start_row, idx_t count); + void RevertAppend(DuckTransaction &transaction, idx_t start_row, idx_t count); void RevertAppendInternal(idx_t start_row); - void ScanTableSegment(idx_t start_row, idx_t count, const std::function &function); + void ScanTableSegment(DuckTransaction &transaction, idx_t start_row, idx_t count, + 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); @@ -174,6 +172,7 @@ class DataTable { void SetAsRoot() { this->is_root = true; } + bool IsRoot() { return this->is_root; } @@ -215,7 +214,6 @@ class DataTable { void InitializeIndexes(ClientContext &context); bool HasIndexes() const; - void AddIndex(unique_ptr index); bool HasForeignKeyIndex(const vector &keys, ForeignKeyType type); void SetIndexStorageInfo(vector index_storage_info); void VacuumIndexes(); @@ -226,21 +224,30 @@ class DataTable { TableStorageInfo GetStorageInfo(); -public: + idx_t GetRowGroupSize() const; + static void VerifyUniqueIndexes(TableIndexList &indexes, ClientContext &context, DataChunk &chunk, optional_ptr conflict_manager); + //! 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); + //! AddIndex moves an index to this table's index list. + void AddIndex(unique_ptr index); + private: //! Verify the new added constraints against current persistent&local data void VerifyNewConstraint(LocalStorage &local_storage, DataTable &parent, const BoundConstraint &constraint); + //! Verify constraints with a chunk from the Update containing only the specified column_ids void VerifyUpdateConstraints(ConstraintState &state, ClientContext &context, DataChunk &chunk, const vector &column_ids); //! Verify constraints with a chunk from the Delete containing all columns of the table void VerifyDeleteConstraints(TableDeleteState &state, ClientContext &context, DataChunk &chunk); - void InitializeScanWithOffset(TableScanState &state, const vector &column_ids, idx_t start_row, - idx_t end_row); + void InitializeScanWithOffset(DuckTransaction &transaction, TableScanState &state, + const vector &column_ids, idx_t start_row, idx_t end_row); void VerifyForeignKeyConstraint(const BoundForeignKeyConstraint &bfk, ClientContext &context, DataChunk &chunk, VerifyExistenceType verify_type); 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 383882bef..ebcb46a82 100644 --- a/src/duckdb/src/include/duckdb/storage/standard_buffer_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/standard_buffer_manager.hpp @@ -49,7 +49,7 @@ class StandardBufferManager : public BufferManager { //! Registers an in-memory buffer that cannot be unloaded until it is destroyed. //! This buffer can be small (smaller than the block size of the temporary block manager). //! Unpin and Pin are NOPs on this block of memory. - shared_ptr RegisterSmallMemory(const idx_t size) final; + shared_ptr RegisterSmallMemory(MemoryTag tag, const idx_t size) final; idx_t GetUsedMemory() const final; idx_t GetMaxMemory() const final; @@ -120,7 +120,7 @@ class StandardBufferManager : public BufferManager { shared_ptr RegisterMemory(MemoryTag tag, idx_t block_size, bool can_destroy); //! Garbage collect eviction queue - void PurgeQueue(FileBufferType type) final; + void PurgeQueue(const BlockHandle &handle) final; BufferPool &GetBufferPool() const final; TemporaryMemoryManager &GetTemporaryMemoryManager() final; diff --git a/src/duckdb/src/include/duckdb/storage/statistics/column_statistics.hpp b/src/duckdb/src/include/duckdb/storage/statistics/column_statistics.hpp index 0cc4c69a5..12f8d5672 100644 --- a/src/duckdb/src/include/duckdb/storage/statistics/column_statistics.hpp +++ b/src/duckdb/src/include/duckdb/storage/statistics/column_statistics.hpp @@ -24,7 +24,7 @@ class ColumnStatistics { void Merge(ColumnStatistics &other); - void UpdateDistinctStatistics(Vector &v, idx_t count); + void UpdateDistinctStatistics(Vector &v, idx_t count, Vector &hashes); BaseStatistics &Statistics(); diff --git a/src/duckdb/src/include/duckdb/storage/statistics/distinct_statistics.hpp b/src/duckdb/src/include/duckdb/storage/statistics/distinct_statistics.hpp index 5bfe6e200..aaa4acb0e 100644 --- a/src/duckdb/src/include/duckdb/storage/statistics/distinct_statistics.hpp +++ b/src/duckdb/src/include/duckdb/storage/statistics/distinct_statistics.hpp @@ -34,8 +34,8 @@ class DistinctStatistics { unique_ptr Copy() const; - void Update(Vector &update, idx_t count, bool sample = true); - void Update(UnifiedVectorFormat &update_data, const LogicalType &ptype, idx_t count, bool sample = true); + void UpdateSample(Vector &new_data, idx_t count, Vector &hashes); + void Update(Vector &new_data, idx_t count, Vector &hashes); string ToString() const; idx_t GetCount() const; @@ -45,13 +45,14 @@ class DistinctStatistics { void Serialize(Serializer &serializer) const; static unique_ptr Deserialize(Deserializer &deserializer); +private: + void UpdateInternal(Vector &update, idx_t count, Vector &hashes); + private: //! For distinct statistics we sample the input to speed up insertions static constexpr double BASE_SAMPLE_RATE = 0.1; //! For integers, we sample more: likely to be join keys (and hashing is cheaper than, e.g., strings) static constexpr double INTEGRAL_SAMPLE_RATE = 0.3; - //! For concurrent access - mutable mutex lock; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/storage_info.hpp b/src/duckdb/src/include/duckdb/storage/storage_info.hpp index 17fb6c288..a2047d720 100644 --- a/src/duckdb/src/include/duckdb/storage/storage_info.hpp +++ b/src/duckdb/src/include/duckdb/storage/storage_info.hpp @@ -17,7 +17,7 @@ namespace duckdb { struct FileHandle; //! The standard row group size -#define STANDARD_ROW_GROUPS_SIZE 122880 +#define DEFAULT_ROW_GROUP_SIZE 122880ULL //! The definition of an invalid block #define INVALID_BLOCK (-1) //! The maximum block id is 2^62 @@ -38,10 +38,8 @@ struct Storage { //! The size of the headers. This should be small and written more or less atomically by the hard disk. We default //! to the page size, which is 4KB. (1 << 12) constexpr static idx_t FILE_HEADER_SIZE = 4096U; - //! The number of rows per row group (must be a multiple of the vector size) - constexpr static const idx_t ROW_GROUP_SIZE = STANDARD_ROW_GROUPS_SIZE; - //! The number of vectors per row group - constexpr static const idx_t ROW_GROUP_VECTOR_COUNT = ROW_GROUP_SIZE / STANDARD_VECTOR_SIZE; + //! The maximum row group size + constexpr static const idx_t MAX_ROW_GROUP_SIZE = 1ULL << 30ULL; //! The minimum block allocation size. This is the minimum size we test in our nightly tests. constexpr static idx_t MIN_BLOCK_ALLOC_SIZE = 16384ULL; @@ -118,10 +116,10 @@ struct DatabaseHeader { //! Detect mismatching constant values when compiling -#if (STANDARD_ROW_GROUPS_SIZE % STANDARD_VECTOR_SIZE != 0) +#if (DEFAULT_ROW_GROUP_SIZE % STANDARD_VECTOR_SIZE != 0) #error The row group size must be a multiple of the vector size #endif -#if (STANDARD_ROW_GROUPS_SIZE < STANDARD_VECTOR_SIZE) +#if (DEFAULT_ROW_GROUP_SIZE < STANDARD_VECTOR_SIZE) #error Row groups must be able to hold at least one vector #endif #if (DEFAULT_BLOCK_ALLOC_SIZE & (DEFAULT_BLOCK_ALLOC_SIZE - 1) != 0) diff --git a/src/duckdb/src/include/duckdb/storage/storage_manager.hpp b/src/duckdb/src/include/duckdb/storage/storage_manager.hpp index 1820805ff..b72d3972d 100644 --- a/src/duckdb/src/include/duckdb/storage/storage_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/storage_manager.hpp @@ -15,6 +15,7 @@ #include "duckdb/storage/write_ahead_log.hpp" #include "duckdb/storage/database_size.hpp" #include "duckdb/common/enums/checkpoint_type.hpp" +#include "duckdb/storage/storage_options.hpp" namespace duckdb { class BlockManager; @@ -71,7 +72,7 @@ class StorageManager { //! Initialize a database or load an existing database from the database file path. The block_alloc_size is //! either set, or invalid. If invalid, then DuckDB defaults to the default_block_alloc_size (DBConfig), //! or the file's block allocation size, if it is an existing database. - void Initialize(const optional_idx block_alloc_size); + void Initialize(StorageOptions options); DatabaseInstance &GetDatabase(); AttachedDatabase &GetAttached() { @@ -106,7 +107,7 @@ class StorageManager { virtual BlockManager &GetBlockManager() = 0; protected: - virtual void LoadDatabase(const optional_idx block_alloc_size) = 0; + virtual void LoadDatabase(StorageOptions options) = 0; protected: //! The database this storage manager belongs to @@ -156,6 +157,6 @@ class SingleFileStorageManager : public StorageManager { BlockManager &GetBlockManager() override; protected: - void LoadDatabase(const optional_idx block_alloc_size) override; + void LoadDatabase(StorageOptions options) override; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/core_functions/core_functions.hpp b/src/duckdb/src/include/duckdb/storage/storage_options.hpp similarity index 50% rename from src/duckdb/src/include/duckdb/core_functions/core_functions.hpp rename to src/duckdb/src/include/duckdb/storage/storage_options.hpp index 3705be140..8935f09a5 100644 --- a/src/duckdb/src/include/duckdb/core_functions/core_functions.hpp +++ b/src/duckdb/src/include/duckdb/storage/storage_options.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/core_functions/core_functions.hpp +// duckdb/storage/storage_options.hpp // // //===----------------------------------------------------------------------===// @@ -9,14 +9,15 @@ #pragma once #include "duckdb/common/common.hpp" +#include "duckdb/common/optional_idx.hpp" namespace duckdb { -class Catalog; -struct CatalogTransaction; - -struct CoreFunctions { - static void RegisterFunctions(Catalog &catalog, CatalogTransaction transaction); +struct StorageOptions { + //! The allocation size of blocks for this attached database file (if any) + optional_idx block_alloc_size; + //! The row group size for this attached database (if any) + optional_idx row_group_size; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/table/append_state.hpp b/src/duckdb/src/include/duckdb/storage/table/append_state.hpp index d7d2d37d8..0a5c7b170 100644 --- a/src/duckdb/src/include/duckdb/storage/table/append_state.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/append_state.hpp @@ -72,6 +72,8 @@ struct TableAppendState { TransactionData transaction; //! Table statistics TableStatistics stats; + //! Cached hash vector + Vector hashes; }; struct ConstraintState { diff --git a/src/duckdb/src/include/duckdb/storage/table/row_group.hpp b/src/duckdb/src/include/duckdb/storage/table/row_group.hpp index e3f2e3dbd..1dd5aa5c7 100644 --- a/src/duckdb/src/include/duckdb/storage/table/row_group.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/row_group.hpp @@ -178,6 +178,8 @@ class RowGroup : public SegmentBase { static void Serialize(RowGroupPointer &pointer, Serializer &serializer); static RowGroupPointer Deserialize(Deserializer &deserializer); + idx_t GetRowGroupSize() const; + private: optional_ptr GetVersionInfo(); shared_ptr GetOrCreateVersionInfoPtr(); 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 9184abf50..3f93b58f7 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 @@ -34,11 +34,14 @@ struct VacuumState; struct CollectionCheckpointState; struct PersistentCollectionData; class CheckpointTask; +class TableIOManager; class RowGroupCollection { public: - RowGroupCollection(shared_ptr info, BlockManager &block_manager, vector types, + RowGroupCollection(shared_ptr info, TableIOManager &io_manager, vector types, idx_t row_start, idx_t total_rows = 0); + RowGroupCollection(shared_ptr info, BlockManager &block_manager, vector types, + idx_t row_start, idx_t total_rows, idx_t row_group_size); public: idx_t GetTotalRows() const; @@ -133,12 +136,18 @@ class RowGroupCollection { return allocation_size; } + idx_t GetRowGroupSize() const { + return row_group_size; + } + private: bool IsEmpty(SegmentLock &) const; private: //! BlockManager BlockManager &block_manager; + //! The row group size of the row group collection + const idx_t row_group_size; //! The number of rows in the table atomic total_rows; //! The data table info diff --git a/src/duckdb/src/include/duckdb/storage/table/row_version_manager.hpp b/src/duckdb/src/include/duckdb/storage/table/row_version_manager.hpp index 25bd70dd6..bb0d0056b 100644 --- a/src/duckdb/src/include/duckdb/storage/table/row_version_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/row_version_manager.hpp @@ -49,13 +49,14 @@ class RowVersionManager { private: mutex version_lock; idx_t start; - unique_ptr vector_info[Storage::ROW_GROUP_VECTOR_COUNT]; + vector> vector_info; bool has_changes; vector storage_pointers; private: optional_ptr GetChunkInfo(idx_t vector_idx); ChunkVectorInfo &GetVectorInfo(idx_t vector_idx); + void FillVectorInfo(idx_t vector_idx); }; } // namespace duckdb 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 bd7d03771..2b8e0dfc9 100644 --- a/src/duckdb/src/include/duckdb/storage/table/scan_state.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/scan_state.hpp @@ -13,8 +13,10 @@ #include "duckdb/storage/buffer/buffer_handle.hpp" #include "duckdb/storage/storage_lock.hpp" #include "duckdb/common/enums/scan_options.hpp" +#include "duckdb/common/random_engine.hpp" #include "duckdb/storage/table/segment_lock.hpp" #include "duckdb/common/types/data_chunk.hpp" +#include "duckdb/parser/parsed_data/sample_options.hpp" namespace duckdb { class AdaptiveFilter; @@ -36,6 +38,7 @@ class RowGroupSegmentTree; class TableFilter; struct AdaptiveFilterState; struct TableScanOptions; +struct ScanSamplingInfo; struct SegmentScanState { virtual ~SegmentScanState() { @@ -188,10 +191,13 @@ class CollectionScanState { //! The valid selection SelectionVector valid_sel; + RandomEngine random; + public: void Initialize(const vector &types); const vector &GetColumnIds(); ScanFilterInfo &GetFilterInfo(); + ScanSamplingInfo &GetSamplingInfo(); TableScanOptions &GetOptions(); bool Scan(DuckTransaction &transaction, DataChunk &result); bool ScanCommitted(DataChunk &result, TableScanType type); @@ -201,6 +207,13 @@ class CollectionScanState { TableScanState &parent; }; +struct ScanSamplingInfo { + //! Whether or not to do a system sample during scanning + bool do_system_sample = false; + //! The sampling rate to use + double sample_rate; +}; + struct TableScanOptions { //! Fetch rows one-at-a-time instead of using the regular scans. bool force_fetch_row = false; @@ -230,14 +243,19 @@ class TableScanState { shared_ptr checkpoint_lock; //! Filter info ScanFilterInfo filters; + //! Sampling info + ScanSamplingInfo sampling_info; public: - void Initialize(vector column_ids, optional_ptr table_filters = nullptr); + void Initialize(vector column_ids, optional_ptr table_filters = nullptr, + optional_ptr table_sampling = nullptr); const vector &GetColumnIds(); ScanFilterInfo &GetFilterInfo(); + ScanSamplingInfo &GetSamplingInfo(); + private: //! The column identifiers of the scan vector column_ids; 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 4f1f681f3..59f5e099b 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 @@ -9,8 +9,8 @@ #pragma once #include "duckdb/common/mutex.hpp" -#include "duckdb/storage/index.hpp" #include "duckdb/parser/constraint.hpp" +#include "duckdb/storage/index.hpp" namespace duckdb { diff --git a/src/duckdb/src/include/duckdb/storage/table/update_segment.hpp b/src/duckdb/src/include/duckdb/storage/table/update_segment.hpp index 71fba059c..a0e325c31 100644 --- a/src/duckdb/src/include/duckdb/storage/table/update_segment.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/update_segment.hpp @@ -12,6 +12,7 @@ #include "duckdb/storage/storage_lock.hpp" #include "duckdb/storage/statistics/segment_statistics.hpp" #include "duckdb/common/types/string_heap.hpp" +#include "duckdb/transaction/undo_buffer_allocator.hpp" namespace duckdb { class ColumnData; @@ -19,6 +20,7 @@ class DataTable; class Vector; struct UpdateInfo; struct UpdateNode; +struct UndoBufferAllocator; class UpdateSegment { public: @@ -51,7 +53,7 @@ class UpdateSegment { private: //! The lock for the update segment - StorageLock lock; + mutable StorageLock lock; //! The root node (if any) unique_ptr root; //! Update statistics @@ -64,16 +66,16 @@ class UpdateSegment { StringHeap heap; public: - typedef void (*initialize_update_function_t)(UpdateInfo *base_info, Vector &base_data, UpdateInfo *update_info, + typedef void (*initialize_update_function_t)(UpdateInfo &base_info, Vector &base_data, UpdateInfo &update_info, Vector &update, const SelectionVector &sel); - typedef void (*merge_update_function_t)(UpdateInfo *base_info, Vector &base_data, UpdateInfo *update_info, + typedef void (*merge_update_function_t)(UpdateInfo &base_info, Vector &base_data, UpdateInfo &update_info, Vector &update, row_t *ids, idx_t count, const SelectionVector &sel); - typedef void (*fetch_update_function_t)(transaction_t start_time, transaction_t transaction_id, UpdateInfo *info, + typedef void (*fetch_update_function_t)(transaction_t start_time, transaction_t transaction_id, UpdateInfo &info, Vector &result); - typedef void (*fetch_committed_function_t)(UpdateInfo *info, Vector &result); - typedef void (*fetch_committed_range_function_t)(UpdateInfo *info, idx_t start, idx_t end, idx_t result_offset, + typedef void (*fetch_committed_function_t)(UpdateInfo &info, Vector &result); + typedef void (*fetch_committed_range_function_t)(UpdateInfo &info, idx_t start, idx_t end, idx_t result_offset, Vector &result); - typedef void (*fetch_row_function_t)(transaction_t start_time, transaction_t transaction_id, UpdateInfo *info, + typedef void (*fetch_row_function_t)(transaction_t start_time, transaction_t transaction_id, UpdateInfo &info, idx_t row_idx, Vector &result, idx_t result_idx); typedef void (*rollback_update_function_t)(UpdateInfo &base_info, UpdateInfo &rollback_info); typedef idx_t (*statistics_update_function_t)(UpdateSegment *segment, SegmentStatistics &stats, Vector &update, @@ -90,18 +92,18 @@ class UpdateSegment { statistics_update_function_t statistics_update_function; private: + UndoBufferPointer GetUpdateNode(idx_t vector_idx) const; + void InitializeUpdateInfo(idx_t vector_idx); void InitializeUpdateInfo(UpdateInfo &info, row_t *ids, const SelectionVector &sel, idx_t count, idx_t vector_index, idx_t vector_offset); }; -struct UpdateNodeData { - unique_ptr info; - unsafe_unique_array tuples; - unsafe_unique_array tuple_data; -}; - struct UpdateNode { - unique_ptr info[Storage::ROW_GROUP_VECTOR_COUNT]; + explicit UpdateNode(BufferManager &manager); + ~UpdateNode(); + + UndoBufferAllocator allocator; + vector info; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/table_io_manager.hpp b/src/duckdb/src/include/duckdb/storage/table_io_manager.hpp index eff63da03..babe17274 100644 --- a/src/duckdb/src/include/duckdb/storage/table_io_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/table_io_manager.hpp @@ -30,6 +30,9 @@ class TableIOManager { virtual BlockManager &GetBlockManagerForRowData() = 0; virtual MetadataManager &GetMetadataManager() = 0; + + //! Returns the target row group size for the table + virtual idx_t GetRowGroupSize() const = 0; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/temporary_file_manager.hpp b/src/duckdb/src/include/duckdb/storage/temporary_file_manager.hpp index e5587547e..780b113ee 100644 --- a/src/duckdb/src/include/duckdb/storage/temporary_file_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/temporary_file_manager.hpp @@ -9,73 +9,113 @@ #pragma once #include "duckdb/common/allocator.hpp" +#include "duckdb/common/array.hpp" #include "duckdb/common/atomic.hpp" +#include "duckdb/common/enum_class_hash.hpp" #include "duckdb/common/file_system.hpp" #include "duckdb/common/mutex.hpp" -#include "duckdb/storage/block_manager.hpp" -#include "duckdb/storage/buffer/block_handle.hpp" -#include "duckdb/storage/buffer/buffer_pool.hpp" +#include "duckdb/common/random_engine.hpp" +#include "duckdb/common/unordered_map.hpp" #include "duckdb/storage/buffer_manager.hpp" namespace duckdb { +class TemporaryFileManager; + //===--------------------------------------------------------------------===// -// BlockIndexManager +// TemporaryBufferSize //===--------------------------------------------------------------------===// +static constexpr uint64_t TEMPORARY_BUFFER_SIZE_GRANULARITY = 32ULL * 1024ULL; + +enum class TemporaryBufferSize : uint64_t { + INVALID = 0, + S32K = 32768, + S64K = 65536, + S96K = 98304, + S128K = 131072, + S160K = 163840, + S192K = 196608, + S224K = 229376, + DEFAULT = DEFAULT_BLOCK_ALLOC_SIZE, +}; -class TemporaryFileManager; +//===--------------------------------------------------------------------===// +// TemporaryFileIdentifier/TemporaryFileIndex +//===--------------------------------------------------------------------===// +struct TemporaryFileIdentifier { +public: + TemporaryFileIdentifier(); + TemporaryFileIdentifier(TemporaryBufferSize size, idx_t file_index); + +public: + //! Whether this temporary file identifier is valid (fields have been set) + bool IsValid() const; +public: + //! The size of the buffers within the temp file + TemporaryBufferSize size; + //! The index of the temp file + optional_idx file_index; +}; + +struct TemporaryFileIndex { +public: + TemporaryFileIndex(); + TemporaryFileIndex(TemporaryFileIdentifier identifier, idx_t block_index); + +public: + //! Whether this temporary file index is valid (fields have been set) + bool IsValid() const; + +public: + //! The identifier for the temporary file + TemporaryFileIdentifier identifier; + //! The block index within the temporary file + optional_idx block_index; +}; + +//===--------------------------------------------------------------------===// +// BlockIndexManager +//===--------------------------------------------------------------------===// struct BlockIndexManager { public: - explicit BlockIndexManager(TemporaryFileManager &manager); BlockIndexManager(); + explicit BlockIndexManager(TemporaryFileManager &manager); public: //! Obtains a new block index from the index manager - idx_t GetNewBlockIndex(); - //! Removes an index from the block manager - //! Returns true if the max_index has been altered - bool RemoveIndex(idx_t index); - idx_t GetMaxIndex(); - bool HasFreeBlocks(); + idx_t GetNewBlockIndex(TemporaryBufferSize size); + //! Removes an index from the block manager (returns true if the max_index has been altered) + bool RemoveIndex(idx_t index, TemporaryBufferSize size); + //! Get the maximum block index + idx_t GetMaxIndex() const; + //! Whether there are free blocks available within the file + bool HasFreeBlocks() const; private: - void SetMaxIndex(idx_t blocks); - idx_t GetNewBlockIndexInternal(); + //! Get/set max block index + idx_t GetNewBlockIndexInternal(TemporaryBufferSize size); + void SetMaxIndex(idx_t new_index, TemporaryBufferSize size); private: + //! The maximum block index idx_t max_index; + //! Free indexes within the file set free_indexes; + //! Used indexes within the file set indexes_in_use; + //! The TemporaryFileManager that "owns" this BlockIndexManager optional_ptr manager; }; -//===--------------------------------------------------------------------===// -// TemporaryFileIndex -//===--------------------------------------------------------------------===// - -// FIXME: should be optional_idx -struct TemporaryFileIndex { - explicit TemporaryFileIndex(idx_t file_index = DConstants::INVALID_INDEX, - idx_t block_index = DConstants::INVALID_INDEX); - - idx_t file_index; - idx_t block_index; - -public: - bool IsValid() const; -}; - //===--------------------------------------------------------------------===// // TemporaryFileHandle //===--------------------------------------------------------------------===// - class TemporaryFileHandle { constexpr static idx_t MAX_ALLOWED_INDEX_BASE = 4000; public: - TemporaryFileHandle(idx_t temp_file_count, DatabaseInstance &db, const string &temp_directory, idx_t index, - TemporaryFileManager &manager); + TemporaryFileHandle(TemporaryFileManager &manager, TemporaryFileIdentifier identifier, idx_t temp_file_count); public: struct TemporaryFileLock { @@ -87,99 +127,226 @@ class TemporaryFileHandle { }; public: + //! Try to get an index of where to write in this file. Returns an invalid index if full TemporaryFileIndex TryGetBlockIndex(); - void WriteTemporaryFile(FileBuffer &buffer, TemporaryFileIndex index); - unique_ptr ReadTemporaryBuffer(idx_t block_index, unique_ptr reusable_buffer); + //! Remove block index from this TemporaryFileHandle void EraseBlockIndex(block_id_t block_index); + + //! Read/Write temporary buffers at given positions in this file (potentially compressed) + unique_ptr ReadTemporaryBuffer(idx_t block_index, unique_ptr reusable_buffer) const; + void WriteTemporaryBuffer(FileBuffer &buffer, idx_t block_index, AllocatedData &compressed_buffer) const; + + //! Deletes the file if there are no more blocks bool DeleteIfEmpty(); + //! Get information about this temporary file TemporaryFileInformation GetTemporaryFile(); private: + //! Create temporary file if it did not exist yet void CreateFileIfNotExists(TemporaryFileLock &); + //! Remove block index from this file void RemoveTempBlockIndex(TemporaryFileLock &, idx_t index); - idx_t GetPositionInFile(idx_t index); + //! Get the position of a block in the file + idx_t GetPositionInFile(idx_t index) const; private: - const idx_t max_allowed_index; + //! Reference to the DB instance DatabaseInstance &db; + //! The identifier (size/file index) of this TemporaryFileHandle + const TemporaryFileIdentifier identifier; + //! The maximum allowed index + const idx_t max_allowed_index; + //! File path/handle + const string path; unique_ptr handle; - idx_t file_index; - string path; + //! Lock for concurrent access and block index manager mutex file_lock; BlockIndexManager index_manager; }; //===--------------------------------------------------------------------===// -// TemporaryDirectoryHandle +// TemporaryFileMap //===--------------------------------------------------------------------===// +class TemporaryFileMap { +private: + template + using temporary_buffer_size_map_t = unordered_map; + using temporary_file_map_t = unordered_map>; -class TemporaryDirectoryHandle { public: - TemporaryDirectoryHandle(DatabaseInstance &db, string path_p, optional_idx max_swap_space); - ~TemporaryDirectoryHandle(); + explicit TemporaryFileMap(TemporaryFileManager &manager); + void Clear(); + +public: + //! Gets the map for the given size + temporary_file_map_t &GetMapForSize(TemporaryBufferSize size); - TemporaryFileManager &GetTempFile(); + //! Get/create/erase a TemporaryFileHandle for a size/index + optional_ptr GetFile(const TemporaryFileIdentifier &identifier); + TemporaryFileHandle &CreateFile(const TemporaryFileIdentifier &identifier); + void EraseFile(const TemporaryFileIdentifier &identifier); private: - DatabaseInstance &db; - string temp_directory; - bool created_directory = false; - unique_ptr temp_file; + TemporaryFileManager &manager; + temporary_buffer_size_map_t files; }; //===--------------------------------------------------------------------===// -// TemporaryFileManager +// TemporaryFileCompressionLevel/TemporaryFileCompressionAdaptivity //===--------------------------------------------------------------------===// +enum class TemporaryCompressionLevel : int { + ZSTD_MINUS_FIVE = -5, + ZSTD_MINUS_THREE = -3, + ZSTD_MINUS_ONE = -1, + UNCOMPRESSED = 0, + ZSTD_ONE = 1, + ZSTD_THREE = 3, + ZSTD_FIVE = 5, +}; + +class TemporaryFileCompressionAdaptivity { +public: + TemporaryFileCompressionAdaptivity(); + +public: + //! Get current time in nanoseconds to measure write times + static int64_t GetCurrentTimeNanos(); + //! Get the compression level to use based on current write times + TemporaryCompressionLevel GetCompressionLevel(); + //! Update write time for given compression level + void Update(TemporaryCompressionLevel level, int64_t time_before_ns); + +private: + //! Convert from level to index into write time array and back + static TemporaryCompressionLevel IndexToLevel(idx_t index); + static idx_t LevelToIndex(TemporaryCompressionLevel level); + //! Min/max compression levels + static TemporaryCompressionLevel MinimumCompressionLevel(); + static TemporaryCompressionLevel MaximumCompressionLevel(); +private: + //! The value to initialize the atomic write counters to + static constexpr int64_t INITIAL_NS = 50000; + //! How many compression levels we adapt between + static constexpr idx_t LEVELS = 6; + //! Bias towards compressed writes: we only choose uncompressed if it is more than 2x faster than compressed + static constexpr double DURATION_RATIO_THRESHOLD = 2.0; + //! Probability to deviate from the current best write behavior (1 in 20) + static constexpr double COMPRESSION_DEVIATION = 0.5; + //! Weight to use for moving weighted average + static constexpr int64_t WEIGHT = 16; + + //! Random engine to (sometimes) randomize compression + RandomEngine random_engine; + //! Duration of the last uncompressed write + int64_t last_uncompressed_write_ns; + //! Duration of the last compressed writes + int64_t last_compressed_writes_ns[LEVELS]; +}; + +//===--------------------------------------------------------------------===// +// TemporaryFileManager +//===--------------------------------------------------------------------===// class TemporaryFileManager { + friend struct BlockIndexManager; + friend class TemporaryFileHandle; + public: TemporaryFileManager(DatabaseInstance &db, const string &temp_directory_p); ~TemporaryFileManager(); +private: + struct CompressionResult { + TemporaryBufferSize size; + TemporaryCompressionLevel level; + }; + public: - struct TemporaryManagerLock { + struct TemporaryFileManagerLock { public: - explicit TemporaryManagerLock(mutex &mutex); + explicit TemporaryFileManagerLock(mutex &mutex); public: lock_guard lock; }; + //! Create/Read/Update/Delete operations for temporary buffers void WriteTemporaryBuffer(block_id_t block_id, FileBuffer &buffer); bool HasTemporaryBuffer(block_id_t block_id); unique_ptr ReadTemporaryBuffer(block_id_t id, unique_ptr reusable_buffer); void DeleteTemporaryBuffer(block_id_t id); + + //! Get the list of temporary files and their sizes vector GetTemporaryFiles(); - idx_t GetTotalUsedSpaceInBytes(); + + //! Get/set maximum swap space optional_idx GetMaxSwapSpace() const; void SetMaxSwapSpace(optional_idx limit); + + //! Get temporary file size + idx_t GetTotalUsedSpaceInBytes() const; //! Register temporary file size growth void IncreaseSizeOnDisk(idx_t amount); //! Register temporary file size decrease void DecreaseSizeOnDisk(idx_t amount); private: - void EraseUsedBlock(TemporaryManagerLock &lock, block_id_t id, TemporaryFileHandle *handle, + //! Compress buffer, write it in compressed_buffer and return the size/level + CompressionResult CompressBuffer(TemporaryFileCompressionAdaptivity &compression_adaptivity, FileBuffer &buffer, + AllocatedData &compressed_buffer); + + //! Create file name for given size/index + string CreateTemporaryFileName(const TemporaryFileIdentifier &identifier) const; + + //! Get/erase a temporary block + TemporaryFileIndex GetTempBlockIndex(TemporaryFileManagerLock &, block_id_t id); + void EraseUsedBlock(TemporaryFileManagerLock &lock, block_id_t id, TemporaryFileHandle &handle, TemporaryFileIndex index); - TemporaryFileHandle *GetFileHandle(TemporaryManagerLock &, idx_t index); - TemporaryFileIndex GetTempBlockIndex(TemporaryManagerLock &, block_id_t id); - void EraseFileHandle(TemporaryManagerLock &, idx_t file_index); + + //! Get/erase a temporary file handle + optional_ptr GetFileHandle(TemporaryFileManagerLock &, + const TemporaryFileIdentifier &identifier); + void EraseFileHandle(TemporaryFileManagerLock &, const TemporaryFileIdentifier &identifier); private: + //! Reference to the DB instance DatabaseInstance &db; - mutex manager_lock; //! The temporary directory string temp_directory; + //! Lock for parallel access + mutex manager_lock; //! The set of active temporary file handles - unordered_map> files; - //! map of block_id -> temporary file position + TemporaryFileMap files; + //! Map of block_id -> temporary file position unordered_map used_blocks; - //! Manager of in-use temporary file indexes - BlockIndexManager index_manager; + //! Map of TemporaryBufferSize -> manager of in-use temporary file indexes + unordered_map index_managers; //! The size in bytes of the temporary files that are currently alive atomic size_on_disk; //! The max amount of disk space that can be used idx_t max_swap_space; + //! How many compression adaptivities we have so that threads don't all share the same one + static constexpr idx_t COMPRESSION_ADAPTIVITIES = 64; + //! Class that oversees when/how much to compress + array compression_adaptivities; +}; + +//===--------------------------------------------------------------------===// +// TemporaryDirectoryHandle +//===--------------------------------------------------------------------===// +class TemporaryDirectoryHandle { +public: + TemporaryDirectoryHandle(DatabaseInstance &db, string path_p, optional_idx max_swap_space); + ~TemporaryDirectoryHandle(); + +public: + TemporaryFileManager &GetTempFile() const; + +private: + DatabaseInstance &db; + string temp_directory; + bool created_directory = false; + unique_ptr temp_file; }; } // namespace duckdb 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 a5e295f2f..bef1e2f28 100644 --- a/src/duckdb/src/include/duckdb/storage/write_ahead_log.hpp +++ b/src/duckdb/src/include/duckdb/storage/write_ahead_log.hpp @@ -93,7 +93,7 @@ class WriteAheadLog { //! Sets the table used for subsequent insert/delete/update commands void WriteSetTable(const string &schema, const string &table); - void WriteAlter(const AlterInfo &info); + void WriteAlter(CatalogEntry &entry, const AlterInfo &info); void WriteInsert(DataChunk &chunk); void WriteRowGroupData(const PersistentCollectionData &data); diff --git a/src/duckdb/src/include/duckdb/transaction/commit_state.hpp b/src/duckdb/src/include/duckdb/transaction/commit_state.hpp index d92056d36..382de7296 100644 --- a/src/duckdb/src/include/duckdb/transaction/commit_state.hpp +++ b/src/duckdb/src/include/duckdb/transaction/commit_state.hpp @@ -14,6 +14,7 @@ namespace duckdb { class CatalogEntry; class DataChunk; +class DuckTransaction; class WriteAheadLog; class ClientContext; @@ -23,7 +24,7 @@ struct UpdateInfo; class CommitState { public: - explicit CommitState(transaction_t commit_id); + explicit CommitState(DuckTransaction &transaction, transaction_t commit_id); public: void CommitEntry(UndoFlags type, data_ptr_t data); @@ -33,6 +34,7 @@ class CommitState { void CommitEntryDrop(CatalogEntry &entry, data_ptr_t extra_data); private: + DuckTransaction &transaction; transaction_t commit_id; }; diff --git a/src/duckdb/src/include/duckdb/transaction/duck_transaction.hpp b/src/duckdb/src/include/duckdb/transaction/duck_transaction.hpp index 5399b2ef0..e17c048be 100644 --- a/src/duckdb/src/include/duckdb/transaction/duck_transaction.hpp +++ b/src/duckdb/src/include/duckdb/transaction/duck_transaction.hpp @@ -11,6 +11,7 @@ #include "duckdb/transaction/transaction.hpp" #include "duckdb/common/reference_map.hpp" #include "duckdb/common/error_data.hpp" +#include "duckdb/transaction/undo_buffer.hpp" namespace duckdb { class CheckpointLock; @@ -58,7 +59,7 @@ class DuckTransaction : public Transaction { bool AutomaticCheckpoint(AttachedDatabase &db, const UndoBufferProperties &properties); //! Rollback - void Rollback() noexcept; + ErrorData Rollback(); //! Cleanup the undo buffer void Cleanup(transaction_t lowest_active_transaction); @@ -69,7 +70,7 @@ class DuckTransaction : public Transaction { idx_t base_row); void PushSequenceUsage(SequenceCatalogEntry &entry, const SequenceData &data); void PushAppend(DataTable &table, idx_t row_start, idx_t row_count); - UpdateInfo *CreateUpdateInfo(idx_t type_size, idx_t entries); + UndoBufferReference CreateUpdateInfo(idx_t type_size, idx_t entries); bool IsDuckTransaction() const override { return true; 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 0371d4e97..deaaf0b4d 100644 --- a/src/duckdb/src/include/duckdb/transaction/duck_transaction_manager.hpp +++ b/src/duckdb/src/include/duckdb/transaction/duck_transaction_manager.hpp @@ -14,6 +14,7 @@ namespace duckdb { class DuckTransaction; +struct UndoBufferProperties; //! The Transaction Manager is responsible for creating and managing //! transactions diff --git a/src/duckdb/src/include/duckdb/transaction/local_storage.hpp b/src/duckdb/src/include/duckdb/transaction/local_storage.hpp index aa345b1ef..32715121a 100644 --- a/src/duckdb/src/include/duckdb/transaction/local_storage.hpp +++ b/src/duckdb/src/include/duckdb/transaction/local_storage.hpp @@ -92,10 +92,6 @@ class LocalTableManager { //! The LocalStorage class holds appends that have not been committed yet class LocalStorage { -public: - // Threshold to merge row groups instead of appending - static constexpr const idx_t MERGE_THRESHOLD = Storage::ROW_GROUP_SIZE; - public: struct CommitState { CommitState(); diff --git a/src/duckdb/src/include/duckdb/transaction/rollback_state.hpp b/src/duckdb/src/include/duckdb/transaction/rollback_state.hpp index 19d6cdad4..3195c2a6a 100644 --- a/src/duckdb/src/include/duckdb/transaction/rollback_state.hpp +++ b/src/duckdb/src/include/duckdb/transaction/rollback_state.hpp @@ -13,15 +13,18 @@ namespace duckdb { class DataChunk; class DataTable; +class DuckTransaction; class WriteAheadLog; class RollbackState { public: - RollbackState() { - } + explicit RollbackState(DuckTransaction &transaction); public: void RollbackEntry(UndoFlags type, data_ptr_t data); + +private: + DuckTransaction &transaction; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/transaction/transaction.hpp b/src/duckdb/src/include/duckdb/transaction/transaction.hpp index a2122a68f..db0a90eee 100644 --- a/src/duckdb/src/include/duckdb/transaction/transaction.hpp +++ b/src/duckdb/src/include/duckdb/transaction/transaction.hpp @@ -10,10 +10,9 @@ #include "duckdb/catalog/catalog_entry/sequence_catalog_entry.hpp" #include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/transaction/undo_buffer.hpp" -#include "duckdb/common/atomic.hpp" #include "duckdb/transaction/transaction_data.hpp" #include "duckdb/common/shared_ptr.hpp" +#include "duckdb/common/atomic.hpp" namespace duckdb { class SequenceCatalogEntry; diff --git a/src/duckdb/src/include/duckdb/transaction/undo_buffer.hpp b/src/duckdb/src/include/duckdb/transaction/undo_buffer.hpp index 0eb865222..ab37d5cca 100644 --- a/src/duckdb/src/include/duckdb/transaction/undo_buffer.hpp +++ b/src/duckdb/src/include/duckdb/transaction/undo_buffer.hpp @@ -10,11 +10,14 @@ #include "duckdb/common/common.hpp" #include "duckdb/common/enums/undo_flags.hpp" -#include "duckdb/storage/arena_allocator.hpp" +#include "duckdb/transaction/undo_buffer_allocator.hpp" namespace duckdb { +class BufferManager; +class DuckTransaction; class StorageCommitState; class WriteAheadLog; +struct UndoBufferPointer; struct UndoBufferProperties { idx_t estimated_size = 0; @@ -30,17 +33,17 @@ struct UndoBufferProperties { class UndoBuffer { public: struct IteratorState { - ArenaChunk *current; + BufferHandle handle; + optional_ptr current; data_ptr_t start; data_ptr_t end; }; public: - explicit UndoBuffer(ClientContext &context); + explicit UndoBuffer(DuckTransaction &transaction, ClientContext &context); - //! Reserve space for an entry of the specified type and length in the undo - //! buffer - data_ptr_t CreateEntry(UndoFlags type, idx_t len); + //! Write a specified entry to the undo buffer + UndoBufferReference CreateEntry(UndoFlags type, idx_t len); bool ChangesMade(); UndoBufferProperties GetProperties(); @@ -55,10 +58,11 @@ class UndoBuffer { void RevertCommit(UndoBuffer::IteratorState &iterator_state, transaction_t transaction_id); //! Rollback the changes made in this UndoBuffer: should be called on //! rollback - void Rollback() noexcept; + void Rollback(); private: - ArenaAllocator allocator; + DuckTransaction &transaction; + UndoBufferAllocator allocator; private: template diff --git a/src/duckdb/src/include/duckdb/transaction/undo_buffer_allocator.hpp b/src/duckdb/src/include/duckdb/transaction/undo_buffer_allocator.hpp new file mode 100644 index 000000000..a318fe8ff --- /dev/null +++ b/src/duckdb/src/include/duckdb/transaction/undo_buffer_allocator.hpp @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/transaction/undo_buffer_allocator.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/common.hpp" +#include "duckdb/storage/buffer/buffer_handle.hpp" + +namespace duckdb { +class BufferManager; +class BlockHandle; +struct UndoBufferEntry; +struct UndoBufferPointer; + +struct UndoBufferEntry { + explicit UndoBufferEntry(BufferManager &buffer_manager) : buffer_manager(buffer_manager) { + } + ~UndoBufferEntry(); + + BufferManager &buffer_manager; + shared_ptr block; + idx_t position = 0; + idx_t capacity = 0; + unique_ptr next; + optional_ptr prev; +}; + +struct UndoBufferReference { + UndoBufferReference() : entry(nullptr), position(0) { + } + UndoBufferReference(UndoBufferEntry &entry_p, BufferHandle handle_p, idx_t position) + : entry(&entry_p), handle(std::move(handle_p)), position(position) { + } + + optional_ptr entry; + BufferHandle handle; + idx_t position; + + data_ptr_t Ptr() { + return handle.Ptr() + position; + } + bool IsSet() const { + return entry; + } + + UndoBufferPointer GetBufferPointer(); +}; + +struct UndoBufferPointer { + UndoBufferPointer() : entry(nullptr), position(0) { + } + UndoBufferPointer(UndoBufferEntry &entry_p, idx_t position) : entry(&entry_p), position(position) { + } + + UndoBufferEntry *entry; + idx_t position; + + UndoBufferReference Pin() const; + bool IsSet() const { + return entry; + } +}; + +struct UndoBufferAllocator { + explicit UndoBufferAllocator(BufferManager &buffer_manager); + + UndoBufferReference Allocate(idx_t alloc_len); + + BufferManager &buffer_manager; + unique_ptr head; + optional_ptr tail; +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/transaction/update_info.hpp b/src/duckdb/src/include/duckdb/transaction/update_info.hpp index e7dc7dfcb..7cccd923e 100644 --- a/src/duckdb/src/include/duckdb/transaction/update_info.hpp +++ b/src/duckdb/src/include/duckdb/transaction/update_info.hpp @@ -11,12 +11,18 @@ #include "duckdb/common/constants.hpp" #include "duckdb/common/types/vector.hpp" #include "duckdb/common/types/validity_mask.hpp" +#include "duckdb/transaction/undo_buffer_allocator.hpp" #include "duckdb/common/atomic.hpp" namespace duckdb { class UpdateSegment; struct DataTableInfo; +//! UpdateInfo is a class that represents a set of updates applied to a single vector. +//! The UpdateInfo struct contains metadata associated with the update. +//! After the UpdateInfo, we must ALWAYS allocate the list of tuples and the data as contiguous arrays: +//! [UpdateInfo][TUPLES (sel_t[max])][DATA (T[max])] +//! The required allocation size can be obtained using UpdateInfo::GetAllocSize struct UpdateInfo { //! The update segment that this update info affects UpdateSegment *segment; @@ -30,27 +36,44 @@ struct UpdateInfo { sel_t N; // NOLINT //! The maximum amount of tuples that can fit into this UpdateInfo sel_t max; - //! The row ids of the tuples that have been updated. This should always be kept sorted! - sel_t *tuples; - //! The data of the tuples - data_ptr_t tuple_data; //! The previous update info (or nullptr if it is the base) - UpdateInfo *prev; + UndoBufferPointer prev; //! The next update info in the chain (or nullptr if it is the last) - UpdateInfo *next; + UndoBufferPointer next; + + //! The row ids of the tuples that have been updated. This should always be kept sorted! + sel_t *GetTuples(); + + //! The update values + data_ptr_t GetValues(); + + template + T *GetData() { + return reinterpret_cast(GetValues()); + } + + bool AppliesToTransaction(transaction_t start_time, transaction_t transaction_id) { + // these tuples were either committed AFTER this transaction started or are not committed yet, use + // tuples stored in this version + return version_number > start_time && version_number != transaction_id; + } //! Loop over the update chain and execute the specified callback on all UpdateInfo's that are relevant for that //! transaction in-order of newest to oldest template - static void UpdatesForTransaction(UpdateInfo *current, transaction_t start_time, transaction_t transaction_id, + static void UpdatesForTransaction(UpdateInfo ¤t, transaction_t start_time, transaction_t transaction_id, T &&callback) { - while (current) { - if (current->version_number > start_time && current->version_number != transaction_id) { - // these tuples were either committed AFTER this transaction started or are not committed yet, use - // tuples stored in this version - callback(current); + if (current.AppliesToTransaction(start_time, transaction_id)) { + callback(current); + } + auto update_ptr = current.next; + while (update_ptr.IsSet()) { + auto pin = update_ptr.Pin(); + auto &info = Get(pin); + if (info.AppliesToTransaction(start_time, transaction_id)) { + callback(info); } - current = current->next; + update_ptr = info.next; } } @@ -58,6 +81,13 @@ struct UpdateInfo { string ToString(); void Print(); void Verify(); + bool HasPrev() const; + bool HasNext() const; + static UpdateInfo &Get(UndoBufferReference &entry); + //! Returns the total allocation size for an UpdateInfo entry, together with space for the tuple data + static idx_t GetAllocSize(idx_t type_size); + //! Initialize an UpdateInfo struct that has been allocated using GetAllocSize (i.e. has extra space after it) + static void Initialize(UpdateInfo &info, transaction_t transaction_id); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/transaction/wal_write_state.hpp b/src/duckdb/src/include/duckdb/transaction/wal_write_state.hpp index 0a4b1e1c1..aad1a672c 100644 --- a/src/duckdb/src/include/duckdb/transaction/wal_write_state.hpp +++ b/src/duckdb/src/include/duckdb/transaction/wal_write_state.hpp @@ -14,6 +14,7 @@ namespace duckdb { class CatalogEntry; class DataChunk; +class DuckTransaction; class WriteAheadLog; class ClientContext; @@ -23,7 +24,8 @@ struct UpdateInfo; class WALWriteState { public: - explicit WALWriteState(WriteAheadLog &log, optional_ptr commit_state); + explicit WALWriteState(DuckTransaction &transaction, WriteAheadLog &log, + optional_ptr commit_state); public: void CommitEntry(UndoFlags type, data_ptr_t data); @@ -36,6 +38,7 @@ class WALWriteState { void WriteUpdate(UpdateInfo &info); private: + DuckTransaction &transaction; WriteAheadLog &log; optional_ptr commit_state; diff --git a/src/duckdb/src/include/duckdb_extension.h b/src/duckdb/src/include/duckdb_extension.h index c70eb8a80..e044e167a 100644 --- a/src/duckdb/src/include/duckdb_extension.h +++ b/src/duckdb/src/include/duckdb_extension.h @@ -486,6 +486,18 @@ typedef struct { duckdb_data_chunk (*duckdb_stream_fetch_chunk)(duckdb_result result); #endif +#ifdef DUCKDB_EXTENSION_API_VERSION_DEV // dev + // WARNING! the functions below are not (yet) stable + + duckdb_state (*duckdb_appender_create_ext)(duckdb_connection connection, const char *catalog, const char *schema, + const char *table, duckdb_appender *out_appender); + duckdb_state (*duckdb_table_description_create_ext)(duckdb_connection connection, const char *catalog, + const char *schema, const char *table, + duckdb_table_description *out); + char *(*duckdb_table_description_get_column_name)(duckdb_table_description table_description, idx_t index); + duckdb_logical_type (*duckdb_param_logical_type)(duckdb_prepared_statement prepared_statement, idx_t param_idx); +#endif + } duckdb_ext_api_v0; //===--------------------------------------------------------------------===// @@ -865,6 +877,12 @@ typedef struct { #define duckdb_register_cast_function duckdb_ext_api.duckdb_register_cast_function #define duckdb_destroy_cast_function duckdb_ext_api.duckdb_destroy_cast_function +// Version dev +#define duckdb_param_logical_type duckdb_ext_api.duckdb_param_logical_type +#define duckdb_appender_create_ext duckdb_ext_api.duckdb_appender_create_ext +#define duckdb_table_description_create_ext duckdb_ext_api.duckdb_table_description_create_ext +#define duckdb_table_description_get_column_name duckdb_ext_api.duckdb_table_description_get_column_name + //===--------------------------------------------------------------------===// // Struct Global Macros //===--------------------------------------------------------------------===// @@ -874,7 +892,7 @@ typedef struct { #define DUCKDB_EXTENSION_API_INIT(info, access, minimum_api_version) \ duckdb_ext_api_v0 *res = (duckdb_ext_api_v0 *)access->get_api(info, minimum_api_version); \ if (!res) { \ - return; \ + return false; \ }; \ duckdb_ext_api = *res; @@ -892,30 +910,31 @@ typedef struct { // Main entrypoint: opens (and closes) a connection automatically for the extension to register its functionality // through #define DUCKDB_EXTENSION_ENTRYPOINT \ - DUCKDB_EXTENSION_GLOBAL static void DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal)( \ + DUCKDB_EXTENSION_GLOBAL static bool DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal)( \ duckdb_connection connection, duckdb_extension_info info, duckdb_extension_access * access); \ - DUCKDB_EXTENSION_EXTERN_C_GUARD_OPEN DUCKDB_EXTENSION_API void DUCKDB_EXTENSION_GLUE( \ + DUCKDB_EXTENSION_EXTERN_C_GUARD_OPEN DUCKDB_EXTENSION_API bool DUCKDB_EXTENSION_GLUE( \ DUCKDB_EXTENSION_NAME, _init_c_api)(duckdb_extension_info info, duckdb_extension_access * access) { \ DUCKDB_EXTENSION_API_INIT(info, access, DUCKDB_EXTENSION_API_VERSION_STRING); \ duckdb_database *db = access->get_database(info); \ duckdb_connection conn; \ if (duckdb_connect(*db, &conn) == DuckDBError) { \ access->set_error(info, "Failed to open connection to database"); \ - return; \ + return false; \ } \ - DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal)(conn, info, access); \ + auto init_result = DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal)(conn, info, access); \ duckdb_disconnect(&conn); \ + return init_result; \ } \ - DUCKDB_EXTENSION_EXTERN_C_GUARD_CLOSE static void DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal) + DUCKDB_EXTENSION_EXTERN_C_GUARD_CLOSE static bool DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal) // Custom entrypoint: just forwards the info and access #define DUCKDB_EXTENSION_ENTRYPOINT_CUSTOM \ - DUCKDB_EXTENSION_GLOBAL static void DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal)( \ + DUCKDB_EXTENSION_GLOBAL static bool DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal)( \ duckdb_extension_info info, duckdb_extension_access * access); \ - DUCKDB_EXTENSION_EXTERN_C_GUARD_OPEN DUCKDB_EXTENSION_API void DUCKDB_EXTENSION_GLUE( \ + DUCKDB_EXTENSION_EXTERN_C_GUARD_OPEN DUCKDB_EXTENSION_API bool DUCKDB_EXTENSION_GLUE( \ DUCKDB_EXTENSION_NAME, _init_c_api)(duckdb_extension_info info, duckdb_extension_access * access) { \ DUCKDB_EXTENSION_API_INIT(info, access, DUCKDB_EXTENSION_API_VERSION_STRING); \ - DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal)(info, access); \ + return DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal)(info, access); \ } \ - DUCKDB_EXTENSION_EXTERN_C_GUARD_CLOSE static void DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal) + DUCKDB_EXTENSION_EXTERN_C_GUARD_CLOSE static bool DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal) #endif diff --git a/src/duckdb/src/main/appender.cpp b/src/duckdb/src/main/appender.cpp index 33ef17bf4..4d222b35e 100644 --- a/src/duckdb/src/main/appender.cpp +++ b/src/duckdb/src/main/appender.cpp @@ -53,13 +53,17 @@ InternalAppender::~InternalAppender() { Destructor(); } -Appender::Appender(Connection &con, const string &schema_name, const string &table_name) +Appender::Appender(Connection &con, const string &database_name, const string &schema_name, const string &table_name) : BaseAppender(Allocator::DefaultAllocator(), AppenderType::LOGICAL), context(con.context) { - description = con.TableInfo(schema_name, table_name); + + description = con.TableInfo(database_name, schema_name, table_name); if (!description) { - // table could not be found throw CatalogException(StringUtil::Format("Table \"%s.%s\" could not be found", schema_name, table_name)); } + if (description->readonly) { + throw InvalidInputException("Cannot append to a readonly database."); + } + vector> defaults; for (auto &column : description->columns) { if (column.Generated()) { @@ -68,31 +72,35 @@ Appender::Appender(Connection &con, const string &schema_name, const string &tab types.push_back(column.Type()); defaults.push_back(column.HasDefaultValue() ? &column.DefaultValue() : nullptr); } - auto binder = Binder::CreateBinder(*context); + auto binder = Binder::CreateBinder(*context); context->RunFunctionInTransaction([&]() { for (idx_t i = 0; i < types.size(); i++) { auto &type = types[i]; auto &expr = defaults[i]; if (!expr) { - // Insert NULL + // The default value is NULL. default_values[i] = Value(type); continue; } + auto default_copy = expr->Copy(); D_ASSERT(!default_copy->HasParameter()); + ConstantBinder default_binder(*binder, *context, "DEFAULT value"); default_binder.target_type = type; auto bound_default = default_binder.Bind(default_copy); + Value result_value; - if (bound_default->IsFoldable() && - ExpressionExecutor::TryEvaluateScalar(*context, *bound_default, result_value)) { - // Insert the evaluated Value - default_values[i] = result_value; - } else { - // These are not supported currently, we don't add them to the 'default_values' map + if (bound_default->IsFoldable()) { + auto eval_success = ExpressionExecutor::TryEvaluateScalar(*context, *bound_default, result_value); + if (eval_success) { + // Insert the default Value. + default_values[i] = result_value; + } } + // All other cases are not supported currently. } }); @@ -100,7 +108,12 @@ Appender::Appender(Connection &con, const string &schema_name, const string &tab collection = make_uniq(allocator, types); } -Appender::Appender(Connection &con, const string &table_name) : Appender(con, DEFAULT_SCHEMA, table_name) { +Appender::Appender(Connection &con, const string &schema_name, const string &table_name) + : Appender(con, INVALID_CATALOG, schema_name, table_name) { +} + +Appender::Appender(Connection &con, const string &table_name) + : Appender(con, INVALID_CATALOG, DEFAULT_SCHEMA, table_name) { } Appender::~Appender() { @@ -364,18 +377,45 @@ void BaseAppender::AppendValue(const Value &value) { column++; } -void BaseAppender::AppendDataChunk(DataChunk &chunk) { - auto chunk_types = chunk.GetTypes(); - if (chunk_types != types) { - for (idx_t i = 0; i < chunk.ColumnCount(); i++) { - if (chunk.data[i].GetType() != types[i]) { - throw InvalidInputException("Type mismatch in Append DataChunk and the types required for appender, " - "expected %s but got %s for column %d", - types[i].ToString(), chunk.data[i].GetType().ToString(), i + 1); - } +void BaseAppender::AppendDataChunk(DataChunk &chunk_p) { + auto chunk_types = chunk_p.GetTypes(); + + // Early-out, if types match. + if (chunk_types == types) { + collection->Append(chunk_p); + if (collection->Count() >= flush_count) { + Flush(); } + return; } - collection->Append(chunk); + + auto count = chunk_p.ColumnCount(); + if (count != types.size()) { + throw InvalidInputException("incorrect column count in AppendDataChunk, expected %d, got %d", types.size(), + count); + } + + // We try to cast the chunk. + auto size = chunk_p.size(); + DataChunk cast_chunk; + cast_chunk.Initialize(allocator, types); + cast_chunk.SetCardinality(size); + + for (idx_t i = 0; i < count; i++) { + if (chunk_p.data[i].GetType() == types[i]) { + cast_chunk.data[i].Reference(chunk_p.data[i]); + continue; + } + + string error_msg; + auto success = VectorOperations::DefaultTryCast(chunk_p.data[i], cast_chunk.data[i], size, &error_msg); + if (!success) { + throw InvalidInputException("type mismatch in AppendDataChunk, expected %s, got %s for column %d", + types[i].ToString(), chunk_p.data[i].GetType().ToString(), i); + } + } + + collection->Append(cast_chunk); if (collection->Count() >= flush_count) { Flush(); } diff --git a/src/duckdb/src/main/attached_database.cpp b/src/duckdb/src/main/attached_database.cpp index 5a435b1dd..51546d6c3 100644 --- a/src/duckdb/src/main/attached_database.cpp +++ b/src/duckdb/src/main/attached_database.cpp @@ -25,7 +25,6 @@ AttachOptions::AttachOptions(const unique_ptr &info, const AccessMod : access_mode(default_access_mode) { for (auto &entry : info->options) { - if (entry.first == "readonly" || entry.first == "read_only") { // Extract the read access mode. @@ -40,7 +39,6 @@ AttachOptions::AttachOptions(const unique_ptr &info, const AccessMod if (entry.first == "readwrite" || entry.first == "read_write") { // Extract the write access mode. - auto read_write = BooleanValue::Get(entry.second.DefaultCastAs(LogicalType::BOOLEAN)); if (!read_write) { access_mode = AccessMode::READ_ONLY; @@ -56,11 +54,12 @@ AttachOptions::AttachOptions(const unique_ptr &info, const AccessMod continue; } - // We allow unrecognized options in storage extensions. To track that we saw an unrecognized option, - // we set unrecognized_option. - if (unrecognized_option.empty()) { - unrecognized_option = entry.first; + if (entry.first == "default_table") { + default_table = QualifiedName::Parse(StringValue::Get(entry.second.DefaultCastAs(LogicalType::VARCHAR))); + continue; } + + options[entry.first] = entry.second; } } @@ -93,6 +92,15 @@ AttachedDatabase::AttachedDatabase(DatabaseInstance &db, Catalog &catalog_p, str } else { type = AttachedDatabaseType::READ_WRITE_DATABASE; } + for (auto &entry : options.options) { + if (StringUtil::CIEquals(entry.first, "block_size")) { + continue; + } + if (StringUtil::CIEquals(entry.first, "row_group_size")) { + continue; + } + throw BinderException("Unrecognized option for attach \"%s\"", entry.first); + } // We create the storage after the catalog to guarantee we allow extensions to instantiate the DuckCatalog. catalog = make_uniq(*this); @@ -163,14 +171,14 @@ string AttachedDatabase::ExtractDatabaseName(const string &dbpath, FileSystem &f return name; } -void AttachedDatabase::Initialize(const optional_idx block_alloc_size) { +void AttachedDatabase::Initialize(StorageOptions options) { if (IsSystem()) { catalog->Initialize(true); } else { catalog->Initialize(false); } if (storage) { - storage->Initialize(block_alloc_size); + storage->Initialize(options); } } diff --git a/src/duckdb/src/main/capi/appender-c.cpp b/src/duckdb/src/main/capi/appender-c.cpp index eed34fb97..9f67d9154 100644 --- a/src/duckdb/src/main/capi/appender-c.cpp +++ b/src/duckdb/src/main/capi/appender-c.cpp @@ -15,18 +15,27 @@ using duckdb::uhugeint_t; duckdb_state duckdb_appender_create(duckdb_connection connection, const char *schema, const char *table, duckdb_appender *out_appender) { + return duckdb_appender_create_ext(connection, INVALID_CATALOG, schema, table, out_appender); +} + +duckdb_state duckdb_appender_create_ext(duckdb_connection connection, const char *catalog, const char *schema, + const char *table, duckdb_appender *out_appender) { Connection *conn = reinterpret_cast(connection); if (!connection || !table || !out_appender) { return DuckDBError; } + if (catalog == nullptr) { + catalog = INVALID_CATALOG; + } if (schema == nullptr) { schema = DEFAULT_SCHEMA; } + auto wrapper = new AppenderWrapper(); *out_appender = (duckdb_appender)wrapper; try { - wrapper->appender = duckdb::make_uniq(*conn, schema, table); + wrapper->appender = duckdb::make_uniq(*conn, catalog, schema, table); } catch (std::exception &ex) { ErrorData error(ex); wrapper->error = error.RawMessage(); @@ -261,6 +270,6 @@ duckdb_state duckdb_append_data_chunk(duckdb_appender appender, duckdb_data_chun if (!chunk) { return DuckDBError; } - auto data_chunk = (duckdb::DataChunk *)chunk; + auto data_chunk = reinterpret_cast(chunk); return duckdb_appender_run_function(appender, [&](Appender &appender) { appender.AppendDataChunk(*data_chunk); }); } diff --git a/src/duckdb/src/main/capi/config-c.cpp b/src/duckdb/src/main/capi/config-c.cpp index daa4bcb0a..68605056d 100644 --- a/src/duckdb/src/main/capi/config-c.cpp +++ b/src/duckdb/src/main/capi/config-c.cpp @@ -1,6 +1,7 @@ #include "duckdb/main/capi/capi_internal.hpp" #include "duckdb/main/config.hpp" #include "duckdb/common/types/value.hpp" +#include "duckdb/main/extension_helper.hpp" using duckdb::DBConfig; using duckdb::Value; @@ -22,19 +23,31 @@ duckdb_state duckdb_create_config(duckdb_config *out_config) { } size_t duckdb_config_count() { - return DBConfig::GetOptionCount(); + return DBConfig::GetOptionCount() + duckdb::ExtensionHelper::ArraySize(duckdb::EXTENSION_SETTINGS); } duckdb_state duckdb_get_config_flag(size_t index, const char **out_name, const char **out_description) { auto option = DBConfig::GetOptionByIndex(index); - if (!option) { + if (option) { + if (out_name) { + *out_name = option->name; + } + if (out_description) { + *out_description = option->description; + } + return DuckDBSuccess; + } + + // extension index? + auto entry = duckdb::ExtensionHelper::GetArrayEntry(duckdb::EXTENSION_SETTINGS, index - DBConfig::GetOptionCount()); + if (!entry) { return DuckDBError; } if (out_name) { - *out_name = option->name; + *out_name = entry->name; } if (out_description) { - *out_description = option->description; + *out_description = entry->extension; } return DuckDBSuccess; } diff --git a/src/duckdb/src/main/capi/prepared-c.cpp b/src/duckdb/src/main/capi/prepared-c.cpp index a0df37a21..d97bc041d 100644 --- a/src/duckdb/src/main/capi/prepared-c.cpp +++ b/src/duckdb/src/main/capi/prepared-c.cpp @@ -122,22 +122,35 @@ const char *duckdb_parameter_name(duckdb_prepared_statement prepared_statement, } duckdb_type duckdb_param_type(duckdb_prepared_statement prepared_statement, idx_t param_idx) { + auto logical_type = duckdb_param_logical_type(prepared_statement, param_idx); + if (!logical_type) { + return DUCKDB_TYPE_INVALID; + } + + auto type = duckdb_get_type_id(logical_type); + + duckdb_destroy_logical_type(&logical_type); + + return type; +} + +duckdb_logical_type duckdb_param_logical_type(duckdb_prepared_statement prepared_statement, idx_t param_idx) { auto wrapper = reinterpret_cast(prepared_statement); if (!wrapper || !wrapper->statement || wrapper->statement->HasError()) { - return DUCKDB_TYPE_INVALID; + return nullptr; } LogicalType param_type; auto identifier = std::to_string(param_idx); if (wrapper->statement->data->TryGetType(identifier, param_type)) { - return ConvertCPPTypeToC(param_type); + return reinterpret_cast(new LogicalType(param_type)); } // The value_map is gone after executing the prepared statement // See if this is the case and we still have a value registered for it auto it = wrapper->values.find(identifier); if (it != wrapper->values.end()) { - return ConvertCPPTypeToC(it->second.return_type.id()); + return reinterpret_cast(new LogicalType(it->second.return_type)); } - return DUCKDB_TYPE_INVALID; + return nullptr; } duckdb_state duckdb_clear_bindings(duckdb_prepared_statement prepared_statement) { diff --git a/src/duckdb/src/main/capi/table_description-c.cpp b/src/duckdb/src/main/capi/table_description-c.cpp index 495267f98..26624bbfc 100644 --- a/src/duckdb/src/main/capi/table_description-c.cpp +++ b/src/duckdb/src/main/capi/table_description-c.cpp @@ -8,24 +8,31 @@ using duckdb::TableDescriptionWrapper; duckdb_state duckdb_table_description_create(duckdb_connection connection, const char *schema, const char *table, duckdb_table_description *out) { + return duckdb_table_description_create_ext(connection, INVALID_CATALOG, schema, table, out); +} + +duckdb_state duckdb_table_description_create_ext(duckdb_connection connection, const char *catalog, const char *schema, + const char *table, duckdb_table_description *out) { Connection *conn = reinterpret_cast(connection); if (!out) { return DuckDBError; } auto wrapper = new TableDescriptionWrapper(); - *out = (duckdb_table_description)wrapper; + *out = reinterpret_cast(wrapper); if (!connection || !table) { return DuckDBError; } - + if (catalog == nullptr) { + catalog = INVALID_CATALOG; + } if (schema == nullptr) { schema = DEFAULT_SCHEMA; } try { - wrapper->description = conn->TableInfo(schema, table); + wrapper->description = conn->TableInfo(catalog, schema, table); } catch (std::exception &ex) { ErrorData error(ex); wrapper->error = error.RawMessage(); @@ -61,22 +68,48 @@ const char *duckdb_table_description_error(duckdb_table_description table) { return wrapper->error.c_str(); } -duckdb_state duckdb_column_has_default(duckdb_table_description table_description, idx_t index, bool *out) { - auto wrapper = reinterpret_cast(table_description); - if (!wrapper || !out) { - if (wrapper) { - wrapper->error = "Please provide a valid (non-null) 'out' variable"; - } +duckdb_state GetTableDescription(TableDescriptionWrapper *wrapper, idx_t index) { + if (!wrapper) { return DuckDBError; } - auto &table = wrapper->description; if (index >= table->columns.size()) { wrapper->error = duckdb::StringUtil::Format("Column index %d is out of range, table only has %d columns", index, table->columns.size()); return DuckDBError; } + return DuckDBSuccess; +} + +duckdb_state duckdb_column_has_default(duckdb_table_description table_description, idx_t index, bool *out) { + auto wrapper = reinterpret_cast(table_description); + if (GetTableDescription(wrapper, index) == DuckDBError) { + return DuckDBError; + } + if (!out) { + wrapper->error = "Please provide a valid (non-null) 'out' variable"; + return DuckDBError; + } + + auto &table = wrapper->description; auto &column = table->columns[index]; *out = column.HasDefaultValue(); return DuckDBSuccess; } + +char *duckdb_table_description_get_column_name(duckdb_table_description table_description, idx_t index) { + auto wrapper = reinterpret_cast(table_description); + if (GetTableDescription(wrapper, index) == DuckDBError) { + return nullptr; + } + + auto &table = wrapper->description; + auto &column = table->columns[index]; + + auto name = column.GetName(); + auto result = reinterpret_cast(malloc(sizeof(char) * (name.size() + 1))); + memcpy(result, name.c_str(), name.size()); + result[name.size()] = '\0'; + + return result; +} diff --git a/src/duckdb/src/main/client_context.cpp b/src/duckdb/src/main/client_context.cpp index 90c029ab4..304e51861 100644 --- a/src/duckdb/src/main/client_context.cpp +++ b/src/duckdb/src/main/client_context.cpp @@ -1107,19 +1107,20 @@ void ClientContext::RunFunctionInTransaction(const std::function &fu RunFunctionInTransactionInternal(*lock, fun, requires_valid_transaction); } -unique_ptr ClientContext::TableInfo(const string &schema_name, const string &table_name) { +unique_ptr ClientContext::TableInfo(const string &database_name, const string &schema_name, + const string &table_name) { unique_ptr result; RunFunctionInTransaction([&]() { - // obtain the table info - auto table = Catalog::GetEntry(*this, INVALID_CATALOG, schema_name, table_name, + // Obtain the table from the catalog. + auto table = Catalog::GetEntry(*this, database_name, schema_name, table_name, OnEntryNotFound::RETURN_NULL); if (!table) { return; } - // write the table info to the result - result = make_uniq(); - result->schema = schema_name; - result->table = table_name; + // Create the table description. + result = make_uniq(database_name, schema_name, table_name); + auto &catalog = Catalog::GetCatalog(*this, database_name); + result->readonly = catalog.GetAttached().IsReadOnly(); for (auto &column : table->GetColumns().Logical()) { result->columns.emplace_back(column.Copy()); } @@ -1127,10 +1128,14 @@ unique_ptr ClientContext::TableInfo(const string &schema_name, return result; } +unique_ptr ClientContext::TableInfo(const string &schema_name, const string &table_name) { + return TableInfo(INVALID_CATALOG, schema_name, table_name); +} + void ClientContext::Append(TableDescription &description, ColumnDataCollection &collection) { RunFunctionInTransaction([&]() { auto &table_entry = - Catalog::GetEntry(*this, INVALID_CATALOG, description.schema, description.table); + Catalog::GetEntry(*this, description.database, description.schema, description.table); // verify that the table columns and types match up if (description.PhysicalColumnCount() != table_entry.GetColumns().PhysicalColumnCount()) { throw InvalidInputException("Failed to append: table entry has different number of columns!"); @@ -1153,22 +1158,24 @@ void ClientContext::Append(TableDescription &description, ColumnDataCollection & }); } +void ClientContext::InternalTryBindRelation(Relation &relation, vector &result_columns) { + // bind the expressions + auto binder = Binder::CreateBinder(*this); + auto result = relation.Bind(*binder); + D_ASSERT(result.names.size() == result.types.size()); + + result_columns.reserve(result_columns.size() + result.names.size()); + for (idx_t i = 0; i < result.names.size(); i++) { + result_columns.emplace_back(result.names[i], result.types[i]); + } +} + void ClientContext::TryBindRelation(Relation &relation, vector &result_columns) { #ifdef DEBUG D_ASSERT(!relation.GetAlias().empty()); D_ASSERT(!relation.ToString().empty()); #endif - RunFunctionInTransaction([&]() { - // bind the expressions - auto binder = Binder::CreateBinder(*this); - auto result = relation.Bind(*binder); - D_ASSERT(result.names.size() == result.types.size()); - - result_columns.reserve(result_columns.size() + result.names.size()); - for (idx_t i = 0; i < result.names.size(); i++) { - result_columns.emplace_back(result.names[i], result.types[i]); - } - }); + RunFunctionInTransaction([&]() { InternalTryBindRelation(relation, result_columns); }); } unordered_set ClientContext::GetTableNames(const string &query) { @@ -1304,7 +1311,7 @@ ClientProperties ClientContext::GetClientProperties() const { timezone = result.ToString(); } return {timezone, db->config.options.arrow_offset_size, db->config.options.arrow_use_list_view, - db->config.options.produce_arrow_string_views, db->config.options.arrow_arrow_lossless_conversion}; + db->config.options.produce_arrow_string_views, db->config.options.arrow_lossless_conversion}; } bool ClientContext::ExecutionIsFinished() { diff --git a/src/duckdb/src/main/client_context_wrapper.cpp b/src/duckdb/src/main/client_context_wrapper.cpp index d79b09300..74783c79d 100644 --- a/src/duckdb/src/main/client_context_wrapper.cpp +++ b/src/duckdb/src/main/client_context_wrapper.cpp @@ -19,4 +19,8 @@ shared_ptr ClientContextWrapper::GetContext() { return actual_context; } +void ClientContextWrapper::TryBindRelation(Relation &relation, vector &columns) { + GetContext()->TryBindRelation(relation, columns); +} + } // namespace duckdb diff --git a/src/duckdb/src/main/client_data.cpp b/src/duckdb/src/main/client_data.cpp index 50e460b60..fb07894c4 100644 --- a/src/duckdb/src/main/client_data.cpp +++ b/src/duckdb/src/main/client_data.cpp @@ -42,7 +42,7 @@ ClientData::ClientData(ClientContext &context) : catalog_search_path(make_uniq(); file_opener = make_uniq(context); client_file_system = make_uniq(context); - temporary_objects->Initialize(DEFAULT_BLOCK_ALLOC_SIZE); + temporary_objects->Initialize(); } ClientData::~ClientData() { diff --git a/src/duckdb/src/main/config.cpp b/src/duckdb/src/main/config.cpp index 6921cb497..b72ec07cb 100644 --- a/src/duckdb/src/main/config.cpp +++ b/src/duckdb/src/main/config.cpp @@ -54,109 +54,111 @@ bool DBConfigOptions::debug_print_bindings = false; _PARAM::ResetLocal, _PARAM::GetSetting \ } #define FINAL_SETTING \ - { nullptr, nullptr, LogicalTypeId::INVALID, nullptr, nullptr, nullptr, nullptr, nullptr } + { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr } static const ConfigurationOption internal_options[] = { DUCKDB_GLOBAL(AccessModeSetting), - DUCKDB_GLOBAL(AllowPersistentSecrets), - DUCKDB_GLOBAL(CatalogErrorMaxSchema), + DUCKDB_GLOBAL(AllocatorBackgroundThreadsSetting), + DUCKDB_GLOBAL(AllocatorBulkDeallocationFlushThresholdSetting), + DUCKDB_GLOBAL(AllocatorFlushThresholdSetting), + DUCKDB_GLOBAL(AllowCommunityExtensionsSetting), + DUCKDB_GLOBAL(AllowExtensionsMetadataMismatchSetting), + DUCKDB_GLOBAL(AllowPersistentSecretsSetting), + DUCKDB_GLOBAL(AllowUnredactedSecretsSetting), + DUCKDB_GLOBAL(AllowUnsignedExtensionsSetting), + DUCKDB_GLOBAL(AllowedDirectoriesSetting), + DUCKDB_GLOBAL(AllowedPathsSetting), + DUCKDB_GLOBAL(ArrowLargeBufferSizeSetting), + DUCKDB_GLOBAL(ArrowLosslessConversionSetting), + DUCKDB_GLOBAL(ArrowOutputListViewSetting), + DUCKDB_GLOBAL(AutoinstallExtensionRepositorySetting), + DUCKDB_GLOBAL(AutoinstallKnownExtensionsSetting), + DUCKDB_GLOBAL(AutoloadKnownExtensionsSetting), + DUCKDB_GLOBAL(CatalogErrorMaxSchemasSetting), DUCKDB_GLOBAL(CheckpointThresholdSetting), - DUCKDB_GLOBAL(DebugCheckpointAbort), - DUCKDB_GLOBAL(DebugSkipCheckpointOnCommit), - DUCKDB_GLOBAL(StorageCompatibilityVersion), - DUCKDB_LOCAL(DebugForceExternal), - DUCKDB_LOCAL(DebugForceNoCrossProduct), - DUCKDB_LOCAL(DebugAsOfIEJoin), - DUCKDB_LOCAL(PreferRangeJoins), - DUCKDB_GLOBAL(DebugWindowMode), + DUCKDB_GLOBAL_ALIAS("wal_autocheckpoint", CheckpointThresholdSetting), + DUCKDB_GLOBAL(CustomExtensionRepositorySetting), + DUCKDB_LOCAL(CustomProfilingSettingsSetting), + DUCKDB_GLOBAL(CustomUserAgentSetting), + DUCKDB_LOCAL(DebugAsofIejoinSetting), + DUCKDB_GLOBAL(DebugCheckpointAbortSetting), + DUCKDB_LOCAL(DebugForceExternalSetting), + DUCKDB_LOCAL(DebugForceNoCrossProductSetting), + DUCKDB_GLOBAL(DebugSkipCheckpointOnCommitSetting), + DUCKDB_GLOBAL(DebugWindowModeSetting), + DUCKDB_GLOBAL(DefaultBlockSizeSetting), DUCKDB_GLOBAL_LOCAL(DefaultCollationSetting), - DUCKDB_GLOBAL(DefaultOrderSetting), DUCKDB_GLOBAL(DefaultNullOrderSetting), - DUCKDB_GLOBAL(DisabledFileSystemsSetting), + DUCKDB_GLOBAL_ALIAS("null_order", DefaultNullOrderSetting), + DUCKDB_GLOBAL(DefaultOrderSetting), + DUCKDB_GLOBAL(DefaultSecretStorageSetting), + DUCKDB_GLOBAL(DisabledFilesystemsSetting), DUCKDB_GLOBAL(DisabledOptimizersSetting), + DUCKDB_GLOBAL(DuckDBAPISetting), DUCKDB_GLOBAL(EnableExternalAccessSetting), - DUCKDB_GLOBAL(EnableFSSTVectors), - DUCKDB_GLOBAL(AllowUnsignedExtensionsSetting), - DUCKDB_GLOBAL(AllowCommunityExtensionsSetting), - DUCKDB_GLOBAL(AllowExtensionsMetadataMismatchSetting), - DUCKDB_GLOBAL(AllowUnredactedSecretsSetting), - DUCKDB_GLOBAL(CustomExtensionRepository), - DUCKDB_GLOBAL(AutoloadExtensionRepository), - DUCKDB_GLOBAL(AutoinstallKnownExtensions), - DUCKDB_GLOBAL(AutoloadKnownExtensions), - DUCKDB_GLOBAL(EnableObjectCacheSetting), + DUCKDB_GLOBAL(EnableFSSTVectorsSetting), + DUCKDB_LOCAL(EnableHTTPLoggingSetting), DUCKDB_GLOBAL(EnableHTTPMetadataCacheSetting), + DUCKDB_GLOBAL(EnableMacroDependenciesSetting), + DUCKDB_GLOBAL(EnableObjectCacheSetting), DUCKDB_LOCAL(EnableProfilingSetting), DUCKDB_LOCAL(EnableProgressBarSetting), DUCKDB_LOCAL(EnableProgressBarPrintSetting), - DUCKDB_LOCAL(ErrorsAsJsonSetting), + DUCKDB_GLOBAL(EnableViewDependenciesSetting), + DUCKDB_LOCAL(ErrorsAsJSONSetting), DUCKDB_LOCAL(ExplainOutputSetting), DUCKDB_GLOBAL(ExtensionDirectorySetting), DUCKDB_GLOBAL(ExternalThreadsSetting), DUCKDB_LOCAL(FileSearchPathSetting), - DUCKDB_GLOBAL(ForceCompressionSetting), DUCKDB_GLOBAL(ForceBitpackingModeSetting), + DUCKDB_GLOBAL(ForceCompressionSetting), DUCKDB_LOCAL(HomeDirectorySetting), - DUCKDB_GLOBAL(HTTPProxy), - DUCKDB_GLOBAL(HTTPProxyUsername), - DUCKDB_GLOBAL(HTTPProxyPassword), - DUCKDB_LOCAL(LogQueryPathSetting), - DUCKDB_GLOBAL(EnableMacrosDependencies), - DUCKDB_GLOBAL(EnableViewDependencies), - DUCKDB_GLOBAL(LockConfigurationSetting), + DUCKDB_LOCAL(HTTPLoggingOutputSetting), + DUCKDB_GLOBAL(HTTPProxySetting), + DUCKDB_GLOBAL(HTTPProxyPasswordSetting), + DUCKDB_GLOBAL(HTTPProxyUsernameSetting), DUCKDB_LOCAL(IEEEFloatingPointOpsSetting), DUCKDB_GLOBAL(ImmediateTransactionModeSetting), + DUCKDB_GLOBAL(IndexScanMaxCountSetting), + DUCKDB_GLOBAL(IndexScanPercentageSetting), DUCKDB_LOCAL(IntegerDivisionSetting), - DUCKDB_LOCAL(MaximumExpressionDepthSetting), - DUCKDB_LOCAL(StreamingBufferSize), - DUCKDB_GLOBAL(MaximumMemorySetting), - DUCKDB_GLOBAL(MaximumTempDirectorySize), - DUCKDB_GLOBAL(MaximumVacuumTasks), - DUCKDB_LOCAL(MergeJoinThreshold), - DUCKDB_LOCAL(NestedLoopJoinThreshold), - DUCKDB_GLOBAL(OldImplicitCasting), - DUCKDB_GLOBAL_ALIAS("memory_limit", MaximumMemorySetting), - DUCKDB_GLOBAL_ALIAS("null_order", DefaultNullOrderSetting), - DUCKDB_LOCAL(OrderByNonIntegerLiteral), - DUCKDB_LOCAL(OrderedAggregateThreshold), + DUCKDB_GLOBAL(LockConfigurationSetting), + DUCKDB_LOCAL(LogQueryPathSetting), + DUCKDB_LOCAL(MaxExpressionDepthSetting), + DUCKDB_GLOBAL(MaxMemorySetting), + DUCKDB_GLOBAL_ALIAS("memory_limit", MaxMemorySetting), + DUCKDB_GLOBAL(MaxTempDirectorySizeSetting), + DUCKDB_GLOBAL(MaxVacuumTasksSetting), + DUCKDB_LOCAL(MergeJoinThresholdSetting), + DUCKDB_LOCAL(NestedLoopJoinThresholdSetting), + DUCKDB_GLOBAL(OldImplicitCastingSetting), + DUCKDB_LOCAL(OrderByNonIntegerLiteralSetting), + DUCKDB_LOCAL(OrderedAggregateThresholdSetting), + DUCKDB_LOCAL(PartitionedWriteFlushThresholdSetting), + DUCKDB_LOCAL(PartitionedWriteMaxOpenFilesSetting), DUCKDB_GLOBAL(PasswordSetting), - DUCKDB_LOCAL(PerfectHashThresholdSetting), - DUCKDB_LOCAL(PivotFilterThreshold), + DUCKDB_LOCAL(PerfectHtThresholdSetting), + DUCKDB_LOCAL(PivotFilterThresholdSetting), DUCKDB_LOCAL(PivotLimitSetting), - DUCKDB_LOCAL(PreserveIdentifierCase), - DUCKDB_GLOBAL(PreserveInsertionOrder), + DUCKDB_LOCAL(PreferRangeJoinsSetting), + DUCKDB_LOCAL(PreserveIdentifierCaseSetting), + DUCKDB_GLOBAL(PreserveInsertionOrderSetting), + DUCKDB_GLOBAL(ProduceArrowStringViewSetting), DUCKDB_LOCAL(ProfileOutputSetting), - DUCKDB_LOCAL(ProfilingModeSetting), DUCKDB_LOCAL_ALIAS("profiling_output", ProfileOutputSetting), - DUCKDB_LOCAL(CustomProfilingSettings), + DUCKDB_LOCAL(ProfilingModeSetting), DUCKDB_LOCAL(ProgressBarTimeSetting), + DUCKDB_LOCAL(ScalarSubqueryErrorOnMultipleRowsSetting), DUCKDB_LOCAL(SchemaSetting), DUCKDB_LOCAL(SearchPathSetting), - DUCKDB_LOCAL(ScalarSubqueryErrorOnMultipleRows), DUCKDB_GLOBAL(SecretDirectorySetting), - DUCKDB_GLOBAL(DefaultSecretStorage), + DUCKDB_GLOBAL(StorageCompatibilityVersionSetting), + DUCKDB_LOCAL(StreamingBufferSizeSetting), DUCKDB_GLOBAL(TempDirectorySetting), DUCKDB_GLOBAL(ThreadsSetting), + DUCKDB_GLOBAL_ALIAS("worker_threads", ThreadsSetting), DUCKDB_GLOBAL(UsernameSetting), - DUCKDB_GLOBAL(ExportLargeBufferArrow), - DUCKDB_GLOBAL(ArrowOutputListView), - DUCKDB_GLOBAL(LosslessConversionArrow), - DUCKDB_GLOBAL(ProduceArrowStringView), DUCKDB_GLOBAL_ALIAS("user", UsernameSetting), - DUCKDB_GLOBAL_ALIAS("wal_autocheckpoint", CheckpointThresholdSetting), - DUCKDB_GLOBAL_ALIAS("worker_threads", ThreadsSetting), - DUCKDB_GLOBAL(AllocatorFlushThreshold), - DUCKDB_GLOBAL(AllocatorBulkDeallocationFlushThreshold), - DUCKDB_GLOBAL(AllocatorBackgroundThreadsSetting), - DUCKDB_GLOBAL(DuckDBApiSetting), - DUCKDB_GLOBAL(CustomUserAgentSetting), - DUCKDB_LOCAL(PartitionedWriteFlushThreshold), - DUCKDB_LOCAL(PartitionedWriteMaxOpenFiles), - DUCKDB_GLOBAL(DefaultBlockAllocSize), - DUCKDB_GLOBAL(IndexScanPercentage), - DUCKDB_GLOBAL(IndexScanMaxCount), - DUCKDB_LOCAL(EnableHTTPLoggingSetting), - DUCKDB_LOCAL(HTTPLoggingOutputSetting), FINAL_SETTING}; vector DBConfig::GetOptions() { @@ -241,7 +243,7 @@ void DBConfig::SetOption(DatabaseInstance *db, const ConfigurationOption &option throw InvalidInputException("Could not set option \"%s\" as a global option", option.name); } D_ASSERT(option.reset_global); - Value input = value.DefaultCastAs(option.parameter_type); + Value input = value.DefaultCastAs(ParseLogicalType(option.parameter_type)); option.set_global(db, *this, input); } @@ -273,6 +275,27 @@ void DBConfig::ResetOption(const string &name) { } } +LogicalType DBConfig::ParseLogicalType(const string &type) { + if (StringUtil::EndsWith(type, "[]")) { + // array - recurse + auto child_type = ParseLogicalType(type.substr(0, type.size() - 2)); + return LogicalType::LIST(child_type); + } + if (StringUtil::EndsWith(type, "()")) { + if (type != "STRUCT()") { + throw InternalException("Error while generating extension function overloads - expected STRUCT(), not %s", + type); + } + return LogicalType::STRUCT({}); + } + auto type_id = TransformStringToLogicalTypeId(type); + if (type_id == LogicalTypeId::USER) { + throw InternalException("Error while generating extension function overloads - unrecognized logical type %s", + type); + } + return type_id; +} + void DBConfig::AddExtensionOption(const string &name, string description, LogicalType parameter, const Value &default_value, set_option_callback_t function) { extension_parameters.insert( @@ -322,7 +345,9 @@ void DBConfig::SetDefaultMaxMemory() { } void DBConfig::SetDefaultTempDirectory() { - if (DBConfig::IsInMemoryDatabase(options.database_path.c_str())) { + if (!options.use_temporary_directory) { + options.temporary_directory = string(); + } else if (DBConfig::IsInMemoryDatabase(options.database_path.c_str())) { options.temporary_directory = ".tmp"; } else { options.temporary_directory = options.database_path + ".tmp"; @@ -548,6 +573,94 @@ const string DBConfig::UserAgent() const { return user_agent; } +string DBConfig::SanitizeAllowedPath(const string &path) const { + auto path_sep = file_system->PathSeparator(path); + if (path_sep != "/") { + // allowed_directories/allowed_path always uses forward slashes regardless of the OS + return StringUtil::Replace(path, path_sep, "/"); + } + return path; +} + +void DBConfig::AddAllowedDirectory(const string &path) { + auto allowed_directory = SanitizeAllowedPath(path); + if (allowed_directory.empty()) { + throw InvalidInputException("Cannot provide an empty string for allowed_directory"); + } + // ensure the directory ends with a path separator + if (!StringUtil::EndsWith(allowed_directory, "/")) { + allowed_directory += "/"; + } + options.allowed_directories.insert(allowed_directory); +} + +void DBConfig::AddAllowedPath(const string &path) { + auto allowed_path = SanitizeAllowedPath(path); + options.allowed_paths.insert(allowed_path); +} + +bool DBConfig::CanAccessFile(const string &input_path, FileType type) { + if (options.enable_external_access) { + // 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; + } + if (type == FileType::FILE_TYPE_DIR) { + // make sure directories end with a / + if (!StringUtil::EndsWith(path, "/")) { + path += "/"; + } + } + auto start_bound = options.allowed_directories.lower_bound(path); + if (start_bound != options.allowed_directories.begin()) { + --start_bound; + } + auto end_bound = options.allowed_directories.upper_bound(path); + + string prefix; + for (auto it = start_bound; it != end_bound; ++it) { + if (StringUtil::StartsWith(path, *it)) { + prefix = *it; + break; + } + } + if (prefix.empty()) { + // no common prefix found - path is not inside an allowed directory + 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; +} + SerializationCompatibility SerializationCompatibility::FromString(const string &input) { if (input.empty()) { throw InvalidInputException("Version string can not be empty"); diff --git a/src/duckdb/src/main/connection.cpp b/src/duckdb/src/main/connection.cpp index 4dd7ad11e..0f7616292 100644 --- a/src/duckdb/src/main/connection.cpp +++ b/src/duckdb/src/main/connection.cpp @@ -50,11 +50,7 @@ Connection::~Connection() { string Connection::GetProfilingInformation(ProfilerPrintFormat format) { auto &profiler = QueryProfiler::Get(*context); - if (format == ProfilerPrintFormat::JSON) { - return profiler.ToJSON(); - } else { - return profiler.QueryTreeToString(); - } + return profiler.ToString(format); } optional_ptr Connection::GetProfilingTree() { @@ -160,12 +156,17 @@ unique_ptr Connection::QueryParamsRecursive(const string &query, ve return statement->Execute(values, false); } -unique_ptr Connection::TableInfo(const string &table_name) { - return TableInfo(INVALID_SCHEMA, table_name); +unique_ptr Connection::TableInfo(const string &database_name, const string &schema_name, + const string &table_name) { + return context->TableInfo(database_name, schema_name, table_name); } unique_ptr Connection::TableInfo(const string &schema_name, const string &table_name) { - return context->TableInfo(schema_name, table_name); + return TableInfo(INVALID_CATALOG, schema_name, table_name); +} + +unique_ptr Connection::TableInfo(const string &table_name) { + return TableInfo(INVALID_CATALOG, DEFAULT_SCHEMA, table_name); } vector> Connection::ExtractStatements(const string &query) { @@ -194,7 +195,7 @@ shared_ptr Connection::Table(const string &table_name) { } shared_ptr Connection::Table(const string &schema_name, const string &table_name) { - auto table_info = TableInfo(schema_name, table_name); + auto table_info = TableInfo(INVALID_CATALOG, schema_name, table_name); if (!table_info) { throw CatalogException("Table '%s' does not exist!", table_name); } diff --git a/src/duckdb/src/main/database.cpp b/src/duckdb/src/main/database.cpp index 0a82e4598..412fc5f0b 100644 --- a/src/duckdb/src/main/database.cpp +++ b/src/duckdb/src/main/database.cpp @@ -275,11 +275,6 @@ void DatabaseInstance::Initialize(const char *database_path, DBConfig *user_conf create_api_v0 = CreateAPIv0Wrapper; - if (user_config && !user_config->options.use_temporary_directory) { - // temporary directories explicitly disabled - config.options.temporary_directory = string(); - } - db_file_system = make_uniq(*this); db_manager = make_uniq(*this); if (config.buffer_manager) { @@ -418,6 +413,13 @@ void DatabaseInstance::Configure(DBConfig &new_config, const char *database_path } else { config.file_system = make_uniq(); } + if (database_path && !config.options.enable_external_access) { + config.AddAllowedPath(database_path); + config.AddAllowedPath(database_path + string(".wal")); + if (!config.options.temporary_directory.empty()) { + config.AddAllowedDirectory(config.options.temporary_directory); + } + } if (new_config.secret_manager) { config.secret_manager = std::move(new_config.secret_manager); } diff --git a/src/duckdb/src/main/database_manager.cpp b/src/duckdb/src/main/database_manager.cpp index 5750ab9f9..b20394027 100644 --- a/src/duckdb/src/main/database_manager.cpp +++ b/src/duckdb/src/main/database_manager.cpp @@ -134,17 +134,21 @@ void DatabaseManager::EraseDatabasePath(const string &path) { } } +vector DatabaseManager::GetAttachedDatabasePaths() { + lock_guard path_lock(db_paths_lock); + vector paths; + for (auto &path : db_paths) { + paths.push_back(path); + } + return paths; +} + void DatabaseManager::GetDatabaseType(ClientContext &context, AttachInfo &info, const DBConfig &config, AttachOptions &options) { // Test if the database is a DuckDB database file. if (StringUtil::CIEquals(options.db_type, "DUCKDB")) { options.db_type = ""; - - // The DuckDB format does not allow unrecognized options. - if (!options.unrecognized_option.empty()) { - throw BinderException("Unrecognized option for attach \"%s\"", options.unrecognized_option); - } return; } @@ -166,12 +170,6 @@ void DatabaseManager::GetDatabaseType(ClientContext &context, AttachInfo &info, } return; } - - // The DuckDB file format does not allow unrecognized options, except for the block_size option, - // which is specific to DuckDB files. - if (!options.unrecognized_option.empty() && options.unrecognized_option != "block_size") { - throw BinderException("Unrecognized option for attach \"%s\"", options.unrecognized_option); - } } const string &DatabaseManager::GetDefaultDatabase(ClientContext &context) { diff --git a/src/duckdb/src/main/extension/extension_helper.cpp b/src/duckdb/src/main/extension/extension_helper.cpp index 0742b503b..18b7cbb2e 100644 --- a/src/duckdb/src/main/extension/extension_helper.cpp +++ b/src/duckdb/src/main/extension/extension_helper.cpp @@ -12,6 +12,10 @@ // Note that c++ preprocessor doesn't have a nice way to clean this up so we need to set the defines we use to false // explicitly when they are undefined +#ifndef DUCKDB_EXTENSION_CORE_FUNCTIONS_LINKED +#define DUCKDB_EXTENSION_CORE_FUNCTIONS_LINKED false +#endif + #ifndef DUCKDB_EXTENSION_ICU_LINKED #define DUCKDB_EXTENSION_ICU_LINKED false #endif @@ -58,6 +62,10 @@ #else // TODO: rewrite package_build.py to allow also loading out-of-tree extensions in non-cmake builds, after that // these can be removed +#if DUCKDB_EXTENSION_CORE_FUNCTIONS_LINKED +#include "core_functions_extension.hpp" +#endif + #if DUCKDB_EXTENSION_ICU_LINKED #include "icu_extension.hpp" #endif @@ -93,6 +101,7 @@ #if DUCKDB_EXTENSION_AUTOCOMPLETE_LINKED #include "autocomplete_extension.hpp" #endif + #endif namespace duckdb { @@ -101,6 +110,7 @@ namespace duckdb { // Default Extensions //===--------------------------------------------------------------------===// static const DefaultExtension internal_extensions[] = { + {"core_functions", "Core function library", DUCKDB_EXTENSION_CORE_FUNCTIONS_LINKED}, {"icu", "Adds support for time zones and collations using the ICU library", DUCKDB_EXTENSION_ICU_LINKED}, {"excel", "Adds support for Excel-like format strings", DUCKDB_EXTENSION_EXCEL_LINKED}, {"parquet", "Adds support for reading and writing parquet files", DUCKDB_EXTENSION_PARQUET_LINKED}, @@ -212,7 +222,8 @@ bool ExtensionHelper::TryAutoLoadExtension(ClientContext &context, const string try { if (dbconfig.options.autoinstall_known_extensions) { auto &config = DBConfig::GetConfig(context); - auto autoinstall_repo = ExtensionRepository::GetRepositoryByUrl(config.options.autoinstall_extension_repo); + auto autoinstall_repo = ExtensionRepository::GetRepositoryByUrl( + StringValue::Get(config.GetSetting(context))); ExtensionInstallOptions options; options.repository = autoinstall_repo; ExtensionHelper::InstallExtension(context, extension_name, options); @@ -403,8 +414,8 @@ void ExtensionHelper::LoadAllExtensions(DuckDB &db) { // The in-tree extensions that we check. Non-cmake builds are currently limited to these for static linking // TODO: rewrite package_build.py to allow also loading out-of-tree extensions in non-cmake builds, after that // these can be removed - unordered_set extensions {"parquet", "icu", "tpch", "tpcds", "fts", "httpfs", - "json", "excel", "inet", "jemalloc", "autocomplete"}; + vector extensions {"parquet", "icu", "tpch", "tpcds", "fts", "httpfs", + "json", "excel", "inet", "jemalloc", "autocomplete", "core_functions"}; for (auto &ext : extensions) { LoadExtensionInternal(db, ext, true); } @@ -539,6 +550,13 @@ ExtensionLoadResult ExtensionHelper::LoadExtensionInternal(DuckDB &db, const std #else // inet extension required but not build: skip this test return ExtensionLoadResult::NOT_LOADED; +#endif + } else if (extension == "core_functions") { +#if DUCKDB_EXTENSION_CORE_FUNCTIONS_LINKED + db.LoadStaticExtension(); +#else + // core_functions extension required but not build: skip this test + return ExtensionLoadResult::NOT_LOADED; #endif } diff --git a/src/duckdb/src/main/extension/extension_load.cpp b/src/duckdb/src/main/extension/extension_load.cpp index b0282a710..bb2a89570 100644 --- a/src/duckdb/src/main/extension/extension_load.cpp +++ b/src/duckdb/src/main/extension/extension_load.cpp @@ -67,8 +67,15 @@ struct ExtensionAccess { static void SetError(duckdb_extension_info info, const char *error) { auto &load_state = DuckDBExtensionLoadState::Get(info); - load_state.has_error = true; - load_state.error_data = ErrorData(ExceptionType::UNKNOWN_TYPE, error); + if (error) { + load_state.has_error = true; + load_state.error_data = ErrorData(error); + } else { + load_state.has_error = true; + load_state.error_data = ErrorData( + ExceptionType::UNKNOWN_TYPE, + "Extension has indicated an error occured during initialization, but did not set an error message."); + } } //! Called by the extension get a pointer to the database that is loading it @@ -119,7 +126,7 @@ struct ExtensionAccess { // The C++ init function typedef void (*ext_init_fun_t)(DatabaseInstance &); // The C init function -typedef void (*ext_init_c_api_fun_t)(duckdb_extension_info info, duckdb_extension_access *access); +typedef bool (*ext_init_c_api_fun_t)(duckdb_extension_info info, duckdb_extension_access *access); typedef const char *(*ext_version_fun_t)(void); typedef bool (*ext_is_storage_t)(void); @@ -532,13 +539,23 @@ void ExtensionHelper::LoadExternalExtension(DatabaseInstance &db, FileSystem &fs DuckDBExtensionLoadState load_state(db); auto access = ExtensionAccess::CreateAccessStruct(); - (*init_fun_capi)(load_state.ToCStruct(), &access); + auto result = (*init_fun_capi)(load_state.ToCStruct(), &access); // Throw any error that the extension might have encountered if (load_state.has_error) { load_state.error_data.Throw("An error was thrown during initialization of the extension '" + extension + "': "); } + // Extensions are expected to either set an error or return true indicating successful initialization + if (result == false) { + throw FatalException( + "Extension '%s' failed to initialize but did not return an error. This indicates an " + "error in the extension: C API extensions should return a boolean `true` to indicate succesful " + "initialization. " + "This means that the Extension may be partially initialized resulting in an inconsistent state of DuckDB.", + extension); + } + D_ASSERT(res.install_info); db.SetExtensionLoaded(extension, *res.install_info); diff --git a/src/duckdb/src/main/extension/extension_util.cpp b/src/duckdb/src/main/extension/extension_util.cpp index bcad31464..609fd4b7d 100644 --- a/src/duckdb/src/main/extension/extension_util.cpp +++ b/src/duckdb/src/main/extension/extension_util.cpp @@ -24,31 +24,39 @@ void ExtensionUtil::RegisterExtension(DatabaseInstance &db, const string &name, db.AddExtensionInfo(name, description); } +void ExtensionUtil::RegisterFunction(DatabaseInstance &db, ScalarFunction function) { + ScalarFunctionSet set(function.name); + set.AddFunction(std::move(function)); + RegisterFunction(db, std::move(set)); +} + void ExtensionUtil::RegisterFunction(DatabaseInstance &db, ScalarFunctionSet set) { - D_ASSERT(!set.name.empty()); CreateScalarFunctionInfo info(std::move(set)); + info.on_conflict = OnCreateConflict::ALTER_ON_CONFLICT; + RegisterFunction(db, std::move(info)); +} + +void ExtensionUtil::RegisterFunction(DatabaseInstance &db, CreateScalarFunctionInfo info) { + D_ASSERT(!info.functions.name.empty()); auto &system_catalog = Catalog::GetSystemCatalog(db); auto data = CatalogTransaction::GetSystemTransaction(db); system_catalog.CreateFunction(data, info); } -void ExtensionUtil::RegisterFunction(DatabaseInstance &db, ScalarFunction function) { - D_ASSERT(!function.name.empty()); - ScalarFunctionSet set(function.name); - set.AddFunction(std::move(function)); - RegisterFunction(db, std::move(set)); -} - void ExtensionUtil::RegisterFunction(DatabaseInstance &db, AggregateFunction function) { - D_ASSERT(!function.name.empty()); AggregateFunctionSet set(function.name); set.AddFunction(std::move(function)); RegisterFunction(db, std::move(set)); } void ExtensionUtil::RegisterFunction(DatabaseInstance &db, AggregateFunctionSet set) { - D_ASSERT(!set.name.empty()); CreateAggregateFunctionInfo info(std::move(set)); + info.on_conflict = OnCreateConflict::ALTER_ON_CONFLICT; + RegisterFunction(db, std::move(info)); +} + +void ExtensionUtil::RegisterFunction(DatabaseInstance &db, CreateAggregateFunctionInfo info) { + D_ASSERT(!info.functions.name.empty()); auto &system_catalog = Catalog::GetSystemCatalog(db); auto data = CatalogTransaction::GetSystemTransaction(db); system_catalog.CreateFunction(data, info); @@ -61,7 +69,6 @@ void ExtensionUtil::RegisterFunction(DatabaseInstance &db, CreateSecretFunction } void ExtensionUtil::RegisterFunction(DatabaseInstance &db, TableFunction function) { - D_ASSERT(!function.name.empty()); TableFunctionSet set(function.name); set.AddFunction(std::move(function)); RegisterFunction(db, std::move(set)); @@ -70,6 +77,12 @@ void ExtensionUtil::RegisterFunction(DatabaseInstance &db, TableFunction functio void ExtensionUtil::RegisterFunction(DatabaseInstance &db, TableFunctionSet function) { D_ASSERT(!function.name.empty()); CreateTableFunctionInfo info(std::move(function)); + info.on_conflict = OnCreateConflict::ALTER_ON_CONFLICT; + RegisterFunction(db, std::move(info)); +} + +void ExtensionUtil::RegisterFunction(DatabaseInstance &db, CreateTableFunctionInfo info) { + D_ASSERT(!info.functions.name.empty()); auto &system_catalog = Catalog::GetSystemCatalog(db); auto data = CatalogTransaction::GetSystemTransaction(db); system_catalog.CreateFunction(data, info); @@ -138,24 +151,32 @@ void ExtensionUtil::AddFunctionOverload(DatabaseInstance &db, TableFunctionSet f } } -ScalarFunctionCatalogEntry &ExtensionUtil::GetFunction(DatabaseInstance &db, const string &name) { +optional_ptr TryGetEntry(DatabaseInstance &db, const string &name, CatalogType type) { D_ASSERT(!name.empty()); auto &system_catalog = Catalog::GetSystemCatalog(db); auto data = CatalogTransaction::GetSystemTransaction(db); auto &schema = system_catalog.GetSchema(data, DEFAULT_SCHEMA); - auto catalog_entry = schema.GetEntry(data, CatalogType::SCALAR_FUNCTION_ENTRY, name); + return schema.GetEntry(data, type, name); +} + +optional_ptr ExtensionUtil::TryGetFunction(DatabaseInstance &db, const string &name) { + return TryGetEntry(db, name, CatalogType::SCALAR_FUNCTION_ENTRY); +} + +ScalarFunctionCatalogEntry &ExtensionUtil::GetFunction(DatabaseInstance &db, const string &name) { + auto catalog_entry = TryGetFunction(db, name); if (!catalog_entry) { throw InvalidInputException("Function with name \"%s\" not found in ExtensionUtil::GetFunction", name); } return catalog_entry->Cast(); } +optional_ptr ExtensionUtil::TryGetTableFunction(DatabaseInstance &db, const string &name) { + return TryGetEntry(db, name, CatalogType::TABLE_FUNCTION_ENTRY); +} + TableFunctionCatalogEntry &ExtensionUtil::GetTableFunction(DatabaseInstance &db, const string &name) { - D_ASSERT(!name.empty()); - auto &system_catalog = Catalog::GetSystemCatalog(db); - auto data = CatalogTransaction::GetSystemTransaction(db); - auto &schema = system_catalog.GetSchema(data, DEFAULT_SCHEMA); - auto catalog_entry = schema.GetEntry(data, CatalogType::TABLE_FUNCTION_ENTRY, name); + auto catalog_entry = TryGetTableFunction(db, name); if (!catalog_entry) { throw InvalidInputException("Function with name \"%s\" not found in ExtensionUtil::GetTableFunction", name); } diff --git a/src/duckdb/src/main/query_profiler.cpp b/src/duckdb/src/main/query_profiler.cpp index 4f91d46d5..114eb042d 100644 --- a/src/duckdb/src/main/query_profiler.cpp +++ b/src/duckdb/src/main/query_profiler.cpp @@ -8,13 +8,12 @@ #include "duckdb/common/tree_renderer/text_tree_renderer.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/execution/operator/helper/physical_execute.hpp" +#include "duckdb/execution/operator/scan/physical_table_scan.hpp" #include "duckdb/execution/physical_operator.hpp" #include "duckdb/main/client_config.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/main/client_data.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/execution/operator/scan/physical_table_scan.hpp" - #include "yyjson.hpp" #include @@ -46,12 +45,35 @@ ProfilerPrintFormat QueryProfiler::GetPrintFormat(ExplainFormat format) const { return ProfilerPrintFormat::QUERY_TREE; case ExplainFormat::JSON: return ProfilerPrintFormat::JSON; + case ExplainFormat::HTML: + return ProfilerPrintFormat::HTML; + case ExplainFormat::GRAPHVIZ: + return ProfilerPrintFormat::GRAPHVIZ; default: throw NotImplementedException("No mapping from ExplainFormat::%s to ProfilerPrintFormat", EnumUtil::ToString(format)); } } +ExplainFormat QueryProfiler::GetExplainFormat(ProfilerPrintFormat format) const { + switch (format) { + case ProfilerPrintFormat::QUERY_TREE: + case ProfilerPrintFormat::QUERY_TREE_OPTIMIZER: + return ExplainFormat::TEXT; + case ProfilerPrintFormat::JSON: + return ExplainFormat::JSON; + case ProfilerPrintFormat::HTML: + return ExplainFormat::HTML; + case ProfilerPrintFormat::GRAPHVIZ: + return ExplainFormat::GRAPHVIZ; + case ProfilerPrintFormat::NO_OUTPUT: + throw InternalException("Should not attempt to get ExplainFormat for ProfilerPrintFormat::NO_OUTPUT"); + default: + throw NotImplementedException("No mapping from ProfilePrintFormat::%s to ExplainFormat", + EnumUtil::ToString(format)); + } +} + bool QueryProfiler::PrintOptimizerOutput() const { return GetPrintFormat() == ProfilerPrintFormat::QUERY_TREE_OPTIMIZER || IsDetailedEnabled(); } @@ -245,7 +267,13 @@ void QueryProfiler::EndQuery() { } string QueryProfiler::ToString(ExplainFormat explain_format) const { - const auto format = GetPrintFormat(explain_format); + return ToString(GetPrintFormat(explain_format)); +} + +string QueryProfiler::ToString(ProfilerPrintFormat format) const { + if (!IsEnabled()) { + return RenderDisabledMessage(format); + } switch (format) { case ProfilerPrintFormat::QUERY_TREE: case ProfilerPrintFormat::QUERY_TREE_OPTIMIZER: @@ -254,6 +282,22 @@ string QueryProfiler::ToString(ExplainFormat explain_format) const { return ToJSON(); case ProfilerPrintFormat::NO_OUTPUT: return ""; + case ProfilerPrintFormat::HTML: + case ProfilerPrintFormat::GRAPHVIZ: { + // checking the tree to ensure the query is really empty + // the query string is empty when a logical plan is deserialized + if (query_info.query_name.empty() && !root) { + return ""; + } + auto renderer = TreeRenderer::CreateRenderer(GetExplainFormat(format)); + std::stringstream str; + auto &info = root->GetProfilingInfo(); + if (info.Enabled(info.expanded_settings, MetricsType::OPERATOR_TIMING)) { + info.metrics[MetricsType::OPERATOR_TIMING] = main_query.Elapsed(); + } + renderer->Render(*root, str); + return str.str(); + } default: throw InternalException("Unknown ProfilerPrintFormat \"%s\"", EnumUtil::ToString(format)); } @@ -522,10 +566,6 @@ void PrintPhaseTimingsToStream(std::ostream &ss, const ProfilingInfo &info, idx_ } void QueryProfiler::QueryTreeToStream(std::ostream &ss) const { - if (!IsEnabled()) { - ss << "Query profiling is disabled. Use 'PRAGMA enable_profiling;' to enable profiling!"; - return; - } ss << "┌─────────────────────────────────────┐\n"; ss << "│┌───────────────────────────────────┐│\n"; ss << "││ Query Profiling Information ││\n"; @@ -550,12 +590,12 @@ void QueryProfiler::QueryTreeToStream(std::ostream &ss) const { ss << "││" + DrawPadded(total_time, TOTAL_BOX_WIDTH - 4) + "││\n"; ss << "│└──────────────────────────────────────────────┘│\n"; ss << "└────────────────────────────────────────────────┘\n"; - // print phase timings - if (PrintOptimizerOutput()) { - PrintPhaseTimingsToStream(ss, root->GetProfilingInfo(), TOTAL_BOX_WIDTH); - } // render the main operator tree if (root) { + // print phase timings + if (PrintOptimizerOutput()) { + PrintPhaseTimingsToStream(ss, root->GetProfilingInfo(), TOTAL_BOX_WIDTH); + } Render(*root, ss); } } @@ -641,10 +681,6 @@ string QueryProfiler::ToJSON() const { auto result_obj = yyjson_mut_obj(doc); yyjson_mut_doc_set_root(doc, result_obj); - if (!IsEnabled()) { - yyjson_mut_obj_add_str(doc, result_obj, "result", "disabled"); - return StringifyAndFree(doc, result_obj); - } if (query_info.query_name.empty() && !root) { yyjson_mut_obj_add_str(doc, result_obj, "result", "empty"); return StringifyAndFree(doc, result_obj); @@ -724,6 +760,40 @@ unique_ptr QueryProfiler::CreateTree(const PhysicalOperator &root return node; } +string QueryProfiler::RenderDisabledMessage(ProfilerPrintFormat format) const { + switch (format) { + case ProfilerPrintFormat::NO_OUTPUT: + return ""; + case ProfilerPrintFormat::QUERY_TREE: + case ProfilerPrintFormat::QUERY_TREE_OPTIMIZER: + return "Query profiling is disabled. Use 'PRAGMA enable_profiling;' to enable profiling!"; + case ProfilerPrintFormat::HTML: + return R"( + + + Query profiling is disabled. Use 'PRAGMA enable_profiling;' to enable profiling! + + )"; + case ProfilerPrintFormat::GRAPHVIZ: + return R"( + digraph G { + node [shape=box, style=rounded, fontname="Courier New", fontsize=10]; + node_0_0 [label="Query profiling is disabled. Use 'PRAGMA enable_profiling;' to enable profiling!"]; + } + )"; + case ProfilerPrintFormat::JSON: { + auto doc = yyjson_mut_doc_new(nullptr); + auto result_obj = yyjson_mut_obj(doc); + yyjson_mut_doc_set_root(doc, result_obj); + + yyjson_mut_obj_add_str(doc, result_obj, "result", "disabled"); + return StringifyAndFree(doc, result_obj); + } + default: + throw InternalException("Unknown ProfilerPrintFormat \"%s\"", EnumUtil::ToString(format)); + } +} + void QueryProfiler::Initialize(const PhysicalOperator &root_op) { if (!IsEnabled() || !running) { return; diff --git a/src/duckdb/src/main/relation.cpp b/src/duckdb/src/main/relation.cpp index 95a4c6bbd..3bb0a3848 100644 --- a/src/duckdb/src/main/relation.cpp +++ b/src/duckdb/src/main/relation.cpp @@ -38,7 +38,7 @@ shared_ptr Relation::Project(const string &expression, const string &a } shared_ptr Relation::Project(const string &select_list, const vector &aliases) { - auto expressions = Parser::ParseExpressionList(select_list, context.GetContext()->GetParserOptions()); + auto expressions = Parser::ParseExpressionList(select_list, context->GetContext()->GetParserOptions()); return make_shared_ptr(shared_from_this(), std::move(expressions), aliases); } @@ -52,7 +52,7 @@ shared_ptr Relation::Project(vector> expr return make_shared_ptr(shared_from_this(), std::move(expressions), aliases); } -static vector> StringListToExpressionList(ClientContext &context, +static vector> StringListToExpressionList(const ClientContext &context, const vector &expressions) { if (expressions.empty()) { throw ParserException("Zero expressions provided"); @@ -69,12 +69,12 @@ static vector> StringListToExpressionList(ClientCon } shared_ptr Relation::Project(const vector &expressions, const vector &aliases) { - auto result_list = StringListToExpressionList(*context.GetContext(), expressions); + auto result_list = StringListToExpressionList(*context->GetContext(), expressions); return make_shared_ptr(shared_from_this(), std::move(result_list), aliases); } shared_ptr Relation::Filter(const string &expression) { - auto expression_list = Parser::ParseExpressionList(expression, context.GetContext()->GetParserOptions()); + auto expression_list = Parser::ParseExpressionList(expression, context->GetContext()->GetParserOptions()); if (expression_list.size() != 1) { throw ParserException("Expected a single expression as filter condition"); } @@ -87,7 +87,7 @@ shared_ptr Relation::Filter(unique_ptr expression) { shared_ptr Relation::Filter(const vector &expressions) { // if there are multiple expressions, we AND them together - auto expression_list = StringListToExpressionList(*context.GetContext(), expressions); + auto expression_list = StringListToExpressionList(*context->GetContext(), expressions); D_ASSERT(!expression_list.empty()); auto expr = std::move(expression_list[0]); @@ -103,7 +103,7 @@ shared_ptr Relation::Limit(int64_t limit, int64_t offset) { } shared_ptr Relation::Order(const string &expression) { - auto order_list = Parser::ParseOrderList(expression, context.GetContext()->GetParserOptions()); + auto order_list = Parser::ParseOrderList(expression, context->GetContext()->GetParserOptions()); return Order(std::move(order_list)); } @@ -117,7 +117,7 @@ shared_ptr Relation::Order(const vector &expressions) { } vector order_list; for (auto &expression : expressions) { - auto inner_list = Parser::ParseOrderList(expression, context.GetContext()->GetParserOptions()); + auto inner_list = Parser::ParseOrderList(expression, context->GetContext()->GetParserOptions()); if (inner_list.size() != 1) { throw ParserException("Expected a single ORDER BY expression in the expression list"); } @@ -128,7 +128,7 @@ shared_ptr Relation::Order(const vector &expressions) { shared_ptr Relation::Join(const shared_ptr &other, const string &condition, JoinType type, JoinRefType ref_type) { - auto expression_list = Parser::ParseExpressionList(condition, context.GetContext()->GetParserOptions()); + auto expression_list = Parser::ParseExpressionList(condition, context->GetContext()->GetParserOptions()); D_ASSERT(!expression_list.empty()); return Join(other, std::move(expression_list), type, ref_type); } @@ -181,7 +181,7 @@ shared_ptr Relation::Alias(const string &alias) { } shared_ptr Relation::Aggregate(const string &aggregate_list) { - auto expression_list = Parser::ParseExpressionList(aggregate_list, context.GetContext()->GetParserOptions()); + auto expression_list = Parser::ParseExpressionList(aggregate_list, context->GetContext()->GetParserOptions()); return make_shared_ptr(shared_from_this(), std::move(expression_list)); } @@ -190,13 +190,13 @@ shared_ptr Relation::Aggregate(vector> ex } shared_ptr Relation::Aggregate(const string &aggregate_list, const string &group_list) { - auto expression_list = Parser::ParseExpressionList(aggregate_list, context.GetContext()->GetParserOptions()); - auto groups = Parser::ParseGroupByList(group_list, context.GetContext()->GetParserOptions()); + auto expression_list = Parser::ParseExpressionList(aggregate_list, context->GetContext()->GetParserOptions()); + auto groups = Parser::ParseGroupByList(group_list, context->GetContext()->GetParserOptions()); return make_shared_ptr(shared_from_this(), std::move(expression_list), std::move(groups)); } shared_ptr Relation::Aggregate(const vector &aggregates) { - auto aggregate_list = StringListToExpressionList(*context.GetContext(), aggregates); + auto aggregate_list = StringListToExpressionList(*context->GetContext(), aggregates); return make_shared_ptr(shared_from_this(), std::move(aggregate_list)); } @@ -207,7 +207,7 @@ shared_ptr Relation::Aggregate(const vector &aggregates, const } shared_ptr Relation::Aggregate(vector> expressions, const string &group_list) { - auto groups = Parser::ParseGroupByList(group_list, context.GetContext()->GetParserOptions()); + auto groups = Parser::ParseGroupByList(group_list, context->GetContext()->GetParserOptions()); return make_shared_ptr(shared_from_this(), std::move(expressions), std::move(groups)); } @@ -222,7 +222,7 @@ unique_ptr Relation::GetTableRef() { } unique_ptr Relation::Execute() { - return context.GetContext()->Execute(shared_from_this()); + return context->GetContext()->Execute(shared_from_this()); } unique_ptr Relation::ExecuteOrThrow() { @@ -259,7 +259,7 @@ void Relation::Insert(const string &schema_name, const string &table_name) { void Relation::Insert(const vector> &values) { vector column_names; - auto rel = make_shared_ptr(context.GetContext(), values, std::move(column_names), "values"); + auto rel = make_shared_ptr(context->GetContext(), values, std::move(column_names), "values"); rel->Insert(GetAlias()); } @@ -323,8 +323,8 @@ shared_ptr Relation::CreateView(const string &schema_name, const strin return shared_from_this(); } -unique_ptr Relation::Query(const string &sql) { - return context.GetContext()->Query(sql, false); +unique_ptr Relation::Query(const string &sql) const { + return context->GetContext()->Query(sql, false); } unique_ptr Relation::Query(const string &name, const string &sql) { @@ -339,6 +339,10 @@ unique_ptr Relation::Explain(ExplainType type, ExplainFormat format return explain->Execute(); } +void Relation::TryBindRelation(vector &columns) { + context->TryBindRelation(*this, columns); +} + void Relation::Update(const string &update, const string &condition) { throw InvalidInputException("UPDATE can only be used on base tables!"); } @@ -349,12 +353,12 @@ void Relation::Delete(const string &condition) { shared_ptr Relation::TableFunction(const std::string &fname, const vector &values, const named_parameter_map_t &named_parameters) { - return make_shared_ptr(context.GetContext(), fname, values, named_parameters, + return make_shared_ptr(context->GetContext(), fname, values, named_parameters, shared_from_this()); } shared_ptr Relation::TableFunction(const std::string &fname, const vector &values) { - return make_shared_ptr(context.GetContext(), fname, values, shared_from_this()); + return make_shared_ptr(context->GetContext(), fname, values, shared_from_this()); } string Relation::ToString() { diff --git a/src/duckdb/src/main/relation.cpp.orig b/src/duckdb/src/main/relation.cpp.orig new file mode 100644 index 000000000..bd382b9aa --- /dev/null +++ b/src/duckdb/src/main/relation.cpp.orig @@ -0,0 +1,414 @@ +#include "duckdb/main/relation.hpp" +#include "duckdb/common/printer.hpp" +#include "duckdb/parser/parser.hpp" +#include "duckdb/main/relation/aggregate_relation.hpp" +#include "duckdb/main/relation/cross_product_relation.hpp" +#include "duckdb/main/relation/distinct_relation.hpp" +#include "duckdb/main/relation/explain_relation.hpp" +#include "duckdb/main/relation/filter_relation.hpp" +#include "duckdb/main/relation/insert_relation.hpp" +#include "duckdb/main/relation/limit_relation.hpp" +#include "duckdb/main/relation/order_relation.hpp" +#include "duckdb/main/relation/projection_relation.hpp" +#include "duckdb/main/relation/setop_relation.hpp" +#include "duckdb/main/relation/subquery_relation.hpp" +#include "duckdb/main/relation/table_function_relation.hpp" +#include "duckdb/main/relation/create_table_relation.hpp" +#include "duckdb/main/relation/create_view_relation.hpp" +#include "duckdb/main/relation/write_csv_relation.hpp" +#include "duckdb/main/relation/write_parquet_relation.hpp" +#include "duckdb/main/client_context.hpp" +#include "duckdb/planner/binder.hpp" +#include "duckdb/parser/tableref/subqueryref.hpp" +#include "duckdb/parser/statement/select_statement.hpp" +#include "duckdb/parser/expression/conjunction_expression.hpp" +#include "duckdb/parser/expression/columnref_expression.hpp" +#include "duckdb/main/relation/join_relation.hpp" +#include "duckdb/main/relation/value_relation.hpp" +#include "duckdb/parser/statement/explain_statement.hpp" + +namespace duckdb { + +shared_ptr Relation::Project(const string &select_list) { + return Project(select_list, vector()); +} + +shared_ptr Relation::Project(const string &expression, const string &alias) { + return Project(expression, vector({alias})); +} + +shared_ptr Relation::Project(const string &select_list, const vector &aliases) { + auto expressions = Parser::ParseExpressionList(select_list, context->GetContext()->GetParserOptions()); + return make_shared_ptr(shared_from_this(), std::move(expressions), aliases); +} + +shared_ptr Relation::Project(const vector &expressions) { + vector aliases; + return Project(expressions, aliases); +} + +shared_ptr Relation::Project(vector> expressions, + const vector &aliases) { + return make_shared_ptr(shared_from_this(), std::move(expressions), aliases); +} + +static vector> StringListToExpressionList(const ClientContext &context, + const vector &expressions) { + if (expressions.empty()) { + throw ParserException("Zero expressions provided"); + } + vector> result_list; + for (auto &expr : expressions) { + auto expression_list = Parser::ParseExpressionList(expr, context.GetParserOptions()); + if (expression_list.size() != 1) { + throw ParserException("Expected a single expression in the expression list"); + } + result_list.push_back(std::move(expression_list[0])); + } + return result_list; +} + +shared_ptr Relation::Project(const vector &expressions, const vector &aliases) { + auto result_list = StringListToExpressionList(*context->GetContext(), expressions); + return make_shared_ptr(shared_from_this(), std::move(result_list), aliases); +} + +shared_ptr Relation::Filter(const string &expression) { + auto expression_list = Parser::ParseExpressionList(expression, context->GetContext()->GetParserOptions()); + if (expression_list.size() != 1) { + throw ParserException("Expected a single expression as filter condition"); + } + return Filter(std::move(expression_list[0])); +} + +shared_ptr Relation::Filter(unique_ptr expression) { + return make_shared_ptr(shared_from_this(), std::move(expression)); +} + +shared_ptr Relation::Filter(const vector &expressions) { + // if there are multiple expressions, we AND them together + auto expression_list = StringListToExpressionList(*context->GetContext(), expressions); + D_ASSERT(!expression_list.empty()); + + auto expr = std::move(expression_list[0]); + for (idx_t i = 1; i < expression_list.size(); i++) { + expr = make_uniq(ExpressionType::CONJUNCTION_AND, std::move(expr), + std::move(expression_list[i])); + } + return make_shared_ptr(shared_from_this(), std::move(expr)); +} + +shared_ptr Relation::Limit(int64_t limit, int64_t offset) { + return make_shared_ptr(shared_from_this(), limit, offset); +} + +shared_ptr Relation::Order(const string &expression) { + auto order_list = Parser::ParseOrderList(expression, context->GetContext()->GetParserOptions()); + return Order(std::move(order_list)); +} + +shared_ptr Relation::Order(vector order_list) { + return make_shared_ptr(shared_from_this(), std::move(order_list)); +} + +shared_ptr Relation::Order(const vector &expressions) { + if (expressions.empty()) { + throw ParserException("Zero ORDER BY expressions provided"); + } + vector order_list; + for (auto &expression : expressions) { + auto inner_list = Parser::ParseOrderList(expression, context->GetContext()->GetParserOptions()); + if (inner_list.size() != 1) { + throw ParserException("Expected a single ORDER BY expression in the expression list"); + } + order_list.push_back(std::move(inner_list[0])); + } + return Order(std::move(order_list)); +} + +shared_ptr Relation::Join(const shared_ptr &other, const string &condition, JoinType type, + JoinRefType ref_type) { + auto expression_list = Parser::ParseExpressionList(condition, context->GetContext()->GetParserOptions()); + D_ASSERT(!expression_list.empty()); + return Join(other, std::move(expression_list), type, ref_type); +} + +shared_ptr Relation::Join(const shared_ptr &other, + vector> expression_list, JoinType type, + JoinRefType ref_type) { + if (expression_list.size() > 1 || expression_list[0]->type == ExpressionType::COLUMN_REF) { + // multiple columns or single column ref: the condition is a USING list + vector using_columns; + for (auto &expr : expression_list) { + if (expr->type != ExpressionType::COLUMN_REF) { + throw ParserException("Expected a single expression as join condition"); + } + auto &colref = expr->Cast(); + if (colref.IsQualified()) { + throw ParserException("Expected unqualified column for column in USING clause"); + } + using_columns.push_back(colref.column_names[0]); + } + return make_shared_ptr(shared_from_this(), other, std::move(using_columns), type, ref_type); + } else { + // single expression that is not a column reference: use the expression as a join condition + return make_shared_ptr(shared_from_this(), other, std::move(expression_list[0]), type, ref_type); + } +} + +shared_ptr Relation::CrossProduct(const shared_ptr &other, JoinRefType join_ref_type) { + return make_shared_ptr(shared_from_this(), other, join_ref_type); +} + +shared_ptr Relation::Union(const shared_ptr &other) { + return make_shared_ptr(shared_from_this(), other, SetOperationType::UNION, true); +} + +shared_ptr Relation::Except(const shared_ptr &other) { + return make_shared_ptr(shared_from_this(), other, SetOperationType::EXCEPT, true); +} + +shared_ptr Relation::Intersect(const shared_ptr &other) { + return make_shared_ptr(shared_from_this(), other, SetOperationType::INTERSECT, true); +} + +shared_ptr Relation::Distinct() { + return make_shared_ptr(shared_from_this()); +} + +shared_ptr Relation::Alias(const string &alias) { + return make_shared_ptr(shared_from_this(), alias); +} + +shared_ptr Relation::Aggregate(const string &aggregate_list) { + auto expression_list = Parser::ParseExpressionList(aggregate_list, context->GetContext()->GetParserOptions()); + return make_shared_ptr(shared_from_this(), std::move(expression_list)); +} + +shared_ptr Relation::Aggregate(vector> expressions) { + return make_shared_ptr(shared_from_this(), std::move(expressions)); +} + +shared_ptr Relation::Aggregate(const string &aggregate_list, const string &group_list) { + auto expression_list = Parser::ParseExpressionList(aggregate_list, context->GetContext()->GetParserOptions()); + auto groups = Parser::ParseGroupByList(group_list, context->GetContext()->GetParserOptions()); + return make_shared_ptr(shared_from_this(), std::move(expression_list), std::move(groups)); +} + +shared_ptr Relation::Aggregate(const vector &aggregates) { + auto aggregate_list = StringListToExpressionList(*context->GetContext(), aggregates); + return make_shared_ptr(shared_from_this(), std::move(aggregate_list)); +} + +shared_ptr Relation::Aggregate(const vector &aggregates, const vector &groups) { + auto aggregate_list = StringUtil::Join(aggregates, ", "); + auto group_list = StringUtil::Join(groups, ", "); + return this->Aggregate(aggregate_list, group_list); +} + +shared_ptr Relation::Aggregate(vector> expressions, const string &group_list) { + auto groups = Parser::ParseGroupByList(group_list, context->GetContext()->GetParserOptions()); + return make_shared_ptr(shared_from_this(), std::move(expressions), std::move(groups)); +} + +string Relation::GetAlias() { + return "relation"; +} + +unique_ptr Relation::GetTableRef() { + auto select = make_uniq(); + select->node = GetQueryNode(); + return make_uniq(std::move(select), GetAlias()); +} + +unique_ptr Relation::Execute() { + return context->GetContext()->Execute(shared_from_this()); +} + +unique_ptr Relation::ExecuteOrThrow() { + auto res = Execute(); + D_ASSERT(res); + if (res->HasError()) { + res->ThrowError(); + } + return res; +} + +BoundStatement Relation::Bind(Binder &binder) { + SelectStatement stmt; + stmt.node = GetQueryNode(); + return binder.Bind(stmt.Cast()); +} + +shared_ptr Relation::InsertRel(const string &schema_name, const string &table_name) { + return make_shared_ptr(shared_from_this(), schema_name, table_name); +} + +void Relation::Insert(const string &table_name) { + Insert(INVALID_SCHEMA, table_name); +} + +void Relation::Insert(const string &schema_name, const string &table_name) { + auto insert = InsertRel(schema_name, table_name); + auto res = insert->Execute(); + if (res->HasError()) { + const string prepended_message = "Failed to insert into table '" + table_name + "': "; + res->ThrowError(prepended_message); + } +} + +void Relation::Insert(const vector> &values) { + vector column_names; + auto rel = make_shared_ptr(context->GetContext(), values, std::move(column_names), "values"); + rel->Insert(GetAlias()); +} + +shared_ptr Relation::CreateRel(const string &schema_name, const string &table_name, bool temporary) { + return make_shared_ptr(shared_from_this(), schema_name, table_name, temporary); +} + +void Relation::Create(const string &table_name, bool temporary) { + Create(INVALID_SCHEMA, table_name, temporary); +} + +void Relation::Create(const string &schema_name, const string &table_name, bool temporary) { + auto create = CreateRel(schema_name, table_name, temporary); + auto res = create->Execute(); + if (res->HasError()) { + const string prepended_message = "Failed to create table '" + table_name + "': "; + res->ThrowError(prepended_message); + } +} + +shared_ptr Relation::WriteCSVRel(const string &csv_file, case_insensitive_map_t> options) { + return make_shared_ptr(shared_from_this(), csv_file, std::move(options)); +} + +void Relation::WriteCSV(const string &csv_file, case_insensitive_map_t> options) { + auto write_csv = WriteCSVRel(csv_file, std::move(options)); + auto res = write_csv->Execute(); + if (res->HasError()) { + const string prepended_message = "Failed to write '" + csv_file + "': "; + res->ThrowError(prepended_message); + } +} + +shared_ptr Relation::WriteParquetRel(const string &parquet_file, + case_insensitive_map_t> options) { + auto write_parquet = + make_shared_ptr(shared_from_this(), parquet_file, std::move(options)); + return std::move(write_parquet); +} + +void Relation::WriteParquet(const string &parquet_file, case_insensitive_map_t> options) { + auto write_parquet = WriteParquetRel(parquet_file, std::move(options)); + auto res = write_parquet->Execute(); + if (res->HasError()) { + const string prepended_message = "Failed to write '" + parquet_file + "': "; + res->ThrowError(prepended_message); + } +} + +shared_ptr Relation::CreateView(const string &name, bool replace, bool temporary) { + return CreateView(INVALID_SCHEMA, name, replace, temporary); +} + +shared_ptr Relation::CreateView(const string &schema_name, const string &name, bool replace, bool temporary) { + auto view = make_shared_ptr(shared_from_this(), schema_name, name, replace, temporary); + auto res = view->Execute(); + if (res->HasError()) { + const string prepended_message = "Failed to create view '" + name + "': "; + res->ThrowError(prepended_message); + } + return shared_from_this(); +} + +unique_ptr Relation::Query(const string &sql) const { + return context->GetContext()->Query(sql, false); +} + +unique_ptr Relation::Query(const string &name, const string &sql) { + CreateView(name); + return Query(sql); +} + +unique_ptr Relation::Explain(ExplainType type, ExplainFormat format) { + auto explain = make_shared_ptr(shared_from_this(), type, format); + return explain->Execute(); +} + +void Relation::TryBindRelation(vector &columns) { + context->TryBindRelation(*this, columns); +} + +void Relation::Update(const string &update, const string &condition) { + throw InvalidInputException("UPDATE can only be used on base tables!"); +} + +void Relation::Delete(const string &condition) { + throw InvalidInputException("DELETE can only be used on base tables!"); +} + +shared_ptr Relation::TableFunction(const std::string &fname, const vector &values, + const named_parameter_map_t &named_parameters) { + return make_shared_ptr(context->GetContext(), fname, values, named_parameters, + shared_from_this()); +} + +shared_ptr Relation::TableFunction(const std::string &fname, const vector &values) { + return make_shared_ptr(context->GetContext(), fname, values, shared_from_this()); +} + +string Relation::ToString() { + string str; + str += "---------------------\n"; + str += "--- Relation Tree ---\n"; + str += "---------------------\n"; + str += ToString(0); + str += "\n\n"; + str += "---------------------\n"; + str += "-- Result Columns --\n"; + str += "---------------------\n"; + auto &cols = Columns(); + for (idx_t i = 0; i < cols.size(); i++) { + str += "- " + cols[i].Name() + " (" + cols[i].Type().ToString() + ")\n"; + } + return str; +} + +// LCOV_EXCL_START +unique_ptr Relation::GetQueryNode() { + throw InternalException("Cannot create a query node from this node type"); +} + +void Relation::Head(idx_t limit) { + auto limit_node = Limit(NumericCast(limit)); + limit_node->Execute()->Print(); +} +// LCOV_EXCL_STOP + +void Relation::Print() { + Printer::Print(ToString()); +} + +string Relation::RenderWhitespace(idx_t depth) { + return string(depth * 2, ' '); +} + +void Relation::AddExternalDependency(shared_ptr dependency) { + external_dependencies.push_back(std::move(dependency)); +} + +vector> Relation::GetAllDependencies() { + vector> all_dependencies; + Relation *cur = this; + while (cur) { + for (auto &dep : cur->external_dependencies) { + all_dependencies.push_back(dep); + } + cur = cur->ChildRelation(); + } + return all_dependencies; +} + +} // namespace duckdb diff --git a/src/duckdb/src/main/relation/aggregate_relation.cpp b/src/duckdb/src/main/relation/aggregate_relation.cpp index c84036ad4..daf663e3b 100644 --- a/src/duckdb/src/main/relation/aggregate_relation.cpp +++ b/src/duckdb/src/main/relation/aggregate_relation.cpp @@ -10,7 +10,7 @@ AggregateRelation::AggregateRelation(shared_ptr child_p, : Relation(child_p->context, RelationType::AGGREGATE_RELATION), expressions(std::move(parsed_expressions)), child(std::move(child_p)) { // bind the expressions - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } AggregateRelation::AggregateRelation(shared_ptr child_p, @@ -18,7 +18,7 @@ AggregateRelation::AggregateRelation(shared_ptr child_p, : Relation(child_p->context, RelationType::AGGREGATE_RELATION), expressions(std::move(parsed_expressions)), groups(std::move(groups_p)), child(std::move(child_p)) { // bind the expressions - context.GetContext()->TryBindRelation(*this, this->columns); + Relation::TryBindRelation(columns); } AggregateRelation::AggregateRelation(shared_ptr child_p, @@ -36,7 +36,7 @@ AggregateRelation::AggregateRelation(shared_ptr child_p, groups.grouping_sets.push_back(std::move(grouping_set)); } // bind the expressions - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } unique_ptr AggregateRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/create_table_relation.cpp b/src/duckdb/src/main/relation/create_table_relation.cpp index bff69e3aa..7ff390e00 100644 --- a/src/duckdb/src/main/relation/create_table_relation.cpp +++ b/src/duckdb/src/main/relation/create_table_relation.cpp @@ -10,7 +10,7 @@ CreateTableRelation::CreateTableRelation(shared_ptr child_p, string sc bool temporary_p) : Relation(child_p->context, RelationType::CREATE_TABLE_RELATION), child(std::move(child_p)), schema_name(std::move(schema_name)), table_name(std::move(table_name)), temporary(temporary_p) { - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } BoundStatement CreateTableRelation::Bind(Binder &binder) { diff --git a/src/duckdb/src/main/relation/create_view_relation.cpp b/src/duckdb/src/main/relation/create_view_relation.cpp index b9c80c074..c00deef38 100644 --- a/src/duckdb/src/main/relation/create_view_relation.cpp +++ b/src/duckdb/src/main/relation/create_view_relation.cpp @@ -9,7 +9,7 @@ CreateViewRelation::CreateViewRelation(shared_ptr child_p, string view bool temporary_p) : Relation(child_p->context, RelationType::CREATE_VIEW_RELATION), child(std::move(child_p)), view_name(std::move(view_name_p)), replace(replace_p), temporary(temporary_p) { - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } CreateViewRelation::CreateViewRelation(shared_ptr child_p, string schema_name_p, string view_name_p, @@ -17,7 +17,7 @@ CreateViewRelation::CreateViewRelation(shared_ptr child_p, string sche : Relation(child_p->context, RelationType::CREATE_VIEW_RELATION), child(std::move(child_p)), schema_name(std::move(schema_name_p)), view_name(std::move(view_name_p)), replace(replace_p), temporary(temporary_p) { - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } BoundStatement CreateViewRelation::Bind(Binder &binder) { diff --git a/src/duckdb/src/main/relation/cross_product_relation.cpp b/src/duckdb/src/main/relation/cross_product_relation.cpp index ca3abfbed..e0645fae1 100644 --- a/src/duckdb/src/main/relation/cross_product_relation.cpp +++ b/src/duckdb/src/main/relation/cross_product_relation.cpp @@ -10,10 +10,10 @@ CrossProductRelation::CrossProductRelation(shared_ptr left_p, shared_p JoinRefType ref_type) : Relation(left_p->context, RelationType::CROSS_PRODUCT_RELATION), left(std::move(left_p)), right(std::move(right_p)), ref_type(ref_type) { - if (left->context.GetContext() != right->context.GetContext()) { + if (left->context->GetContext() != right->context->GetContext()) { throw InvalidInputException("Cannot combine LEFT and RIGHT relations of different connections!"); } - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } unique_ptr CrossProductRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/delete_relation.cpp b/src/duckdb/src/main/relation/delete_relation.cpp index 8afc8226e..bbc0d58ef 100644 --- a/src/duckdb/src/main/relation/delete_relation.cpp +++ b/src/duckdb/src/main/relation/delete_relation.cpp @@ -6,11 +6,11 @@ namespace duckdb { -DeleteRelation::DeleteRelation(ClientContextWrapper &context, unique_ptr condition_p, +DeleteRelation::DeleteRelation(shared_ptr &context, unique_ptr condition_p, string schema_name_p, string table_name_p) : Relation(context, RelationType::DELETE_RELATION), condition(std::move(condition_p)), schema_name(std::move(schema_name_p)), table_name(std::move(table_name_p)) { - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } BoundStatement DeleteRelation::Bind(Binder &binder) { diff --git a/src/duckdb/src/main/relation/delim_get_relation.cpp b/src/duckdb/src/main/relation/delim_get_relation.cpp index 6613c60d8..3f1b9cbc8 100644 --- a/src/duckdb/src/main/relation/delim_get_relation.cpp +++ b/src/duckdb/src/main/relation/delim_get_relation.cpp @@ -8,7 +8,7 @@ namespace duckdb { DelimGetRelation::DelimGetRelation(const shared_ptr &context, vector chunk_types_p) : Relation(context, RelationType::DELIM_GET_RELATION), chunk_types(std::move(chunk_types_p)) { - context->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } unique_ptr DelimGetRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/distinct_relation.cpp b/src/duckdb/src/main/relation/distinct_relation.cpp index 0f96d4580..16bb53822 100644 --- a/src/duckdb/src/main/relation/distinct_relation.cpp +++ b/src/duckdb/src/main/relation/distinct_relation.cpp @@ -8,7 +8,7 @@ DistinctRelation::DistinctRelation(shared_ptr child_p) : Relation(child_p->context, RelationType::DISTINCT_RELATION), child(std::move(child_p)) { D_ASSERT(child.get() != this); vector dummy_columns; - context.GetContext()->TryBindRelation(*this, dummy_columns); + TryBindRelation(dummy_columns); } unique_ptr DistinctRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/explain_relation.cpp b/src/duckdb/src/main/relation/explain_relation.cpp index 9b8ed1edb..f91e1d29f 100644 --- a/src/duckdb/src/main/relation/explain_relation.cpp +++ b/src/duckdb/src/main/relation/explain_relation.cpp @@ -10,7 +10,7 @@ namespace duckdb { ExplainRelation::ExplainRelation(shared_ptr child_p, ExplainType type, ExplainFormat format) : Relation(child_p->context, RelationType::EXPLAIN_RELATION), child(std::move(child_p)), type(type), format(format) { - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } BoundStatement ExplainRelation::Bind(Binder &binder) { diff --git a/src/duckdb/src/main/relation/filter_relation.cpp b/src/duckdb/src/main/relation/filter_relation.cpp index 2abaa41aa..738e83577 100644 --- a/src/duckdb/src/main/relation/filter_relation.cpp +++ b/src/duckdb/src/main/relation/filter_relation.cpp @@ -12,7 +12,7 @@ FilterRelation::FilterRelation(shared_ptr child_p, unique_ptr dummy_columns; - context.GetContext()->TryBindRelation(*this, dummy_columns); + TryBindRelation(dummy_columns); } unique_ptr FilterRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/insert_relation.cpp b/src/duckdb/src/main/relation/insert_relation.cpp index c6738d486..9728570a0 100644 --- a/src/duckdb/src/main/relation/insert_relation.cpp +++ b/src/duckdb/src/main/relation/insert_relation.cpp @@ -10,7 +10,7 @@ namespace duckdb { InsertRelation::InsertRelation(shared_ptr child_p, string schema_name, string table_name) : Relation(child_p->context, RelationType::INSERT_RELATION), child(std::move(child_p)), schema_name(std::move(schema_name)), table_name(std::move(table_name)) { - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } BoundStatement InsertRelation::Bind(Binder &binder) { diff --git a/src/duckdb/src/main/relation/join_relation.cpp b/src/duckdb/src/main/relation/join_relation.cpp index 3d9572f76..fa83316e6 100644 --- a/src/duckdb/src/main/relation/join_relation.cpp +++ b/src/duckdb/src/main/relation/join_relation.cpp @@ -4,6 +4,7 @@ #include "duckdb/parser/expression/star_expression.hpp" #include "duckdb/parser/tableref/joinref.hpp" #include "duckdb/common/enum_util.hpp" +#include "duckdb/main/client_context_wrapper.hpp" namespace duckdb { @@ -11,20 +12,20 @@ JoinRelation::JoinRelation(shared_ptr left_p, shared_ptr rig unique_ptr condition_p, JoinType type, JoinRefType join_ref_type) : Relation(left_p->context, RelationType::JOIN_RELATION), left(std::move(left_p)), right(std::move(right_p)), condition(std::move(condition_p)), join_type(type), join_ref_type(join_ref_type) { - if (left->context.GetContext() != right->context.GetContext()) { + if (left->context->GetContext() != right->context->GetContext()) { throw InvalidInputException("Cannot combine LEFT and RIGHT relations of different connections!"); } - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } JoinRelation::JoinRelation(shared_ptr left_p, shared_ptr right_p, vector using_columns_p, JoinType type, JoinRefType join_ref_type) : Relation(left_p->context, RelationType::JOIN_RELATION), left(std::move(left_p)), right(std::move(right_p)), using_columns(std::move(using_columns_p)), join_type(type), join_ref_type(join_ref_type) { - if (left->context.GetContext() != right->context.GetContext()) { + if (left->context->GetContext() != right->context->GetContext()) { throw InvalidInputException("Cannot combine LEFT and RIGHT relations of different connections!"); } - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } unique_ptr JoinRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/order_relation.cpp b/src/duckdb/src/main/relation/order_relation.cpp index 7a9c16dc5..ac97d1c52 100644 --- a/src/duckdb/src/main/relation/order_relation.cpp +++ b/src/duckdb/src/main/relation/order_relation.cpp @@ -10,7 +10,7 @@ OrderRelation::OrderRelation(shared_ptr child_p, vector o : Relation(child_p->context, RelationType::ORDER_RELATION), orders(std::move(orders)), child(std::move(child_p)) { D_ASSERT(child.get() != this); // bind the expressions - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } unique_ptr OrderRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/projection_relation.cpp b/src/duckdb/src/main/relation/projection_relation.cpp index eb1f57fd3..651bbd997 100644 --- a/src/duckdb/src/main/relation/projection_relation.cpp +++ b/src/duckdb/src/main/relation/projection_relation.cpp @@ -18,7 +18,7 @@ ProjectionRelation::ProjectionRelation(shared_ptr child_p, } } // bind the expressions - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } unique_ptr ProjectionRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/query_relation.cpp b/src/duckdb/src/main/relation/query_relation.cpp index bc0b51502..bc0bfd4e5 100644 --- a/src/duckdb/src/main/relation/query_relation.cpp +++ b/src/duckdb/src/main/relation/query_relation.cpp @@ -20,7 +20,7 @@ QueryRelation::QueryRelation(const shared_ptr &context, unique_pt if (query.empty()) { query = select_stmt->ToString(); } - context->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } QueryRelation::~QueryRelation() { diff --git a/src/duckdb/src/main/relation/setop_relation.cpp b/src/duckdb/src/main/relation/setop_relation.cpp index 4023099c6..a0253df37 100644 --- a/src/duckdb/src/main/relation/setop_relation.cpp +++ b/src/duckdb/src/main/relation/setop_relation.cpp @@ -9,10 +9,10 @@ SetOpRelation::SetOpRelation(shared_ptr left_p, shared_ptr r bool setop_all) : Relation(left_p->context, RelationType::SET_OPERATION_RELATION), left(std::move(left_p)), right(std::move(right_p)), setop_type(setop_type_p), setop_all(setop_all) { - if (left->context.GetContext() != right->context.GetContext()) { + if (left->context->GetContext() != right->context->GetContext()) { throw InvalidInputException("Cannot combine LEFT and RIGHT relations of different connections!"); } - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } unique_ptr SetOpRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/subquery_relation.cpp b/src/duckdb/src/main/relation/subquery_relation.cpp index 5ee1e0329..c541054b2 100644 --- a/src/duckdb/src/main/relation/subquery_relation.cpp +++ b/src/duckdb/src/main/relation/subquery_relation.cpp @@ -9,7 +9,7 @@ SubqueryRelation::SubqueryRelation(shared_ptr child_p, string alias_p) alias(std::move(alias_p)) { D_ASSERT(child.get() != this); vector dummy_columns; - context.GetContext()->TryBindRelation(*this, dummy_columns); + Relation::TryBindRelation(dummy_columns); } unique_ptr SubqueryRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/table_function_relation.cpp b/src/duckdb/src/main/relation/table_function_relation.cpp index 7d0b2d9b1..5111752e2 100644 --- a/src/duckdb/src/main/relation/table_function_relation.cpp +++ b/src/duckdb/src/main/relation/table_function_relation.cpp @@ -37,6 +37,15 @@ TableFunctionRelation::TableFunctionRelation(const shared_ptr &co InitializeColumns(); } +TableFunctionRelation::TableFunctionRelation(const shared_ptr &context, string name_p, + vector parameters_p, named_parameter_map_t named_parameters, + shared_ptr input_relation_p, bool auto_init) + : Relation(context, RelationType::TABLE_FUNCTION_RELATION), name(std::move(name_p)), + parameters(std::move(parameters_p)), named_parameters(std::move(named_parameters)), + input_relation(std::move(input_relation_p)), auto_initialize(auto_init) { + InitializeColumns(); +} + TableFunctionRelation::TableFunctionRelation(const shared_ptr &context, string name_p, vector parameters_p, shared_ptr input_relation_p, bool auto_init) @@ -49,7 +58,7 @@ void TableFunctionRelation::InitializeColumns() { if (!auto_initialize) { return; } - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } unique_ptr TableFunctionRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/table_relation.cpp b/src/duckdb/src/main/relation/table_relation.cpp index 4a0ff6e0e..f5211238a 100644 --- a/src/duckdb/src/main/relation/table_relation.cpp +++ b/src/duckdb/src/main/relation/table_relation.cpp @@ -13,6 +13,11 @@ TableRelation::TableRelation(const shared_ptr &context, unique_pt : Relation(context, RelationType::TABLE_RELATION), description(std::move(description)) { } +TableRelation::TableRelation(const shared_ptr &context, + unique_ptr description) + : Relation(context, RelationType::TABLE_RELATION), description(std::move(description)) { +} + unique_ptr TableRelation::GetQueryNode() { auto result = make_uniq(); result->select_list.push_back(make_uniq()); @@ -54,15 +59,15 @@ static unique_ptr ParseCondition(ClientContext &context, const void TableRelation::Update(const string &update_list, const string &condition) { vector update_columns; vector> expressions; - auto cond = ParseCondition(*context.GetContext(), condition); - Parser::ParseUpdateList(update_list, update_columns, expressions, context.GetContext()->GetParserOptions()); + auto cond = ParseCondition(*context->GetContext(), condition); + Parser::ParseUpdateList(update_list, update_columns, expressions, context->GetContext()->GetParserOptions()); auto update = make_shared_ptr(context, std::move(cond), description->schema, description->table, std::move(update_columns), std::move(expressions)); update->Execute(); } void TableRelation::Delete(const string &condition) { - auto cond = ParseCondition(*context.GetContext(), condition); + auto cond = ParseCondition(*context->GetContext(), condition); auto del = make_shared_ptr(context, std::move(cond), description->schema, description->table); del->Execute(); } diff --git a/src/duckdb/src/main/relation/update_relation.cpp b/src/duckdb/src/main/relation/update_relation.cpp index 152d04af3..6dd34dfc5 100644 --- a/src/duckdb/src/main/relation/update_relation.cpp +++ b/src/duckdb/src/main/relation/update_relation.cpp @@ -6,14 +6,14 @@ namespace duckdb { -UpdateRelation::UpdateRelation(ClientContextWrapper &context, unique_ptr condition_p, +UpdateRelation::UpdateRelation(shared_ptr &context, unique_ptr condition_p, string schema_name_p, string table_name_p, vector update_columns_p, vector> expressions_p) : Relation(context, RelationType::UPDATE_RELATION), condition(std::move(condition_p)), schema_name(std::move(schema_name_p)), table_name(std::move(table_name_p)), update_columns(std::move(update_columns_p)), expressions(std::move(expressions_p)) { D_ASSERT(update_columns.size() == expressions.size()); - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } BoundStatement UpdateRelation::Bind(Binder &binder) { diff --git a/src/duckdb/src/main/relation/value_relation.cpp b/src/duckdb/src/main/relation/value_relation.cpp index 3e11ed6bb..6556eaff1 100644 --- a/src/duckdb/src/main/relation/value_relation.cpp +++ b/src/duckdb/src/main/relation/value_relation.cpp @@ -21,7 +21,7 @@ ValueRelation::ValueRelation(const shared_ptr &context, const vec this->expressions.push_back(std::move(expressions)); } QueryResult::DeduplicateColumns(names); - context->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } ValueRelation::ValueRelation(const shared_ptr &context, const string &values_list, @@ -29,7 +29,23 @@ ValueRelation::ValueRelation(const shared_ptr &context, const str : Relation(context, RelationType::VALUE_LIST_RELATION), names(std::move(names_p)), alias(std::move(alias_p)) { this->expressions = Parser::ParseValuesList(values_list, context->GetParserOptions()); QueryResult::DeduplicateColumns(names); - context->TryBindRelation(*this, this->columns); + TryBindRelation(columns); +} + +ValueRelation::ValueRelation(const shared_ptr &context, const vector> &values, + vector names_p, string alias_p) + : Relation(context, RelationType::VALUE_LIST_RELATION), names(std::move(names_p)), alias(std::move(alias_p)) { + // create constant expressions for the values + for (idx_t row_idx = 0; row_idx < values.size(); row_idx++) { + auto &list = values[row_idx]; + vector> expressions; + for (idx_t col_idx = 0; col_idx < list.size(); col_idx++) { + expressions.push_back(make_uniq(list[col_idx])); + } + this->expressions.push_back(std::move(expressions)); + } + QueryResult::DeduplicateColumns(names); + TryBindRelation(columns); } unique_ptr ValueRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/view_relation.cpp b/src/duckdb/src/main/relation/view_relation.cpp index 7b6b73c56..16c1bdc37 100644 --- a/src/duckdb/src/main/relation/view_relation.cpp +++ b/src/duckdb/src/main/relation/view_relation.cpp @@ -10,12 +10,18 @@ namespace duckdb { ViewRelation::ViewRelation(const shared_ptr &context, string schema_name_p, string view_name_p) : Relation(context, RelationType::VIEW_RELATION), schema_name(std::move(schema_name_p)), view_name(std::move(view_name_p)) { - context->TryBindRelation(*this, this->columns); + TryBindRelation(columns); +} + +ViewRelation::ViewRelation(const shared_ptr &context, string schema_name_p, string view_name_p) + : Relation(context, RelationType::VIEW_RELATION), schema_name(std::move(schema_name_p)), + view_name(std::move(view_name_p)) { + TryBindRelation(columns); } ViewRelation::ViewRelation(const shared_ptr &context, unique_ptr ref, const string &view_name) : Relation(context, RelationType::VIEW_RELATION), view_name(view_name), premade_tableref(std::move(ref)) { - context->TryBindRelation(*this, this->columns); + TryBindRelation(columns); premade_tableref->alias = view_name; } diff --git a/src/duckdb/src/main/relation/write_csv_relation.cpp b/src/duckdb/src/main/relation/write_csv_relation.cpp index a521f8cae..4795c7a51 100644 --- a/src/duckdb/src/main/relation/write_csv_relation.cpp +++ b/src/duckdb/src/main/relation/write_csv_relation.cpp @@ -10,7 +10,7 @@ WriteCSVRelation::WriteCSVRelation(shared_ptr child_p, string csv_file case_insensitive_map_t> options_p) : Relation(child_p->context, RelationType::WRITE_CSV_RELATION), child(std::move(child_p)), csv_file(std::move(csv_file_p)), options(std::move(options_p)) { - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } BoundStatement WriteCSVRelation::Bind(Binder &binder) { diff --git a/src/duckdb/src/main/relation/write_parquet_relation.cpp b/src/duckdb/src/main/relation/write_parquet_relation.cpp index c2d937a2f..d6e403618 100644 --- a/src/duckdb/src/main/relation/write_parquet_relation.cpp +++ b/src/duckdb/src/main/relation/write_parquet_relation.cpp @@ -10,7 +10,7 @@ WriteParquetRelation::WriteParquetRelation(shared_ptr child_p, string case_insensitive_map_t> options_p) : Relation(child_p->context, RelationType::WRITE_PARQUET_RELATION), child(std::move(child_p)), parquet_file(std::move(parquet_file_p)), options(std::move(options_p)) { - context.GetContext()->TryBindRelation(*this, this->columns); + TryBindRelation(columns); } BoundStatement WriteParquetRelation::Bind(Binder &binder) { diff --git a/src/duckdb/src/main/settings/autogenerated_settings.cpp b/src/duckdb/src/main/settings/autogenerated_settings.cpp new file mode 100644 index 000000000..1fac3ffe4 --- /dev/null +++ b/src/duckdb/src/main/settings/autogenerated_settings.cpp @@ -0,0 +1,1068 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// This code is autogenerated from 'update_settings_definitions.py'. +// Please do not make any changes directly here, as they will be overwritten. +// If you need to implement a custom function for a new setting, enable the +// 'custom_implementation' in 'settings.json' for this setting. +// +//===----------------------------------------------------------------------===// + +#include "duckdb/main/settings.hpp" +#include "duckdb/common/enum_util.hpp" +#include "duckdb/main/client_context.hpp" +#include "duckdb/main/config.hpp" + +namespace duckdb { + +//===----------------------------------------------------------------------===// +// Access Mode +//===----------------------------------------------------------------------===// +void AccessModeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + if (!OnGlobalSet(db, config, input)) { + return; + } + auto str_input = StringUtil::Upper(input.GetValue()); + config.options.access_mode = EnumUtil::FromString(str_input); +} + +void AccessModeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.access_mode = DBConfig().options.access_mode; +} + +Value AccessModeSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(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 = DBConfig().options.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 = DBConfig().options.allow_community_extensions; +} + +Value AllowCommunityExtensionsSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.allow_community_extensions); +} + +//===----------------------------------------------------------------------===// +// Allow Extensions Metadata Mismatch +//===----------------------------------------------------------------------===// +void AllowExtensionsMetadataMismatchSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.allow_extensions_metadata_mismatch = input.GetValue(); +} + +void AllowExtensionsMetadataMismatchSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.allow_extensions_metadata_mismatch = DBConfig().options.allow_extensions_metadata_mismatch; +} + +Value AllowExtensionsMetadataMismatchSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.allow_extensions_metadata_mismatch); +} + +//===----------------------------------------------------------------------===// +// 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 = DBConfig().options.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 = DBConfig().options.allow_unsigned_extensions; +} + +Value AllowUnsignedExtensionsSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.allow_unsigned_extensions); +} + +//===----------------------------------------------------------------------===// +// Arrow Large Buffer Size +//===----------------------------------------------------------------------===// +void ArrowLargeBufferSizeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.arrow_offset_size = DBConfig().options.arrow_offset_size; +} + +//===----------------------------------------------------------------------===// +// Arrow Lossless Conversion +//===----------------------------------------------------------------------===// +void ArrowLosslessConversionSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.arrow_lossless_conversion = input.GetValue(); +} + +void ArrowLosslessConversionSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.arrow_lossless_conversion = DBConfig().options.arrow_lossless_conversion; +} + +Value ArrowLosslessConversionSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.arrow_lossless_conversion); +} + +//===----------------------------------------------------------------------===// +// Arrow Output List View +//===----------------------------------------------------------------------===// +void ArrowOutputListViewSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.arrow_use_list_view = input.GetValue(); +} + +void ArrowOutputListViewSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.arrow_use_list_view = DBConfig().options.arrow_use_list_view; +} + +Value ArrowOutputListViewSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.arrow_use_list_view); +} + +//===----------------------------------------------------------------------===// +// 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 = DBConfig().options.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 = DBConfig().options.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 = DBConfig().options.autoload_known_extensions; +} + +Value AutoloadKnownExtensionsSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.autoload_known_extensions); +} + +//===----------------------------------------------------------------------===// +// Catalog Error Max Schemas +//===----------------------------------------------------------------------===// +void CatalogErrorMaxSchemasSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.catalog_error_max_schemas = input.GetValue(); +} + +void CatalogErrorMaxSchemasSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.catalog_error_max_schemas = DBConfig().options.catalog_error_max_schemas; +} + +Value CatalogErrorMaxSchemasSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::UBIGINT(config.options.catalog_error_max_schemas); +} + +//===----------------------------------------------------------------------===// +// Checkpoint Threshold +//===----------------------------------------------------------------------===// +void CheckpointThresholdSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.checkpoint_wal_size = DBConfig().options.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 = DBConfig().options.custom_extension_repo; +} + +Value CustomExtensionRepositorySetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(config.options.custom_extension_repo); +} + +//===----------------------------------------------------------------------===// +// Custom User Agent +//===----------------------------------------------------------------------===// +Value CustomUserAgentSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(config.options.custom_user_agent); +} + +//===----------------------------------------------------------------------===// +// Debug Asof Iejoin +//===----------------------------------------------------------------------===// +void DebugAsofIejoinSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.force_asof_iejoin = input.GetValue(); +} + +void DebugAsofIejoinSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).force_asof_iejoin = ClientConfig().force_asof_iejoin; +} + +Value DebugAsofIejoinSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::BOOLEAN(config.force_asof_iejoin); +} + +//===----------------------------------------------------------------------===// +// Debug Checkpoint Abort +//===----------------------------------------------------------------------===// +void DebugCheckpointAbortSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto str_input = StringUtil::Upper(input.GetValue()); + config.options.checkpoint_abort = EnumUtil::FromString(str_input); +} + +void DebugCheckpointAbortSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.checkpoint_abort = DBConfig().options.checkpoint_abort; +} + +Value DebugCheckpointAbortSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(StringUtil::Lower(EnumUtil::ToString(config.options.checkpoint_abort))); +} + +//===----------------------------------------------------------------------===// +// Debug Force External +//===----------------------------------------------------------------------===// +void DebugForceExternalSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.force_external = input.GetValue(); +} + +void DebugForceExternalSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).force_external = ClientConfig().force_external; +} + +Value DebugForceExternalSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::BOOLEAN(config.force_external); +} + +//===----------------------------------------------------------------------===// +// Debug Force No Cross Product +//===----------------------------------------------------------------------===// +void DebugForceNoCrossProductSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.force_no_cross_product = input.GetValue(); +} + +void DebugForceNoCrossProductSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).force_no_cross_product = ClientConfig().force_no_cross_product; +} + +Value DebugForceNoCrossProductSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::BOOLEAN(config.force_no_cross_product); +} + +//===----------------------------------------------------------------------===// +// Debug Skip Checkpoint On Commit +//===----------------------------------------------------------------------===// +void DebugSkipCheckpointOnCommitSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.debug_skip_checkpoint_on_commit = input.GetValue(); +} + +void DebugSkipCheckpointOnCommitSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.debug_skip_checkpoint_on_commit = DBConfig().options.debug_skip_checkpoint_on_commit; +} + +Value DebugSkipCheckpointOnCommitSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.debug_skip_checkpoint_on_commit); +} + +//===----------------------------------------------------------------------===// +// Debug Window Mode +//===----------------------------------------------------------------------===// +void DebugWindowModeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto str_input = StringUtil::Upper(input.GetValue()); + config.options.window_mode = EnumUtil::FromString(str_input); +} + +void DebugWindowModeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.window_mode = DBConfig().options.window_mode; +} + +Value DebugWindowModeSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(StringUtil::Lower(EnumUtil::ToString(config.options.window_mode))); +} + +//===----------------------------------------------------------------------===// +// Default Null Order +//===----------------------------------------------------------------------===// +void DefaultNullOrderSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.default_null_order = DBConfig().options.default_null_order; +} + +Value DefaultNullOrderSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(StringUtil::Lower(EnumUtil::ToString(config.options.default_null_order))); +} + +//===----------------------------------------------------------------------===// +// Default Order +//===----------------------------------------------------------------------===// +void DefaultOrderSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.default_order_type = DBConfig().options.default_order_type; +} + +//===----------------------------------------------------------------------===// +// 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 = DBConfig().options.enable_external_access; +} + +Value EnableExternalAccessSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.enable_external_access); +} + +//===----------------------------------------------------------------------===// +// Enable F S S T Vectors +//===----------------------------------------------------------------------===// +void EnableFSSTVectorsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.enable_fsst_vectors = input.GetValue(); +} + +void EnableFSSTVectorsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.enable_fsst_vectors = DBConfig().options.enable_fsst_vectors; +} + +Value EnableFSSTVectorsSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.enable_fsst_vectors); +} + +//===----------------------------------------------------------------------===// +// Enable H T T P Logging +//===----------------------------------------------------------------------===// +void EnableHTTPLoggingSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.enable_http_logging = input.GetValue(); +} + +void EnableHTTPLoggingSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).enable_http_logging = ClientConfig().enable_http_logging; +} + +Value EnableHTTPLoggingSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::BOOLEAN(config.enable_http_logging); +} + +//===----------------------------------------------------------------------===// +// 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 = DBConfig().options.http_metadata_cache_enable; +} + +Value EnableHTTPMetadataCacheSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.http_metadata_cache_enable); +} + +//===----------------------------------------------------------------------===// +// Enable Macro Dependencies +//===----------------------------------------------------------------------===// +void EnableMacroDependenciesSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.enable_macro_dependencies = input.GetValue(); +} + +void EnableMacroDependenciesSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.enable_macro_dependencies = DBConfig().options.enable_macro_dependencies; +} + +Value EnableMacroDependenciesSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.enable_macro_dependencies); +} + +//===----------------------------------------------------------------------===// +// Enable Object Cache +//===----------------------------------------------------------------------===// +void EnableObjectCacheSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.object_cache_enable = input.GetValue(); +} + +void EnableObjectCacheSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.object_cache_enable = DBConfig().options.object_cache_enable; +} + +Value EnableObjectCacheSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.object_cache_enable); +} + +//===----------------------------------------------------------------------===// +// Enable Progress Bar +//===----------------------------------------------------------------------===// +void EnableProgressBarSetting::SetLocal(ClientContext &context, const Value &input) { + if (!OnLocalSet(context, input)) { + return; + } + auto &config = ClientConfig::GetConfig(context); + config.enable_progress_bar = input.GetValue(); +} + +void EnableProgressBarSetting::ResetLocal(ClientContext &context) { + if (!OnLocalReset(context)) { + return; + } + ClientConfig::GetConfig(context).enable_progress_bar = ClientConfig().enable_progress_bar; +} + +Value EnableProgressBarSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::BOOLEAN(config.enable_progress_bar); +} + +//===----------------------------------------------------------------------===// +// Enable View Dependencies +//===----------------------------------------------------------------------===// +void EnableViewDependenciesSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.enable_view_dependencies = input.GetValue(); +} + +void EnableViewDependenciesSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.enable_view_dependencies = DBConfig().options.enable_view_dependencies; +} + +Value EnableViewDependenciesSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.enable_view_dependencies); +} + +//===----------------------------------------------------------------------===// +// 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 = DBConfig().options.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 = DBConfig().options.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 Logging Output +//===----------------------------------------------------------------------===// +void HTTPLoggingOutputSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.http_logging_output = input.GetValue(); +} + +void HTTPLoggingOutputSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).http_logging_output = ClientConfig().http_logging_output; +} + +Value HTTPLoggingOutputSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value(config.http_logging_output); +} + +//===----------------------------------------------------------------------===// +// 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 = DBConfig().options.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 = DBConfig().options.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 = DBConfig().options.http_proxy_username; +} + +Value HTTPProxyUsernameSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(config.options.http_proxy_username); +} + +//===----------------------------------------------------------------------===// +// I E E E Floating Point Ops +//===----------------------------------------------------------------------===// +void IEEEFloatingPointOpsSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.ieee_floating_point_ops = input.GetValue(); +} + +void IEEEFloatingPointOpsSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).ieee_floating_point_ops = ClientConfig().ieee_floating_point_ops; +} + +Value IEEEFloatingPointOpsSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::BOOLEAN(config.ieee_floating_point_ops); +} + +//===----------------------------------------------------------------------===// +// Immediate Transaction Mode +//===----------------------------------------------------------------------===// +void ImmediateTransactionModeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.immediate_transaction_mode = input.GetValue(); +} + +void ImmediateTransactionModeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.immediate_transaction_mode = DBConfig().options.immediate_transaction_mode; +} + +Value ImmediateTransactionModeSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.immediate_transaction_mode); +} + +//===----------------------------------------------------------------------===// +// Index Scan Max Count +//===----------------------------------------------------------------------===// +void IndexScanMaxCountSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.index_scan_max_count = input.GetValue(); +} + +void IndexScanMaxCountSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.index_scan_max_count = DBConfig().options.index_scan_max_count; +} + +Value IndexScanMaxCountSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::UBIGINT(config.options.index_scan_max_count); +} + +//===----------------------------------------------------------------------===// +// Index Scan Percentage +//===----------------------------------------------------------------------===// +void IndexScanPercentageSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + if (!OnGlobalSet(db, config, input)) { + return; + } + config.options.index_scan_percentage = input.GetValue(); +} + +void IndexScanPercentageSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.index_scan_percentage = DBConfig().options.index_scan_percentage; +} + +Value IndexScanPercentageSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::DOUBLE(config.options.index_scan_percentage); +} + +//===----------------------------------------------------------------------===// +// Integer Division +//===----------------------------------------------------------------------===// +void IntegerDivisionSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.integer_division = input.GetValue(); +} + +void IntegerDivisionSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).integer_division = ClientConfig().integer_division; +} + +Value IntegerDivisionSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::BOOLEAN(config.integer_division); +} + +//===----------------------------------------------------------------------===// +// Lock Configuration +//===----------------------------------------------------------------------===// +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 = DBConfig().options.lock_configuration; +} + +Value LockConfigurationSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.lock_configuration); +} + +//===----------------------------------------------------------------------===// +// Max Expression Depth +//===----------------------------------------------------------------------===// +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); +} + +//===----------------------------------------------------------------------===// +// Max Vacuum Tasks +//===----------------------------------------------------------------------===// +void MaxVacuumTasksSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.max_vacuum_tasks = input.GetValue(); +} + +void MaxVacuumTasksSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.max_vacuum_tasks = DBConfig().options.max_vacuum_tasks; +} + +Value MaxVacuumTasksSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::UBIGINT(config.options.max_vacuum_tasks); +} + +//===----------------------------------------------------------------------===// +// Merge Join Threshold +//===----------------------------------------------------------------------===// +void MergeJoinThresholdSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.merge_join_threshold = input.GetValue(); +} + +void MergeJoinThresholdSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).merge_join_threshold = ClientConfig().merge_join_threshold; +} + +Value MergeJoinThresholdSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::UBIGINT(config.merge_join_threshold); +} + +//===----------------------------------------------------------------------===// +// Nested Loop Join Threshold +//===----------------------------------------------------------------------===// +void NestedLoopJoinThresholdSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.nested_loop_join_threshold = input.GetValue(); +} + +void NestedLoopJoinThresholdSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).nested_loop_join_threshold = ClientConfig().nested_loop_join_threshold; +} + +Value NestedLoopJoinThresholdSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::UBIGINT(config.nested_loop_join_threshold); +} + +//===----------------------------------------------------------------------===// +// Old Implicit Casting +//===----------------------------------------------------------------------===// +void OldImplicitCastingSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.old_implicit_casting = input.GetValue(); +} + +void OldImplicitCastingSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.old_implicit_casting = DBConfig().options.old_implicit_casting; +} + +Value OldImplicitCastingSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.old_implicit_casting); +} + +//===----------------------------------------------------------------------===// +// Order By Non Integer Literal +//===----------------------------------------------------------------------===// +void OrderByNonIntegerLiteralSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.order_by_non_integer_literal = input.GetValue(); +} + +void OrderByNonIntegerLiteralSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).order_by_non_integer_literal = ClientConfig().order_by_non_integer_literal; +} + +Value OrderByNonIntegerLiteralSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::BOOLEAN(config.order_by_non_integer_literal); +} + +//===----------------------------------------------------------------------===// +// Ordered Aggregate Threshold +//===----------------------------------------------------------------------===// +void OrderedAggregateThresholdSetting::SetLocal(ClientContext &context, const Value &input) { + if (!OnLocalSet(context, input)) { + return; + } + auto &config = ClientConfig::GetConfig(context); + config.ordered_aggregate_threshold = input.GetValue(); +} + +void OrderedAggregateThresholdSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).ordered_aggregate_threshold = ClientConfig().ordered_aggregate_threshold; +} + +Value OrderedAggregateThresholdSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::UBIGINT(config.ordered_aggregate_threshold); +} + +//===----------------------------------------------------------------------===// +// Partitioned Write Flush Threshold +//===----------------------------------------------------------------------===// +void PartitionedWriteFlushThresholdSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.partitioned_write_flush_threshold = input.GetValue(); +} + +void PartitionedWriteFlushThresholdSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).partitioned_write_flush_threshold = + ClientConfig().partitioned_write_flush_threshold; +} + +Value PartitionedWriteFlushThresholdSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::UBIGINT(config.partitioned_write_flush_threshold); +} + +//===----------------------------------------------------------------------===// +// Partitioned Write Max Open Files +//===----------------------------------------------------------------------===// +void PartitionedWriteMaxOpenFilesSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.partitioned_write_max_open_files = input.GetValue(); +} + +void PartitionedWriteMaxOpenFilesSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).partitioned_write_max_open_files = ClientConfig().partitioned_write_max_open_files; +} + +Value PartitionedWriteMaxOpenFilesSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::UBIGINT(config.partitioned_write_max_open_files); +} + +//===----------------------------------------------------------------------===// +// Perfect Ht Threshold +//===----------------------------------------------------------------------===// +void PerfectHtThresholdSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).perfect_ht_threshold = ClientConfig().perfect_ht_threshold; +} + +//===----------------------------------------------------------------------===// +// Pivot Filter Threshold +//===----------------------------------------------------------------------===// +void PivotFilterThresholdSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.pivot_filter_threshold = input.GetValue(); +} + +void PivotFilterThresholdSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).pivot_filter_threshold = ClientConfig().pivot_filter_threshold; +} + +Value PivotFilterThresholdSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::UBIGINT(config.pivot_filter_threshold); +} + +//===----------------------------------------------------------------------===// +// Pivot Limit +//===----------------------------------------------------------------------===// +void PivotLimitSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.pivot_limit = input.GetValue(); +} + +void PivotLimitSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).pivot_limit = ClientConfig().pivot_limit; +} + +Value PivotLimitSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::UBIGINT(config.pivot_limit); +} + +//===----------------------------------------------------------------------===// +// Prefer Range Joins +//===----------------------------------------------------------------------===// +void PreferRangeJoinsSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.prefer_range_joins = input.GetValue(); +} + +void PreferRangeJoinsSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).prefer_range_joins = ClientConfig().prefer_range_joins; +} + +Value PreferRangeJoinsSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::BOOLEAN(config.prefer_range_joins); +} + +//===----------------------------------------------------------------------===// +// Preserve Identifier Case +//===----------------------------------------------------------------------===// +void PreserveIdentifierCaseSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.preserve_identifier_case = input.GetValue(); +} + +void PreserveIdentifierCaseSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).preserve_identifier_case = ClientConfig().preserve_identifier_case; +} + +Value PreserveIdentifierCaseSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::BOOLEAN(config.preserve_identifier_case); +} + +//===----------------------------------------------------------------------===// +// Preserve Insertion Order +//===----------------------------------------------------------------------===// +void PreserveInsertionOrderSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.preserve_insertion_order = input.GetValue(); +} + +void PreserveInsertionOrderSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.preserve_insertion_order = DBConfig().options.preserve_insertion_order; +} + +Value PreserveInsertionOrderSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.preserve_insertion_order); +} + +//===----------------------------------------------------------------------===// +// Produce Arrow String View +//===----------------------------------------------------------------------===// +void ProduceArrowStringViewSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.produce_arrow_string_views = input.GetValue(); +} + +void ProduceArrowStringViewSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.produce_arrow_string_views = DBConfig().options.produce_arrow_string_views; +} + +Value ProduceArrowStringViewSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.produce_arrow_string_views); +} + +//===----------------------------------------------------------------------===// +// Scalar Subquery Error On Multiple Rows +//===----------------------------------------------------------------------===// +void ScalarSubqueryErrorOnMultipleRowsSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.scalar_subquery_error_on_multiple_rows = input.GetValue(); +} + +void ScalarSubqueryErrorOnMultipleRowsSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).scalar_subquery_error_on_multiple_rows = + ClientConfig().scalar_subquery_error_on_multiple_rows; +} + +Value ScalarSubqueryErrorOnMultipleRowsSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::BOOLEAN(config.scalar_subquery_error_on_multiple_rows); +} + +} // namespace duckdb diff --git a/src/duckdb/src/main/settings/custom_settings.cpp b/src/duckdb/src/main/settings/custom_settings.cpp new file mode 100644 index 000000000..887c3ce1e --- /dev/null +++ b/src/duckdb/src/main/settings/custom_settings.cpp @@ -0,0 +1,1220 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// This file will not be overwritten. To implement a custom function for +// a new setting, enable 'custom_implementation' in 'settings.json' +// for this setting. The 'update_settings_definitions.py' may include new +// setting methods' signatures that need to be implemented in this file. You +// can check the functions declaration in 'settings.hpp' and what is +// autogenerated in 'autogenerated_settings.cpp'. +// +//===----------------------------------------------------------------------===// + +#include "duckdb/main/settings.hpp" + +#include "duckdb/common/enums/access_mode.hpp" +#include "duckdb/catalog/catalog_search_path.hpp" +#include "duckdb/common/string_util.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/main/query_profiler.hpp" +#include "duckdb/main/secret/secret_manager.hpp" +#include "duckdb/parallel/task_scheduler.hpp" +#include "duckdb/parser/parser.hpp" +#include "duckdb/planner/expression_binder.hpp" +#include "duckdb/storage/buffer/buffer_pool.hpp" +#include "duckdb/storage/buffer_manager.hpp" +#include "duckdb/storage/storage_manager.hpp" + +namespace duckdb { + +const string GetDefaultUserAgent() { + return StringUtil::Format("duckdb/%s(%s)", DuckDB::LibraryVersion(), DuckDB::Platform()); +} + +//===----------------------------------------------------------------------===// +// Access Mode +//===----------------------------------------------------------------------===// +bool AccessModeSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { + if (db) { + throw InvalidInputException("Cannot change access_mode setting while database is running - it must be set when " + "opening or attaching the database"); + } + return true; +} + +//===----------------------------------------------------------------------===// +// 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(DBConfig().options.allocator_background_threads); + } + return true; +} + +//===----------------------------------------------------------------------===// +// Allocator Bulk Deallocation Flush Threshold +//===----------------------------------------------------------------------===// +void AllocatorBulkDeallocationFlushThresholdSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, + const Value &input) { + config.options.allocator_bulk_deallocation_flush_threshold = DBConfig::ParseMemoryLimit(input.ToString()); + if (db) { + BufferManager::GetBufferManager(*db).GetBufferPool().SetAllocatorBulkDeallocationFlushThreshold( + config.options.allocator_bulk_deallocation_flush_threshold); + } +} + +void AllocatorBulkDeallocationFlushThresholdSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.allocator_bulk_deallocation_flush_threshold = + DBConfig().options.allocator_bulk_deallocation_flush_threshold; + if (db) { + BufferManager::GetBufferManager(*db).GetBufferPool().SetAllocatorBulkDeallocationFlushThreshold( + config.options.allocator_bulk_deallocation_flush_threshold); + } +} + +Value AllocatorBulkDeallocationFlushThresholdSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(StringUtil::BytesToHumanReadableString(config.options.allocator_bulk_deallocation_flush_threshold)); +} + +//===----------------------------------------------------------------------===// +// Allocator Flush Threshold +//===----------------------------------------------------------------------===// +void AllocatorFlushThresholdSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.allocator_flush_threshold = DBConfig::ParseMemoryLimit(input.ToString()); + if (db) { + TaskScheduler::GetScheduler(*db).SetAllocatorFlushTreshold(config.options.allocator_flush_threshold); + } +} + +void AllocatorFlushThresholdSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.allocator_flush_threshold = DBConfig().options.allocator_flush_threshold; + if (db) { + TaskScheduler::GetScheduler(*db).SetAllocatorFlushTreshold(config.options.allocator_flush_threshold); + } +} + +Value AllocatorFlushThresholdSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(StringUtil::BytesToHumanReadableString(config.options.allocator_flush_threshold)); +} + +//===----------------------------------------------------------------------===// +// 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 (DBConfig().options.allow_community_extensions) { + throw InvalidInputException("Cannot upgrade allow_community_extensions setting while database is running"); + } + return false; + } + return true; +} + +//===----------------------------------------------------------------------===// +// Allow Persistent Secrets +//===----------------------------------------------------------------------===// +void AllowPersistentSecretsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto value = input.DefaultCastAs(LogicalType::BOOLEAN); + config.secret_manager->SetEnablePersistentSecrets(value.GetValue()); +} + +void AllowPersistentSecretsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.secret_manager->ResetEnablePersistentSecrets(); +} + +Value AllowPersistentSecretsSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.secret_manager->PersistentSecretsEnabled()); +} + +//===----------------------------------------------------------------------===// +// 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) { + throw InvalidInputException("Cannot change allow_unredacted_secrets setting while database is running"); + } + return true; +} + +//===----------------------------------------------------------------------===// +// Allow Unsigned Extensions +//===----------------------------------------------------------------------===// +bool AllowUnsignedExtensionsSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { + if (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) { + throw InvalidInputException("Cannot change allowed_directories when enable_external_access is disabled"); + } + config.options.allowed_directories.clear(); + auto &list = ListValue::GetChildren(input); + for (auto &val : list) { + config.AddAllowedDirectory(val.GetValue()); + } +} + +void AllowedDirectoriesSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + if (!config.options.enable_external_access) { + throw InvalidInputException("Cannot change allowed_directories when enable_external_access is disabled"); + } + config.options.allowed_directories = DBConfig().options.allowed_directories; +} + +Value AllowedDirectoriesSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + vector allowed_directories; + for (auto &dir : config.options.allowed_directories) { + allowed_directories.emplace_back(dir); + } + return Value::LIST(LogicalType::VARCHAR, std::move(allowed_directories)); +} + +//===----------------------------------------------------------------------===// +// Allowed Paths +//===----------------------------------------------------------------------===//void +void AllowedPathsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + if (!config.options.enable_external_access) { + throw InvalidInputException("Cannot change allowed_paths when enable_external_access is disabled"); + } + config.options.allowed_paths.clear(); + auto &list = ListValue::GetChildren(input); + for (auto &val : list) { + config.AddAllowedPath(val.GetValue()); + } +} + +void AllowedPathsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + if (!config.options.enable_external_access) { + throw InvalidInputException("Cannot change allowed_paths when enable_external_access is disabled"); + } + config.options.allowed_paths = DBConfig().options.allowed_paths; +} + +Value AllowedPathsSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + vector allowed_paths; + for (auto &dir : config.options.allowed_paths) { + allowed_paths.emplace_back(dir); + } + return Value::LIST(LogicalType::VARCHAR, std::move(allowed_paths)); +} + +//===----------------------------------------------------------------------===// +// Arrow Large Buffer Size +//===----------------------------------------------------------------------===// +void ArrowLargeBufferSizeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto export_large_buffers_arrow = input.GetValue(); + config.options.arrow_offset_size = export_large_buffers_arrow ? ArrowOffsetSize::LARGE : ArrowOffsetSize::REGULAR; +} + +Value ArrowLargeBufferSizeSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + bool export_large_buffers_arrow = config.options.arrow_offset_size == ArrowOffsetSize::LARGE; + return Value::BOOLEAN(export_large_buffers_arrow); +} + +//===----------------------------------------------------------------------===// +// Checkpoint Threshold +//===----------------------------------------------------------------------===// +void CheckpointThresholdSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + idx_t new_limit = DBConfig::ParseMemoryLimit(input.ToString()); + config.options.checkpoint_wal_size = new_limit; +} + +Value CheckpointThresholdSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(StringUtil::BytesToHumanReadableString(config.options.checkpoint_wal_size)); +} + +//===----------------------------------------------------------------------===// +// Custom Profiling Settings +//===----------------------------------------------------------------------===// +bool IsEnabledOptimizer(MetricsType metric, const set &disabled_optimizers) { + auto matching_optimizer_type = MetricsUtils::GetOptimizerTypeByMetric(metric); + if (matching_optimizer_type != OptimizerType::INVALID && + disabled_optimizers.find(matching_optimizer_type) == disabled_optimizers.end()) { + return true; + } + return false; +} + +static profiler_settings_t FillTreeNodeSettings(unordered_map &json, + const set &disabled_optimizers) { + profiler_settings_t metrics; + + string invalid_settings; + for (auto &entry : json) { + MetricsType setting; + try { + setting = EnumUtil::FromString(StringUtil::Upper(entry.first)); + } catch (std::exception &ex) { + if (!invalid_settings.empty()) { + invalid_settings += ", "; + } + invalid_settings += entry.first; + continue; + } + if (StringUtil::Lower(entry.second) == "true" && + (!MetricsUtils::IsOptimizerMetric(setting) || IsEnabledOptimizer(setting, disabled_optimizers))) { + metrics.insert(setting); + } + } + + if (!invalid_settings.empty()) { + throw IOException("Invalid custom profiler settings: \"%s\"", invalid_settings); + } + return metrics; +} + +void AddOptimizerMetrics(profiler_settings_t &settings, const set &disabled_optimizers) { + if (settings.find(MetricsType::ALL_OPTIMIZERS) != settings.end()) { + auto optimizer_metrics = MetricsUtils::GetOptimizerMetrics(); + for (auto &metric : optimizer_metrics) { + if (IsEnabledOptimizer(metric, disabled_optimizers)) { + settings.insert(metric); + } + } + } +} + +void CustomProfilingSettingsSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + + // parse the file content + unordered_map json; + try { + json = StringUtil::ParseJSONMap(input.ToString()); + } catch (std::exception &ex) { + throw IOException("Could not parse the custom profiler settings file due to incorrect JSON: \"%s\". Make sure " + "all the keys and values start with a quote. ", + input.ToString()); + } + + config.enable_profiler = true; + auto &db_config = DBConfig::GetConfig(context); + auto &disabled_optimizers = db_config.options.disabled_optimizers; + + auto settings = FillTreeNodeSettings(json, disabled_optimizers); + AddOptimizerMetrics(settings, disabled_optimizers); + config.profiler_settings = settings; +} + +void CustomProfilingSettingsSetting::ResetLocal(ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + config.enable_profiler = ClientConfig().enable_profiler; + config.profiler_settings = ProfilingInfo::DefaultSettings(); +} + +Value CustomProfilingSettingsSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + + string profiling_settings_str; + for (auto &entry : config.profiler_settings) { + if (!profiling_settings_str.empty()) { + profiling_settings_str += ", "; + } + profiling_settings_str += StringUtil::Format("\"%s\": \"true\"", EnumUtil::ToString(entry)); + } + return Value(StringUtil::Format("{%s}", profiling_settings_str)); +} + +//===----------------------------------------------------------------------===// +// Custom User Agent +//===----------------------------------------------------------------------===// +void CustomUserAgentSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto new_value = input.GetValue(); + if (db) { + throw InvalidInputException("Cannot change custom_user_agent setting while database is running"); + } + config.options.custom_user_agent = + config.options.custom_user_agent.empty() ? new_value : config.options.custom_user_agent + " " + new_value; +} + +void CustomUserAgentSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + if (db) { + throw InvalidInputException("Cannot change custom_user_agent setting while database is running"); + } + config.options.custom_user_agent = DBConfig().options.custom_user_agent; +} + +//===----------------------------------------------------------------------===// +// Default Block Size +//===----------------------------------------------------------------------===// +void DefaultBlockSizeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const 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 = DBConfig().options.default_block_alloc_size; +} + +Value DefaultBlockSizeSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::UBIGINT(config.options.default_block_alloc_size); +} + +//===----------------------------------------------------------------------===// +// Default Collation +//===----------------------------------------------------------------------===// +void DefaultCollationSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto parameter = StringUtil::Lower(input.ToString()); + config.options.collation = parameter; +} + +void DefaultCollationSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.collation = DBConfig().options.collation; +} + +void DefaultCollationSetting::SetLocal(ClientContext &context, const Value &input) { + auto parameter = input.ToString(); + // bind the collation to verify that it exists + ExpressionBinder::TestCollation(context, parameter); + auto &config = DBConfig::GetConfig(context); + config.options.collation = parameter; +} + +void DefaultCollationSetting::ResetLocal(ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + config.options.collation = DBConfig().options.collation; +} + +Value DefaultCollationSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(config.options.collation); +} + +//===----------------------------------------------------------------------===// +// Default Null Order +//===----------------------------------------------------------------------===// +void DefaultNullOrderSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto parameter = StringUtil::Lower(input.ToString()); + + if (parameter == "nulls_first" || parameter == "nulls first" || parameter == "null first" || parameter == "first") { + config.options.default_null_order = DefaultOrderByNullType::NULLS_FIRST; + } else if (parameter == "nulls_last" || parameter == "nulls last" || parameter == "null last" || + parameter == "last") { + config.options.default_null_order = DefaultOrderByNullType::NULLS_LAST; + } else if (parameter == "nulls_first_on_asc_last_on_desc" || parameter == "sqlite" || parameter == "mysql") { + config.options.default_null_order = DefaultOrderByNullType::NULLS_FIRST_ON_ASC_LAST_ON_DESC; + } else if (parameter == "nulls_last_on_asc_first_on_desc" || parameter == "postgres") { + config.options.default_null_order = DefaultOrderByNullType::NULLS_LAST_ON_ASC_FIRST_ON_DESC; + } else { + throw ParserException("Unrecognized parameter for option NULL_ORDER \"%s\", expected either NULLS FIRST, NULLS " + "LAST, SQLite, MySQL or Postgres", + parameter); + } +} + +//===----------------------------------------------------------------------===// +// Default Order +//===----------------------------------------------------------------------===// +void DefaultOrderSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto parameter = StringUtil::Lower(input.ToString()); + if (parameter == "ascending" || parameter == "asc") { + config.options.default_order_type = OrderType::ASCENDING; + } else if (parameter == "descending" || parameter == "desc") { + config.options.default_order_type = OrderType::DESCENDING; + } else { + throw InvalidInputException("Unrecognized parameter for option DEFAULT_ORDER \"%s\". Expected ASC or DESC.", + parameter); + } +} + +Value DefaultOrderSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + switch (config.options.default_order_type) { + case OrderType::ASCENDING: + return "asc"; + case OrderType::DESCENDING: + return "desc"; + default: + throw InternalException("Unknown order type setting"); + } +} + +//===----------------------------------------------------------------------===// +// Default Secret Storage +//===----------------------------------------------------------------------===// +void DefaultSecretStorageSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.secret_manager->SetDefaultStorage(input.ToString()); +} + +void DefaultSecretStorageSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.secret_manager->ResetDefaultStorage(); +} + +Value DefaultSecretStorageSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return config.secret_manager->DefaultStorage(); +} + +//===----------------------------------------------------------------------===// +// Disabled Filesystems +//===----------------------------------------------------------------------===// +void DisabledFilesystemsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + if (!db) { + throw InternalException("disabled_filesystems can only be set in an active database"); + } + auto &fs = FileSystem::GetFileSystem(*db); + auto list = StringUtil::Split(input.ToString(), ","); + fs.SetDisabledFileSystems(list); +} + +void DisabledFilesystemsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + if (!db) { + throw InternalException("disabled_filesystems can only be set in an active database"); + } + auto &fs = FileSystem::GetFileSystem(*db); + fs.SetDisabledFileSystems(vector()); +} + +Value DisabledFilesystemsSetting::GetSetting(const ClientContext &context) { + return Value(""); +} + +//===----------------------------------------------------------------------===// +// Disabled Optimizers +//===----------------------------------------------------------------------===// +void DisabledOptimizersSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto list = StringUtil::Split(input.ToString(), ","); + set disabled_optimizers; + for (auto &entry : list) { + auto param = StringUtil::Lower(entry); + StringUtil::Trim(param); + if (param.empty()) { + continue; + } + disabled_optimizers.insert(OptimizerTypeFromString(param)); + } + config.options.disabled_optimizers = std::move(disabled_optimizers); +} + +void DisabledOptimizersSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.disabled_optimizers = DBConfig().options.disabled_optimizers; +} + +Value DisabledOptimizersSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + string result; + for (auto &optimizer : config.options.disabled_optimizers) { + if (!result.empty()) { + result += ","; + } + result += OptimizerTypeToString(optimizer); + } + return Value(result); +} + +//===----------------------------------------------------------------------===// +// Duckdb Api +//===----------------------------------------------------------------------===// +void DuckDBAPISetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto new_value = input.GetValue(); + if (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; + } + if (input.GetValue()) { + throw InvalidInputException("Cannot change enable_external_access setting while database is running"); + } + if (db && config.options.enable_external_access) { + // we are turning off external access - add any already attached databases to the list of accepted paths + auto &db_manager = DatabaseManager::Get(*db); + auto attached_paths = db_manager.GetAttachedDatabasePaths(); + for (auto &path : attached_paths) { + config.AddAllowedPath(path); + config.AddAllowedPath(path + ".wal"); + } + } + 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 Profiling +//===----------------------------------------------------------------------===// +void EnableProfilingSetting::SetLocal(ClientContext &context, const Value &input) { + auto parameter = StringUtil::Lower(input.ToString()); + + auto &config = ClientConfig::GetConfig(context); + config.enable_profiler = true; + config.emit_profiler_output = true; + config.profiler_settings = ClientConfig().profiler_settings; + + if (parameter == "json") { + config.profiler_print_format = ProfilerPrintFormat::JSON; + } else if (parameter == "query_tree") { + config.profiler_print_format = ProfilerPrintFormat::QUERY_TREE; + } else if (parameter == "query_tree_optimizer") { + config.profiler_print_format = ProfilerPrintFormat::QUERY_TREE_OPTIMIZER; + + // add optimizer settings to the profiler settings + auto optimizer_settings = MetricsUtils::GetOptimizerMetrics(); + for (auto &setting : optimizer_settings) { + config.profiler_settings.insert(setting); + } + + // add the phase timing settings to the profiler settings + auto phase_timing_settings = MetricsUtils::GetPhaseTimingMetrics(); + for (auto &setting : phase_timing_settings) { + config.profiler_settings.insert(setting); + } + } else if (parameter == "no_output") { + config.profiler_print_format = ProfilerPrintFormat::NO_OUTPUT; + config.emit_profiler_output = false; + } else if (parameter == "html") { + config.profiler_print_format = ProfilerPrintFormat::HTML; + } else if (parameter == "graphviz") { + config.profiler_print_format = ProfilerPrintFormat::GRAPHVIZ; + } else { + throw ParserException( + "Unrecognized print format %s, supported formats: [json, query_tree, query_tree_optimizer, no_output]", + parameter); + } +} + +void EnableProfilingSetting::ResetLocal(ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + config.profiler_print_format = ClientConfig().profiler_print_format; + config.enable_profiler = ClientConfig().enable_profiler; + config.emit_profiler_output = ClientConfig().emit_profiler_output; + config.profiler_settings = ClientConfig().profiler_settings; +} + +Value EnableProfilingSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + if (!config.enable_profiler) { + return Value(); + } + switch (config.profiler_print_format) { + case ProfilerPrintFormat::JSON: + return Value("json"); + case ProfilerPrintFormat::QUERY_TREE: + return Value("query_tree"); + case ProfilerPrintFormat::QUERY_TREE_OPTIMIZER: + return Value("query_tree_optimizer"); + case ProfilerPrintFormat::NO_OUTPUT: + return Value("no_output"); + case ProfilerPrintFormat::HTML: + return Value("html"); + case ProfilerPrintFormat::GRAPHVIZ: + return Value("graphviz"); + default: + throw InternalException("Unsupported profiler print format"); + } +} + +//===----------------------------------------------------------------------===// +// Enable Progress Bar Print +//===----------------------------------------------------------------------===// +void EnableProgressBarPrintSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + ProgressBar::SystemOverrideCheck(config); + config.print_progress_bar = input.GetValue(); +} + +void EnableProgressBarPrintSetting::ResetLocal(ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + ProgressBar::SystemOverrideCheck(config); + config.print_progress_bar = ClientConfig().print_progress_bar; +} + +Value EnableProgressBarPrintSetting::GetSetting(const ClientContext &context) { + return Value::BOOLEAN(ClientConfig::GetConfig(context).print_progress_bar); +} + +//===----------------------------------------------------------------------===// +// Enable Progress Bar +//===----------------------------------------------------------------------===// +bool EnableProgressBarSetting::OnLocalSet(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + ProgressBar::SystemOverrideCheck(config); + return true; +} + +bool EnableProgressBarSetting::OnLocalReset(ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + ProgressBar::SystemOverrideCheck(config); + return true; +} + +//===----------------------------------------------------------------------===// +// 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 = DBConfig().options.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"); + } + config.options.force_bitpacking_mode = mode; +} + +void ForceBitpackingModeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.force_bitpacking_mode = DBConfig().options.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) { + auto compression = StringUtil::Lower(input.ToString()); + if (compression == "none" || compression == "auto") { + config.options.force_compression = CompressionType::COMPRESSION_AUTO; + } else { + auto compression_type = CompressionTypeFromString(compression); + if (CompressionTypeIsDeprecated(compression_type)) { + throw ParserException("Attempted to force a deprecated compression type (%s)", + 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 = DBConfig().options.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"); + } + config.home_directory = input.IsNull() ? string() : input.ToString(); +} + +//===----------------------------------------------------------------------===// +// Index Scan Percentage +//===----------------------------------------------------------------------===// +bool IndexScanPercentageSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto index_scan_percentage = input.GetValue(); + if (index_scan_percentage < 0 || index_scan_percentage > 1.0) { + throw InvalidInputException("the index scan percentage must be within [0, 1]"); + } + return true; +} + +//===----------------------------------------------------------------------===// +// Log Query Path +//===----------------------------------------------------------------------===// +void LogQueryPathSetting::SetLocal(ClientContext &context, const Value &input) { + auto &client_data = ClientData::Get(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, + BufferedFileWriter::DEFAULT_OPEN_FLAGS); + } +} + +void LogQueryPathSetting::ResetLocal(ClientContext &context) { + auto &client_data = ClientData::Get(context); + // TODO: verify that this does the right thing + client_data.log_query_writer = std::move(ClientData(context).log_query_writer); +} + +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 +//===----------------------------------------------------------------------===// +void MaxMemorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.maximum_memory = DBConfig::ParseMemoryLimit(input.ToString()); + if (db) { + BufferManager::GetBufferManager(*db).SetMemoryLimit(config.options.maximum_memory); + } +} + +void MaxMemorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.SetDefaultMaxMemory(); +} + +Value MaxMemorySetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(StringUtil::BytesToHumanReadableString(config.options.maximum_memory)); +} + +//===----------------------------------------------------------------------===// +// Max Temp Directory Size +//===----------------------------------------------------------------------===// +void MaxTempDirectorySizeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto maximum_swap_space = DBConfig::ParseMemoryLimit(input.ToString()); + if (maximum_swap_space == DConstants::INVALID_INDEX) { + // We use INVALID_INDEX to indicate that the value is not set by the user + // use one lower to indicate 'unlimited' + maximum_swap_space--; + } + if (!db) { + config.options.maximum_swap_space = maximum_swap_space; + return; + } + auto &buffer_manager = BufferManager::GetBufferManager(*db); + buffer_manager.SetSwapLimit(maximum_swap_space); + config.options.maximum_swap_space = maximum_swap_space; +} + +void MaxTempDirectorySizeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.maximum_swap_space = DConstants::INVALID_INDEX; + if (!db) { + return; + } + auto &buffer_manager = BufferManager::GetBufferManager(*db); + buffer_manager.SetSwapLimit(); +} + +Value MaxTempDirectorySizeSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + if (config.options.maximum_swap_space != DConstants::INVALID_INDEX) { + // Explicitly set by the user + return Value(StringUtil::BytesToHumanReadableString(config.options.maximum_swap_space)); + } + auto &buffer_manager = BufferManager::GetBufferManager(context); + // Database is initialized, use the setting from the temporary directory + auto max_swap = buffer_manager.GetMaxSwap(); + if (max_swap.IsValid()) { + return Value(StringUtil::BytesToHumanReadableString(max_swap.GetIndex())); + } else { + // The temp directory has not been used yet + return Value(StringUtil::BytesToHumanReadableString(0)); + } +} + +//===----------------------------------------------------------------------===// +// Ordered Aggregate Threshold +//===----------------------------------------------------------------------===// +bool OrderedAggregateThresholdSetting::OnLocalSet(ClientContext &context, const Value &input) { + const auto param = input.GetValue(); + if (param <= 0) { + throw ParserException("Invalid option for PRAGMA ordered_aggregate_threshold, value must be positive"); + } + return true; +} + +//===----------------------------------------------------------------------===// +// 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 +//===----------------------------------------------------------------------===// +void PerfectHtThresholdSetting::SetLocal(ClientContext &context, const Value &input) { + auto bits = input.GetValue(); + if (bits < 0 || bits > 32) { + throw ParserException("Perfect HT threshold out of range: should be within range 0 - 32"); + } + ClientConfig::GetConfig(context).perfect_ht_threshold = NumericCast(bits); +} + +Value PerfectHtThresholdSetting::GetSetting(const ClientContext &context) { + return Value::BIGINT(NumericCast(ClientConfig::GetConfig(context).perfect_ht_threshold)); +} + +//===----------------------------------------------------------------------===// +// Profile Output +//===----------------------------------------------------------------------===// +void ProfileOutputSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + auto parameter = input.ToString(); + config.profiler_save_location = parameter; +} + +void ProfileOutputSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).profiler_save_location = ClientConfig().profiler_save_location; +} + +Value ProfileOutputSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value(config.profiler_save_location); +} + +//===----------------------------------------------------------------------===// +// Profiling Mode +//===----------------------------------------------------------------------===// +void ProfilingModeSetting::SetLocal(ClientContext &context, const Value &input) { + auto parameter = StringUtil::Lower(input.ToString()); + auto &config = ClientConfig::GetConfig(context); + if (parameter == "standard") { + config.enable_profiler = true; + config.enable_detailed_profiling = false; + } else if (parameter == "detailed") { + config.enable_profiler = true; + config.enable_detailed_profiling = true; + + // add optimizer settings to the profiler settings + auto optimizer_settings = MetricsUtils::GetOptimizerMetrics(); + for (auto &setting : optimizer_settings) { + config.profiler_settings.insert(setting); + } + + // add the phase timing settings to the profiler settings + auto phase_timing_settings = MetricsUtils::GetPhaseTimingMetrics(); + for (auto &setting : phase_timing_settings) { + config.profiler_settings.insert(setting); + } + } else { + throw ParserException("Unrecognized profiling mode \"%s\", supported formats: [standard, detailed]", parameter); + } +} + +void ProfilingModeSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).enable_profiler = ClientConfig().enable_profiler; + ClientConfig::GetConfig(context).enable_detailed_profiling = ClientConfig().enable_detailed_profiling; + ClientConfig::GetConfig(context).emit_profiler_output = ClientConfig().emit_profiler_output; + ClientConfig::GetConfig(context).profiler_settings = ClientConfig().profiler_settings; +} + +Value ProfilingModeSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + if (!config.enable_profiler) { + return Value(); + } + return Value(config.enable_detailed_profiling ? "detailed" : "standard"); +} + +//===----------------------------------------------------------------------===// +// Progress Bar Time +//===----------------------------------------------------------------------===// +void ProgressBarTimeSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + ProgressBar::SystemOverrideCheck(config); + config.wait_time = input.GetValue(); + config.enable_progress_bar = true; +} + +void ProgressBarTimeSetting::ResetLocal(ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + ProgressBar::SystemOverrideCheck(config); + config.wait_time = ClientConfig().wait_time; + config.enable_progress_bar = ClientConfig().enable_progress_bar; +} + +Value ProgressBarTimeSetting::GetSetting(const ClientContext &context) { + return Value::BIGINT(ClientConfig::GetConfig(context).wait_time); +} + +//===----------------------------------------------------------------------===// +// Schema +//===----------------------------------------------------------------------===// +void SchemaSetting::SetLocal(ClientContext &context, const Value &input) { + auto parameter = input.ToString(); + auto &client_data = ClientData::Get(context); + client_data.catalog_search_path->Set(CatalogSearchEntry::Parse(parameter), CatalogSetPathType::SET_SCHEMA); +} + +void SchemaSetting::ResetLocal(ClientContext &context) { + // FIXME: catalog_search_path is controlled by both SchemaSetting and SearchPathSetting + auto &client_data = ClientData::Get(context); + client_data.catalog_search_path->Reset(); +} + +Value SchemaSetting::GetSetting(const ClientContext &context) { + auto &client_data = ClientData::Get(context); + return client_data.catalog_search_path->GetDefault().schema; +} + +//===----------------------------------------------------------------------===// +// Search Path +//===----------------------------------------------------------------------===// +void SearchPathSetting::SetLocal(ClientContext &context, const Value &input) { + auto parameter = input.ToString(); + auto &client_data = ClientData::Get(context); + client_data.catalog_search_path->Set(CatalogSearchEntry::ParseList(parameter), CatalogSetPathType::SET_SCHEMAS); +} + +void SearchPathSetting::ResetLocal(ClientContext &context) { + // FIXME: catalog_search_path is controlled by both SchemaSetting and SearchPathSetting + auto &client_data = ClientData::Get(context); + client_data.catalog_search_path->Reset(); +} + +Value SearchPathSetting::GetSetting(const ClientContext &context) { + auto &client_data = ClientData::Get(context); + auto &set_paths = client_data.catalog_search_path->GetSetPaths(); + return Value(CatalogSearchEntry::ListToString(set_paths)); +} + +//===----------------------------------------------------------------------===// +// Secret Directory +//===----------------------------------------------------------------------===// +void SecretDirectorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.secret_manager->SetPersistentSecretPath(input.ToString()); +} + +void SecretDirectorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.secret_manager->ResetPersistentSecretPath(); +} + +Value SecretDirectorySetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return config.secret_manager->PersistentSecretPath(); +} + +//===----------------------------------------------------------------------===// +// Storage Compatibility Version +//===----------------------------------------------------------------------===// +void StorageCompatibilityVersionSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto version_string = input.GetValue(); + auto serialization_compatibility = SerializationCompatibility::FromString(version_string); + config.options.serialization_compatibility = serialization_compatibility; +} + +void StorageCompatibilityVersionSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.serialization_compatibility = DBConfig().options.serialization_compatibility; +} + +Value StorageCompatibilityVersionSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + + auto &version_name = config.options.serialization_compatibility.duckdb_version; + return Value(version_name); +} + +//===----------------------------------------------------------------------===// +// Streaming Buffer Size +//===----------------------------------------------------------------------===// +void StreamingBufferSizeSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.streaming_buffer_size = DBConfig::ParseMemoryLimit(input.ToString()); +} + +void StreamingBufferSizeSetting::ResetLocal(ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + config.SetDefaultStreamingBufferSize(); +} + +Value StreamingBufferSizeSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value(StringUtil::BytesToHumanReadableString(config.streaming_buffer_size)); +} + +//===----------------------------------------------------------------------===// +// Temp Directory +//===----------------------------------------------------------------------===// +void TempDirectorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + if (!config.options.enable_external_access) { + throw PermissionException("Modifying the temp_directory has been disabled by configuration"); + } + config.options.temporary_directory = input.ToString(); + config.options.use_temporary_directory = !config.options.temporary_directory.empty(); + if (db) { + auto &buffer_manager = BufferManager::GetBufferManager(*db); + buffer_manager.SetTemporaryDirectory(config.options.temporary_directory); + } +} + +void TempDirectorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + if (!config.options.enable_external_access) { + throw PermissionException("Modifying the temp_directory has been disabled by configuration"); + } + config.SetDefaultTempDirectory(); + config.options.use_temporary_directory = DBConfig().options.use_temporary_directory; + if (db) { + auto &buffer_manager = BufferManager::GetBufferManager(*db); + buffer_manager.SetTemporaryDirectory(config.options.temporary_directory); + } +} + +Value TempDirectorySetting::GetSetting(const ClientContext &context) { + auto &buffer_manager = BufferManager::GetBufferManager(context); + return Value(buffer_manager.GetTemporaryDirectory()); +} + +//===----------------------------------------------------------------------===// +// Threads +//===----------------------------------------------------------------------===// +void ThreadsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto new_val = input.GetValue(); + if (new_val < 1) { + throw SyntaxException("Must have at least 1 thread!"); + } + auto new_maximum_threads = NumericCast(new_val); + if (db) { + TaskScheduler::GetScheduler(*db).SetThreads(new_maximum_threads, config.options.external_threads); + } + config.options.maximum_threads = new_maximum_threads; +} + +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); + } + config.options.maximum_threads = new_maximum_threads; +} + +Value ThreadsSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BIGINT(NumericCast(config.options.maximum_threads)); +} + +//===----------------------------------------------------------------------===// +// Username +//===----------------------------------------------------------------------===// +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(); +} + +} // namespace duckdb diff --git a/src/duckdb/src/main/settings/settings.cpp b/src/duckdb/src/main/settings/settings.cpp deleted file mode 100644 index 8cdcf42ef..000000000 --- a/src/duckdb/src/main/settings/settings.cpp +++ /dev/null @@ -1,2056 +0,0 @@ -#include "duckdb/main/settings.hpp" - -#include "duckdb/catalog/catalog_search_path.hpp" -#include "duckdb/common/string_util.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/main/query_profiler.hpp" -#include "duckdb/main/secret/secret_manager.hpp" -#include "duckdb/parallel/task_scheduler.hpp" -#include "duckdb/parser/parser.hpp" -#include "duckdb/planner/expression_binder.hpp" -#include "duckdb/storage/buffer/buffer_pool.hpp" -#include "duckdb/storage/buffer_manager.hpp" -#include "duckdb/storage/storage_manager.hpp" - -namespace duckdb { - -const string GetDefaultUserAgent() { - return StringUtil::Format("duckdb/%s(%s)", DuckDB::LibraryVersion(), DuckDB::Platform()); -} - -//===--------------------------------------------------------------------===// -// Access Mode -//===--------------------------------------------------------------------===// -void AccessModeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (db) { - throw InvalidInputException("Cannot change access_mode setting while database is running - it must be set when " - "opening or attaching the database"); - } - auto parameter = StringUtil::Lower(input.ToString()); - if (parameter == "automatic") { - config.options.access_mode = AccessMode::AUTOMATIC; - } else if (parameter == "read_only") { - config.options.access_mode = AccessMode::READ_ONLY; - } else if (parameter == "read_write") { - config.options.access_mode = AccessMode::READ_WRITE; - } else { - throw InvalidInputException( - "Unrecognized parameter for option ACCESS_MODE \"%s\". Expected READ_ONLY or READ_WRITE.", parameter); - } -} - -void AccessModeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.access_mode = DBConfig().options.access_mode; -} - -Value AccessModeSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - switch (config.options.access_mode) { - case AccessMode::AUTOMATIC: - return "automatic"; - case AccessMode::READ_ONLY: - return "read_only"; - case AccessMode::READ_WRITE: - return "read_write"; - default: - throw InternalException("Unknown access mode setting"); - } -} - -//===--------------------------------------------------------------------===// -// Allow Persistent Secrets -//===--------------------------------------------------------------------===// -void AllowPersistentSecrets::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto value = input.DefaultCastAs(LogicalType::BOOLEAN); - config.secret_manager->SetEnablePersistentSecrets(value.GetValue()); -} - -void AllowPersistentSecrets::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.secret_manager->ResetEnablePersistentSecrets(); -} - -Value AllowPersistentSecrets::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.secret_manager->PersistentSecretsEnabled()); -} - -//===--------------------------------------------------------------------===// -// Access Mode -//===--------------------------------------------------------------------===// -void CatalogErrorMaxSchema::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.catalog_error_max_schemas = UBigIntValue::Get(input); -} - -void CatalogErrorMaxSchema::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.catalog_error_max_schemas = DBConfig().options.catalog_error_max_schemas; -} - -Value CatalogErrorMaxSchema::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::UBIGINT(config.options.catalog_error_max_schemas); -} - -//===--------------------------------------------------------------------===// -// Checkpoint Threshold -//===--------------------------------------------------------------------===// -void CheckpointThresholdSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - idx_t new_limit = DBConfig::ParseMemoryLimit(input.ToString()); - config.options.checkpoint_wal_size = new_limit; -} - -void CheckpointThresholdSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.checkpoint_wal_size = DBConfig().options.checkpoint_wal_size; -} - -Value CheckpointThresholdSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(StringUtil::BytesToHumanReadableString(config.options.checkpoint_wal_size)); -} - -//===--------------------------------------------------------------------===// -// Debug Checkpoint Abort -//===--------------------------------------------------------------------===// -void DebugCheckpointAbort::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto checkpoint_abort = StringUtil::Lower(input.ToString()); - if (checkpoint_abort == "none") { - config.options.checkpoint_abort = CheckpointAbort::NO_ABORT; - } else if (checkpoint_abort == "before_truncate") { - config.options.checkpoint_abort = CheckpointAbort::DEBUG_ABORT_BEFORE_TRUNCATE; - } else if (checkpoint_abort == "before_header") { - config.options.checkpoint_abort = CheckpointAbort::DEBUG_ABORT_BEFORE_HEADER; - } else if (checkpoint_abort == "after_free_list_write") { - config.options.checkpoint_abort = CheckpointAbort::DEBUG_ABORT_AFTER_FREE_LIST_WRITE; - } else { - throw ParserException( - "Unrecognized option for PRAGMA debug_checkpoint_abort, expected none, before_truncate or before_header"); - } -} - -void DebugCheckpointAbort::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.checkpoint_abort = DBConfig().options.checkpoint_abort; -} - -Value DebugCheckpointAbort::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(*context.db); - auto setting = config.options.checkpoint_abort; - switch (setting) { - case CheckpointAbort::NO_ABORT: - return "none"; - case CheckpointAbort::DEBUG_ABORT_BEFORE_TRUNCATE: - return "before_truncate"; - case CheckpointAbort::DEBUG_ABORT_BEFORE_HEADER: - return "before_header"; - case CheckpointAbort::DEBUG_ABORT_AFTER_FREE_LIST_WRITE: - return "after_free_list_write"; - default: - throw InternalException("Type not implemented for CheckpointAbort"); - } -} - -//===--------------------------------------------------------------------===// -// Debug Force External -//===--------------------------------------------------------------------===// -void DebugForceExternal::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).force_external = ClientConfig().force_external; -} - -void DebugForceExternal::SetLocal(ClientContext &context, const Value &input) { - ClientConfig::GetConfig(context).force_external = input.GetValue(); -} - -Value DebugForceExternal::GetSetting(const ClientContext &context) { - return Value::BOOLEAN(ClientConfig::GetConfig(context).force_external); -} - -//===--------------------------------------------------------------------===// -// Debug Force NoCrossProduct -//===--------------------------------------------------------------------===// -void DebugForceNoCrossProduct::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).force_no_cross_product = ClientConfig().force_no_cross_product; -} - -void DebugForceNoCrossProduct::SetLocal(ClientContext &context, const Value &input) { - ClientConfig::GetConfig(context).force_no_cross_product = input.GetValue(); -} - -Value DebugForceNoCrossProduct::GetSetting(const ClientContext &context) { - return Value::BOOLEAN(ClientConfig::GetConfig(context).force_no_cross_product); -} - -//===--------------------------------------------------------------------===// -// Debug Skip Checkpoint On Commit -//===--------------------------------------------------------------------===// -void DebugSkipCheckpointOnCommit::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter) { - config.options.debug_skip_checkpoint_on_commit = BooleanValue::Get(parameter); -} - -void DebugSkipCheckpointOnCommit::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.debug_skip_checkpoint_on_commit = DBConfig().options.debug_skip_checkpoint_on_commit; -} - -Value DebugSkipCheckpointOnCommit::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(*context.db); - return Value::BOOLEAN(config.options.debug_skip_checkpoint_on_commit); -} - -//===--------------------------------------------------------------------===// -// Ordered Aggregate Threshold -//===--------------------------------------------------------------------===// -void OrderedAggregateThreshold::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).ordered_aggregate_threshold = ClientConfig().ordered_aggregate_threshold; -} - -void OrderedAggregateThreshold::SetLocal(ClientContext &context, const Value &input) { - const auto param = input.GetValue(); - if (param <= 0) { - throw ParserException("Invalid option for PRAGMA ordered_aggregate_threshold, value must be positive"); - } - ClientConfig::GetConfig(context).ordered_aggregate_threshold = param; -} - -Value OrderedAggregateThreshold::GetSetting(const ClientContext &context) { - return Value::UBIGINT(ClientConfig::GetConfig(context).ordered_aggregate_threshold); -} - -//===--------------------------------------------------------------------===// -// Debug Window Mode -//===--------------------------------------------------------------------===// -void DebugWindowMode::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto param = StringUtil::Lower(input.ToString()); - if (param == "window") { - config.options.window_mode = WindowAggregationMode::WINDOW; - } else if (param == "combine") { - config.options.window_mode = WindowAggregationMode::COMBINE; - } else if (param == "separate") { - config.options.window_mode = WindowAggregationMode::SEPARATE; - } else { - throw ParserException("Unrecognized option for PRAGMA debug_window_mode, expected window, combine or separate"); - } -} - -void DebugWindowMode::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.window_mode = DBConfig().options.window_mode; -} - -Value DebugWindowMode::GetSetting(const ClientContext &context) { - return Value(); -} - -//===--------------------------------------------------------------------===// -// Debug AsOf Join -//===--------------------------------------------------------------------===// -void DebugAsOfIEJoin::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).force_asof_iejoin = ClientConfig().force_asof_iejoin; -} - -void DebugAsOfIEJoin::SetLocal(ClientContext &context, const Value &input) { - ClientConfig::GetConfig(context).force_asof_iejoin = input.GetValue(); -} - -Value DebugAsOfIEJoin::GetSetting(const ClientContext &context) { - return Value::BOOLEAN(ClientConfig::GetConfig(context).force_asof_iejoin); -} - -//===--------------------------------------------------------------------===// -// Prefer Range Joins -//===--------------------------------------------------------------------===// -void PreferRangeJoins::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).prefer_range_joins = ClientConfig().prefer_range_joins; -} - -void PreferRangeJoins::SetLocal(ClientContext &context, const Value &input) { - ClientConfig::GetConfig(context).prefer_range_joins = input.GetValue(); -} - -Value PreferRangeJoins::GetSetting(const ClientContext &context) { - return Value::BOOLEAN(ClientConfig::GetConfig(context).prefer_range_joins); -} - -//===--------------------------------------------------------------------===// -// Default Collation -//===--------------------------------------------------------------------===// -void DefaultCollationSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto parameter = StringUtil::Lower(input.ToString()); - config.options.collation = parameter; -} - -void DefaultCollationSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.collation = DBConfig().options.collation; -} - -void DefaultCollationSetting::ResetLocal(ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - config.options.collation = DBConfig().options.collation; -} - -void DefaultCollationSetting::SetLocal(ClientContext &context, const Value &input) { - auto parameter = input.ToString(); - // bind the collation to verify that it exists - ExpressionBinder::TestCollation(context, parameter); - auto &config = DBConfig::GetConfig(context); - config.options.collation = parameter; -} - -Value DefaultCollationSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.collation); -} - -//===--------------------------------------------------------------------===// -// Default Order -//===--------------------------------------------------------------------===// -void DefaultOrderSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto parameter = StringUtil::Lower(input.ToString()); - if (parameter == "ascending" || parameter == "asc") { - config.options.default_order_type = OrderType::ASCENDING; - } else if (parameter == "descending" || parameter == "desc") { - config.options.default_order_type = OrderType::DESCENDING; - } else { - throw InvalidInputException("Unrecognized parameter for option DEFAULT_ORDER \"%s\". Expected ASC or DESC.", - parameter); - } -} - -void DefaultOrderSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.default_order_type = DBConfig().options.default_order_type; -} - -Value DefaultOrderSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - switch (config.options.default_order_type) { - case OrderType::ASCENDING: - return "asc"; - case OrderType::DESCENDING: - return "desc"; - default: - throw InternalException("Unknown order type setting"); - } -} - -//===--------------------------------------------------------------------===// -// Default Null Order -//===--------------------------------------------------------------------===// -void DefaultNullOrderSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto parameter = StringUtil::Lower(input.ToString()); - - if (parameter == "nulls_first" || parameter == "nulls first" || parameter == "null first" || parameter == "first") { - config.options.default_null_order = DefaultOrderByNullType::NULLS_FIRST; - } else if (parameter == "nulls_last" || parameter == "nulls last" || parameter == "null last" || - parameter == "last") { - config.options.default_null_order = DefaultOrderByNullType::NULLS_LAST; - } else if (parameter == "nulls_first_on_asc_last_on_desc" || parameter == "sqlite" || parameter == "mysql") { - config.options.default_null_order = DefaultOrderByNullType::NULLS_FIRST_ON_ASC_LAST_ON_DESC; - } else if (parameter == "nulls_last_on_asc_first_on_desc" || parameter == "postgres") { - config.options.default_null_order = DefaultOrderByNullType::NULLS_LAST_ON_ASC_FIRST_ON_DESC; - } else { - throw ParserException("Unrecognized parameter for option NULL_ORDER \"%s\", expected either NULLS FIRST, NULLS " - "LAST, SQLite, MySQL or Postgres", - parameter); - } -} - -void DefaultNullOrderSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.default_null_order = DBConfig().options.default_null_order; -} - -Value DefaultNullOrderSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - switch (config.options.default_null_order) { - case DefaultOrderByNullType::NULLS_FIRST: - return "nulls_first"; - case DefaultOrderByNullType::NULLS_LAST: - return "nulls_last"; - case DefaultOrderByNullType::NULLS_FIRST_ON_ASC_LAST_ON_DESC: - return "nulls_first_on_asc_last_on_desc"; - case DefaultOrderByNullType::NULLS_LAST_ON_ASC_FIRST_ON_DESC: - return "nulls_last_on_asc_first_on_desc"; - default: - throw InternalException("Unknown null order setting"); - } -} - -//===--------------------------------------------------------------------===// -// Default Secret Storage -//===--------------------------------------------------------------------===// -void DefaultSecretStorage::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.secret_manager->SetDefaultStorage(input.ToString()); -} - -void DefaultSecretStorage::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.secret_manager->ResetDefaultStorage(); -} - -Value DefaultSecretStorage::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return config.secret_manager->DefaultStorage(); -} - -//===--------------------------------------------------------------------===// -// Disabled File Systems -//===--------------------------------------------------------------------===// -void DisabledFileSystemsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!db) { - throw InternalException("disabled_filesystems can only be set in an active database"); - } - auto &fs = FileSystem::GetFileSystem(*db); - auto list = StringUtil::Split(input.ToString(), ","); - fs.SetDisabledFileSystems(list); -} - -void DisabledFileSystemsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!db) { - throw InternalException("disabled_filesystems can only be set in an active database"); - } - auto &fs = FileSystem::GetFileSystem(*db); - fs.SetDisabledFileSystems(vector()); -} - -Value DisabledFileSystemsSetting::GetSetting(const ClientContext &context) { - return Value(""); -} - -//===--------------------------------------------------------------------===// -// Disabled Optimizer -//===--------------------------------------------------------------------===// -void DisabledOptimizersSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto list = StringUtil::Split(input.ToString(), ","); - set disabled_optimizers; - for (auto &entry : list) { - auto param = StringUtil::Lower(entry); - StringUtil::Trim(param); - if (param.empty()) { - continue; - } - disabled_optimizers.insert(OptimizerTypeFromString(param)); - } - config.options.disabled_optimizers = std::move(disabled_optimizers); -} - -void DisabledOptimizersSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.disabled_optimizers = DBConfig().options.disabled_optimizers; -} - -Value DisabledOptimizersSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - string result; - for (auto &optimizer : config.options.disabled_optimizers) { - if (!result.empty()) { - result += ","; - } - result += OptimizerTypeToString(optimizer); - } - return Value(result); -} - -//===--------------------------------------------------------------------===// -// Enable External Access -//===--------------------------------------------------------------------===// -void EnableExternalAccessSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto new_value = input.GetValue(); - if (db && new_value) { - throw InvalidInputException("Cannot change enable_external_access setting while database is running"); - } - config.options.enable_external_access = new_value; -} - -void EnableExternalAccessSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (db) { - throw InvalidInputException("Cannot change enable_external_access setting while database is running"); - } - config.options.enable_external_access = DBConfig().options.enable_external_access; -} - -Value EnableExternalAccessSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.enable_external_access); -} - -//===--------------------------------------------------------------------===// -// Enable Macro Dependencies -//===--------------------------------------------------------------------===// -void EnableMacrosDependencies::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.enable_macro_dependencies = input.GetValue(); -} - -void EnableMacrosDependencies::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.enable_macro_dependencies = DBConfig().options.enable_macro_dependencies; -} - -Value EnableMacrosDependencies::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.enable_macro_dependencies); -} - -//===--------------------------------------------------------------------===// -// Enable View Dependencies -//===--------------------------------------------------------------------===// -void EnableViewDependencies::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.enable_view_dependencies = input.GetValue(); -} - -void EnableViewDependencies::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.enable_view_dependencies = DBConfig().options.enable_view_dependencies; -} - -Value EnableViewDependencies::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.enable_view_dependencies); -} - -//===--------------------------------------------------------------------===// -// Enable FSST Vectors -//===--------------------------------------------------------------------===// -void EnableFSSTVectors::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.enable_fsst_vectors = input.GetValue(); -} - -void EnableFSSTVectors::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.enable_fsst_vectors = DBConfig().options.enable_fsst_vectors; -} - -Value EnableFSSTVectors::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.enable_fsst_vectors); -} - -//===--------------------------------------------------------------------===// -// Allow Unsigned Extensions -//===--------------------------------------------------------------------===// -void AllowUnsignedExtensionsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto new_value = input.GetValue(); - if (db && new_value) { - throw InvalidInputException("Cannot change allow_unsigned_extensions setting while database is running"); - } - config.options.allow_unsigned_extensions = new_value; -} - -void AllowUnsignedExtensionsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (db) { - throw InvalidInputException("Cannot change allow_unsigned_extensions setting while database is running"); - } - config.options.allow_unsigned_extensions = DBConfig().options.allow_unsigned_extensions; -} - -Value AllowUnsignedExtensionsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.allow_unsigned_extensions); -} - -//===--------------------------------------------------------------------===// -// Allow Community Extensions -//===--------------------------------------------------------------------===// -void AllowCommunityExtensionsSetting::SetGlobal(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; - } - auto new_value = input.GetValue(); - config.options.allow_community_extensions = new_value; -} - -void AllowCommunityExtensionsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (db && !config.options.allow_community_extensions) { - if (DBConfig().options.allow_community_extensions) { - throw InvalidInputException("Cannot upgrade allow_community_extensions setting while database is running"); - } - return; - } - config.options.allow_community_extensions = DBConfig().options.allow_community_extensions; -} - -Value AllowCommunityExtensionsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.allow_community_extensions); -} - -//===--------------------------------------------------------------------===// -// Allow Extensions Metadata Mismatch -//===--------------------------------------------------------------------===// -void AllowExtensionsMetadataMismatchSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto new_value = input.GetValue(); - config.options.allow_extensions_metadata_mismatch = new_value; -} - -void AllowExtensionsMetadataMismatchSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.allow_extensions_metadata_mismatch = DBConfig().options.allow_extensions_metadata_mismatch; -} - -Value AllowExtensionsMetadataMismatchSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.allow_extensions_metadata_mismatch); -} - -//===--------------------------------------------------------------------===// -// Allow Unredacted Secrets -//===--------------------------------------------------------------------===// -void AllowUnredactedSecretsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto new_value = input.GetValue(); - if (db && new_value) { - throw InvalidInputException("Cannot change allow_unredacted_secrets setting while database is running"); - } - config.options.allow_unredacted_secrets = new_value; -} - -void AllowUnredactedSecretsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (db) { - throw InvalidInputException("Cannot change allow_unredacted_secrets setting while database is running"); - } - config.options.allow_unredacted_secrets = DBConfig().options.allow_unredacted_secrets; -} - -Value AllowUnredactedSecretsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.allow_unredacted_secrets); -} - -//===--------------------------------------------------------------------===// -// Enable Object Cache -//===--------------------------------------------------------------------===// -void EnableObjectCacheSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.object_cache_enable = input.GetValue(); -} - -void EnableObjectCacheSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.object_cache_enable = DBConfig().options.object_cache_enable; -} - -Value EnableObjectCacheSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.object_cache_enable); -} - -//===--------------------------------------------------------------------===// -// Storage Compatibility Version (for serialization) -//===--------------------------------------------------------------------===// -void StorageCompatibilityVersion::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto version_string = input.GetValue(); - auto serialization_compatibility = SerializationCompatibility::FromString(version_string); - config.options.serialization_compatibility = serialization_compatibility; -} - -void StorageCompatibilityVersion::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.serialization_compatibility = DBConfig().options.serialization_compatibility; -} - -Value StorageCompatibilityVersion::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - - auto &version_name = config.options.serialization_compatibility.duckdb_version; - return Value(version_name); -} - -//===--------------------------------------------------------------------===// -// Enable HTTP 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 = DBConfig().options.http_metadata_cache_enable; -} - -Value EnableHTTPMetadataCacheSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.http_metadata_cache_enable); -} - -//===--------------------------------------------------------------------===// -// Enable Profiling -//===--------------------------------------------------------------------===// -void EnableProfilingSetting::ResetLocal(ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - config.profiler_print_format = ClientConfig().profiler_print_format; - config.enable_profiler = ClientConfig().enable_profiler; - config.emit_profiler_output = ClientConfig().emit_profiler_output; - config.profiler_settings = ClientConfig().profiler_settings; -} - -void EnableProfilingSetting::SetLocal(ClientContext &context, const Value &input) { - auto parameter = StringUtil::Lower(input.ToString()); - - auto &config = ClientConfig::GetConfig(context); - config.enable_profiler = true; - config.emit_profiler_output = true; - config.profiler_settings = ClientConfig().profiler_settings; - - if (parameter == "json") { - config.profiler_print_format = ProfilerPrintFormat::JSON; - } else if (parameter == "query_tree") { - config.profiler_print_format = ProfilerPrintFormat::QUERY_TREE; - } else if (parameter == "query_tree_optimizer") { - config.profiler_print_format = ProfilerPrintFormat::QUERY_TREE_OPTIMIZER; - - // add optimizer settings to the profiler settings - auto optimizer_settings = MetricsUtils::GetOptimizerMetrics(); - for (auto &setting : optimizer_settings) { - config.profiler_settings.insert(setting); - } - - // add the phase timing settings to the profiler settings - auto phase_timing_settings = MetricsUtils::GetPhaseTimingMetrics(); - for (auto &setting : phase_timing_settings) { - config.profiler_settings.insert(setting); - } - } else if (parameter == "no_output") { - config.profiler_print_format = ProfilerPrintFormat::NO_OUTPUT; - config.emit_profiler_output = false; - } else { - throw ParserException( - "Unrecognized print format %s, supported formats: [json, query_tree, query_tree_optimizer, no_output]", - parameter); - } -} - -Value EnableProfilingSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - if (!config.enable_profiler) { - return Value(); - } - switch (config.profiler_print_format) { - case ProfilerPrintFormat::JSON: - return Value("json"); - case ProfilerPrintFormat::QUERY_TREE: - return Value("query_tree"); - case ProfilerPrintFormat::QUERY_TREE_OPTIMIZER: - return Value("query_tree_optimizer"); - case ProfilerPrintFormat::NO_OUTPUT: - return Value("no_output"); - default: - throw InternalException("Unsupported profiler print format"); - } -} - -//===--------------------------------------------------------------------===// -// Custom Profiling Settings -//===--------------------------------------------------------------------===// - -bool IsEnabledOptimizer(MetricsType metric, const set &disabled_optimizers) { - auto matching_optimizer_type = MetricsUtils::GetOptimizerTypeByMetric(metric); - if (matching_optimizer_type != OptimizerType::INVALID && - disabled_optimizers.find(matching_optimizer_type) == disabled_optimizers.end()) { - return true; - } - return false; -} - -static profiler_settings_t FillTreeNodeSettings(unordered_map &json, - const set &disabled_optimizers) { - profiler_settings_t metrics; - - string invalid_settings; - for (auto &entry : json) { - MetricsType setting; - try { - setting = EnumUtil::FromString(StringUtil::Upper(entry.first)); - } catch (std::exception &ex) { - if (!invalid_settings.empty()) { - invalid_settings += ", "; - } - invalid_settings += entry.first; - continue; - } - if (StringUtil::Lower(entry.second) == "true" && - (!MetricsUtils::IsOptimizerMetric(setting) || IsEnabledOptimizer(setting, disabled_optimizers))) { - metrics.insert(setting); - } - } - - if (!invalid_settings.empty()) { - throw IOException("Invalid custom profiler settings: \"%s\"", invalid_settings); - } - return metrics; -} - -void AddOptimizerMetrics(profiler_settings_t &settings, const set &disabled_optimizers) { - if (settings.find(MetricsType::ALL_OPTIMIZERS) != settings.end()) { - auto optimizer_metrics = MetricsUtils::GetOptimizerMetrics(); - for (auto &metric : optimizer_metrics) { - if (IsEnabledOptimizer(metric, disabled_optimizers)) { - settings.insert(metric); - } - } - } -} - -void CustomProfilingSettings::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - - // parse the file content - unordered_map json; - try { - json = StringUtil::ParseJSONMap(input.ToString()); - } catch (std::exception &ex) { - throw IOException("Could not parse the custom profiler settings file due to incorrect JSON: \"%s\". Make sure " - "all the keys and values start with a quote. ", - input.ToString()); - } - - config.enable_profiler = true; - auto &db_config = DBConfig::GetConfig(context); - auto &disabled_optimizers = db_config.options.disabled_optimizers; - - auto settings = FillTreeNodeSettings(json, disabled_optimizers); - AddOptimizerMetrics(settings, disabled_optimizers); - config.profiler_settings = settings; -} - -void CustomProfilingSettings::ResetLocal(ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - config.enable_profiler = ClientConfig().enable_profiler; - config.profiler_settings = ProfilingInfo::DefaultSettings(); -} - -Value CustomProfilingSettings::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - - string profiling_settings_str; - for (auto &entry : config.profiler_settings) { - if (!profiling_settings_str.empty()) { - profiling_settings_str += ", "; - } - profiling_settings_str += StringUtil::Format("\"%s\": \"true\"", EnumUtil::ToString(entry)); - } - return Value(StringUtil::Format("{%s}", profiling_settings_str)); -} - -//===--------------------------------------------------------------------===// -// Custom Extension Repository -//===--------------------------------------------------------------------===// -void CustomExtensionRepository::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.custom_extension_repo = DBConfig().options.custom_extension_repo; -} - -void CustomExtensionRepository::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.custom_extension_repo = input.ToString(); -} - -Value CustomExtensionRepository::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.custom_extension_repo); -} - -//===--------------------------------------------------------------------===// -// Autoload Extension Repository -//===--------------------------------------------------------------------===// -void AutoloadExtensionRepository::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.autoinstall_extension_repo = DBConfig().options.autoinstall_extension_repo; -} - -void AutoloadExtensionRepository::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.autoinstall_extension_repo = input.ToString(); -} - -Value AutoloadExtensionRepository::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.autoinstall_extension_repo); -} - -//===--------------------------------------------------------------------===// -// Autoinstall Known Extensions -//===--------------------------------------------------------------------===// -void AutoinstallKnownExtensions::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.autoinstall_known_extensions = input.GetValue(); -} - -void AutoinstallKnownExtensions::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.autoinstall_known_extensions = DBConfig().options.autoinstall_known_extensions; -} - -Value AutoinstallKnownExtensions::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.autoinstall_known_extensions); -} -//===--------------------------------------------------------------------===// -// Autoload Known Extensions -//===--------------------------------------------------------------------===// -void AutoloadKnownExtensions::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.autoload_known_extensions = input.GetValue(); -} - -void AutoloadKnownExtensions::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.autoload_known_extensions = DBConfig().options.autoload_known_extensions; -} - -Value AutoloadKnownExtensions::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.autoload_known_extensions); -} - -//===--------------------------------------------------------------------===// -// Enable Progress Bar -//===--------------------------------------------------------------------===// -void EnableProgressBarSetting::ResetLocal(ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - ProgressBar::SystemOverrideCheck(config); - config.enable_progress_bar = ClientConfig().enable_progress_bar; -} - -void EnableProgressBarSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - ProgressBar::SystemOverrideCheck(config); - config.enable_progress_bar = input.GetValue(); -} - -Value EnableProgressBarSetting::GetSetting(const ClientContext &context) { - return Value::BOOLEAN(ClientConfig::GetConfig(context).enable_progress_bar); -} - -//===--------------------------------------------------------------------===// -// Enable Progress Bar Print -//===--------------------------------------------------------------------===// -void EnableProgressBarPrintSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - ProgressBar::SystemOverrideCheck(config); - config.print_progress_bar = input.GetValue(); -} - -void EnableProgressBarPrintSetting::ResetLocal(ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - ProgressBar::SystemOverrideCheck(config); - config.print_progress_bar = ClientConfig().print_progress_bar; -} - -Value EnableProgressBarPrintSetting::GetSetting(const ClientContext &context) { - return Value::BOOLEAN(ClientConfig::GetConfig(context).print_progress_bar); -} - -//===--------------------------------------------------------------------===// -// Errors As JSON -//===--------------------------------------------------------------------===// -void ErrorsAsJsonSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).errors_as_json = ClientConfig().errors_as_json; -} - -void ErrorsAsJsonSetting::SetLocal(ClientContext &context, const Value &input) { - ClientConfig::GetConfig(context).errors_as_json = BooleanValue::Get(input); -} - -Value ErrorsAsJsonSetting::GetSetting(const ClientContext &context) { - return Value::BOOLEAN(ClientConfig::GetConfig(context).errors_as_json); -} - -//===--------------------------------------------------------------------===// -// Explain Output -//===--------------------------------------------------------------------===// -void ExplainOutputSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).explain_output_type = ClientConfig().explain_output_type; -} - -void ExplainOutputSetting::SetLocal(ClientContext &context, const Value &input) { - auto parameter = StringUtil::Lower(input.ToString()); - if (parameter == "all") { - ClientConfig::GetConfig(context).explain_output_type = ExplainOutputType::ALL; - } else if (parameter == "optimized_only") { - ClientConfig::GetConfig(context).explain_output_type = ExplainOutputType::OPTIMIZED_ONLY; - } else if (parameter == "physical_only") { - ClientConfig::GetConfig(context).explain_output_type = ExplainOutputType::PHYSICAL_ONLY; - } else { - throw ParserException("Unrecognized output type \"%s\", expected either ALL, OPTIMIZED_ONLY or PHYSICAL_ONLY", - parameter); - } -} - -Value ExplainOutputSetting::GetSetting(const ClientContext &context) { - switch (ClientConfig::GetConfig(context).explain_output_type) { - case ExplainOutputType::ALL: - return "all"; - case ExplainOutputType::OPTIMIZED_ONLY: - return "optimized_only"; - case ExplainOutputType::PHYSICAL_ONLY: - return "physical_only"; - default: - throw InternalException("Unrecognized explain output type"); - } -} - -//===--------------------------------------------------------------------===// -// Extension Directory Setting -//===--------------------------------------------------------------------===// -void ExtensionDirectorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.extension_directory = input.ToString(); -} - -void ExtensionDirectorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.extension_directory = DBConfig().options.extension_directory; -} - -Value ExtensionDirectorySetting::GetSetting(const ClientContext &context) { - return Value(DBConfig::GetConfig(context).options.extension_directory); -} - -//===--------------------------------------------------------------------===// -// External Threads Setting -//===--------------------------------------------------------------------===// -void ExternalThreadsSetting::SetGlobal(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); - } - config.options.external_threads = new_external_threads; -} - -void ExternalThreadsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - idx_t new_external_threads = DBConfig().options.external_threads; - if (db) { - TaskScheduler::GetScheduler(*db).SetThreads(config.options.maximum_threads, new_external_threads); - } - config.options.external_threads = new_external_threads; -} - -Value ExternalThreadsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BIGINT(NumericCast(config.options.external_threads)); -} - -//===--------------------------------------------------------------------===// -// File Search Path -//===--------------------------------------------------------------------===// -void FileSearchPathSetting::ResetLocal(ClientContext &context) { - auto &client_data = ClientData::Get(context); - client_data.file_search_path.clear(); -} - -void FileSearchPathSetting::SetLocal(ClientContext &context, const Value &input) { - auto parameter = input.ToString(); - auto &client_data = ClientData::Get(context); - client_data.file_search_path = parameter; -} - -Value FileSearchPathSetting::GetSetting(const ClientContext &context) { - auto &client_data = ClientData::Get(context); - return Value(client_data.file_search_path); -} - -//===--------------------------------------------------------------------===// -// Force Compression -//===--------------------------------------------------------------------===// -void ForceCompressionSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto compression = StringUtil::Lower(input.ToString()); - if (compression == "none" || compression == "auto") { - config.options.force_compression = CompressionType::COMPRESSION_AUTO; - } else { - auto compression_type = CompressionTypeFromString(compression); - if (CompressionTypeIsDeprecated(compression_type)) { - throw ParserException("Attempted to force a deprecated compression type (%s)", - 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 = DBConfig().options.force_compression; -} - -Value ForceCompressionSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(*context.db); - return CompressionTypeToString(config.options.force_compression); -} - -//===--------------------------------------------------------------------===// -// 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"); - } - config.options.force_bitpacking_mode = mode; -} - -void ForceBitpackingModeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.force_bitpacking_mode = DBConfig().options.force_bitpacking_mode; -} - -Value ForceBitpackingModeSetting::GetSetting(const ClientContext &context) { - return Value(BitpackingModeToString(context.db->config.options.force_bitpacking_mode)); -} - -//===--------------------------------------------------------------------===// -// Home Directory -//===--------------------------------------------------------------------===// -void HomeDirectorySetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).home_directory = ClientConfig().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"); - } - - config.home_directory = input.IsNull() ? string() : input.ToString(); -} - -Value HomeDirectorySetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value(config.home_directory); -} - -//===--------------------------------------------------------------------===// -// HTTP Proxy -//===--------------------------------------------------------------------===// -void HTTPProxy::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.http_proxy = DBConfig().options.http_proxy; -} - -void HTTPProxy::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter) { - config.options.http_proxy = parameter.GetValue(); -} - -Value HTTPProxy::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return config.options.http_proxy; -} - -//===--------------------------------------------------------------------===// -// HTTP Proxy Username -//===--------------------------------------------------------------------===// -void HTTPProxyUsername::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.http_proxy_username = DBConfig().options.http_proxy_username; -} - -void HTTPProxyUsername::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter) { - config.options.http_proxy_username = parameter.GetValue(); -} - -Value HTTPProxyUsername::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return config.options.http_proxy_username; -} - -//===--------------------------------------------------------------------===// -// HTTP Proxy Password -//===--------------------------------------------------------------------===// -void HTTPProxyPassword::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.http_proxy_password = DBConfig().options.http_proxy_password; -} - -void HTTPProxyPassword::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter) { - config.options.http_proxy_password = parameter.GetValue(); -} - -Value HTTPProxyPassword::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return config.options.http_proxy_password; -} - -//===--------------------------------------------------------------------===// -// Integer Division -//===--------------------------------------------------------------------===// -void IntegerDivisionSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).integer_division = ClientConfig().integer_division; -} - -void IntegerDivisionSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.integer_division = input.GetValue(); -} - -Value IntegerDivisionSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value(config.integer_division); -} - -//===--------------------------------------------------------------------===// -// Log Query Path -//===--------------------------------------------------------------------===// -void LogQueryPathSetting::ResetLocal(ClientContext &context) { - auto &client_data = ClientData::Get(context); - // TODO: verify that this does the right thing - client_data.log_query_writer = std::move(ClientData(context).log_query_writer); -} - -void LogQueryPathSetting::SetLocal(ClientContext &context, const Value &input) { - auto &client_data = ClientData::Get(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, - BufferedFileWriter::DEFAULT_OPEN_FLAGS); - } -} - -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(); -} - -//===--------------------------------------------------------------------===// -// Lock Configuration -//===--------------------------------------------------------------------===// -void LockConfigurationSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto new_value = input.GetValue(); - config.options.lock_configuration = new_value; -} - -void LockConfigurationSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.lock_configuration = DBConfig().options.lock_configuration; -} - -Value LockConfigurationSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.lock_configuration); -} - -//===--------------------------------------------------------------------===// -// IEEE Floating Points -//===--------------------------------------------------------------------===// -void IEEEFloatingPointOpsSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).ieee_floating_point_ops = ClientConfig().ieee_floating_point_ops; -} - -void IEEEFloatingPointOpsSetting::SetLocal(ClientContext &context, const Value &input) { - ClientConfig::GetConfig(context).ieee_floating_point_ops = input.GetValue(); -} - -Value IEEEFloatingPointOpsSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::BOOLEAN(config.ieee_floating_point_ops); -} - -//===--------------------------------------------------------------------===// -// Immediate Transaction Mode -//===--------------------------------------------------------------------===// -void ImmediateTransactionModeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.immediate_transaction_mode = BooleanValue::Get(input); -} - -void ImmediateTransactionModeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.immediate_transaction_mode = DBConfig().options.immediate_transaction_mode; -} - -Value ImmediateTransactionModeSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.immediate_transaction_mode); -} - -//===--------------------------------------------------------------------===// -// Maximum Expression Depth -//===--------------------------------------------------------------------===// -void MaximumExpressionDepthSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).max_expression_depth = ClientConfig().max_expression_depth; -} - -void MaximumExpressionDepthSetting::SetLocal(ClientContext &context, const Value &input) { - ClientConfig::GetConfig(context).max_expression_depth = input.GetValue(); -} - -Value MaximumExpressionDepthSetting::GetSetting(const ClientContext &context) { - return Value::UBIGINT(ClientConfig::GetConfig(context).max_expression_depth); -} - -//===--------------------------------------------------------------------===// -// Maximum Memory -//===--------------------------------------------------------------------===// -void MaximumMemorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.maximum_memory = DBConfig::ParseMemoryLimit(input.ToString()); - if (db) { - BufferManager::GetBufferManager(*db).SetMemoryLimit(config.options.maximum_memory); - } -} - -void MaximumMemorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.SetDefaultMaxMemory(); -} - -Value MaximumMemorySetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(StringUtil::BytesToHumanReadableString(config.options.maximum_memory)); -} - -//===--------------------------------------------------------------------===// -// Streaming Buffer Size -//===--------------------------------------------------------------------===// -void StreamingBufferSize::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.streaming_buffer_size = DBConfig::ParseMemoryLimit(input.ToString()); -} - -void StreamingBufferSize::ResetLocal(ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - config.SetDefaultStreamingBufferSize(); -} - -Value StreamingBufferSize::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value(StringUtil::BytesToHumanReadableString(config.streaming_buffer_size)); -} - -//===--------------------------------------------------------------------===// -// Maximum Temp Directory Size -//===--------------------------------------------------------------------===// -void MaximumTempDirectorySize::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto maximum_swap_space = DBConfig::ParseMemoryLimit(input.ToString()); - if (maximum_swap_space == DConstants::INVALID_INDEX) { - // We use INVALID_INDEX to indicate that the value is not set by the user - // use one lower to indicate 'unlimited' - maximum_swap_space--; - } - if (!db) { - config.options.maximum_swap_space = maximum_swap_space; - return; - } - auto &buffer_manager = BufferManager::GetBufferManager(*db); - buffer_manager.SetSwapLimit(maximum_swap_space); - config.options.maximum_swap_space = maximum_swap_space; -} - -void MaximumTempDirectorySize::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.maximum_swap_space = DConstants::INVALID_INDEX; - if (!db) { - return; - } - auto &buffer_manager = BufferManager::GetBufferManager(*db); - buffer_manager.SetSwapLimit(); -} - -Value MaximumTempDirectorySize::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - if (config.options.maximum_swap_space != DConstants::INVALID_INDEX) { - // Explicitly set by the user - return Value(StringUtil::BytesToHumanReadableString(config.options.maximum_swap_space)); - } - auto &buffer_manager = BufferManager::GetBufferManager(context); - // Database is initialized, use the setting from the temporary directory - auto max_swap = buffer_manager.GetMaxSwap(); - if (max_swap.IsValid()) { - return Value(StringUtil::BytesToHumanReadableString(max_swap.GetIndex())); - } else { - // The temp directory has not been used yet - return Value(StringUtil::BytesToHumanReadableString(0)); - } -} - -//===--------------------------------------------------------------------===// -// Maximum Vacuum Size -//===--------------------------------------------------------------------===// -void MaximumVacuumTasks::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.max_vacuum_tasks = input.GetValue(); -} - -void MaximumVacuumTasks::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.max_vacuum_tasks = DBConfig().options.max_vacuum_tasks; -} - -Value MaximumVacuumTasks::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::UBIGINT(config.options.max_vacuum_tasks); -} - -//===--------------------------------------------------------------------===// -// Merge Join Threshold -//===--------------------------------------------------------------------===// -void MergeJoinThreshold::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.merge_join_threshold = input.GetValue(); -} - -void MergeJoinThreshold::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).merge_join_threshold = ClientConfig().merge_join_threshold; -} - -Value MergeJoinThreshold::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::UBIGINT(config.merge_join_threshold); -} - -//===--------------------------------------------------------------------===// -// Nested Loop Join Threshold -//===--------------------------------------------------------------------===// -void NestedLoopJoinThreshold::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.nested_loop_join_threshold = input.GetValue(); -} - -void NestedLoopJoinThreshold::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).nested_loop_join_threshold = ClientConfig().nested_loop_join_threshold; -} - -Value NestedLoopJoinThreshold::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::UBIGINT(config.nested_loop_join_threshold); -} - -//===--------------------------------------------------------------------===// -// Old Implicit Casting -//===--------------------------------------------------------------------===// -void OldImplicitCasting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.old_implicit_casting = input.GetValue(); -} - -void OldImplicitCasting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.old_implicit_casting = DBConfig().options.old_implicit_casting; -} - -Value OldImplicitCasting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.old_implicit_casting); -} - -//===--------------------------------------------------------------------===// -// Old Implicit Casting -//===--------------------------------------------------------------------===// -void OrderByNonIntegerLiteral::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).order_by_non_integer_literal = ClientConfig().order_by_non_integer_literal; -} - -void OrderByNonIntegerLiteral::SetLocal(ClientContext &context, const Value &input) { - ClientConfig::GetConfig(context).order_by_non_integer_literal = input.GetValue(); -} - -Value OrderByNonIntegerLiteral::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::BOOLEAN(config.order_by_non_integer_literal); -} - -//===--------------------------------------------------------------------===// -// Partitioned Write Flush Threshold -//===--------------------------------------------------------------------===// -void PartitionedWriteFlushThreshold::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).partitioned_write_flush_threshold = - ClientConfig().partitioned_write_flush_threshold; -} - -void PartitionedWriteFlushThreshold::SetLocal(ClientContext &context, const Value &input) { - ClientConfig::GetConfig(context).partitioned_write_flush_threshold = input.GetValue(); -} - -Value PartitionedWriteFlushThreshold::GetSetting(const ClientContext &context) { - return Value::UBIGINT(ClientConfig::GetConfig(context).partitioned_write_flush_threshold); -} - -//===--------------------------------------------------------------------===// -// Partitioned Write Flush Threshold -//===--------------------------------------------------------------------===// -void PartitionedWriteMaxOpenFiles::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).partitioned_write_max_open_files = ClientConfig().partitioned_write_max_open_files; -} - -void PartitionedWriteMaxOpenFiles::SetLocal(ClientContext &context, const Value &input) { - ClientConfig::GetConfig(context).partitioned_write_max_open_files = input.GetValue(); -} - -Value PartitionedWriteMaxOpenFiles::GetSetting(const ClientContext &context) { - return Value::UBIGINT(ClientConfig::GetConfig(context).partitioned_write_max_open_files); -} - -//===--------------------------------------------------------------------===// -// Preferred block allocation size -//===--------------------------------------------------------------------===// -void DefaultBlockAllocSize::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto block_alloc_size = input.GetValue(); - Storage::VerifyBlockAllocSize(block_alloc_size); - config.options.default_block_alloc_size = block_alloc_size; -} - -void DefaultBlockAllocSize::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.default_block_alloc_size = DBConfig().options.default_block_alloc_size; -} - -Value DefaultBlockAllocSize::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::UBIGINT(config.options.default_block_alloc_size); -} - -//===--------------------------------------------------------------------===// -// Index scan percentage -//===--------------------------------------------------------------------===// -void IndexScanPercentage::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto index_scan_percentage = input.GetValue(); - if (index_scan_percentage < 0 || index_scan_percentage > 1.0) { - throw InvalidInputException("the index scan percentage must be within [0, 1]"); - } - config.options.index_scan_percentage = index_scan_percentage; -} - -void IndexScanPercentage::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.index_scan_percentage = DBConfig().options.index_scan_percentage; -} - -Value IndexScanPercentage::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::DOUBLE(config.options.index_scan_percentage); -} - -//===--------------------------------------------------------------------===// -// Index scan max count -//===--------------------------------------------------------------------===// -void IndexScanMaxCount::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto index_scan_max_count = input.GetValue(); - config.options.index_scan_max_count = index_scan_max_count; -} - -void IndexScanMaxCount::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.index_scan_max_count = DBConfig().options.index_scan_max_count; -} - -Value IndexScanMaxCount::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::UBIGINT(config.options.index_scan_max_count); -} - -//===--------------------------------------------------------------------===// -// Password Setting -//===--------------------------------------------------------------------===// -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 Hash Threshold -//===--------------------------------------------------------------------===// -void PerfectHashThresholdSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).perfect_ht_threshold = ClientConfig().perfect_ht_threshold; -} - -void PerfectHashThresholdSetting::SetLocal(ClientContext &context, const Value &input) { - auto bits = input.GetValue(); - if (bits < 0 || bits > 32) { - throw ParserException("Perfect HT threshold out of range: should be within range 0 - 32"); - } - ClientConfig::GetConfig(context).perfect_ht_threshold = NumericCast(bits); -} - -Value PerfectHashThresholdSetting::GetSetting(const ClientContext &context) { - return Value::BIGINT(NumericCast(ClientConfig::GetConfig(context).perfect_ht_threshold)); -} - -//===--------------------------------------------------------------------===// -// Pivot Filter Threshold -//===--------------------------------------------------------------------===// -void PivotFilterThreshold::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).pivot_filter_threshold = ClientConfig().pivot_filter_threshold; -} - -void PivotFilterThreshold::SetLocal(ClientContext &context, const Value &input) { - ClientConfig::GetConfig(context).pivot_filter_threshold = input.GetValue(); -} - -Value PivotFilterThreshold::GetSetting(const ClientContext &context) { - return Value::BIGINT(NumericCast(ClientConfig::GetConfig(context).pivot_filter_threshold)); -} - -//===--------------------------------------------------------------------===// -// Pivot Limit -//===--------------------------------------------------------------------===// -void PivotLimitSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).pivot_limit = ClientConfig().pivot_limit; -} - -void PivotLimitSetting::SetLocal(ClientContext &context, const Value &input) { - ClientConfig::GetConfig(context).pivot_limit = input.GetValue(); -} - -Value PivotLimitSetting::GetSetting(const ClientContext &context) { - return Value::BIGINT(NumericCast(ClientConfig::GetConfig(context).pivot_limit)); -} - -//===--------------------------------------------------------------------===// -// PreserveIdentifierCase -//===--------------------------------------------------------------------===// -void PreserveIdentifierCase::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).preserve_identifier_case = ClientConfig().preserve_identifier_case; -} - -void PreserveIdentifierCase::SetLocal(ClientContext &context, const Value &input) { - ClientConfig::GetConfig(context).preserve_identifier_case = input.GetValue(); -} - -Value PreserveIdentifierCase::GetSetting(const ClientContext &context) { - return Value::BOOLEAN(ClientConfig::GetConfig(context).preserve_identifier_case); -} - -//===--------------------------------------------------------------------===// -// PreserveInsertionOrder -//===--------------------------------------------------------------------===// -void PreserveInsertionOrder::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.preserve_insertion_order = input.GetValue(); -} - -void PreserveInsertionOrder::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.preserve_insertion_order = DBConfig().options.preserve_insertion_order; -} - -Value PreserveInsertionOrder::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.preserve_insertion_order); -} - -//===--------------------------------------------------------------------===// -// ExportLargeBufferArrow -//===--------------------------------------------------------------------===// -void ExportLargeBufferArrow::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto export_large_buffers_arrow = input.GetValue(); - - config.options.arrow_offset_size = export_large_buffers_arrow ? ArrowOffsetSize::LARGE : ArrowOffsetSize::REGULAR; -} - -void ExportLargeBufferArrow::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.arrow_offset_size = DBConfig().options.arrow_offset_size; -} - -Value ExportLargeBufferArrow::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - bool export_large_buffers_arrow = config.options.arrow_offset_size == ArrowOffsetSize::LARGE; - return Value::BOOLEAN(export_large_buffers_arrow); -} - -//===--------------------------------------------------------------------===// -// ArrowOutputListView -//===--------------------------------------------------------------------===// -void ArrowOutputListView::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto arrow_output_list_view = input.GetValue(); - - config.options.arrow_use_list_view = arrow_output_list_view; -} - -void ArrowOutputListView::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.arrow_use_list_view = DBConfig().options.arrow_use_list_view; -} - -Value ArrowOutputListView::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - bool arrow_output_list_view = config.options.arrow_use_list_view; - return Value::BOOLEAN(arrow_output_list_view); -} - -//===--------------------------------------------------------------------===// -// LosslessConversionArrow -//===--------------------------------------------------------------------===// -void LosslessConversionArrow::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto arrow_arrow_lossless_conversion = input.GetValue(); - - config.options.arrow_arrow_lossless_conversion = arrow_arrow_lossless_conversion; -} - -void LosslessConversionArrow::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.arrow_arrow_lossless_conversion = DBConfig().options.arrow_arrow_lossless_conversion; -} - -Value LosslessConversionArrow::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - bool arrow_arrow_lossless_conversion = config.options.arrow_arrow_lossless_conversion; - return Value::BOOLEAN(arrow_arrow_lossless_conversion); -} - -//===--------------------------------------------------------------------===// -// ProduceArrowStringView -//===--------------------------------------------------------------------===// -void ProduceArrowStringView::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.produce_arrow_string_views = input.GetValue(); -} - -void ProduceArrowStringView::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.produce_arrow_string_views = DBConfig().options.produce_arrow_string_views; -} - -Value ProduceArrowStringView::GetSetting(const ClientContext &context) { - return Value::BOOLEAN(DBConfig::GetConfig(context).options.produce_arrow_string_views); -} - -//===--------------------------------------------------------------------===// -// ScalarSubqueryErrorOnMultipleRows -//===--------------------------------------------------------------------===// -void ScalarSubqueryErrorOnMultipleRows::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).scalar_subquery_error_on_multiple_rows = - ClientConfig().scalar_subquery_error_on_multiple_rows; -} - -void ScalarSubqueryErrorOnMultipleRows::SetLocal(ClientContext &context, const Value &input) { - ClientConfig::GetConfig(context).scalar_subquery_error_on_multiple_rows = input.GetValue(); -} - -Value ScalarSubqueryErrorOnMultipleRows::GetSetting(const ClientContext &context) { - return Value::BOOLEAN(ClientConfig::GetConfig(context).scalar_subquery_error_on_multiple_rows); -} - -//===--------------------------------------------------------------------===// -// Profile Output -//===--------------------------------------------------------------------===// -void ProfileOutputSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).profiler_save_location = ClientConfig().profiler_save_location; -} - -void ProfileOutputSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - auto parameter = input.ToString(); - config.profiler_save_location = parameter; -} - -Value ProfileOutputSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value(config.profiler_save_location); -} - -//===--------------------------------------------------------------------===// -// Profiling Mode -//===--------------------------------------------------------------------===// -void ProfilingModeSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).enable_profiler = ClientConfig().enable_profiler; - ClientConfig::GetConfig(context).enable_detailed_profiling = ClientConfig().enable_detailed_profiling; - ClientConfig::GetConfig(context).emit_profiler_output = ClientConfig().emit_profiler_output; - ClientConfig::GetConfig(context).profiler_settings = ClientConfig().profiler_settings; -} - -void ProfilingModeSetting::SetLocal(ClientContext &context, const Value &input) { - auto parameter = StringUtil::Lower(input.ToString()); - auto &config = ClientConfig::GetConfig(context); - if (parameter == "standard") { - config.enable_profiler = true; - config.enable_detailed_profiling = false; - } else if (parameter == "detailed") { - config.enable_profiler = true; - config.enable_detailed_profiling = true; - - // add optimizer settings to the profiler settings - auto optimizer_settings = MetricsUtils::GetOptimizerMetrics(); - for (auto &setting : optimizer_settings) { - config.profiler_settings.insert(setting); - } - - // add the phase timing settings to the profiler settings - auto phase_timing_settings = MetricsUtils::GetPhaseTimingMetrics(); - for (auto &setting : phase_timing_settings) { - config.profiler_settings.insert(setting); - } - } else { - throw ParserException("Unrecognized profiling mode \"%s\", supported formats: [standard, detailed]", parameter); - } -} - -Value ProfilingModeSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - if (!config.enable_profiler) { - return Value(); - } - return Value(config.enable_detailed_profiling ? "detailed" : "standard"); -} - -//===--------------------------------------------------------------------===// -// Progress Bar Time -//===--------------------------------------------------------------------===// -void ProgressBarTimeSetting::ResetLocal(ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - ProgressBar::SystemOverrideCheck(config); - config.wait_time = ClientConfig().wait_time; - config.enable_progress_bar = ClientConfig().enable_progress_bar; -} - -void ProgressBarTimeSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - ProgressBar::SystemOverrideCheck(config); - config.wait_time = input.GetValue(); - config.enable_progress_bar = true; -} - -Value ProgressBarTimeSetting::GetSetting(const ClientContext &context) { - return Value::BIGINT(ClientConfig::GetConfig(context).wait_time); -} - -//===--------------------------------------------------------------------===// -// Schema -//===--------------------------------------------------------------------===// -void SchemaSetting::ResetLocal(ClientContext &context) { - // FIXME: catalog_search_path is controlled by both SchemaSetting and SearchPathSetting - auto &client_data = ClientData::Get(context); - client_data.catalog_search_path->Reset(); -} - -void SchemaSetting::SetLocal(ClientContext &context, const Value &input) { - auto parameter = input.ToString(); - auto &client_data = ClientData::Get(context); - client_data.catalog_search_path->Set(CatalogSearchEntry::Parse(parameter), CatalogSetPathType::SET_SCHEMA); -} - -Value SchemaSetting::GetSetting(const ClientContext &context) { - auto &client_data = ClientData::Get(context); - return client_data.catalog_search_path->GetDefault().schema; -} - -//===--------------------------------------------------------------------===// -// Search Path -//===--------------------------------------------------------------------===// -void SearchPathSetting::ResetLocal(ClientContext &context) { - // FIXME: catalog_search_path is controlled by both SchemaSetting and SearchPathSetting - auto &client_data = ClientData::Get(context); - client_data.catalog_search_path->Reset(); -} - -void SearchPathSetting::SetLocal(ClientContext &context, const Value &input) { - auto parameter = input.ToString(); - auto &client_data = ClientData::Get(context); - client_data.catalog_search_path->Set(CatalogSearchEntry::ParseList(parameter), CatalogSetPathType::SET_SCHEMAS); -} - -Value SearchPathSetting::GetSetting(const ClientContext &context) { - auto &client_data = ClientData::Get(context); - auto &set_paths = client_data.catalog_search_path->GetSetPaths(); - return Value(CatalogSearchEntry::ListToString(set_paths)); -} - -//===--------------------------------------------------------------------===// -// Secret Directory -//===--------------------------------------------------------------------===// -void SecretDirectorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.secret_manager->SetPersistentSecretPath(input.ToString()); -} - -void SecretDirectorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.secret_manager->ResetPersistentSecretPath(); -} - -Value SecretDirectorySetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return config.secret_manager->PersistentSecretPath(); -} - -//===--------------------------------------------------------------------===// -// Temp Directory -//===--------------------------------------------------------------------===// -void TempDirectorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.temporary_directory = input.ToString(); - config.options.use_temporary_directory = !config.options.temporary_directory.empty(); - if (db) { - auto &buffer_manager = BufferManager::GetBufferManager(*db); - buffer_manager.SetTemporaryDirectory(config.options.temporary_directory); - } -} - -void TempDirectorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.SetDefaultTempDirectory(); - - config.options.use_temporary_directory = DBConfig().options.use_temporary_directory; - if (db) { - auto &buffer_manager = BufferManager::GetBufferManager(*db); - buffer_manager.SetTemporaryDirectory(config.options.temporary_directory); - } -} - -Value TempDirectorySetting::GetSetting(const ClientContext &context) { - auto &buffer_manager = BufferManager::GetBufferManager(context); - return Value(buffer_manager.GetTemporaryDirectory()); -} - -//===--------------------------------------------------------------------===// -// Threads Setting -//===--------------------------------------------------------------------===// -void ThreadsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto new_val = input.GetValue(); - if (new_val < 1) { - throw SyntaxException("Must have at least 1 thread!"); - } - auto new_maximum_threads = NumericCast(new_val); - if (db) { - TaskScheduler::GetScheduler(*db).SetThreads(new_maximum_threads, config.options.external_threads); - } - config.options.maximum_threads = new_maximum_threads; -} - -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); - } - config.options.maximum_threads = new_maximum_threads; -} - -Value ThreadsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BIGINT(NumericCast(config.options.maximum_threads)); -} - -//===--------------------------------------------------------------------===// -// Username Setting -//===--------------------------------------------------------------------===// -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(); -} - -//===--------------------------------------------------------------------===// -// Allocator Flush Threshold -//===--------------------------------------------------------------------===// -void AllocatorFlushThreshold::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.allocator_flush_threshold = DBConfig::ParseMemoryLimit(input.ToString()); - if (db) { - TaskScheduler::GetScheduler(*db).SetAllocatorFlushTreshold(config.options.allocator_flush_threshold); - } -} - -void AllocatorFlushThreshold::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.allocator_flush_threshold = DBConfig().options.allocator_flush_threshold; - if (db) { - TaskScheduler::GetScheduler(*db).SetAllocatorFlushTreshold(config.options.allocator_flush_threshold); - } -} - -Value AllocatorFlushThreshold::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(StringUtil::BytesToHumanReadableString(config.options.allocator_flush_threshold)); -} - -//===--------------------------------------------------------------------===// -// Allocator Bulk Deallocation Flush Threshold -//===--------------------------------------------------------------------===// -void AllocatorBulkDeallocationFlushThreshold::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.allocator_bulk_deallocation_flush_threshold = DBConfig::ParseMemoryLimit(input.ToString()); - if (db) { - BufferManager::GetBufferManager(*db).GetBufferPool().SetAllocatorBulkDeallocationFlushThreshold( - config.options.allocator_bulk_deallocation_flush_threshold); - } -} - -void AllocatorBulkDeallocationFlushThreshold::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.allocator_bulk_deallocation_flush_threshold = - DBConfig().options.allocator_bulk_deallocation_flush_threshold; - if (db) { - BufferManager::GetBufferManager(*db).GetBufferPool().SetAllocatorBulkDeallocationFlushThreshold( - config.options.allocator_bulk_deallocation_flush_threshold); - } -} - -Value AllocatorBulkDeallocationFlushThreshold::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(StringUtil::BytesToHumanReadableString(config.options.allocator_bulk_deallocation_flush_threshold)); -} - -//===--------------------------------------------------------------------===// -// Allocator Background Threads -//===--------------------------------------------------------------------===// -void AllocatorBackgroundThreadsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.allocator_background_threads = input.GetValue(); - if (db) { - TaskScheduler::GetScheduler(*db).SetAllocatorBackgroundThreads(config.options.allocator_background_threads); - } -} - -void AllocatorBackgroundThreadsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.allocator_background_threads = DBConfig().options.allocator_background_threads; - if (db) { - TaskScheduler::GetScheduler(*db).SetAllocatorBackgroundThreads(config.options.allocator_background_threads); - } -} - -Value AllocatorBackgroundThreadsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.allocator_background_threads); -} - -//===--------------------------------------------------------------------===// -// DuckDBApi Setting -//===--------------------------------------------------------------------===// - -void DuckDBApiSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto new_value = input.GetValue(); - if (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); -} - -//===--------------------------------------------------------------------===// -// CustomUserAgent Setting -//===--------------------------------------------------------------------===// - -void CustomUserAgentSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto new_value = input.GetValue(); - if (db) { - throw InvalidInputException("Cannot change custom_user_agent setting while database is running"); - } - config.options.custom_user_agent = - config.options.custom_user_agent.empty() ? new_value : config.options.custom_user_agent + " " + new_value; -} - -void CustomUserAgentSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (db) { - throw InvalidInputException("Cannot change custom_user_agent setting while database is running"); - } - config.options.custom_user_agent = DBConfig().options.custom_user_agent; -} - -Value CustomUserAgentSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.custom_user_agent); -} - -//===--------------------------------------------------------------------===// -// EnableHTTPLogging Setting -//===--------------------------------------------------------------------===// -void EnableHTTPLoggingSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).enable_http_logging = ClientConfig().enable_http_logging; -} - -void EnableHTTPLoggingSetting::SetLocal(ClientContext &context, const Value &input) { - ClientConfig::GetConfig(context).enable_http_logging = input.GetValue(); -} - -Value EnableHTTPLoggingSetting::GetSetting(const ClientContext &context) { - return Value(ClientConfig::GetConfig(context).enable_http_logging); -} - -//===--------------------------------------------------------------------===// -// HTTPLoggingOutput Setting -//===--------------------------------------------------------------------===// -void HTTPLoggingOutputSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).http_logging_output = ClientConfig().http_logging_output; -} - -void HTTPLoggingOutputSetting::SetLocal(ClientContext &context, const Value &input) { - ClientConfig::GetConfig(context).http_logging_output = input.GetValue(); -} - -Value HTTPLoggingOutputSetting::GetSetting(const ClientContext &context) { - return Value(ClientConfig::GetConfig(context).http_logging_output); -} - -} // namespace duckdb diff --git a/src/duckdb/src/optimizer/build_probe_side_optimizer.cpp b/src/duckdb/src/optimizer/build_probe_side_optimizer.cpp index 91ba551a9..cebafb774 100644 --- a/src/duckdb/src/optimizer/build_probe_side_optimizer.cpp +++ b/src/duckdb/src/optimizer/build_probe_side_optimizer.cpp @@ -3,11 +3,11 @@ #include "duckdb/common/enums/join_type.hpp" #include "duckdb/common/type_visitor.hpp" #include "duckdb/common/types/row/tuple_data_layout.hpp" -#include "duckdb/execution/physical_plan_generator.hpp" #include "duckdb/planner/operator/logical_any_join.hpp" #include "duckdb/planner/operator/logical_comparison_join.hpp" #include "duckdb/planner/operator/logical_get.hpp" #include "duckdb/planner/operator/logical_join.hpp" +#include "duckdb/planner/operator/logical_order.hpp" namespace duckdb { @@ -38,6 +38,7 @@ BuildProbeSideOptimizer::BuildProbeSideOptimizer(ClientContext &context, Logical GetRowidBindings(op, preferred_on_probe_side); op.ResolveOperatorTypes(); } + static void FlipChildren(LogicalOperator &op) { std::swap(op.children[0], op.children[1]); if (op.type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN || op.type == LogicalOperatorType::LOGICAL_DELIM_JOIN) { @@ -132,7 +133,7 @@ idx_t BuildProbeSideOptimizer::ChildHasJoins(LogicalOperator &op) { return ChildHasJoins(*op.children[0]); } -void BuildProbeSideOptimizer::TryFlipJoinChildren(LogicalOperator &op) { +void BuildProbeSideOptimizer::TryFlipJoinChildren(LogicalOperator &op) const { auto &left_child = *op.children[0]; auto &right_child = *op.children[1]; const auto lhs_cardinality = left_child.has_estimated_cardinality ? left_child.estimated_cardinality @@ -188,60 +189,60 @@ void BuildProbeSideOptimizer::TryFlipJoinChildren(LogicalOperator &op) { void BuildProbeSideOptimizer::VisitOperator(LogicalOperator &op) { switch (op.type) { + case LogicalOperatorType::LOGICAL_DELIM_JOIN: { + auto &join = op.Cast(); + if (HasInverseJoinType(join.join_type)) { + FlipChildren(join); + join.delim_flipped = true; + } + break; + } case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: { auto &join = op.Cast(); - switch (join.join_type) { - case JoinType::INNER: - case JoinType::OUTER: - TryFlipJoinChildren(join); - break; - case JoinType::LEFT: - case JoinType::RIGHT: - if (join.right_projection_map.empty()) { - TryFlipJoinChildren(join); - } - break; case JoinType::SEMI: case JoinType::ANTI: { + // 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; - if (!PhysicalPlanGenerator::HasEquality(join.conditions, has_range)) { - // if the conditions have no equality, do not flip the children. - // There is no physical join operator (yet) that can do a right_semi/anti join. - break; + if (op.type == LogicalOperatorType::LOGICAL_ANY_JOIN || + (op.Cast().HasEquality(has_range) && !context.config.prefer_range_joins)) { + TryFlipJoinChildren(join); } - TryFlipJoinChildren(join); break; } default: - break; + if (HasInverseJoinType(join.join_type)) { + TryFlipJoinChildren(op); + } } break; } - case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: { - TryFlipJoinChildren(op); - break; - } - case LogicalOperatorType::LOGICAL_ANY_JOIN: { - auto &join = op.Cast(); - if (join.join_type == JoinType::LEFT && join.right_projection_map.empty()) { - TryFlipJoinChildren(join); - } else if (join.join_type == JoinType::INNER) { - TryFlipJoinChildren(join); + case LogicalOperatorType::LOGICAL_ANY_JOIN: + case LogicalOperatorType::LOGICAL_ASOF_JOIN: { + auto &join = op.Cast(); + // We do not yet support the RIGHT_SEMI or RIGHT_ANTI join types for these, so don't try to flip + switch (join.join_type) { + case JoinType::SEMI: + case JoinType::ANTI: + break; // RIGHT_SEMI/RIGHT_ANTI not supported yet for ANY/ASOF + default: + // We cannot flip projection maps are set (YET), but not flipping is worse than just clearing them + // They will be set in the 2nd round of ColumnLifetimeAnalyzer + join.left_projection_map.clear(); + join.right_projection_map.clear(); + TryFlipJoinChildren(op); } break; } - case LogicalOperatorType::LOGICAL_DELIM_JOIN: { - auto &join = op.Cast(); - if (HasInverseJoinType(join.join_type) && join.right_projection_map.empty()) { - FlipChildren(join); - join.delim_flipped = true; - } + case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: { + TryFlipJoinChildren(op); break; } default: break; } + VisitOperatorChildren(op); } diff --git a/src/duckdb/src/optimizer/column_lifetime_analyzer.cpp b/src/duckdb/src/optimizer/column_lifetime_analyzer.cpp index 4df51ba75..f84225eaf 100644 --- a/src/duckdb/src/optimizer/column_lifetime_analyzer.cpp +++ b/src/duckdb/src/optimizer/column_lifetime_analyzer.cpp @@ -1,14 +1,20 @@ #include "duckdb/optimizer/column_lifetime_analyzer.hpp" +#include "duckdb/main/client_context.hpp" +#include "duckdb/optimizer/column_binding_replacer.hpp" +#include "duckdb/optimizer/optimizer.hpp" +#include "duckdb/optimizer/topn_optimizer.hpp" #include "duckdb/planner/expression/bound_columnref_expression.hpp" +#include "duckdb/planner/expression/bound_constant_expression.hpp" +#include "duckdb/planner/expression_iterator.hpp" #include "duckdb/planner/operator/logical_comparison_join.hpp" -#include "duckdb/planner/operator/logical_order.hpp" #include "duckdb/planner/operator/logical_filter.hpp" -#include "duckdb/planner/expression_iterator.hpp" +#include "duckdb/planner/operator/logical_order.hpp" +#include "duckdb/planner/operator/logical_projection.hpp" namespace duckdb { -void ColumnLifetimeAnalyzer::ExtractUnusedColumnBindings(vector bindings, +void ColumnLifetimeAnalyzer::ExtractUnusedColumnBindings(const vector &bindings, column_binding_set_t &unused_bindings) { for (idx_t i = 0; i < bindings.size(); i++) { if (column_references.find(bindings[i]) == column_references.end()) { @@ -37,15 +43,8 @@ void ColumnLifetimeAnalyzer::GenerateProjectionMap(vector binding } void ColumnLifetimeAnalyzer::StandardVisitOperator(LogicalOperator &op) { - LogicalOperatorVisitor::VisitOperatorExpressions(op); - if (op.type == LogicalOperatorType::LOGICAL_DELIM_JOIN) { - // visit the duplicate eliminated columns on the LHS, if any - auto &delim_join = op.Cast(); - for (auto &expr : delim_join.duplicate_eliminated_columns) { - VisitExpression(&expr); - } - } - LogicalOperatorVisitor::VisitOperatorChildren(op); + VisitOperatorExpressions(op); + VisitOperatorChildren(op); } void ExtractColumnBindings(Expression &expr, vector &bindings) { @@ -53,92 +52,87 @@ void ExtractColumnBindings(Expression &expr, vector &bindings) { auto &bound_ref = expr.Cast(); bindings.push_back(bound_ref.binding); } - ExpressionIterator::EnumerateChildren(expr, [&](Expression &expr) { ExtractColumnBindings(expr, bindings); }); + ExpressionIterator::EnumerateChildren(expr, [&](Expression &child) { ExtractColumnBindings(child, bindings); }); } void ColumnLifetimeAnalyzer::VisitOperator(LogicalOperator &op) { + Verify(op); + if (TopN::CanOptimize(op) && op.children[0]->type == LogicalOperatorType::LOGICAL_ORDER_BY) { + // Let's not mess with this, TopN is more important than projection maps + // TopN does not support a projection map like Order does + VisitOperatorExpressions(op); // Visit LIMIT + VisitOperatorExpressions(*op.children[0]); // Visit ORDER + StandardVisitOperator(*op.children[0]->children[0]); // Recurse into child of ORDER + return; + } switch (op.type) { case LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY: { // FIXME: groups that are not referenced can be removed from projection // recurse into the children of the aggregate - ColumnLifetimeAnalyzer analyzer; - analyzer.VisitOperatorExpressions(op); - analyzer.VisitOperator(*op.children[0]); + ColumnLifetimeAnalyzer analyzer(optimizer, root); + analyzer.StandardVisitOperator(op); return; } case LogicalOperatorType::LOGICAL_ASOF_JOIN: case LogicalOperatorType::LOGICAL_DELIM_JOIN: case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: { + auto &comp_join = op.Cast(); if (everything_referenced) { break; } - auto &comp_join = op.Cast(); - // FIXME for now, we only push into the projection map for equality (hash) joins - // FIXME: add projection to LHS as well - bool has_equality = false; - for (auto &cond : comp_join.conditions) { - if (cond.comparison == ExpressionType::COMPARE_EQUAL) { - has_equality = true; - break; - } - } - if (!has_equality) { - break; + + // FIXME: for now, we only push into the projection map for equality (hash) joins + idx_t has_range = 0; + if (!comp_join.HasEquality(has_range) || optimizer.context.config.prefer_range_joins) { + return; } - // visit current operator expressions so they are added to the referenced_columns - LogicalOperatorVisitor::VisitOperatorExpressions(op); - column_binding_set_t unused_bindings; - auto old_bindings = op.GetColumnBindings(); - ExtractUnusedColumnBindings(op.children[1]->GetColumnBindings(), unused_bindings); + column_binding_set_t lhs_unused; + column_binding_set_t rhs_unused; + ExtractUnusedColumnBindings(op.children[0]->GetColumnBindings(), lhs_unused); + ExtractUnusedColumnBindings(op.children[1]->GetColumnBindings(), rhs_unused); - // now recurse into the filter and its children - LogicalOperatorVisitor::VisitOperatorChildren(op); + StandardVisitOperator(op); // then generate the projection map - GenerateProjectionMap(op.children[1]->GetColumnBindings(), unused_bindings, comp_join.right_projection_map); - auto new_bindings = op.GetColumnBindings(); + if (op.type != LogicalOperatorType::LOGICAL_ASOF_JOIN) { + // FIXME: left_projection_map in ASOF join + GenerateProjectionMap(op.children[0]->GetColumnBindings(), lhs_unused, comp_join.left_projection_map); + } + GenerateProjectionMap(op.children[1]->GetColumnBindings(), rhs_unused, comp_join.right_projection_map); return; } case LogicalOperatorType::LOGICAL_UNION: case LogicalOperatorType::LOGICAL_EXCEPT: case LogicalOperatorType::LOGICAL_INTERSECT: - case LogicalOperatorType::LOGICAL_MATERIALIZED_CTE: + case LogicalOperatorType::LOGICAL_MATERIALIZED_CTE: { // for set operations/materialized CTEs we don't remove anything, just recursively visit the children // FIXME: for UNION we can remove unreferenced columns as long as everything_referenced is false (i.e. we // encounter a UNION node that is not preceded by a DISTINCT) - for (auto &child : op.children) { - ColumnLifetimeAnalyzer analyzer(true); - analyzer.VisitOperator(*child); - } + ColumnLifetimeAnalyzer analyzer(optimizer, root, true); + analyzer.StandardVisitOperator(op); return; + } case LogicalOperatorType::LOGICAL_PROJECTION: { // then recurse into the children of this projection - ColumnLifetimeAnalyzer analyzer; - analyzer.VisitOperatorExpressions(op); - analyzer.VisitOperator(*op.children[0]); + ColumnLifetimeAnalyzer analyzer(optimizer, root); + analyzer.StandardVisitOperator(op); return; } - case LogicalOperatorType::LOGICAL_ORDER_BY: - if (!everything_referenced) { - auto &order = op.Cast(); + case LogicalOperatorType::LOGICAL_ORDER_BY: { + auto &order = op.Cast(); + if (everything_referenced) { + break; + } - column_binding_set_t unused_bindings; - ExtractUnusedColumnBindings(op.children[0]->GetColumnBindings(), unused_bindings); + column_binding_set_t unused_bindings; + ExtractUnusedColumnBindings(op.children[0]->GetColumnBindings(), unused_bindings); - // now recurse into the order and its children - LogicalOperatorVisitor::VisitOperatorExpressions(op); - LogicalOperatorVisitor::VisitOperatorChildren(op); + StandardVisitOperator(op); - // then generate the projection map - GenerateProjectionMap(op.children[0]->GetColumnBindings(), unused_bindings, order.projections); - return; - } - // order by, for now reference all columns - // FIXME: for ORDER BY we remove columns below an ORDER BY, we just need to make sure that the projections are - // updated - everything_referenced = true; - break; + GenerateProjectionMap(op.children[0]->GetColumnBindings(), unused_bindings, order.projection_map); + return; + } case LogicalOperatorType::LOGICAL_DISTINCT: { // distinct, all projected columns are used for the DISTINCT computation // mark all columns as used and continue to the children @@ -151,22 +145,15 @@ void ColumnLifetimeAnalyzer::VisitOperator(LogicalOperator &op) { if (everything_referenced) { break; } - // first visit operator expressions to populate referenced columns - LogicalOperatorVisitor::VisitOperatorExpressions(op); + // filter, figure out which columns are not needed after the filter column_binding_set_t unused_bindings; ExtractUnusedColumnBindings(op.children[0]->GetColumnBindings(), unused_bindings); - // now recurse into the filter and its children - LogicalOperatorVisitor::VisitOperatorChildren(op); + StandardVisitOperator(op); // then generate the projection map GenerateProjectionMap(op.children[0]->GetColumnBindings(), unused_bindings, filter.projection_map); - auto bindings = filter.GetColumnBindings(); - - if (bindings.empty()) { - return; - } return; } @@ -176,6 +163,73 @@ void ColumnLifetimeAnalyzer::VisitOperator(LogicalOperator &op) { StandardVisitOperator(op); } +void ColumnLifetimeAnalyzer::Verify(LogicalOperator &op) { +#ifdef DEBUG + if (everything_referenced) { + return; + } + switch (op.type) { + case LogicalOperatorType::LOGICAL_ASOF_JOIN: + case LogicalOperatorType::LOGICAL_DELIM_JOIN: + case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: + AddVerificationProjection(op.children[0]); + if (op.Cast().join_type != JoinType::MARK) { // Can't mess up the mark_index + AddVerificationProjection(op.children[1]); + } + break; + case LogicalOperatorType::LOGICAL_ORDER_BY: + case LogicalOperatorType::LOGICAL_FILTER: + AddVerificationProjection(op.children[0]); + break; + default: + break; + } +#endif +} + +void ColumnLifetimeAnalyzer::AddVerificationProjection(unique_ptr &child) { + child->ResolveOperatorTypes(); + const auto child_types = child->types; + const auto child_bindings = child->GetColumnBindings(); + const auto column_count = child_bindings.size(); + + // If our child has columns [i, j], we will generate a projection like so [NULL, j, NULL, i, NULL] + const auto projection_column_count = column_count * 2 + 1; + vector> expressions; + expressions.reserve(projection_column_count); + + // First fill with all NULLs + for (idx_t col_idx = 0; col_idx < projection_column_count; col_idx++) { + expressions.emplace_back(make_uniq(Value(LogicalType::UTINYINT))); + } + + // Now place the "real" columns in their respective positions, while keeping track of which column becomes which + const auto table_index = optimizer.binder.GenerateTableIndex(); + ColumnBindingReplacer replacer; + for (idx_t col_idx = 0; col_idx < column_count; col_idx++) { + const auto &old_binding = child_bindings[col_idx]; + const auto new_col_idx = projection_column_count - 2 - col_idx * 2; + expressions[new_col_idx] = make_uniq(child_types[col_idx], old_binding); + replacer.replacement_bindings.emplace_back(old_binding, ColumnBinding(table_index, new_col_idx)); + } + + // Create a projection and swap the operators accordingly + auto projection = make_uniq(table_index, std::move(expressions)); + projection->children.emplace_back(std::move(child)); + child = std::move(projection); + + // Replace references to the old binding (higher up in the plan) with references to the new binding + replacer.stop_operator = child.get(); + replacer.VisitOperator(root); + + // Add new bindings to column_references, else they are considered "unused" + for (const auto &replacement_binding : replacer.replacement_bindings) { + if (column_references.find(replacement_binding.old_binding) != column_references.end()) { + column_references.insert(replacement_binding.new_binding); + } + } +} + unique_ptr ColumnLifetimeAnalyzer::VisitReplace(BoundColumnRefExpression &expr, unique_ptr *expr_ptr) { column_references.insert(expr.binding); diff --git a/src/duckdb/src/optimizer/common_aggregate_optimizer.cpp b/src/duckdb/src/optimizer/common_aggregate_optimizer.cpp index 435b94cd3..beb6295b0 100644 --- a/src/duckdb/src/optimizer/common_aggregate_optimizer.cpp +++ b/src/duckdb/src/optimizer/common_aggregate_optimizer.cpp @@ -1,21 +1,35 @@ #include "duckdb/optimizer/common_aggregate_optimizer.hpp" +#include "duckdb/parser/expression_map.hpp" #include "duckdb/planner/expression/bound_columnref_expression.hpp" #include "duckdb/planner/operator/logical_aggregate.hpp" -#include "duckdb/parser/expression_map.hpp" -#include "duckdb/planner/column_binding_map.hpp" namespace duckdb { +void CommonAggregateOptimizer::StandardVisitOperator(LogicalOperator &op) { + VisitOperatorChildren(op); + VisitOperatorExpressions(op); +} + void CommonAggregateOptimizer::VisitOperator(LogicalOperator &op) { - LogicalOperatorVisitor::VisitOperator(op); switch (op.type) { - case LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY: - ExtractCommonAggregates(op.Cast()); - break; + case LogicalOperatorType::LOGICAL_UNION: + case LogicalOperatorType::LOGICAL_EXCEPT: + case LogicalOperatorType::LOGICAL_INTERSECT: + case LogicalOperatorType::LOGICAL_MATERIALIZED_CTE: + case LogicalOperatorType::LOGICAL_PROJECTION: { + CommonAggregateOptimizer common_aggregate; + common_aggregate.StandardVisitOperator(op); + return; + } default: break; } + + StandardVisitOperator(op); + if (op.type == LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY) { + ExtractCommonAggregates(op.Cast()); + } } unique_ptr CommonAggregateOptimizer::VisitReplace(BoundColumnRefExpression &expr, diff --git a/src/duckdb/src/optimizer/compressed_materialization.cpp b/src/duckdb/src/optimizer/compressed_materialization.cpp index 3a8198077..5e6c30760 100644 --- a/src/duckdb/src/optimizer/compressed_materialization.cpp +++ b/src/duckdb/src/optimizer/compressed_materialization.cpp @@ -1,7 +1,7 @@ #include "duckdb/optimizer/compressed_materialization.hpp" #include "duckdb/execution/expression_executor.hpp" -#include "duckdb/function/scalar/compressed_materialization_functions.hpp" +#include "duckdb/function/scalar/compressed_materialization_utils.hpp" #include "duckdb/function/scalar/operators.hpp" #include "duckdb/optimizer/column_binding_replacer.hpp" #include "duckdb/optimizer/optimizer.hpp" @@ -333,7 +333,7 @@ static Value GetIntegralRangeValue(ClientContext &context, const LogicalType &ty vector> arguments; arguments.emplace_back(make_uniq(max)); arguments.emplace_back(make_uniq(min)); - BoundFunctionExpression sub(type, SubtractFun::GetFunction(type, type), std::move(arguments), nullptr); + BoundFunctionExpression sub(type, SubtractFunction::GetFunction(type, type), std::move(arguments), nullptr); Value result; if (ExpressionExecutor::TryEvaluateScalar(context, sub, result)) { @@ -401,7 +401,7 @@ unique_ptr CompressedMaterialization::GetStringCompress(uniq const auto max_string_length = StringStats::MaxStringLength(stats); LogicalType cast_type = LogicalType::INVALID; - for (const auto &compressed_type : CompressedMaterializationFunctions::StringTypes()) { + for (const auto &compressed_type : CMUtils::StringTypes()) { if (max_string_length < GetTypeIdSize(compressed_type.InternalType())) { cast_type = compressed_type; break; diff --git a/src/duckdb/src/optimizer/empty_result_pullup.cpp b/src/duckdb/src/optimizer/empty_result_pullup.cpp new file mode 100644 index 000000000..999ea1439 --- /dev/null +++ b/src/duckdb/src/optimizer/empty_result_pullup.cpp @@ -0,0 +1,93 @@ +#include "duckdb/optimizer/empty_result_pullup.hpp" +#include "duckdb/common/enums/logical_operator_type.hpp" +#include "duckdb/planner/operator/logical_comparison_join.hpp" +#include "duckdb/planner/operator/logical_empty_result.hpp" +#include "duckdb/planner/operator/logical_any_join.hpp" + +namespace duckdb { + +unique_ptr EmptyResultPullup::PullUpEmptyJoinChildren(unique_ptr op) { + JoinType join_type = JoinType::INVALID; + D_ASSERT(op->type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN || + op->type == LogicalOperatorType::LOGICAL_ANY_JOIN || op->type == LogicalOperatorType::LOGICAL_EXCEPT); + switch (op->type) { + case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: + join_type = op->Cast().join_type; + break; + case LogicalOperatorType::LOGICAL_ANY_JOIN: + join_type = op->Cast().join_type; + break; + case LogicalOperatorType::LOGICAL_EXCEPT: + join_type = JoinType::ANTI; + break; + case LogicalOperatorType::LOGICAL_INTERSECT: + join_type = JoinType::SEMI; + break; + default: + break; + } + + switch (join_type) { + case JoinType::SEMI: + case JoinType::INNER: { + for (auto &child : op->children) { + if (child->type == LogicalOperatorType::LOGICAL_EMPTY_RESULT) { + op = make_uniq(std::move(op)); + break; + } + } + break; + } + // TODO: For ANTI joins, if the right child is empty, you can replace the whole join with + // the left child + case JoinType::ANTI: + case JoinType::MARK: + case JoinType::SINGLE: + case JoinType::LEFT: { + if (op->children[0]->type == LogicalOperatorType::LOGICAL_EMPTY_RESULT) { + op = make_uniq(std::move(op)); + } + break; + } + default: + break; + } + return op; +} + +unique_ptr EmptyResultPullup::Optimize(unique_ptr op) { + for (idx_t i = 0; i < op->children.size(); i++) { + op->children[i] = Optimize(std::move(op->children[i])); + } + switch (op->type) { + case LogicalOperatorType::LOGICAL_PROJECTION: + case LogicalOperatorType::LOGICAL_FILTER: + case LogicalOperatorType::LOGICAL_DISTINCT: + case LogicalOperatorType::LOGICAL_WINDOW: + case LogicalOperatorType::LOGICAL_MATERIALIZED_CTE: + case LogicalOperatorType::LOGICAL_GET: + case LogicalOperatorType::LOGICAL_INTERSECT: + case LogicalOperatorType::LOGICAL_PIVOT: + case LogicalOperatorType::LOGICAL_ASOF_JOIN: + case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: { + for (auto &child : op->children) { + if (child->type == LogicalOperatorType::LOGICAL_EMPTY_RESULT) { + op = make_uniq(std::move(op)); + break; + } + } + return op; + } + case LogicalOperatorType::LOGICAL_EXCEPT: + case LogicalOperatorType::LOGICAL_ANY_JOIN: + case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: { + op = PullUpEmptyJoinChildren(std::move(op)); + break; + } + default: + break; + } + return op; +} + +} // namespace duckdb diff --git a/src/duckdb/src/optimizer/expression_rewriter.cpp b/src/duckdb/src/optimizer/expression_rewriter.cpp index fea861e9d..a8ab28358 100644 --- a/src/duckdb/src/optimizer/expression_rewriter.cpp +++ b/src/duckdb/src/optimizer/expression_rewriter.cpp @@ -4,6 +4,7 @@ #include "duckdb/planner/expression_iterator.hpp" #include "duckdb/planner/operator/logical_filter.hpp" #include "duckdb/function/scalar/generic_functions.hpp" +#include "duckdb/function/scalar/generic_common.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" @@ -48,9 +49,11 @@ unique_ptr ExpressionRewriter::ConstantOrNull(unique_ptr unique_ptr ExpressionRewriter::ConstantOrNull(vector> children, Value value) { auto type = value.type(); + auto func = ConstantOrNullFun::GetFunction(); + func.arguments[0] = type; + func.return_type = type; children.insert(children.begin(), make_uniq(value)); - return make_uniq(type, ConstantOrNull::GetFunction(type), std::move(children), - ConstantOrNull::Bind(std::move(value))); + return make_uniq(type, func, std::move(children), ConstantOrNull::Bind(std::move(value))); } void ExpressionRewriter::VisitOperator(LogicalOperator &op) { diff --git a/src/duckdb/src/optimizer/filter_combiner.cpp b/src/duckdb/src/optimizer/filter_combiner.cpp index 91b512f8c..fe2382630 100644 --- a/src/duckdb/src/optimizer/filter_combiner.cpp +++ b/src/duckdb/src/optimizer/filter_combiner.cpp @@ -1,6 +1,7 @@ #include "duckdb/optimizer/filter_combiner.hpp" #include "duckdb/execution/expression_executor.hpp" +#include "duckdb/optimizer/optimizer.hpp" #include "duckdb/planner/expression.hpp" #include "duckdb/planner/expression/bound_between_expression.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" @@ -10,11 +11,11 @@ #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression/bound_operator_expression.hpp" -#include "duckdb/planner/table_filter.hpp" #include "duckdb/planner/filter/constant_filter.hpp" #include "duckdb/planner/filter/null_filter.hpp" +#include "duckdb/planner/filter/optional_filter.hpp" #include "duckdb/planner/filter/struct_filter.hpp" -#include "duckdb/optimizer/optimizer.hpp" +#include "duckdb/planner/table_filter.hpp" namespace duckdb { @@ -595,40 +596,110 @@ TableFilterSet FilterCombiner::GenerateTableScanFilters(const vector &col //! Check if values are consecutive, if yes transform them to >= <= (only for integers) // e.g. if we have x IN (1, 2, 3, 4, 5) we transform this into x >= 1 AND x <= 5 + bool can_simplify_in_to_range = true; + if (type.IsIntegral()) { + for (idx_t i = 1; i < func.children.size(); i++) { + auto &const_value_expr = func.children[i]->Cast(); + D_ASSERT(!const_value_expr.value.IsNull()); + in_values.push_back(const_value_expr.value.GetValue()); + } + + if (in_values.empty()) { + continue; + } + + sort(in_values.begin(), in_values.end()); + + for (idx_t in_val_idx = 1; in_val_idx < in_values.size(); in_val_idx++) { + if (in_values[in_val_idx] - in_values[in_val_idx - 1] > 1) { + can_simplify_in_to_range = false; + break; + } + } + } if (!type.IsIntegral()) { continue; } + if (can_simplify_in_to_range) { + auto lower_bound = make_uniq(ExpressionType::COMPARE_GREATERTHANOREQUALTO, + Value::Numeric(type, in_values.front())); + auto upper_bound = make_uniq(ExpressionType::COMPARE_LESSTHANOREQUALTO, + Value::Numeric(type, in_values.back())); + table_filters.PushFilter(column_index, std::move(lower_bound)); + table_filters.PushFilter(column_index, std::move(upper_bound)); + table_filters.PushFilter(column_index, make_uniq()); - for (idx_t i = 1; i < func.children.size(); i++) { - auto &const_value_expr = func.children[i]->Cast(); - D_ASSERT(!const_value_expr.value.IsNull()); - in_values.push_back(const_value_expr.value.GetValue()); + remaining_filters.erase_at(rem_fil_idx); } - if (in_values.empty()) { - continue; + // if we are still Integral, then we can push a zonemap filter. + else if (type.IsIntegral()) { + auto optional_filter = make_uniq(); + auto or_filter = make_uniq(); + for (idx_t in_val_idx = 1; in_val_idx < func.children.size(); in_val_idx++) { + D_ASSERT(func.children[in_val_idx]->type == ExpressionType::VALUE_CONSTANT); + auto &const_val = func.children[in_val_idx]->Cast(); + auto const_filter = make_uniq(ExpressionType::COMPARE_EQUAL, const_val.value); + or_filter->child_filters.push_back(std::move(const_filter)); + } + optional_filter->child_filter = std::move(or_filter); + table_filters.PushFilter(column_index, std::move(optional_filter)); } + } + } - sort(in_values.begin(), in_values.end()); + for (idx_t rem_fil_idx = 0; rem_fil_idx < remaining_filters.size(); rem_fil_idx++) { + auto &remaining_filter = remaining_filters[rem_fil_idx]; + if (remaining_filter->expression_class == ExpressionClass::BOUND_CONJUNCTION) { + auto &conj = remaining_filter->Cast(); + if (conj.type == ExpressionType::CONJUNCTION_OR) { + optional_idx column_id; + auto optional_filter = make_uniq(); + auto conj_filter = make_uniq(); + for (auto &child : conj.children) { + if (child->GetExpressionClass() != ExpressionClass::BOUND_COMPARISON) { + column_id.SetInvalid(); + break; + } + optional_ptr column_ref = nullptr; + optional_ptr const_val = nullptr; + auto &comp = child->Cast(); + if (comp.left->expression_class == ExpressionClass::BOUND_COLUMN_REF && + comp.right->expression_class == ExpressionClass::BOUND_CONSTANT) { + column_ref = comp.left->Cast(); + const_val = comp.right->Cast(); + } else if (comp.left->expression_class == ExpressionClass::BOUND_CONSTANT && + comp.right->expression_class == ExpressionClass::BOUND_COLUMN_REF) { + column_ref = comp.right->Cast(); + const_val = comp.left->Cast(); + } else { + // child of OR filter is not simple so we do not push the or filter down at all + column_id.SetInvalid(); + break; + } - bool can_simplify_in_clause = true; - for (idx_t in_val_idx = 1; in_val_idx < in_values.size(); in_val_idx++) { - if (in_values[in_val_idx] - in_values[in_val_idx - 1] > 1) { - can_simplify_in_clause = false; - break; + if (!column_id.IsValid()) { + if (IsRowIdColumnId(column_ids[column_ref->binding.column_index])) { + break; + } + column_id = column_ids[column_ref->binding.column_index]; + } else if (column_id.GetIndex() != column_ids[column_ref->binding.column_index]) { + column_id.SetInvalid(); + break; + } + + if (const_val->value.type().IsTemporal() || + const_val->value.type().id() == LogicalTypeId::VARCHAR) { + column_id.SetInvalid(); + break; + } + auto const_filter = make_uniq(comp.type, const_val->value); + conj_filter->child_filters.push_back(std::move(const_filter)); + } + if (column_id.IsValid()) { + optional_filter->child_filter = std::move(conj_filter); + table_filters.PushFilter(column_id.GetIndex(), std::move(optional_filter)); } } - if (!can_simplify_in_clause) { - continue; - } - auto lower_bound = make_uniq(ExpressionType::COMPARE_GREATERTHANOREQUALTO, - Value::Numeric(type, in_values.front())); - auto upper_bound = make_uniq(ExpressionType::COMPARE_LESSTHANOREQUALTO, - Value::Numeric(type, in_values.back())); - table_filters.PushFilter(column_index, std::move(lower_bound)); - table_filters.PushFilter(column_index, std::move(upper_bound)); - table_filters.PushFilter(column_index, make_uniq()); - - remaining_filters.erase_at(rem_fil_idx); } } diff --git a/src/duckdb/src/optimizer/filter_pushdown.cpp b/src/duckdb/src/optimizer/filter_pushdown.cpp index f5a7b405f..d789394be 100644 --- a/src/duckdb/src/optimizer/filter_pushdown.cpp +++ b/src/duckdb/src/optimizer/filter_pushdown.cpp @@ -1,5 +1,4 @@ #include "duckdb/optimizer/filter_pushdown.hpp" - #include "duckdb/optimizer/filter_combiner.hpp" #include "duckdb/optimizer/optimizer.hpp" #include "duckdb/planner/expression_iterator.hpp" @@ -107,6 +106,8 @@ unique_ptr FilterPushdown::Rewrite(unique_ptr return PushdownLimit(std::move(op)); case LogicalOperatorType::LOGICAL_WINDOW: return PushdownWindow(std::move(op)); + case LogicalOperatorType::LOGICAL_UNNEST: + return PushdownUnnest(std::move(op)); default: return FinishPushdown(std::move(op)); } @@ -121,7 +122,7 @@ unique_ptr FilterPushdown::PushdownJoin(unique_ptrtype == LogicalOperatorType::LOGICAL_ASOF_JOIN || op->type == LogicalOperatorType::LOGICAL_ANY_JOIN || op->type == LogicalOperatorType::LOGICAL_DELIM_JOIN); auto &join = op->Cast(); - if (!join.left_projection_map.empty() || !join.right_projection_map.empty()) { + if (join.HasProjectionMap()) { // cannot push down further otherwise the projection maps won't be preserved return FinishPushdown(std::move(op)); } diff --git a/src/duckdb/src/optimizer/join_filter_pushdown_optimizer.cpp b/src/duckdb/src/optimizer/join_filter_pushdown_optimizer.cpp index 60b8c83af..c59734474 100644 --- a/src/duckdb/src/optimizer/join_filter_pushdown_optimizer.cpp +++ b/src/duckdb/src/optimizer/join_filter_pushdown_optimizer.cpp @@ -1,20 +1,158 @@ #include "duckdb/optimizer/join_filter_pushdown_optimizer.hpp" -#include "duckdb/planner/operator/logical_comparison_join.hpp" -#include "duckdb/planner/operator/logical_get.hpp" -#include "duckdb/planner/operator/logical_projection.hpp" + #include "duckdb/execution/operator/join/join_filter_pushdown.hpp" -#include "duckdb/planner/expression/bound_columnref_expression.hpp" -#include "duckdb/core_functions/aggregate/distributive_functions.hpp" -#include "duckdb/optimizer/optimizer.hpp" -#include "duckdb/function/function_binder.hpp" #include "duckdb/execution/operator/join/physical_comparison_join.hpp" +#include "duckdb/function/aggregate/distributive_function_utils.hpp" +#include "duckdb/function/function_binder.hpp" +#include "duckdb/optimizer/optimizer.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" +#include "duckdb/planner/expression/bound_columnref_expression.hpp" +#include "duckdb/planner/operator/logical_aggregate.hpp" +#include "duckdb/planner/operator/logical_comparison_join.hpp" +#include "duckdb/planner/operator/logical_get.hpp" +#include "duckdb/planner/operator/logical_projection.hpp" +#include "duckdb/planner/operator/logical_set_operation.hpp" +#include "duckdb/planner/operator/logical_unnest.hpp" namespace duckdb { JoinFilterPushdownOptimizer::JoinFilterPushdownOptimizer(Optimizer &optimizer) : optimizer(optimizer) { } +bool PushdownJoinFilterExpression(Expression &expr, JoinFilterPushdownColumn &filter) { + if (expr.type != ExpressionType::BOUND_COLUMN_REF) { + // not a simple column ref - bail-out + return false; + } + // column-ref - pass through the new column binding + auto &colref = expr.Cast(); + filter.probe_column_index = colref.binding; + return true; +} + +void GenerateJoinFiltersRecursive(LogicalOperator &op, vector columns, + JoinFilterPushdownInfo &pushdown_info) { + auto &probe_child = op; + switch (probe_child.type) { + case LogicalOperatorType::LOGICAL_LIMIT: + case LogicalOperatorType::LOGICAL_FILTER: + case LogicalOperatorType::LOGICAL_ORDER_BY: + case LogicalOperatorType::LOGICAL_TOP_N: + case LogicalOperatorType::LOGICAL_DISTINCT: + case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: + case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: + // does not affect probe side - recurse into left child + // FIXME: we can probably recurse into more operators here (e.g. window, unnest) + GenerateJoinFiltersRecursive(*probe_child.children[0], std::move(columns), pushdown_info); + break; + case LogicalOperatorType::LOGICAL_UNNEST: { + auto &unnest = probe_child.Cast(); + // check if the filters apply to the unnest index + for (auto &filter : columns) { + if (filter.probe_column_index.table_index == unnest.unnest_index) { + // the filter applies to the unnest index - bail out + return; + } + } + GenerateJoinFiltersRecursive(*probe_child.children[0], std::move(columns), pushdown_info); + break; + } + case LogicalOperatorType::LOGICAL_EXCEPT: + case LogicalOperatorType::LOGICAL_INTERSECT: + case LogicalOperatorType::LOGICAL_UNION: { + auto &setop = probe_child.Cast(); + // union + // check if the filters apply to this table index + for (auto &filter : columns) { + if (filter.probe_column_index.table_index != setop.table_index) { + // the filter does not apply to the union - bail-out + return; + } + } + for (auto &child : probe_child.children) { + // rewrite the filters for each of the children of the union + vector child_columns; + auto child_bindings = child->GetColumnBindings(); + child_columns.reserve(columns.size()); + for (auto &child_column : columns) { + JoinFilterPushdownColumn new_col; + new_col.probe_column_index = child_bindings[child_column.probe_column_index.column_index]; + child_columns.push_back(new_col); + } + // then recurse into the child + GenerateJoinFiltersRecursive(*child, std::move(child_columns), pushdown_info); + + // for EXCEPT we can only recurse into the first (left) child + if (probe_child.type == LogicalOperatorType::LOGICAL_EXCEPT) { + break; + } + } + break; + } + case LogicalOperatorType::LOGICAL_GET: { + // found LogicalGet + auto &get = probe_child.Cast(); + if (!get.function.filter_pushdown) { + // filter pushdown is not supported - no need to consider this node + return; + } + for (auto &filter : columns) { + if (filter.probe_column_index.table_index != get.table_index) { + // the filter does not apply to the probe side here - bail-out + return; + } + } + // pushdown info can be applied to this LogicalGet - push the dynamic table filter set + if (!get.dynamic_filters) { + get.dynamic_filters = make_shared_ptr(); + } + + JoinFilterPushdownFilter get_filter; + get_filter.dynamic_filters = get.dynamic_filters; + get_filter.columns = std::move(columns); + pushdown_info.probe_info.push_back(std::move(get_filter)); + break; + } + case LogicalOperatorType::LOGICAL_PROJECTION: { + // projection - check if we all of the expressions are only column references + auto &proj = probe_child.Cast(); + for (auto &filter : columns) { + if (filter.probe_column_index.table_index != proj.table_index) { + // index does not belong to this projection - bail-out + return; + } + auto &expr = *proj.expressions[filter.probe_column_index.column_index]; + if (!PushdownJoinFilterExpression(expr, filter)) { + // cannot push through this expression - bail-out + return; + } + } + GenerateJoinFiltersRecursive(*probe_child.children[0], std::move(columns), pushdown_info); + break; + } + case LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY: { + // we can push filters through aggregates IF they all point to groups + auto &aggr = probe_child.Cast(); + for (auto &filter : columns) { + if (filter.probe_column_index.table_index != aggr.group_index) { + // index does not refer to a group - bail-out + return; + } + auto &expr = *aggr.groups[filter.probe_column_index.column_index]; + if (!PushdownJoinFilterExpression(expr, filter)) { + // cannot push through this expression - bail-out + return; + } + } + GenerateJoinFiltersRecursive(*probe_child.children[0], std::move(columns), pushdown_info); + break; + } + default: + // unsupported child type + break; + } +} + void JoinFilterPushdownOptimizer::GenerateJoinFilters(LogicalComparisonJoin &join) { switch (join.join_type) { case JoinType::MARK: @@ -35,6 +173,8 @@ void JoinFilterPushdownOptimizer::GenerateJoinFilters(LogicalComparisonJoin &joi // re-order conditions here - otherwise this will happen later on and invalidate the indexes we generate PhysicalComparisonJoin::ReorderConditions(join.conditions); auto pushdown_info = make_uniq(); + + vector pushdown_columns; for (idx_t cond_idx = 0; cond_idx < join.conditions.size(); cond_idx++) { auto &cond = join.conditions[cond_idx]; if (cond.comparison != ExpressionType::COMPARE_EQUAL) { @@ -54,80 +194,32 @@ void JoinFilterPushdownOptimizer::GenerateJoinFilters(LogicalComparisonJoin &joi continue; } JoinFilterPushdownColumn pushdown_col; - pushdown_col.join_condition = cond_idx; - auto &colref = cond.left->Cast(); pushdown_col.probe_column_index = colref.binding; - pushdown_info->filters.push_back(pushdown_col); + pushdown_columns.push_back(pushdown_col); + + pushdown_info->join_condition.push_back(cond_idx); } - if (pushdown_info->filters.empty()) { + if (pushdown_columns.empty()) { // could not generate any filters - bail-out return; } - // find the child LogicalGet (if possible) - reference probe_source(*join.children[0]); - while (probe_source.get().type != LogicalOperatorType::LOGICAL_GET) { - auto &probe_child = probe_source.get(); - switch (probe_child.type) { - case LogicalOperatorType::LOGICAL_LIMIT: - case LogicalOperatorType::LOGICAL_FILTER: - case LogicalOperatorType::LOGICAL_ORDER_BY: - case LogicalOperatorType::LOGICAL_TOP_N: - case LogicalOperatorType::LOGICAL_DISTINCT: - case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: - case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: - // does not affect probe side - continue into left child - // FIXME: we can probably recurse into more operators here (e.g. window, set operation, unnest) - probe_source = *probe_child.children[0]; - break; - case LogicalOperatorType::LOGICAL_PROJECTION: { - // projection - check if we all of the expressions are only column references - auto &proj = probe_source.get().Cast(); - for (auto &filter : pushdown_info->filters) { - if (filter.probe_column_index.table_index != proj.table_index) { - // index does not belong to this projection - bail-out - return; - } - auto &expr = *proj.expressions[filter.probe_column_index.column_index]; - if (expr.type != ExpressionType::BOUND_COLUMN_REF) { - // not a simple column ref - bail-out - return; - } - // column-ref - pass through the new column binding - auto &colref = expr.Cast(); - filter.probe_column_index = colref.binding; - } - probe_source = *probe_child.children[0]; - break; - } - default: - // unsupported child type - return; - } - } - // found the LogicalGet - auto &get = probe_source.get().Cast(); - if (!get.function.filter_pushdown) { - // filter pushdown is not supported - bail-out + // recurse the query tree to find the LogicalGets in which we can push the filter info + GenerateJoinFiltersRecursive(*join.children[0], pushdown_columns, *pushdown_info); + + if (pushdown_info->probe_info.empty()) { + // no table sources found in which we can push down filters return; } - for (auto &filter : pushdown_info->filters) { - if (filter.probe_column_index.table_index != get.table_index) { - // the filter does not apply to the probe side here - bail-out - return; - } - } - // pushdown can be performed - // set up the min/max aggregates for each of the filters vector aggr_functions; - aggr_functions.push_back(MinFun::GetFunction()); - aggr_functions.push_back(MaxFun::GetFunction()); - for (auto &filter : pushdown_info->filters) { + aggr_functions.push_back(MinFunction::GetFunction()); + aggr_functions.push_back(MaxFunction::GetFunction()); + for (auto &join_condition : pushdown_info->join_condition) { for (auto &aggr : aggr_functions) { FunctionBinder function_binder(optimizer.GetContext()); vector> aggr_children; - aggr_children.push_back(join.conditions[filter.join_condition].right->Copy()); + aggr_children.push_back(join.conditions[join_condition].right->Copy()); auto aggr_expr = function_binder.BindAggregateFunction(aggr, std::move(aggr_children), nullptr, AggregateType::NON_DISTINCT); if (aggr_expr->children.size() != 1) { @@ -137,12 +229,6 @@ void JoinFilterPushdownOptimizer::GenerateJoinFilters(LogicalComparisonJoin &joi pushdown_info->min_max_aggregates.push_back(std::move(aggr_expr)); } } - // set up the dynamic filters (if we don't have any yet) - if (!get.dynamic_filters) { - get.dynamic_filters = make_shared_ptr(); - } - pushdown_info->dynamic_filters = get.dynamic_filters; - // set up the filter pushdown in the join itself join.filter_pushdown = std::move(pushdown_info); } diff --git a/src/duckdb/src/optimizer/optimizer.cpp b/src/duckdb/src/optimizer/optimizer.cpp index 9b5478ace..9eef989e8 100644 --- a/src/duckdb/src/optimizer/optimizer.cpp +++ b/src/duckdb/src/optimizer/optimizer.cpp @@ -10,10 +10,12 @@ #include "duckdb/optimizer/cse_optimizer.hpp" #include "duckdb/optimizer/cte_filter_pusher.hpp" #include "duckdb/optimizer/deliminator.hpp" +#include "duckdb/optimizer/empty_result_pullup.hpp" #include "duckdb/optimizer/expression_heuristics.hpp" #include "duckdb/optimizer/filter_pullup.hpp" #include "duckdb/optimizer/filter_pushdown.hpp" #include "duckdb/optimizer/in_clause_rewriter.hpp" +#include "duckdb/optimizer/join_filter_pushdown_optimizer.hpp" #include "duckdb/optimizer/join_order/join_order_optimizer.hpp" #include "duckdb/optimizer/limit_pushdown.hpp" #include "duckdb/optimizer/regex_range_filter.hpp" @@ -23,10 +25,10 @@ #include "duckdb/optimizer/rule/in_clause_simplification.hpp" #include "duckdb/optimizer/rule/join_dependent_filter.hpp" #include "duckdb/optimizer/rule/list.hpp" +#include "duckdb/optimizer/sampling_pushdown.hpp" #include "duckdb/optimizer/statistics_propagator.hpp" #include "duckdb/optimizer/topn_optimizer.hpp" #include "duckdb/optimizer/unnest_rewriter.hpp" -#include "duckdb/optimizer/join_filter_pushdown_optimizer.hpp" #include "duckdb/planner/binder.hpp" #include "duckdb/planner/planner.hpp" @@ -142,6 +144,12 @@ void Optimizer::RunBuiltInOptimizers() { plan = deliminator.Optimize(std::move(plan)); }); + // Pulls up empty results + RunOptimizer(OptimizerType::EMPTY_RESULT_PULLUP, [&]() { + EmptyResultPullup empty_result_pullup; + plan = empty_result_pullup.Optimize(std::move(plan)); + }); + // then we perform the join ordering optimization // this also rewrites cross products + filters into joins and performs filter pushdowns RunOptimizer(OptimizerType::JOIN_ORDER, [&]() { @@ -173,6 +181,12 @@ void Optimizer::RunBuiltInOptimizers() { cse_optimizer.VisitOperator(*plan); }); + // creates projection maps so unused columns are projected out early + RunOptimizer(OptimizerType::COLUMN_LIFETIME, [&]() { + ColumnLifetimeAnalyzer column_lifetime(*this, *plan, true); + column_lifetime.VisitOperator(*plan); + }); + // Once we know the column lifetime, we have more information regarding // what relations should be the build side/probe side. RunOptimizer(OptimizerType::BUILD_SIDE_PROBE_SIDE, [&]() { @@ -186,18 +200,18 @@ void Optimizer::RunBuiltInOptimizers() { plan = limit_pushdown.Optimize(std::move(plan)); }); + // perform sampling pushdown + RunOptimizer(OptimizerType::SAMPLING_PUSHDOWN, [&]() { + SamplingPushdown sampling_pushdown; + plan = sampling_pushdown.Optimize(std::move(plan)); + }); + // transform ORDER BY + LIMIT to TopN RunOptimizer(OptimizerType::TOP_N, [&]() { TopN topn; plan = topn.Optimize(std::move(plan)); }); - // creates projection maps so unused columns are projected out early - RunOptimizer(OptimizerType::COLUMN_LIFETIME, [&]() { - ColumnLifetimeAnalyzer column_lifetime(true); - column_lifetime.VisitOperator(*plan); - }); - // perform statistics propagation column_binding_map_t> statistics_map; RunOptimizer(OptimizerType::STATISTICS_PROPAGATION, [&]() { @@ -214,7 +228,7 @@ void Optimizer::RunBuiltInOptimizers() { // creates projection maps so unused columns are projected out early RunOptimizer(OptimizerType::COLUMN_LIFETIME, [&]() { - ColumnLifetimeAnalyzer column_lifetime(true); + ColumnLifetimeAnalyzer column_lifetime(*this, *plan, true); column_lifetime.VisitOperator(*plan); }); diff --git a/src/duckdb/src/optimizer/pullup/pullup_filter.cpp b/src/duckdb/src/optimizer/pullup/pullup_filter.cpp index 96395a97c..95fd7f7bb 100644 --- a/src/duckdb/src/optimizer/pullup/pullup_filter.cpp +++ b/src/duckdb/src/optimizer/pullup/pullup_filter.cpp @@ -1,8 +1,8 @@ #include "duckdb/optimizer/filter_pullup.hpp" -#include "duckdb/planner/operator/logical_filter.hpp" +#include "duckdb/planner/expression/bound_between_expression.hpp" #include "duckdb/planner/expression/bound_comparison_expression.hpp" #include "duckdb/planner/expression_iterator.hpp" -#include "duckdb/planner/expression/bound_between_expression.hpp" +#include "duckdb/planner/operator/logical_filter.hpp" namespace duckdb { @@ -10,7 +10,7 @@ unique_ptr FilterPullup::PullupFilter(unique_ptrtype == LogicalOperatorType::LOGICAL_FILTER); auto &filter = op->Cast(); - if (can_pullup && filter.projection_map.empty()) { + if (can_pullup && !filter.HasProjectionMap()) { unique_ptr child = std::move(op->children[0]); child = Rewrite(std::move(child)); // moving filter's expressions diff --git a/src/duckdb/src/optimizer/pushdown/pushdown_filter.cpp b/src/duckdb/src/optimizer/pushdown/pushdown_filter.cpp index 9f3a6b5a3..fdf6fbe6e 100644 --- a/src/duckdb/src/optimizer/pushdown/pushdown_filter.cpp +++ b/src/duckdb/src/optimizer/pushdown/pushdown_filter.cpp @@ -9,7 +9,7 @@ using Filter = FilterPushdown::Filter; unique_ptr FilterPushdown::PushdownFilter(unique_ptr op) { D_ASSERT(op->type == LogicalOperatorType::LOGICAL_FILTER); auto &filter = op->Cast(); - if (!filter.projection_map.empty()) { + if (filter.HasProjectionMap()) { return FinishPushdown(std::move(op)); } // filter: gather the filters and remove the filter from the set of operations diff --git a/src/duckdb/src/optimizer/pushdown/pushdown_projection.cpp b/src/duckdb/src/optimizer/pushdown/pushdown_projection.cpp index ec82b39cd..f66ce66fd 100644 --- a/src/duckdb/src/optimizer/pushdown/pushdown_projection.cpp +++ b/src/duckdb/src/optimizer/pushdown/pushdown_projection.cpp @@ -3,6 +3,8 @@ #include "duckdb/planner/expression_iterator.hpp" #include "duckdb/planner/operator/logical_empty_result.hpp" #include "duckdb/planner/operator/logical_projection.hpp" +#include "duckdb/planner/expression/bound_cast_expression.hpp" +#include "duckdb/common/types.hpp" namespace duckdb { @@ -51,7 +53,7 @@ unique_ptr FilterPushdown::PushdownProjection(unique_ptrCanThrow()) { // We can't push down related expressions if the column in the // expression is generated by the functions which have side effects remain_expressions.push_back(std::move(f.filter)); diff --git a/src/duckdb/src/optimizer/pushdown/pushdown_unnest.cpp b/src/duckdb/src/optimizer/pushdown/pushdown_unnest.cpp new file mode 100644 index 000000000..9bdeb2567 --- /dev/null +++ b/src/duckdb/src/optimizer/pushdown/pushdown_unnest.cpp @@ -0,0 +1,52 @@ +#include "duckdb/optimizer/filter_pushdown.hpp" +#include "duckdb/planner/expression/bound_columnref_expression.hpp" +#include "duckdb/planner/expression_iterator.hpp" +#include "duckdb/planner/operator/logical_empty_result.hpp" +#include "duckdb/planner/operator/logical_unnest.hpp" + +namespace duckdb { + +unique_ptr FilterPushdown::PushdownUnnest(unique_ptr op) { + D_ASSERT(op->type == LogicalOperatorType::LOGICAL_UNNEST); + auto &unnest = op->Cast(); + // push filter through logical projection + // all the BoundColumnRefExpressions in the filter should refer to the LogicalProjection + // we can rewrite them by replacing those references with the expression of the LogicalProjection node + FilterPushdown child_pushdown(optimizer, convert_mark_joins); + // There are some expressions can not be pushed down. We should keep them + // and add an extra filter operator. + vector> remain_expressions; + for (auto &filter : filters) { + auto &f = *filter; + auto can_push = true; + for (auto &binding : f.bindings) { + if (binding == unnest.unnest_index) { + can_push = false; + break; + } + } + // if the expression index table index is the unnest index, then the filter is on the + // unnest, and it should not be pushed down. + if (!can_push) { + // We can't push down related expressions if the column in the + // expression is generated by the functions which have side effects + remain_expressions.push_back(std::move(f.filter)); + } else { + // add the filter to the child pushdown + if (child_pushdown.AddFilter(std::move(f.filter)) == FilterResult::UNSATISFIABLE) { + // filter statically evaluates to false, strip tree + return make_uniq(std::move(op)); + } + } + } + child_pushdown.GenerateFilters(); + // now push into children + op->children[0] = child_pushdown.Rewrite(std::move(op->children[0])); + if (op->children[0]->type == LogicalOperatorType::LOGICAL_EMPTY_RESULT) { + // child returns an empty result: generate an empty result here too + return make_uniq(std::move(op)); + } + return AddLogicalFilter(std::move(op), std::move(remain_expressions)); +} + +} // namespace duckdb diff --git a/src/duckdb/src/optimizer/remove_unused_columns.cpp b/src/duckdb/src/optimizer/remove_unused_columns.cpp index 8425050b1..8515e469c 100644 --- a/src/duckdb/src/optimizer/remove_unused_columns.cpp +++ b/src/duckdb/src/optimizer/remove_unused_columns.cpp @@ -275,7 +275,7 @@ void RemoveUnusedColumns::VisitOperator(LogicalOperator &op) { return; case LogicalOperatorType::LOGICAL_FILTER: { auto &filter = op.Cast(); - if (!filter.projection_map.empty()) { + if (filter.HasProjectionMap()) { // if we have any entries in the filter projection map don't prune any columns // FIXME: we can do something more clever here everything_referenced = true; diff --git a/src/duckdb/src/optimizer/rule/arithmetic_simplification.cpp b/src/duckdb/src/optimizer/rule/arithmetic_simplification.cpp index bd4e0821e..367731fec 100644 --- a/src/duckdb/src/optimizer/rule/arithmetic_simplification.cpp +++ b/src/duckdb/src/optimizer/rule/arithmetic_simplification.cpp @@ -1,9 +1,10 @@ #include "duckdb/optimizer/rule/arithmetic_simplification.hpp" #include "duckdb/common/exception.hpp" +#include "duckdb/function/function_binder.hpp" +#include "duckdb/optimizer/expression_rewriter.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/optimizer/expression_rewriter.hpp" namespace duckdb { diff --git a/src/duckdb/src/optimizer/rule/like_optimizations.cpp b/src/duckdb/src/optimizer/rule/like_optimizations.cpp index 067dfd791..a8398c99f 100644 --- a/src/duckdb/src/optimizer/rule/like_optimizations.cpp +++ b/src/duckdb/src/optimizer/rule/like_optimizations.cpp @@ -1,6 +1,8 @@ #include "duckdb/optimizer/rule/like_optimizations.hpp" #include "duckdb/execution/expression_executor.hpp" +#include "duckdb/function/scalar/string_functions.hpp" +#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_operator_expression.hpp" @@ -132,7 +134,7 @@ unique_ptr LikeOptimizationRule::Apply(LogicalOperator &op, vector RegexOptimizationRule::Apply(LogicalOperator &op, vector< return nullptr; } auto parameter = make_uniq(Value(std::move(escaped_like_string.like_string))); - auto contains = make_uniq(root.return_type, ContainsFun::GetStringContains(), + auto contains = make_uniq(root.return_type, GetStringContains(), std::move(root.children), nullptr); contains->children[1] = std::move(parameter); @@ -205,8 +206,8 @@ unique_ptr RegexOptimizationRule::Apply(LogicalOperator &op, vector< D_ASSERT(root.children.size() == 2); } - auto like_expression = make_uniq(root.return_type, LikeFun::GetLikeFunction(), - std::move(root.children), nullptr); + auto like_expression = + make_uniq(root.return_type, LikeFun::GetFunction(), std::move(root.children), nullptr); auto parameter = make_uniq(Value(std::move(like_string.like_string))); like_expression->children[1] = std::move(parameter); return std::move(like_expression); diff --git a/src/duckdb/src/optimizer/sampling_pushdown.cpp b/src/duckdb/src/optimizer/sampling_pushdown.cpp new file mode 100644 index 000000000..ca805e64e --- /dev/null +++ b/src/duckdb/src/optimizer/sampling_pushdown.cpp @@ -0,0 +1,24 @@ +#include "duckdb/optimizer/sampling_pushdown.hpp" +#include "duckdb/planner/operator/logical_get.hpp" +#include "duckdb/planner/operator/logical_sample.hpp" +#include "duckdb/common/types/value.hpp" +namespace duckdb { + +unique_ptr SamplingPushdown::Optimize(unique_ptr op) { + if (op->type == LogicalOperatorType::LOGICAL_SAMPLE && + op->Cast().sample_options->method == SampleMethod::SYSTEM_SAMPLE && + op->Cast().sample_options->is_percentage && !op->children.empty() && + op->children[0]->type == LogicalOperatorType::LOGICAL_GET && + op->children[0]->Cast().function.sampling_pushdown && op->children[0]->children.empty()) { + auto &get = op->children[0]->Cast(); + // set sampling option + get.extra_info.sample_options = std::move(op->Cast().sample_options); + op = std::move(op->children[0]); + } + for (auto &child : op->children) { + child = Optimize(std::move(child)); + } + return op; +} + +} // namespace duckdb diff --git a/src/duckdb/src/optimizer/statistics/operator/propagate_filter.cpp b/src/duckdb/src/optimizer/statistics/operator/propagate_filter.cpp index 7dbdc6da7..1cb37da95 100644 --- a/src/duckdb/src/optimizer/statistics/operator/propagate_filter.cpp +++ b/src/duckdb/src/optimizer/statistics/operator/propagate_filter.cpp @@ -1,5 +1,5 @@ #include "duckdb/execution/expression_executor.hpp" -#include "duckdb/function/scalar/generic_functions.hpp" +#include "duckdb/function/scalar/generic_common.hpp" #include "duckdb/optimizer/statistics_propagator.hpp" #include "duckdb/planner/expression/bound_between_expression.hpp" #include "duckdb/planner/expression/bound_columnref_expression.hpp" diff --git a/src/duckdb/src/parallel/pipeline.cpp b/src/duckdb/src/parallel/pipeline.cpp index ca0443b9d..04a9f8bb1 100644 --- a/src/duckdb/src/parallel/pipeline.cpp +++ b/src/duckdb/src/parallel/pipeline.cpp @@ -105,8 +105,9 @@ bool Pipeline::ScheduleParallel(shared_ptr &event) { return false; } } - if (sink->RequiresBatchIndex()) { - if (!source->SupportsBatchIndex()) { + auto partition_info = sink->RequiredPartitionInfo(); + if (partition_info.batch_index) { + if (!source->SupportsPartitioning(OperatorPartitionInfo::BatchIndex())) { throw InternalException( "Attempting to schedule a pipeline where the sink requires batch index but source does not support it"); } diff --git a/src/duckdb/src/parallel/pipeline_executor.cpp b/src/duckdb/src/parallel/pipeline_executor.cpp index 105d46299..4b32c99d9 100644 --- a/src/duckdb/src/parallel/pipeline_executor.cpp +++ b/src/duckdb/src/parallel/pipeline_executor.cpp @@ -15,8 +15,9 @@ PipelineExecutor::PipelineExecutor(ClientContext &context_p, Pipeline &pipeline_ D_ASSERT(pipeline.source_state); if (pipeline.sink) { local_sink_state = pipeline.sink->GetLocalSinkState(context); - requires_batch_index = pipeline.sink->RequiresBatchIndex() && pipeline.source->SupportsBatchIndex(); - if (requires_batch_index) { + required_partition_info = pipeline.sink->RequiredPartitionInfo(); + if (required_partition_info.AnyRequired()) { + D_ASSERT(pipeline.source->SupportsPartitioning(OperatorPartitionInfo::BatchIndex())); auto &partition_info = local_sink_state->partition_info; D_ASSERT(!partition_info.batch_index.IsValid()); // batch index is not set yet - initialize before fetching anything @@ -48,7 +49,7 @@ PipelineExecutor::PipelineExecutor(ClientContext &context_p, Pipeline &pipeline_ InitializeChunk(final_chunk); } -bool PipelineExecutor::TryFlushCachingOperators() { +bool PipelineExecutor::TryFlushCachingOperators(ExecutionBudget &chunk_budget) { if (!started_flushing) { // Remainder of this method assumes any in process operators are from flushing D_ASSERT(in_process_operators.empty()); @@ -56,7 +57,9 @@ bool PipelineExecutor::TryFlushCachingOperators() { flushing_idx = IsFinished() ? idx_t(finished_processing_idx) : 0; } - // Go over each operator and keep flushing them using `FinalExecute` until empty + // For each operator that supports FinalExecute, + // extract every chunk from it and push it through the rest of the pipeline + // before moving onto the next operators' FinalExecute while (flushing_idx < pipeline.operators.size()) { if (!pipeline.operators[flushing_idx].get().RequiresFinalExecute()) { flushing_idx++; @@ -76,7 +79,6 @@ bool PipelineExecutor::TryFlushCachingOperators() { auto ¤t_operator = pipeline.operators[flushing_idx].get(); OperatorFinalizeResultType finalize_result; - OperatorResultType push_result; if (in_process_operators.empty()) { curr_chunk.Reset(); @@ -89,7 +91,7 @@ bool PipelineExecutor::TryFlushCachingOperators() { finalize_result = OperatorFinalizeResultType::HAVE_MORE_OUTPUT; } - push_result = ExecutePushInternal(curr_chunk, flushing_idx + 1); + auto push_result = ExecutePushInternal(curr_chunk, chunk_budget, flushing_idx + 1); if (finalize_result == OperatorFinalizeResultType::HAVE_MORE_OUTPUT) { should_flush_current_idx = true; @@ -97,43 +99,58 @@ bool PipelineExecutor::TryFlushCachingOperators() { should_flush_current_idx = false; } - if (push_result == OperatorResultType::BLOCKED) { + switch (push_result) { + case OperatorResultType::BLOCKED: { remaining_sink_chunk = true; return false; - } else if (push_result == OperatorResultType::FINISHED) { + } + case OperatorResultType::HAVE_MORE_OUTPUT: { + D_ASSERT(chunk_budget.IsDepleted()); + // The chunk budget was used up, pushing the chunk through the pipeline created more chunks + // we need to continue this the next time Execute is called. + return false; + } + case OperatorResultType::NEED_MORE_INPUT: + continue; + case OperatorResultType::FINISHED: break; + default: + throw InternalException("Unexpected OperatorResultType (%s) in TryFlushCachingOperators", + EnumUtil::ToString(push_result)); } + break; } return true; } -SinkNextBatchType PipelineExecutor::NextBatch(duckdb::DataChunk &source_chunk) { - D_ASSERT(requires_batch_index); - idx_t next_batch_index; +SinkNextBatchType PipelineExecutor::NextBatch(DataChunk &source_chunk) { + D_ASSERT(required_partition_info.AnyRequired()); auto max_batch_index = pipeline.base_batch_index + PipelineBuildState::BATCH_INCREMENT - 1; - if (source_chunk.size() == 0) { - // set it to the maximum valid batch index value for the current pipeline - next_batch_index = max_batch_index; - } else { - auto batch_index = - pipeline.source->GetBatchIndex(context, source_chunk, *pipeline.source_state, *local_source_state); + // by default set it to the maximum valid batch index value for the current pipeline + OperatorPartitionData next_data(max_batch_index); + if (source_chunk.size() > 0) { + // if we retrieved data - initialize the next batch index + auto partition_data = pipeline.source->GetPartitionData(context, source_chunk, *pipeline.source_state, + *local_source_state, required_partition_info); + auto batch_index = partition_data.batch_index; // we start with the base_batch_index as a valid starting value. Make sure that next batch is called below - next_batch_index = pipeline.base_batch_index + batch_index + 1; - if (next_batch_index >= max_batch_index) { + next_data = std::move(partition_data); + next_data.batch_index = pipeline.base_batch_index + batch_index + 1; + if (next_data.batch_index >= max_batch_index) { throw InternalException("Pipeline batch index - invalid batch index %llu returned by source operator", batch_index); } } auto &partition_info = local_sink_state->partition_info; - if (next_batch_index == partition_info.batch_index.GetIndex()) { + if (next_data.batch_index == partition_info.batch_index.GetIndex()) { // no changes, return return SinkNextBatchType::READY; } // batch index has changed - update it - if (partition_info.batch_index.GetIndex() > next_batch_index) { + if (partition_info.batch_index.GetIndex() > next_data.batch_index) { throw InternalException( "Pipeline batch index - gotten lower batch index %llu (down from previous batch index of %llu)", - next_batch_index, partition_info.batch_index.GetIndex()); + next_data.batch_index, partition_info.batch_index.GetIndex()); } #ifdef DUCKDB_DEBUG_ASYNC_SINK_SOURCE if (debug_blocked_next_batch_count < debug_blocked_target_count) { @@ -150,7 +167,8 @@ SinkNextBatchType PipelineExecutor::NextBatch(duckdb::DataChunk &source_chunk) { } #endif auto current_batch = partition_info.batch_index.GetIndex(); - partition_info.batch_index = next_batch_index; + partition_info.batch_index = next_data.batch_index; + partition_info.partition_data = std::move(next_data.partition_data); OperatorSinkNextBatchInput next_batch_input {*pipeline.sink->sink_state, *local_sink_state, interrupt_state}; // call NextBatch before updating min_batch_index to provide the opportunity to flush the previous batch auto next_batch_result = pipeline.sink->NextBatch(context, next_batch_input); @@ -160,7 +178,7 @@ SinkNextBatchType PipelineExecutor::NextBatch(duckdb::DataChunk &source_chunk) { return SinkNextBatchType::BLOCKED; } - partition_info.min_batch_index = pipeline.UpdateBatchIndex(current_batch, next_batch_index); + partition_info.min_batch_index = pipeline.UpdateBatchIndex(current_batch, next_data.batch_index); return SinkNextBatchType::READY; } @@ -168,7 +186,8 @@ SinkNextBatchType PipelineExecutor::NextBatch(duckdb::DataChunk &source_chunk) { PipelineExecuteResult PipelineExecutor::Execute(idx_t max_chunks) { D_ASSERT(pipeline.sink); auto &source_chunk = pipeline.operators.empty() ? final_chunk : *intermediate_chunks[0]; - for (idx_t i = 0; i < max_chunks; i++) { + ExecutionBudget chunk_budget(max_chunks); + do { if (context.client.interrupted) { throw InterruptException(); } @@ -179,22 +198,27 @@ PipelineExecuteResult PipelineExecutor::Execute(idx_t max_chunks) { break; } else if (remaining_sink_chunk) { // The pipeline was interrupted by the Sink. We should retry sinking the final chunk. - result = ExecutePushInternal(final_chunk); + result = ExecutePushInternal(final_chunk, chunk_budget); + D_ASSERT(result != OperatorResultType::HAVE_MORE_OUTPUT); remaining_sink_chunk = false; } else if (!in_process_operators.empty() && !started_flushing) { - // The pipeline was interrupted by the Sink when pushing a source chunk through the pipeline. We need to - // re-push the same source chunk through the pipeline because there are in_process operators, meaning that - // the result for the pipeline + // Operator(s) in the pipeline have returned `HAVE_MORE_OUTPUT` in the last Execute call + // the operators have to be called with the same input chunk to produce the rest of the output D_ASSERT(source_chunk.size() > 0); - result = ExecutePushInternal(source_chunk); + result = ExecutePushInternal(source_chunk, chunk_budget); } else if (exhausted_source && !next_batch_blocked && !done_flushing) { // The source was exhausted, try flushing all operators - auto flush_completed = TryFlushCachingOperators(); + auto flush_completed = TryFlushCachingOperators(chunk_budget); if (flush_completed) { done_flushing = true; break; } else { - return PipelineExecuteResult::INTERRUPTED; + if (remaining_sink_chunk) { + return PipelineExecuteResult::INTERRUPTED; + } else { + D_ASSERT(chunk_budget.IsDepleted()); + return PipelineExecuteResult::NOT_FINISHED; + } } } else if (!exhausted_source || next_batch_blocked) { SourceResultType source_result; @@ -210,7 +234,7 @@ PipelineExecuteResult PipelineExecutor::Execute(idx_t max_chunks) { } } - if (requires_batch_index) { + if (required_partition_info.AnyRequired()) { auto next_batch_result = NextBatch(source_chunk); next_batch_blocked = next_batch_result == SinkNextBatchType::BLOCKED; if (next_batch_blocked) { @@ -223,7 +247,7 @@ PipelineExecuteResult PipelineExecutor::Execute(idx_t max_chunks) { continue; } - result = ExecutePushInternal(source_chunk); + result = ExecutePushInternal(source_chunk, chunk_budget); } else { throw InternalException("Unexpected state reached in pipeline executor"); } @@ -237,7 +261,7 @@ PipelineExecuteResult PipelineExecutor::Execute(idx_t max_chunks) { if (result == OperatorResultType::FINISHED) { break; } - } + } while (chunk_budget.Next()); if ((!exhausted_source || !done_flushing) && !IsFinished()) { return PipelineExecuteResult::NOT_FINISHED; @@ -254,10 +278,6 @@ PipelineExecuteResult PipelineExecutor::Execute() { return Execute(NumericLimits::Maximum()); } -OperatorResultType PipelineExecutor::ExecutePush(DataChunk &input) { // LCOV_EXCL_START - return ExecutePushInternal(input); -} // LCOV_EXCL_STOP - void PipelineExecutor::FinishProcessing(int32_t operator_idx) { finished_processing_idx = operator_idx < 0 ? NumericLimits::Maximum() : operator_idx; in_process_operators = stack(); @@ -278,7 +298,8 @@ bool PipelineExecutor::IsFinished() { return finished_processing_idx >= 0; } -OperatorResultType PipelineExecutor::ExecutePushInternal(DataChunk &input, idx_t initial_idx) { +OperatorResultType PipelineExecutor::ExecutePushInternal(DataChunk &input, ExecutionBudget &chunk_budget, + idx_t initial_idx) { D_ASSERT(pipeline.sink); if (input.size() == 0) { // LCOV_EXCL_START return OperatorResultType::NEED_MORE_INPUT; @@ -287,11 +308,13 @@ OperatorResultType PipelineExecutor::ExecutePushInternal(DataChunk &input, idx_t // this loop will continuously push the input chunk through the pipeline as long as: // - the OperatorResultType for the Execute is HAVE_MORE_OUTPUT // - the Sink doesn't block - while (true) { - OperatorResultType result; + // - the ExecutionBudget has not been depleted + OperatorResultType result = OperatorResultType::HAVE_MORE_OUTPUT; + do { // Note: if input is the final_chunk, we don't do any executing, the chunk just needs to be sinked if (&input != &final_chunk) { final_chunk.Reset(); + // Execute and put the result into 'final_chunk' result = Execute(input, final_chunk, initial_idx); if (result == OperatorResultType::FINISHED) { return OperatorResultType::FINISHED; @@ -320,7 +343,8 @@ OperatorResultType PipelineExecutor::ExecutePushInternal(DataChunk &input, idx_t if (result == OperatorResultType::NEED_MORE_INPUT) { return OperatorResultType::NEED_MORE_INPUT; } - } + } while (chunk_budget.Next()); + return result; } PipelineExecuteResult PipelineExecutor::PushFinalize() { diff --git a/src/duckdb/src/parser/constraints/unique_constraint.cpp b/src/duckdb/src/parser/constraints/unique_constraint.cpp index 8613231eb..51c4631b3 100644 --- a/src/duckdb/src/parser/constraints/unique_constraint.cpp +++ b/src/duckdb/src/parser/constraints/unique_constraint.cpp @@ -1,6 +1,5 @@ #include "duckdb/parser/constraints/unique_constraint.hpp" -#include "duckdb/common/limits.hpp" #include "duckdb/parser/keyword_helper.hpp" namespace duckdb { @@ -8,10 +7,11 @@ namespace duckdb { UniqueConstraint::UniqueConstraint() : Constraint(ConstraintType::UNIQUE), index(DConstants::INVALID_INDEX) { } -UniqueConstraint::UniqueConstraint(LogicalIndex index, bool is_primary_key) +UniqueConstraint::UniqueConstraint(const LogicalIndex index, const bool is_primary_key) : Constraint(ConstraintType::UNIQUE), index(index), is_primary_key(is_primary_key) { } -UniqueConstraint::UniqueConstraint(vector columns, bool is_primary_key) + +UniqueConstraint::UniqueConstraint(vector columns, const bool is_primary_key) : Constraint(ConstraintType::UNIQUE), index(DConstants::INVALID_INDEX), columns(std::move(columns)), is_primary_key(is_primary_key) { } @@ -30,13 +30,76 @@ string UniqueConstraint::ToString() const { unique_ptr UniqueConstraint::Copy() const { if (!HasIndex()) { return make_uniq(columns, is_primary_key); - } else { - auto result = make_uniq(index, is_primary_key); - if (!columns.empty()) { - result->columns.push_back(columns[0]); - } - return std::move(result); } + + auto result = make_uniq(index, is_primary_key); + if (!columns.empty()) { + result->columns.push_back(columns[0]); + } + return std::move(result); +} + +bool UniqueConstraint::IsPrimaryKey() const { + return is_primary_key; +} + +bool UniqueConstraint::HasIndex() const { + return index.index != DConstants::INVALID_INDEX; +} + +LogicalIndex UniqueConstraint::GetIndex() const { + if (!HasIndex()) { + throw InternalException("UniqueConstraint::GetIndex called on a unique constraint without an index"); + } + return index; +} + +void UniqueConstraint::SetIndex(const LogicalIndex new_index) { + D_ASSERT(new_index.index != DConstants::INVALID_INDEX); + index = new_index; +} + +const vector &UniqueConstraint::GetColumnNames() const { + D_ASSERT(!columns.empty()); + return columns; +} + +vector &UniqueConstraint::GetColumnNamesMutable() { + D_ASSERT(!columns.empty()); + return columns; +} + +vector UniqueConstraint::GetLogicalIndexes(const ColumnList &column_list) const { + if (HasIndex()) { + return {GetIndex()}; + } + + vector indexes; + for (auto &col_name : GetColumnNames()) { + D_ASSERT(column_list.ColumnExists(col_name)); + auto &col = column_list.GetColumn(col_name); + D_ASSERT(!col.Generated()); + indexes.push_back(col.Logical()); + } + return indexes; +} + +string UniqueConstraint::GetName(const string &table_name) const { + auto type = IsPrimaryKey() ? IndexConstraintType::PRIMARY : IndexConstraintType::UNIQUE; + auto type_name = EnumUtil::ToString(type); + + string name; + for (const auto &column_name : GetColumnNames()) { + name += "_" + column_name; + } + return type_name + "_" + table_name + name; +} + +void UniqueConstraint::SetColumnName(const string &column_name) { + if (!columns.empty()) { + return; + } + columns.push_back(column_name); } } // namespace duckdb diff --git a/src/duckdb/src/parser/expression/columnref_expression.cpp b/src/duckdb/src/parser/expression/columnref_expression.cpp index 70720f97d..c1eb6e9cd 100644 --- a/src/duckdb/src/parser/expression/columnref_expression.cpp +++ b/src/duckdb/src/parser/expression/columnref_expression.cpp @@ -3,9 +3,7 @@ #include "duckdb/common/types/hash.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/parser/qualified_name.hpp" - -#include "duckdb/common/serializer/serializer.hpp" -#include "duckdb/common/serializer/deserializer.hpp" +#include "duckdb/planner/binding_alias.hpp" namespace duckdb { @@ -17,6 +15,20 @@ ColumnRefExpression::ColumnRefExpression(string column_name, string table_name) : vector {std::move(table_name), std::move(column_name)}) { } +ColumnRefExpression::ColumnRefExpression(string column_name, const BindingAlias &alias) + : ParsedExpression(ExpressionType::COLUMN_REF, ExpressionClass::COLUMN_REF) { + if (alias.IsSet()) { + if (!alias.GetCatalog().empty()) { + column_names.push_back(alias.GetCatalog()); + } + if (!alias.GetSchema().empty()) { + column_names.push_back(alias.GetSchema()); + } + column_names.push_back(alias.GetAlias()); + } + column_names.push_back(std::move(column_name)); +} + ColumnRefExpression::ColumnRefExpression(string column_name) : ColumnRefExpression(vector {std::move(column_name)}) { } diff --git a/src/duckdb/src/parser/expression/lambdaref_expression.cpp b/src/duckdb/src/parser/expression/lambdaref_expression.cpp index 786d10912..fed844fea 100644 --- a/src/duckdb/src/parser/expression/lambdaref_expression.cpp +++ b/src/duckdb/src/parser/expression/lambdaref_expression.cpp @@ -47,7 +47,7 @@ LambdaRefExpression::FindMatchingBinding(optional_ptr> &lam if (lambda_bindings) { for (idx_t i = lambda_bindings->size(); i > 0; i--) { if ((*lambda_bindings)[i - 1].HasMatchingBinding(column_name)) { - D_ASSERT(!(*lambda_bindings)[i - 1].alias.empty()); + D_ASSERT((*lambda_bindings)[i - 1].alias.IsSet()); return make_uniq(i - 1, column_name); } } diff --git a/src/duckdb/src/parser/expression/star_expression.cpp b/src/duckdb/src/parser/expression/star_expression.cpp index 3589b9533..22279f121 100644 --- a/src/duckdb/src/parser/expression/star_expression.cpp +++ b/src/duckdb/src/parser/expression/star_expression.cpp @@ -33,7 +33,7 @@ string StarExpression::ToString() const { if (!first_entry) { result += ", "; } - result += KeywordHelper::WriteOptionallyQuoted(entry); + result += entry.ToString(); first_entry = false; } result += ")"; @@ -52,6 +52,20 @@ string StarExpression::ToString() const { } result += ")"; } + if (!rename_list.empty()) { + result += " RENAME ("; + bool first_entry = true; + for (auto &entry : rename_list) { + if (!first_entry) { + result += ", "; + } + result += entry.first.ToString(); + result += " AS "; + result += KeywordHelper::WriteOptionallyQuoted(entry.second); + first_entry = false; + } + result += ")"; + } if (columns) { result += ")"; } @@ -59,7 +73,7 @@ string StarExpression::ToString() const { } bool StarExpression::Equal(const StarExpression &a, const StarExpression &b) { - if (a.relation_name != b.relation_name || a.exclude_list != b.exclude_list) { + if (a.relation_name != b.relation_name || a.exclude_list != b.exclude_list || a.rename_list != b.rename_list) { return false; } if (a.columns != b.columns) { @@ -116,6 +130,7 @@ unique_ptr StarExpression::Copy() const { for (auto &entry : replace_list) { copy->replace_list[entry.first] = entry.second->Copy(); } + copy->rename_list = rename_list; copy->columns = columns; copy->expr = expr ? expr->Copy() : nullptr; copy->CopyProperties(*this); @@ -123,4 +138,33 @@ unique_ptr StarExpression::Copy() const { return std::move(copy); } +StarExpression::StarExpression(const case_insensitive_set_t &exclude_list_p, qualified_column_set_t qualified_set) + : ParsedExpression(ExpressionType::STAR, ExpressionClass::STAR), exclude_list(std::move(qualified_set)) { + for (auto &entry : exclude_list_p) { + exclude_list.insert(QualifiedColumnName(entry)); + } +} + +case_insensitive_set_t StarExpression::SerializedExcludeList() const { + // we serialize non-qualified elements in a separate list of only column names for backwards compatibility + case_insensitive_set_t result; + for (auto &entry : exclude_list) { + if (!entry.IsQualified()) { + result.insert(entry.column); + } + } + return result; +} + +qualified_column_set_t StarExpression::SerializedQualifiedExcludeList() const { + // we serialize only qualified elements in the qualified list for backwards compatibility + qualified_column_set_t result; + for (auto &entry : exclude_list) { + if (entry.IsQualified()) { + result.insert(entry); + } + } + return result; +} + } // namespace duckdb diff --git a/src/duckdb/src/parser/parsed_data/alter_info.cpp b/src/duckdb/src/parser/parsed_data/alter_info.cpp index e4a78ba91..2f90d0abf 100644 --- a/src/duckdb/src/parser/parsed_data/alter_info.cpp +++ b/src/duckdb/src/parser/parsed_data/alter_info.cpp @@ -1,7 +1,8 @@ #include "duckdb/parser/parsed_data/alter_info.hpp" -#include "duckdb/parser/parsed_data/alter_table_info.hpp" + #include "duckdb/parser/parsed_data/alter_scalar_function_info.hpp" -#include "duckdb/parser/parsed_data/alter_table_function_info.hpp" +#include "duckdb/parser/parsed_data/alter_table_info.hpp" +#include "duckdb/parser/constraints/unique_constraint.hpp" namespace duckdb { @@ -25,4 +26,27 @@ AlterEntryData AlterInfo::GetAlterEntryData() const { return data; } +bool AlterInfo::IsAddPrimaryKey() const { + if (type != AlterType::ALTER_TABLE) { + return false; + } + + auto &table_info = Cast(); + if (table_info.alter_table_type != AlterTableType::ADD_CONSTRAINT) { + return false; + } + + auto &constraint_info = table_info.Cast(); + if (constraint_info.constraint->type != ConstraintType::UNIQUE) { + return false; + } + + auto &unique_info = constraint_info.constraint->Cast(); + if (!unique_info.IsPrimaryKey()) { + return false; + } + + return true; +} + } // namespace duckdb diff --git a/src/duckdb/src/parser/parsed_data/alter_scalar_function_info.cpp b/src/duckdb/src/parser/parsed_data/alter_scalar_function_info.cpp index 269a87d66..3de4fc52a 100644 --- a/src/duckdb/src/parser/parsed_data/alter_scalar_function_info.cpp +++ b/src/duckdb/src/parser/parsed_data/alter_scalar_function_info.cpp @@ -1,5 +1,5 @@ #include "duckdb/parser/parsed_data/alter_scalar_function_info.hpp" - +#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" #include "duckdb/parser/constraint.hpp" namespace duckdb { @@ -22,7 +22,8 @@ CatalogType AlterScalarFunctionInfo::GetCatalogType() const { //===--------------------------------------------------------------------===// // AddScalarFunctionOverloadInfo //===--------------------------------------------------------------------===// -AddScalarFunctionOverloadInfo::AddScalarFunctionOverloadInfo(AlterEntryData data, ScalarFunctionSet new_overloads_p) +AddScalarFunctionOverloadInfo::AddScalarFunctionOverloadInfo(AlterEntryData data, + unique_ptr new_overloads_p) : AlterScalarFunctionInfo(AlterScalarFunctionType::ADD_FUNCTION_OVERLOADS, std::move(data)), new_overloads(std::move(new_overloads_p)) { this->allow_internal = true; @@ -32,7 +33,8 @@ AddScalarFunctionOverloadInfo::~AddScalarFunctionOverloadInfo() { } unique_ptr AddScalarFunctionOverloadInfo::Copy() const { - return make_uniq_base(GetAlterEntryData(), new_overloads); + return make_uniq_base( + GetAlterEntryData(), unique_ptr_cast(new_overloads->Copy())); } string AddScalarFunctionOverloadInfo::ToString() const { 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 1a82ca1fd..ddf7db07d 100644 --- a/src/duckdb/src/parser/parsed_data/alter_table_info.cpp +++ b/src/duckdb/src/parser/parsed_data/alter_table_info.cpp @@ -261,7 +261,9 @@ string ChangeColumnTypeInfo::ToString() const { result += " ALTER COLUMN "; result += KeywordHelper::WriteOptionallyQuoted(column_name); result += " TYPE "; - result += target_type.ToString(); // FIXME: ToSQLString ? + if (target_type.IsValid()) { + result += target_type.ToString(); + } auto extra_type_info = target_type.AuxInfo(); if (extra_type_info && extra_type_info->type == ExtraTypeInfoType::STRING_TYPE_INFO) { auto &string_info = extra_type_info->Cast(); @@ -445,4 +447,30 @@ string RenameViewInfo::ToString() const { return result; } +//===--------------------------------------------------------------------===// +// AddConstraintInfo +//===--------------------------------------------------------------------===// +AddConstraintInfo::AddConstraintInfo() : AlterTableInfo(AlterTableType::ADD_CONSTRAINT) { +} + +AddConstraintInfo::AddConstraintInfo(AlterEntryData data, unique_ptr constraint_p) + : AlterTableInfo(AlterTableType::ADD_CONSTRAINT, std::move(data)), constraint(std::move(constraint_p)) { +} + +AddConstraintInfo::~AddConstraintInfo() { +} + +unique_ptr AddConstraintInfo::Copy() const { + return make_uniq_base(GetAlterEntryData(), constraint->Copy()); +} + +string AddConstraintInfo::ToString() const { + string result = "ALTER TABLE "; + result += QualifierToString(catalog, schema, name); + result += " ADD "; + result += constraint->ToString(); + result += ";"; + return result; +} + } // namespace duckdb diff --git a/src/duckdb/src/parser/parsed_data/attach_info.cpp b/src/duckdb/src/parser/parsed_data/attach_info.cpp index 63cf8b66c..3ad50d8bb 100644 --- a/src/duckdb/src/parser/parsed_data/attach_info.cpp +++ b/src/duckdb/src/parser/parsed_data/attach_info.cpp @@ -6,18 +6,18 @@ namespace duckdb { -optional_idx AttachInfo::GetBlockAllocSize() const { - +StorageOptions AttachInfo::GetStorageOptions() const { + StorageOptions storage_options; for (auto &entry : options) { if (entry.first == "block_size") { // Extract the block allocation size. This is NOT the actual memory available on a block (block_size), // even though the corresponding option we expose to the user is called "block_size". - idx_t block_alloc_size = UBigIntValue::Get(entry.second.DefaultCastAs(LogicalType::UBIGINT)); - Storage::VerifyBlockAllocSize(block_alloc_size); - return block_alloc_size; + storage_options.block_alloc_size = entry.second.GetValue(); + } else if (entry.first == "row_group_size") { + storage_options.row_group_size = entry.second.GetValue(); } } - return optional_idx(); + return storage_options; } unique_ptr AttachInfo::Copy() const { diff --git a/src/duckdb/src/parser/parsed_data/create_aggregate_function_info.cpp b/src/duckdb/src/parser/parsed_data/create_aggregate_function_info.cpp index 8e4f31e20..4e7476b88 100644 --- a/src/duckdb/src/parser/parsed_data/create_aggregate_function_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_aggregate_function_info.cpp @@ -20,7 +20,7 @@ CreateAggregateFunctionInfo::CreateAggregateFunctionInfo(AggregateFunctionSet se unique_ptr CreateAggregateFunctionInfo::Copy() const { auto result = make_uniq(functions); - CopyProperties(*result); + CopyFunctionProperties(*result); return std::move(result); } diff --git a/src/duckdb/src/parser/parsed_data/create_function_info.cpp b/src/duckdb/src/parser/parsed_data/create_function_info.cpp new file mode 100644 index 000000000..dbaefed99 --- /dev/null +++ b/src/duckdb/src/parser/parsed_data/create_function_info.cpp @@ -0,0 +1,19 @@ +#include "duckdb/parser/parsed_data/create_function_info.hpp" + +namespace duckdb { + +CreateFunctionInfo::CreateFunctionInfo(CatalogType type, string schema) : CreateInfo(type, std::move(schema)) { + D_ASSERT(type == CatalogType::SCALAR_FUNCTION_ENTRY || type == CatalogType::AGGREGATE_FUNCTION_ENTRY || + type == CatalogType::TABLE_FUNCTION_ENTRY || type == CatalogType::PRAGMA_FUNCTION_ENTRY || + type == CatalogType::MACRO_ENTRY || type == CatalogType::TABLE_MACRO_ENTRY); +} + +void CreateFunctionInfo::CopyFunctionProperties(CreateFunctionInfo &other) const { + CopyProperties(other); + other.name = name; + other.description = description; + other.parameter_names = parameter_names; + other.example = example; +} + +} // namespace duckdb diff --git a/src/duckdb/src/parser/parsed_data/create_index_info.cpp b/src/duckdb/src/parser/parsed_data/create_index_info.cpp index 01e2840fa..7fd3a220c 100644 --- a/src/duckdb/src/parser/parsed_data/create_index_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_index_info.cpp @@ -1,6 +1,7 @@ #include "duckdb/parser/parsed_data/create_index_info.hpp" -#include "duckdb/parser/parsed_expression_iterator.hpp" + #include "duckdb/parser/expression/columnref_expression.hpp" +#include "duckdb/parser/parsed_expression_iterator.hpp" namespace duckdb { @@ -14,16 +15,17 @@ CreateIndexInfo::CreateIndexInfo(const duckdb::CreateIndexInfo &info) } static void RemoveTableQualificationRecursive(unique_ptr &expr, const string &table_name) { - if (expr->GetExpressionType() == ExpressionType::COLUMN_REF) { - auto &col_ref = expr->Cast(); - auto &col_names = col_ref.column_names; - if (col_ref.IsQualified() && col_ref.GetTableName() == table_name) { - col_names.erase(col_names.begin()); - } - } else { + if (expr->GetExpressionType() != ExpressionType::COLUMN_REF) { ParsedExpressionIterator::EnumerateChildren(*expr, [&table_name](unique_ptr &child) { RemoveTableQualificationRecursive(child, table_name); }); + return; + } + + auto &col_ref = expr->Cast(); + auto &col_names = col_ref.column_names; + if (col_ref.IsQualified() && col_ref.GetTableName() == table_name) { + col_names.erase(col_names.begin()); } } @@ -33,18 +35,19 @@ vector CreateIndexInfo::ExpressionsToList() const { for (idx_t i = 0; i < parsed_expressions.size(); i++) { auto &expr = parsed_expressions[i]; auto copy = expr->Copy(); - // column ref expressions are qualified with the table name - // we need to remove them to reproduce the original query + + // Column reference expressions are qualified with the table name. + // We need to remove them to reproduce the original query. RemoveTableQualificationRecursive(copy, table); bool add_parenthesis = true; if (copy->type == ExpressionType::COLUMN_REF) { auto &column_ref = copy->Cast(); if (!column_ref.IsQualified()) { - // Only when column references are not qualified, i.e (col1, col2) - // then these expressions do not need to be wrapped in parenthesis + // Only not qualified references like (col1, col2) don't need parenthesis. add_parenthesis = false; } } + if (add_parenthesis) { list.push_back(StringUtil::Format("(%s)", copy->ToString())); } else { @@ -99,7 +102,6 @@ string CreateIndexInfo::ToString() const { } unique_ptr CreateIndexInfo::Copy() const { - auto result = make_uniq(*this); CopyProperties(*result); @@ -109,7 +111,6 @@ unique_ptr CreateIndexInfo::Copy() const { for (auto &expr : parsed_expressions) { result->parsed_expressions.push_back(expr->Copy()); } - return std::move(result); } diff --git a/src/duckdb/src/parser/parsed_data/create_macro_info.cpp b/src/duckdb/src/parser/parsed_data/create_macro_info.cpp index a732eac58..0891b32dc 100644 --- a/src/duckdb/src/parser/parsed_data/create_macro_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_macro_info.cpp @@ -46,7 +46,7 @@ unique_ptr CreateMacroInfo::Copy() const { result->macros.push_back(macro->Copy()); } result->name = name; - CopyProperties(*result); + CopyFunctionProperties(*result); return std::move(result); } diff --git a/src/duckdb/src/parser/parsed_data/create_pragma_function_info.cpp b/src/duckdb/src/parser/parsed_data/create_pragma_function_info.cpp index 6d2c8a154..7e38ee885 100644 --- a/src/duckdb/src/parser/parsed_data/create_pragma_function_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_pragma_function_info.cpp @@ -16,7 +16,7 @@ CreatePragmaFunctionInfo::CreatePragmaFunctionInfo(string name, PragmaFunctionSe unique_ptr CreatePragmaFunctionInfo::Copy() const { auto result = make_uniq(functions.name, functions); - CopyProperties(*result); + CopyFunctionProperties(*result); return std::move(result); } diff --git a/src/duckdb/src/parser/parsed_data/create_scalar_function_info.cpp b/src/duckdb/src/parser/parsed_data/create_scalar_function_info.cpp index 6d01bcfb3..51598a72e 100644 --- a/src/duckdb/src/parser/parsed_data/create_scalar_function_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_scalar_function_info.cpp @@ -22,13 +22,14 @@ unique_ptr CreateScalarFunctionInfo::Copy() const { ScalarFunctionSet set(name); set.functions = functions.functions; auto result = make_uniq(std::move(set)); - CopyProperties(*result); + CopyFunctionProperties(*result); return std::move(result); } unique_ptr CreateScalarFunctionInfo::GetAlterInfo() const { return make_uniq_base( - AlterEntryData(catalog, schema, name, OnEntryNotFound::RETURN_NULL), functions); + AlterEntryData(catalog, schema, name, OnEntryNotFound::RETURN_NULL), + unique_ptr_cast(Copy())); } } // namespace duckdb diff --git a/src/duckdb/src/parser/parsed_data/create_schema_info.cpp b/src/duckdb/src/parser/parsed_data/create_schema_info.cpp index 36796b952..e7c7f3f8b 100644 --- a/src/duckdb/src/parser/parsed_data/create_schema_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_schema_info.cpp @@ -22,7 +22,7 @@ string CreateSchemaInfo::ToString() const { break; } case OnCreateConflict::IGNORE_ON_CONFLICT: { - ret += "CREATE SCHEMA " + qualified + " IF NOT EXISTS;"; + ret += "CREATE SCHEMA IF NOT EXISTS " + qualified + ";"; break; } case OnCreateConflict::REPLACE_ON_CONFLICT: { diff --git a/src/duckdb/src/parser/parsed_data/create_table_function_info.cpp b/src/duckdb/src/parser/parsed_data/create_table_function_info.cpp index c2d297b5e..3e774fba9 100644 --- a/src/duckdb/src/parser/parsed_data/create_table_function_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_table_function_info.cpp @@ -22,7 +22,7 @@ unique_ptr CreateTableFunctionInfo::Copy() const { TableFunctionSet set(name); set.functions = functions.functions; auto result = make_uniq(std::move(set)); - CopyProperties(*result); + CopyFunctionProperties(*result); return std::move(result); } 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 c9df25783..0568a8fd1 100644 --- a/src/duckdb/src/parser/parsed_data/create_table_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_table_info.cpp @@ -47,6 +47,7 @@ string CreateTableInfo::ToString() const { ret += QualifierToString(temporary ? "" : catalog, schema, table); if (query != nullptr) { + ret += TableCatalogEntry::ColumnNamesToSQL(columns); ret += " AS " + query->ToString(); } else { ret += TableCatalogEntry::ColumnsToSQL(columns, constraints) + ";"; diff --git a/src/duckdb/src/parser/parsed_data/sample_options.cpp b/src/duckdb/src/parser/parsed_data/sample_options.cpp index 03c8b322a..010ae2e6f 100644 --- a/src/duckdb/src/parser/parsed_data/sample_options.cpp +++ b/src/duckdb/src/parser/parsed_data/sample_options.cpp @@ -9,6 +9,15 @@ string SampleMethodToString(SampleMethod method) { return EnumUtil::ToString(method); } +SampleOptions::SampleOptions(int64_t seed_) { + if (seed_ >= 0) { + seed = static_cast(seed_); + } + sample_size = 0; + is_percentage = false; + method = SampleMethod::INVALID; +} + unique_ptr SampleOptions::Copy() { auto result = make_uniq(); result->sample_size = sample_size; @@ -18,6 +27,10 @@ unique_ptr SampleOptions::Copy() { return result; } +void SampleOptions::SetSeed(idx_t new_seed) { + seed = new_seed; +} + bool SampleOptions::Equals(SampleOptions *a, SampleOptions *b) { if (a == b) { return true; @@ -25,11 +38,26 @@ bool SampleOptions::Equals(SampleOptions *a, SampleOptions *b) { if (!a || !b) { return false; } + // if only one is valid, they are not equal + if (a->seed.IsValid() != b->seed.IsValid()) { + return false; + } + // if both are invalid, then they are technically the same + if (!a->seed.IsValid() && !b->seed.IsValid()) { + return true; + } if (a->sample_size != b->sample_size || a->is_percentage != b->is_percentage || a->method != b->method || - a->seed != b->seed) { + a->seed.GetIndex() != b->seed.GetIndex()) { return false; } return true; } +int64_t SampleOptions::GetSeed() const { + if (seed.IsValid()) { + return static_cast(seed.GetIndex()); + } + return -1; +} + } // namespace duckdb diff --git a/src/duckdb/src/parser/qualified_name.cpp b/src/duckdb/src/parser/qualified_name.cpp new file mode 100644 index 000000000..9a43cbc2c --- /dev/null +++ b/src/duckdb/src/parser/qualified_name.cpp @@ -0,0 +1,94 @@ +#include "duckdb/parser/qualified_name.hpp" + +namespace duckdb { + +QualifiedName QualifiedName::Parse(const string &input) { + string catalog; + string schema; + string name; + idx_t idx = 0; + vector entries; + string entry; +normal: + //! quote + for (; idx < input.size(); idx++) { + if (input[idx] == '"') { + idx++; + goto quoted; + } else if (input[idx] == '.') { + goto separator; + } + entry += input[idx]; + } + goto end; +separator: + entries.push_back(entry); + entry = ""; + idx++; + goto normal; +quoted: + //! look for another quote + for (; idx < input.size(); idx++) { + if (input[idx] == '"') { + //! unquote + idx++; + goto normal; + } + entry += input[idx]; + } + throw ParserException("Unterminated quote in qualified name!"); +end: + if (entries.empty()) { + catalog = INVALID_CATALOG; + schema = INVALID_SCHEMA; + name = entry; + } else if (entries.size() == 1) { + catalog = INVALID_CATALOG; + schema = entries[0]; + name = entry; + } else if (entries.size() == 2) { + catalog = entries[0]; + schema = entries[1]; + name = entry; + } else { + throw ParserException("Expected catalog.entry, schema.entry or entry: too many entries found"); + } + return QualifiedName {catalog, schema, name}; +} + +QualifiedColumnName::QualifiedColumnName() { +} +QualifiedColumnName::QualifiedColumnName(string column_p) : column(std::move(column_p)) { +} +QualifiedColumnName::QualifiedColumnName(string table_p, string column_p) + : table(std::move(table_p)), column(std::move(column_p)) { +} +QualifiedColumnName::QualifiedColumnName(const BindingAlias &alias, string column_p) + : catalog(alias.GetCatalog()), schema(alias.GetSchema()), table(alias.GetAlias()), column(std::move(column_p)) { +} + +string QualifiedColumnName::ToString() const { + string result; + if (!catalog.empty()) { + result += KeywordHelper::WriteOptionallyQuoted(catalog) + "."; + } + if (!schema.empty()) { + result += KeywordHelper::WriteOptionallyQuoted(schema) + "."; + } + if (!table.empty()) { + result += KeywordHelper::WriteOptionallyQuoted(table) + "."; + } + result += KeywordHelper::WriteOptionallyQuoted(column); + return result; +} + +bool QualifiedColumnName::IsQualified() const { + return !catalog.empty() || !schema.empty() || !table.empty(); +} + +bool QualifiedColumnName::operator==(const QualifiedColumnName &rhs) const { + return StringUtil::CIEquals(catalog, rhs.catalog) && StringUtil::CIEquals(schema, rhs.schema) && + StringUtil::CIEquals(table, rhs.table) && StringUtil::CIEquals(column, rhs.column); +} + +} // namespace duckdb diff --git a/src/duckdb/src/parser/query_node/select_node.cpp b/src/duckdb/src/parser/query_node/select_node.cpp index 66ad5dc72..f42dafdce 100644 --- a/src/duckdb/src/parser/query_node/select_node.cpp +++ b/src/duckdb/src/parser/query_node/select_node.cpp @@ -101,8 +101,8 @@ string SelectNode::ToString() const { result += "%"; } result += " (" + EnumUtil::ToString(sample->method); - if (sample->seed >= 0) { - result += ", " + std::to_string(sample->seed); + if (sample->seed.IsValid()) { + result += ", " + std::to_string(sample->seed.GetIndex()); } result += ")"; } diff --git a/src/duckdb/src/parser/tableref.cpp b/src/duckdb/src/parser/tableref.cpp index f8b8db70c..9ce290237 100644 --- a/src/duckdb/src/parser/tableref.cpp +++ b/src/duckdb/src/parser/tableref.cpp @@ -31,8 +31,8 @@ string TableRef::BaseToString(string result, const vector &column_name_a if (sample) { result += " TABLESAMPLE " + EnumUtil::ToString(sample->method); result += "(" + sample->sample_size.ToString() + " " + string(sample->is_percentage ? "PERCENT" : "ROWS") + ")"; - if (sample->seed >= 0) { - result += "REPEATABLE (" + to_string(sample->seed) + ")"; + if (sample->seed.IsValid()) { + result += "REPEATABLE (" + to_string(sample->seed.GetIndex()) + ")"; } } diff --git a/src/duckdb/src/parser/transform/constraint/transform_constraint.cpp b/src/duckdb/src/parser/transform/constraint/transform_constraint.cpp index dcb467e9c..8439fc863 100644 --- a/src/duckdb/src/parser/transform/constraint/transform_constraint.cpp +++ b/src/duckdb/src/parser/transform/constraint/transform_constraint.cpp @@ -68,50 +68,42 @@ TransformForeignKeyConstraint(duckdb_libpgquery::PGConstraint &constraint, return make_uniq(pk_columns, fk_columns, std::move(fk_info)); } -unique_ptr Transformer::TransformConstraint(duckdb_libpgquery::PGListCell &cell) { - - auto constraint = PGPointerCast(cell.data.ptr_value); - D_ASSERT(constraint); - - switch (constraint->contype) { +unique_ptr Transformer::TransformConstraint(duckdb_libpgquery::PGConstraint &constraint) { + switch (constraint.contype) { case duckdb_libpgquery::PG_CONSTR_UNIQUE: case duckdb_libpgquery::PG_CONSTR_PRIMARY: { - bool is_primary_key = constraint->contype == duckdb_libpgquery::PG_CONSTR_PRIMARY; - if (!constraint->keys) { + bool is_primary_key = constraint.contype == duckdb_libpgquery::PG_CONSTR_PRIMARY; + if (!constraint.keys) { throw ParserException("UNIQUE USING INDEX is not supported"); } vector columns; - for (auto kc = constraint->keys->head; kc; kc = kc->next) { + for (auto kc = constraint.keys->head; kc; kc = kc->next) { auto value = PGPointerCast(kc->data.ptr_value); columns.emplace_back(value->val.str); } return make_uniq(columns, is_primary_key); } case duckdb_libpgquery::PG_CONSTR_CHECK: { - auto expression = TransformExpression(constraint->raw_expr); + auto expression = TransformExpression(constraint.raw_expr); if (expression->HasSubquery()) { throw ParserException("subqueries prohibited in CHECK constraints"); } - return make_uniq(TransformExpression(constraint->raw_expr)); + return make_uniq(TransformExpression(constraint.raw_expr)); } case duckdb_libpgquery::PG_CONSTR_FOREIGN: - return TransformForeignKeyConstraint(*constraint.get()); + return TransformForeignKeyConstraint(constraint); default: throw NotImplementedException("Constraint type not handled yet!"); } } -unique_ptr Transformer::TransformConstraint(duckdb_libpgquery::PGListCell &cell, ColumnDefinition &column, - idx_t index) { - - auto constraint = PGPointerCast(cell.data.ptr_value); - D_ASSERT(constraint); - - switch (constraint->contype) { +unique_ptr Transformer::TransformConstraint(duckdb_libpgquery::PGConstraint &constraint, + ColumnDefinition &column, idx_t index) { + switch (constraint.contype) { case duckdb_libpgquery::PG_CONSTR_NOTNULL: return make_uniq(LogicalIndex(index)); case duckdb_libpgquery::PG_CONSTR_CHECK: - return TransformConstraint(cell); + return TransformConstraint(constraint); case duckdb_libpgquery::PG_CONSTR_PRIMARY: return make_uniq(LogicalIndex(index), true); case duckdb_libpgquery::PG_CONSTR_UNIQUE: @@ -123,23 +115,23 @@ unique_ptr Transformer::TransformConstraint(duckdb_libpgquery::PGLis throw InvalidInputException("\"%s\" has a DEFAULT value set, it can not become a GENERATED column", column.Name()); } - column.SetGeneratedExpression(TransformExpression(constraint->raw_expr)); + column.SetGeneratedExpression(TransformExpression(constraint.raw_expr)); return nullptr; } case duckdb_libpgquery::PG_CONSTR_GENERATED_STORED: throw InvalidInputException("Can not create a STORED generated column!"); case duckdb_libpgquery::PG_CONSTR_DEFAULT: - column.SetDefaultValue(TransformExpression(constraint->raw_expr)); + column.SetDefaultValue(TransformExpression(constraint.raw_expr)); return nullptr; case duckdb_libpgquery::PG_CONSTR_COMPRESSION: - column.SetCompressionType(CompressionTypeFromString(constraint->compression_name)); + 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 or fsst"); } return nullptr; case duckdb_libpgquery::PG_CONSTR_FOREIGN: - return TransformForeignKeyConstraint(*constraint.get(), &column.Name()); + return TransformForeignKeyConstraint(constraint, &column.Name()); default: throw NotImplementedException("Constraint not implemented!"); } diff --git a/src/duckdb/src/parser/transform/expression/transform_columnref.cpp b/src/duckdb/src/parser/transform/expression/transform_columnref.cpp index 7137169f8..5a8e0c90d 100644 --- a/src/duckdb/src/parser/transform/expression/transform_columnref.cpp +++ b/src/duckdb/src/parser/transform/expression/transform_columnref.cpp @@ -6,17 +6,44 @@ namespace duckdb { +QualifiedColumnName TransformQualifiedColumnName(duckdb_libpgquery::PGList &list) { + QualifiedColumnName result; + switch (list.length) { + case 1: + result.column = const_char_ptr_cast(list.head->data.ptr_value); + break; + case 2: + result.table = const_char_ptr_cast(list.head->data.ptr_value); + result.column = const_char_ptr_cast(list.head->next->data.ptr_value); + break; + case 3: + result.schema = const_char_ptr_cast(list.head->data.ptr_value); + result.table = const_char_ptr_cast(list.head->next->data.ptr_value); + result.column = const_char_ptr_cast(list.head->next->next->data.ptr_value); + break; + case 4: + result.catalog = const_char_ptr_cast(list.head->data.ptr_value); + result.schema = const_char_ptr_cast(list.head->next->data.ptr_value); + result.table = const_char_ptr_cast(list.head->next->next->data.ptr_value); + result.column = const_char_ptr_cast(list.head->next->next->next->data.ptr_value); + break; + default: + throw ParserException("Qualified column name must have between 1 and 4 elements"); + } + return result; +} + unique_ptr Transformer::TransformStarExpression(duckdb_libpgquery::PGAStar &star) { auto result = make_uniq(star.relation ? star.relation : string()); if (star.except_list) { for (auto head = star.except_list->head; head; head = head->next) { - auto value = PGPointerCast(head->data.ptr_value); - D_ASSERT(value->type == duckdb_libpgquery::T_PGString); - string exclude_entry = value->val.str; - if (result->exclude_list.find(exclude_entry) != result->exclude_list.end()) { - throw ParserException("Duplicate entry \"%s\" in EXCLUDE list", exclude_entry); + auto exclude_column_list = PGPointerCast(head->data.ptr_value); + auto exclude_column = TransformQualifiedColumnName(*exclude_column_list); + // qualified - add to exclude list + if (result->exclude_list.find(exclude_column) != result->exclude_list.end()) { + throw ParserException("Duplicate entry \"%s\" in EXCLUDE list", exclude_column.ToString()); } - result->exclude_list.insert(std::move(exclude_entry)); + result->exclude_list.insert(std::move(exclude_column)); } } if (star.replace_list) { @@ -27,14 +54,35 @@ unique_ptr Transformer::TransformStarExpression(duckdb_libpgqu TransformExpression(PGPointerCast(list->head->data.ptr_value)); auto value = PGPointerCast(list->tail->data.ptr_value); D_ASSERT(value->type == duckdb_libpgquery::T_PGString); - string exclude_entry = value->val.str; - if (result->replace_list.find(exclude_entry) != result->replace_list.end()) { - throw ParserException("Duplicate entry \"%s\" in REPLACE list", exclude_entry); + string replace_entry = value->val.str; + if (result->replace_list.find(replace_entry) != result->replace_list.end()) { + throw ParserException("Duplicate entry \"%s\" in REPLACE list", replace_entry); + } + if (result->exclude_list.find(QualifiedColumnName(replace_entry)) != result->exclude_list.end()) { + throw ParserException("Column \"%s\" cannot occur in both EXCLUDE and REPLACE list", replace_entry); + } + result->replace_list.insert(make_pair(std::move(replace_entry), std::move(replace_expression))); + } + } + if (star.rename_list) { + for (auto head = star.rename_list->head; head; head = head->next) { + auto list = PGPointerCast(head->data.ptr_value); + D_ASSERT(list->length == 2); + auto rename_column_list = PGPointerCast(list->head->data.ptr_value); + auto rename_column = TransformQualifiedColumnName(*rename_column_list); + string new_name = char_ptr_cast(list->tail->data.ptr_value); + if (result->rename_list.find(rename_column) != result->rename_list.end()) { + throw ParserException("Duplicate entry \"%s\" in EXCLUDE list", rename_column.ToString()); + } + if (result->exclude_list.find(rename_column) != result->exclude_list.end()) { + throw ParserException("Column \"%s\" cannot occur in both EXCLUDE and RENAME list", + rename_column.ToString()); } - if (result->exclude_list.find(exclude_entry) != result->exclude_list.end()) { - throw ParserException("Column \"%s\" cannot occur in both EXCEPT and REPLACE list", exclude_entry); + if (result->replace_list.find(rename_column.column) != result->replace_list.end()) { + throw ParserException("Column \"%s\" cannot occur in both REPLACE and RENAME list", + rename_column.ToString()); } - result->replace_list.insert(make_pair(std::move(exclude_entry), std::move(replace_expression))); + result->rename_list.insert(make_pair(std::move(rename_column), std::move(new_name))); } } if (star.expr) { diff --git a/src/duckdb/src/parser/transform/helpers/transform_sample.cpp b/src/duckdb/src/parser/transform/helpers/transform_sample.cpp index 0cffebfed..1873a1ce9 100644 --- a/src/duckdb/src/parser/transform/helpers/transform_sample.cpp +++ b/src/duckdb/src/parser/transform/helpers/transform_sample.cpp @@ -25,7 +25,13 @@ unique_ptr Transformer::TransformSampleOptions(optional_ptr(); auto &sample_options = PGCast(*options); auto &sample_size = *PGPointerCast(sample_options.sample_size); - auto sample_value = TransformValue(sample_size.sample_size)->value; + auto sample_expression = TransformExpression(sample_size.sample_size); + if (sample_expression->type != ExpressionType::VALUE_CONSTANT) { + throw ParserException(sample_expression->query_location, + "Only constants are supported in sample clause currently"); + } + auto &const_expr = sample_expression->Cast(); + auto &sample_value = const_expr.value; result->is_percentage = sample_size.is_percentage; if (sample_size.is_percentage) { // sample size is given in sample_size: use system sampling @@ -47,8 +53,8 @@ unique_ptr Transformer::TransformSampleOptions(optional_ptrmethod = GetSampleMethod(sample_options.method); } - if (sample_options.has_seed) { - result->seed = sample_options.seed; + if (sample_options.has_seed && sample_options.seed >= 0) { + result->seed = static_cast(sample_options.seed); } return result; } 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 d3b57c8e2..2537daaec 100644 --- a/src/duckdb/src/parser/transform/statement/transform_alter_table.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_alter_table.cpp @@ -39,8 +39,9 @@ unique_ptr Transformer::TransformAlter(duckdb_libpgquery::PGAlte auto column_entry = TransformColumnDefinition(*column_def); if (column_def->constraints) { - for (auto constr = column_def->constraints->head; constr != nullptr; constr = constr->next) { - auto constraint = TransformConstraint(*constr, column_entry, 0); + for (auto cell = column_def->constraints->head; cell != nullptr; cell = cell->next) { + auto pg_constraint = PGPointerCast(cell->data.ptr_value); + auto constraint = TransformConstraint(*pg_constraint, column_entry, 0); if (!constraint) { continue; } @@ -74,6 +75,11 @@ unique_ptr Transformer::TransformAlter(duckdb_libpgquery::PGAlte if (stmt.relkind != duckdb_libpgquery::PG_OBJECT_TABLE) { throw ParserException("Alter column's type is only supported for tables"); } + + if (column_entry.GetType() == LogicalType::UNKNOWN && !column_def->raw_default) { + throw ParserException("Omitting the type is only possible in combination with USING"); + } + if (column_def->raw_default) { expr = TransformExpression(column_def->raw_default); } else { @@ -92,7 +98,16 @@ unique_ptr Transformer::TransformAlter(duckdb_libpgquery::PGAlte result->info = make_uniq(std::move(data), command->name); break; } - case duckdb_libpgquery::PG_AT_DropConstraint: + case duckdb_libpgquery::PG_AT_AddConstraint: { + auto pg_constraint = PGCast(*command->def); + if (pg_constraint.contype != duckdb_libpgquery::PGConstrType::PG_CONSTR_PRIMARY) { + throw NotImplementedException("No support for that ALTER TABLE option yet!"); + } + + auto constraint = TransformConstraint(pg_constraint); + result->info = make_uniq(std::move(data), std::move(constraint)); + break; + } default: throw NotImplementedException("No support for that ALTER TABLE option yet!"); } diff --git a/src/duckdb/src/parser/transform/statement/transform_copy.cpp b/src/duckdb/src/parser/transform/statement/transform_copy.cpp index 1fa2464f5..7c199ac5b 100644 --- a/src/duckdb/src/parser/transform/statement/transform_copy.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_copy.cpp @@ -1,6 +1,5 @@ #include "duckdb/common/string_util.hpp" #include "duckdb/common/types/value.hpp" -#include "duckdb/core_functions/scalar/struct_functions.hpp" #include "duckdb/function/replacement_scan.hpp" #include "duckdb/parser/expression/constant_expression.hpp" #include "duckdb/parser/expression/function_expression.hpp" 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 e0177e4fa..412a73cd3 100644 --- a/src/duckdb/src/parser/transform/statement/transform_create_table.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_create_table.cpp @@ -47,12 +47,22 @@ unique_ptr Transformer::TransformCollateExpr(duckdb_libpgquery } ColumnDefinition Transformer::TransformColumnDefinition(duckdb_libpgquery::PGColumnDef &cdef) { - string colname; + string name; if (cdef.colname) { - colname = cdef.colname; + name = cdef.colname; } - bool optional_type = cdef.category == duckdb_libpgquery::COL_GENERATED; - LogicalType target_type = (optional_type && !cdef.typeName) ? LogicalType::ANY : TransformTypeName(*cdef.typeName); + + auto optional_type = cdef.category == duckdb_libpgquery::COL_GENERATED; + LogicalType target_type; + if (optional_type && !cdef.typeName) { + target_type = LogicalType::ANY; + } else if (!cdef.typeName) { + // ALTER TABLE tbl ALTER TYPE USING ... + target_type = LogicalType::UNKNOWN; + } else { + target_type = TransformTypeName(*cdef.typeName); + } + if (cdef.collClause) { if (cdef.category == duckdb_libpgquery::COL_GENERATED) { throw ParserException("Collations are not supported on generated columns"); @@ -63,7 +73,7 @@ ColumnDefinition Transformer::TransformColumnDefinition(duckdb_libpgquery::PGCol target_type = LogicalType::VARCHAR_COLLATION(TransformCollation(cdef.collClause)); } - return ColumnDefinition(colname, target_type); + return ColumnDefinition(name, target_type); } unique_ptr Transformer::TransformCreateTable(duckdb_libpgquery::PGCreateStmt &stmt) { @@ -97,22 +107,26 @@ unique_ptr Transformer::TransformCreateTable(duckdb_libpgquery: auto node = PGPointerCast(c->data.ptr_value); switch (node->type) { case duckdb_libpgquery::T_PGColumnDef: { - auto cdef = PGPointerCast(c->data.ptr_value); - auto centry = TransformColumnDefinition(*cdef); - if (cdef->constraints) { - for (auto constr = cdef->constraints->head; constr != nullptr; constr = constr->next) { - auto constraint = TransformConstraint(*constr, centry, info->columns.LogicalColumnCount()); + auto pg_col_def = PGPointerCast(c->data.ptr_value); + auto col_def = TransformColumnDefinition(*pg_col_def); + + if (pg_col_def->constraints) { + for (auto cell = pg_col_def->constraints->head; cell != nullptr; cell = cell->next) { + auto pg_constraint = PGPointerCast(cell->data.ptr_value); + auto constraint = TransformConstraint(*pg_constraint, col_def, info->columns.LogicalColumnCount()); if (constraint) { info->constraints.push_back(std::move(constraint)); } } } - info->columns.AddColumn(std::move(centry)); + + info->columns.AddColumn(std::move(col_def)); column_count++; break; } case duckdb_libpgquery::T_PGConstraint: { - info->constraints.push_back(TransformConstraint(*c)); + auto pg_constraint = PGPointerCast(c->data.ptr_value); + info->constraints.push_back(TransformConstraint(*pg_constraint)); break; } default: 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 6af7fe4e7..3770194a7 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 @@ -8,17 +8,25 @@ 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->colNames || stmt.into->options) { + if (stmt.is_select_into || stmt.into->options) { throw NotImplementedException("Unimplemented features for CREATE TABLE as"); } - auto qname = TransformQualifiedName(*stmt.into->rel); if (stmt.query->type != duckdb_libpgquery::T_PGSelectStmt) { throw ParserException("CREATE TABLE AS requires a SELECT clause"); } - auto query = TransformSelectStmt(*stmt.query, false); auto result = make_uniq(); auto info = make_uniq(); + auto qname = TransformQualifiedName(*stmt.into->rel); + auto query = TransformSelectStmt(*stmt.query, false); + + if (stmt.into->colNames) { + auto cols = TransformStringList(stmt.into->colNames); + for (idx_t i = 0; i < cols.size(); i++) { + // We really don't know the type of the columns during parsing, so we just use UNKNOWN + 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_show.cpp b/src/duckdb/src/parser/transform/statement/transform_show.cpp index 12e6d6860..648dbb9b7 100644 --- a/src/duckdb/src/parser/transform/statement/transform_show.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_show.cpp @@ -10,12 +10,30 @@ namespace duckdb { unique_ptr Transformer::TransformShow(duckdb_libpgquery::PGVariableShowStmt &stmt) { - string name = stmt.name; - + // create the query that holds the show statement auto select_node = make_uniq(); select_node->select_list.push_back(make_uniq()); auto showref = make_uniq(); - showref->table_name = std::move(name); + if (stmt.set) { + // describing a set (e.g. SHOW ALL TABLES) - push it in the table name + showref->table_name = stmt.set; + } 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") { + showref->table_name = "\"" + std::move(table_name) + "\""; + } + } + if (showref->table_name.empty()) { + // describing a single relation + // wrap the relation in a "SELECT * FROM [table_name]" query + auto show_select_node = make_uniq(); + show_select_node->select_list.push_back(make_uniq()); + auto tableref = TransformRangeVar(*stmt.relation); + show_select_node->from_table = std::move(tableref); + showref->query = std::move(show_select_node); + } + showref->show_type = stmt.is_summary ? ShowType::SUMMARY : ShowType::DESCRIBE; select_node->from_table = std::move(showref); return std::move(select_node); diff --git a/src/duckdb/src/planner/bind_context.cpp b/src/duckdb/src/planner/bind_context.cpp index d446f3cf9..9ad84ed83 100644 --- a/src/duckdb/src/planner/bind_context.cpp +++ b/src/duckdb/src/planner/bind_context.cpp @@ -24,21 +24,32 @@ namespace duckdb { BindContext::BindContext(Binder &binder) : binder(binder) { } -string BindContext::GetMatchingBinding(const string &column_name) { - string result; - for (auto &kv : bindings) { - auto binding = kv.second.get(); - auto is_using_binding = GetUsingBinding(column_name, kv.first); +string MinimumUniqueAlias(const BindingAlias &alias, const BindingAlias &other) { + if (!StringUtil::CIEquals(alias.GetAlias(), other.GetAlias())) { + return alias.GetAlias(); + } + if (!StringUtil::CIEquals(alias.GetSchema(), other.GetSchema())) { + return alias.GetSchema() + "." + alias.GetAlias(); + } + return alias.ToString(); +} + +optional_ptr BindContext::GetMatchingBinding(const string &column_name) { + optional_ptr result; + for (auto &binding_ptr : bindings_list) { + auto &binding = *binding_ptr; + auto is_using_binding = GetUsingBinding(column_name, binding.alias); if (is_using_binding) { continue; } - if (binding->HasMatchingBinding(column_name)) { - if (!result.empty() || is_using_binding) { + if (binding.HasMatchingBinding(column_name)) { + if (result || is_using_binding) { throw BinderException("Ambiguous reference to column name \"%s\" (use: \"%s.%s\" " "or \"%s.%s\")", - column_name, result, column_name, kv.first, column_name); + column_name, MinimumUniqueAlias(result->alias, binding.alias), column_name, + MinimumUniqueAlias(binding.alias, result->alias), column_name); } - result = kv.first; + result = &binding; } } return result; @@ -46,11 +57,11 @@ string BindContext::GetMatchingBinding(const string &column_name) { vector BindContext::GetSimilarBindings(const string &column_name) { vector> scores; - for (auto &kv : bindings) { - auto binding = kv.second.get(); - for (auto &name : binding->names) { + for (auto &binding_ptr : bindings_list) { + auto binding = *binding_ptr; + for (auto &name : binding.names) { double distance = StringUtil::SimilarityRating(name, column_name); - scores.emplace_back(binding->alias + "." + name, distance); + scores.emplace_back(binding.GetAlias() + "." + name, distance); } } return StringUtil::TopNStrings(scores); @@ -81,7 +92,7 @@ optional_ptr BindContext::GetUsingBinding(const string &column_n } else { result_bindings += ", "; } - result_bindings += binding; + result_bindings += binding.GetAlias(); result_bindings += "."; result_bindings += GetActualColumnName(binding, column_name); } @@ -95,8 +106,8 @@ optional_ptr BindContext::GetUsingBinding(const string &column_n throw InternalException("Using binding found but no entries"); } -optional_ptr BindContext::GetUsingBinding(const string &column_name, const string &binding_name) { - if (binding_name.empty()) { +optional_ptr BindContext::GetUsingBinding(const string &column_name, const BindingAlias &binding) { + if (!binding.IsSet()) { throw InternalException("GetUsingBinding: expected non-empty binding_name"); } auto entry = using_columns.find(column_name); @@ -107,8 +118,10 @@ optional_ptr BindContext::GetUsingBinding(const string &column_n for (auto &using_set_ref : using_bindings) { auto &using_set = using_set_ref.get(); auto &bindings = using_set.bindings; - if (bindings.find(binding_name) != bindings.end()) { - return &using_set; + for (auto &using_binding : bindings) { + if (using_binding == binding) { + return &using_set; + } } } return nullptr; @@ -129,52 +142,59 @@ void BindContext::RemoveUsingBinding(const string &column_name, UsingColumnSet & } void BindContext::TransferUsingBinding(BindContext ¤t_context, optional_ptr current_set, - UsingColumnSet &new_set, const string &binding, const string &using_column) { + UsingColumnSet &new_set, const string &using_column) { AddUsingBinding(using_column, new_set); if (current_set) { current_context.RemoveUsingBinding(using_column, *current_set); } } -string BindContext::GetActualColumnName(const string &binding_name, const string &column_name) { - ErrorData error; - auto binding = GetBinding(binding_name, error); - if (!binding) { - throw InternalException("No binding with name \"%s\": %s", binding_name, error.RawMessage()); - } +string BindContext::GetActualColumnName(Binding &binding, const string &column_name) { column_t binding_index; - if (!binding->TryGetBindingIndex(column_name, binding_index)) { // LCOV_EXCL_START - throw InternalException("Binding with name \"%s\" does not have a column named \"%s\"", binding_name, + if (!binding.TryGetBindingIndex(column_name, binding_index)) { // LCOV_EXCL_START + throw InternalException("Binding with name \"%s\" does not have a column named \"%s\"", binding.GetAlias(), column_name); } // LCOV_EXCL_STOP - return binding->names[binding_index]; + return binding.names[binding_index]; +} + +string BindContext::GetActualColumnName(const BindingAlias &binding_alias, const string &column_name) { + ErrorData error; + auto binding = GetBinding(binding_alias, error); + if (!binding) { + throw InternalException("No binding with name \"%s\": %s", binding_alias.GetAlias(), error.RawMessage()); + } + return GetActualColumnName(*binding, column_name); } -unordered_set BindContext::GetMatchingBindings(const string &column_name) { - unordered_set result; - for (auto &kv : bindings) { - auto binding = kv.second.get(); - if (binding->HasMatchingBinding(column_name)) { - result.insert(kv.first); +vector> BindContext::GetMatchingBindings(const string &column_name) { + vector> result; + for (auto &binding_ptr : bindings_list) { + auto &binding = *binding_ptr; + if (binding.HasMatchingBinding(column_name)) { + result.push_back(binding); } } return result; } -unique_ptr BindContext::ExpandGeneratedColumn(const string &table_name, const string &column_name) { - ErrorData error; - - auto binding = GetBinding(table_name, error); - D_ASSERT(binding && !error.HasError()); - auto &table_binding = binding->Cast(); +unique_ptr BindContext::ExpandGeneratedColumn(TableBinding &table_binding, + const string &column_name) { auto result = table_binding.ExpandGeneratedColumn(column_name); result->alias = column_name; return result; } -unique_ptr BindContext::CreateColumnReference(const string &table_name, const string &column_name) { +unique_ptr BindContext::CreateColumnReference(const BindingAlias &table_alias, + const string &column_name, ColumnBindType bind_type) { + return CreateColumnReference(table_alias.GetCatalog(), table_alias.GetSchema(), table_alias.GetAlias(), column_name, + bind_type); +} + +unique_ptr BindContext::CreateColumnReference(const string &table_name, const string &column_name, + ColumnBindType bind_type) { string schema_name; - return CreateColumnReference(schema_name, table_name, column_name); + return CreateColumnReference(schema_name, table_name, column_name, bind_type); } static bool ColumnIsGenerated(Binding &binding, column_t index) { @@ -195,7 +215,8 @@ static bool ColumnIsGenerated(Binding &binding, column_t index) { } unique_ptr BindContext::CreateColumnReference(const string &catalog_name, const string &schema_name, - const string &table_name, const string &column_name) { + const string &table_name, const string &column_name, + ColumnBindType bind_type) { ErrorData error; vector names; if (!catalog_name.empty()) { @@ -207,14 +228,15 @@ unique_ptr BindContext::CreateColumnReference(const string &ca names.push_back(table_name); names.push_back(column_name); + BindingAlias alias(catalog_name, schema_name, table_name); auto result = make_uniq(std::move(names)); - auto binding = GetBinding(table_name, error); + auto binding = GetBinding(alias, column_name, error); if (!binding) { return std::move(result); } auto column_index = binding->GetBindingIndex(column_name); - if (ColumnIsGenerated(*binding, column_index)) { - return ExpandGeneratedColumn(table_name, column_name); + if (bind_type == ColumnBindType::EXPAND_GENERATED_COLUMNS && ColumnIsGenerated(*binding, column_index)) { + return ExpandGeneratedColumn(binding->Cast(), column_name); } else if (column_index < binding->names.size() && binding->names[column_index] != column_name) { // because of case insensitivity in the binder we rename the column to the original name // as it appears in the binding itself @@ -224,9 +246,9 @@ unique_ptr BindContext::CreateColumnReference(const string &ca } unique_ptr BindContext::CreateColumnReference(const string &schema_name, const string &table_name, - const string &column_name) { + const string &column_name, ColumnBindType bind_type) { string catalog_name; - return CreateColumnReference(catalog_name, schema_name, table_name, column_name); + return CreateColumnReference(catalog_name, schema_name, table_name, column_name, bind_type); } optional_ptr BindContext::GetCTEBinding(const string &ctename) { @@ -237,21 +259,128 @@ optional_ptr BindContext::GetCTEBinding(const string &ctename) { return match->second.get(); } -optional_ptr BindContext::GetBinding(const string &name, ErrorData &out_error) { - auto match = bindings.find(name); - if (match == bindings.end()) { +vector> BindContext::GetBindings(const BindingAlias &alias, ErrorData &out_error) { + if (!alias.IsSet()) { + throw InternalException("BindingAlias is not set"); + } + vector> matching_bindings; + for (auto &binding : bindings_list) { + if (binding->alias.Matches(alias)) { + matching_bindings.push_back(*binding); + } + } + if (matching_bindings.empty()) { // alias not found in this BindContext vector candidates; - for (auto &kv : bindings) { - candidates.push_back(kv.first); + for (auto &binding : bindings_list) { + candidates.push_back(binding->alias.GetAlias()); + } + string candidate_str = StringUtil::CandidatesMessage(StringUtil::TopNJaroWinkler(candidates, alias.GetAlias()), + "Candidate tables"); + out_error = ErrorData(ExceptionType::BINDER, StringUtil::Format("Referenced table \"%s\" not found!%s", + alias.GetAlias(), candidate_str)); + } + return matching_bindings; +} + +string BindContext::AmbiguityException(const BindingAlias &alias, const vector> &bindings) { + D_ASSERT(bindings.size() > 1); + // found multiple matching aliases + string result = "(use: "; + for (idx_t i = 0; i < bindings.size(); i++) { + if (i > 0) { + if (i + 1 == bindings.size()) { + result += " or "; + } else { + result += ", "; + } } - string candidate_str = - StringUtil::CandidatesMessage(StringUtil::TopNJaroWinkler(candidates, name), "Candidate tables"); - out_error = ErrorData(ExceptionType::BINDER, - StringUtil::Format("Referenced table \"%s\" not found!%s", name, candidate_str)); + // find the minimum alias that uniquely describes this table reference + auto ¤t_alias = bindings[i].get().alias; + string minimum_alias; + bool duplicate_alias = false; + for (idx_t k = 0; k < bindings.size(); k++) { + if (k == i) { + continue; + } + auto &other_alias = bindings[k].get().alias; + if (current_alias == other_alias) { + duplicate_alias = true; + } + string new_minimum_alias = MinimumUniqueAlias(current_alias, other_alias); + if (new_minimum_alias.size() > minimum_alias.size()) { + minimum_alias = std::move(new_minimum_alias); + } + } + if (duplicate_alias) { + result = "(duplicate alias \"" + alias.ToString() + + "\", explicitly alias one of the tables using \"AS my_alias\""; + } else { + result += minimum_alias; + } + } + result += ")"; + return result; +} + +optional_ptr BindContext::GetBinding(const BindingAlias &alias, const string &column_name, + ErrorData &out_error) { + auto matching_bindings = GetBindings(alias, out_error); + if (matching_bindings.empty()) { + // no bindings found return nullptr; } - return match->second.get(); + + optional_ptr result; + // find the binding that this column name belongs to + for (auto &binding_ref : matching_bindings) { + auto &binding = binding_ref.get(); + if (!binding.HasMatchingBinding(column_name)) { + continue; + } + if (result) { + // we found multiple bindings that this column name belongs to - ambiguity + string helper_message = AmbiguityException(alias, matching_bindings); + throw BinderException("Ambiguous reference to table \"%s\" %s", alias.ToString(), helper_message); + } else { + result = &binding; + } + } + if (!result) { + // found the table binding - but could not find the column + out_error = matching_bindings[0].get().ColumnNotFoundError(column_name); + } + return result; +} + +optional_ptr BindContext::GetBinding(const BindingAlias &alias, ErrorData &out_error) { + auto matching_bindings = GetBindings(alias, out_error); + if (matching_bindings.empty()) { + return nullptr; + } + if (matching_bindings.size() > 1) { + string helper_message = AmbiguityException(alias, matching_bindings); + throw BinderException("Ambiguous reference to table \"%s\" %s", alias.ToString(), helper_message); + } + // found a single matching alias + return &matching_bindings[0].get(); +} + +optional_ptr BindContext::GetBinding(const string &name, ErrorData &out_error) { + return GetBinding(BindingAlias(name), out_error); +} + +BindingAlias GetBindingAlias(ColumnRefExpression &colref) { + if (colref.column_names.size() <= 1 || colref.column_names.size() > 4) { + throw InternalException("Cannot get binding alias from column ref unless it has 2..4 entries"); + } + if (colref.column_names.size() >= 4) { + return BindingAlias(colref.column_names[0], colref.column_names[1], colref.column_names[2]); + } + if (colref.column_names.size() == 3) { + return BindingAlias(colref.column_names[0], colref.column_names[1]); + } + return BindingAlias(colref.column_names[0]); } BindResult BindContext::BindColumn(ColumnRefExpression &colref, idx_t depth) { @@ -260,7 +389,8 @@ BindResult BindContext::BindColumn(ColumnRefExpression &colref, idx_t depth) { } ErrorData error; - auto binding = GetBinding(colref.GetTableName(), error); + BindingAlias alias; + auto binding = GetBinding(GetBindingAlias(colref), colref.GetColumnName(), error); if (!binding) { return BindResult(std::move(error)); } @@ -271,16 +401,16 @@ string BindContext::BindColumn(PositionalReferenceExpression &ref, string &table idx_t total_columns = 0; idx_t current_position = ref.index - 1; for (auto &entry : bindings_list) { - auto &binding = entry.get(); + auto &binding = *entry; idx_t entry_column_count = binding.names.size(); if (ref.index == 0) { // this is a row id - table_name = binding.alias; + table_name = binding.alias.GetAlias(); column_name = "rowid"; return string(); } if (current_position < entry_column_count) { - table_name = binding.alias; + table_name = binding.alias.GetAlias(); column_name = binding.names[current_position]; return string(); } else { @@ -301,38 +431,54 @@ unique_ptr BindContext::PositionToColumn(PositionalReferenc return make_uniq(column_name, table_name); } -bool BindContext::CheckExclusionList(StarExpression &expr, const string &column_name, - vector> &new_select_list, - case_insensitive_set_t &excluded_columns) { - if (expr.exclude_list.find(column_name) != expr.exclude_list.end()) { - excluded_columns.insert(column_name); +struct ExclusionListInfo { + explicit ExclusionListInfo(vector> &new_select_list) + : new_select_list(new_select_list) { + } + + vector> &new_select_list; + case_insensitive_set_t excluded_columns; + qualified_column_set_t excluded_qualified_columns; +}; + +bool CheckExclusionList(StarExpression &expr, const QualifiedColumnName &qualified_name, ExclusionListInfo &info) { + if (expr.exclude_list.find(qualified_name) != expr.exclude_list.end()) { + info.excluded_qualified_columns.insert(qualified_name); return true; } - auto entry = expr.replace_list.find(column_name); + auto entry = expr.replace_list.find(qualified_name.column); if (entry != expr.replace_list.end()) { auto new_entry = entry->second->Copy(); new_entry->alias = entry->first; - excluded_columns.insert(entry->first); - new_select_list.push_back(std::move(new_entry)); + info.excluded_columns.insert(entry->first); + info.new_select_list.push_back(std::move(new_entry)); return true; } return false; } +void HandleRename(StarExpression &expr, const QualifiedColumnName &qualified_name, ParsedExpression &new_expr) { + auto rename_entry = expr.rename_list.find(qualified_name); + if (rename_entry != expr.rename_list.end()) { + new_expr.alias = rename_entry->second; + } +} + void BindContext::GenerateAllColumnExpressions(StarExpression &expr, vector> &new_select_list) { if (bindings_list.empty()) { throw BinderException("* expression without FROM clause!"); } - case_insensitive_set_t excluded_columns; + ExclusionListInfo exclusion_info(new_select_list); if (expr.relation_name.empty()) { // SELECT * case // bind all expressions of each table in-order reference_set_t handled_using_columns; for (auto &entry : bindings_list) { - auto &binding = entry.get(); + auto &binding = *entry; for (auto &column_name : binding.names) { - if (CheckExclusionList(expr, column_name, new_select_list, excluded_columns)) { + QualifiedColumnName qualified_column(binding.alias, column_name); + if (CheckExclusionList(expr, qualified_column, exclusion_info)) { continue; } // check if this column is a USING column @@ -346,23 +492,28 @@ void BindContext::GenerateAllColumnExpressions(StarExpression &expr, continue; } // we have not! output the using column - if (using_binding.primary_binding.empty()) { + if (!using_binding.primary_binding.IsSet()) { // no primary binding: output a coalesce auto coalesce = make_uniq(ExpressionType::OPERATOR_COALESCE); for (auto &child_binding : using_binding.bindings) { coalesce->children.push_back(make_uniq(column_name, child_binding)); } coalesce->alias = column_name; + HandleRename(expr, qualified_column, *coalesce); new_select_list.push_back(std::move(coalesce)); } else { // primary binding: output the qualified column ref - new_select_list.push_back( - make_uniq(column_name, using_binding.primary_binding)); + auto new_expr = make_uniq(column_name, using_binding.primary_binding); + HandleRename(expr, qualified_column, *new_expr); + new_select_list.push_back(std::move(new_expr)); } handled_using_columns.insert(using_binding); continue; } - new_select_list.push_back(make_uniq(column_name, binding.alias)); + auto new_expr = + CreateColumnReference(binding.alias, column_name, ColumnBindType::DO_NOT_EXPAND_GENERATED_COLUMNS); + HandleRename(expr, qualified_column, *new_expr); + new_select_list.push_back(std::move(new_expr)); } } } else { @@ -372,11 +523,10 @@ void BindContext::GenerateAllColumnExpressions(StarExpression &expr, auto binding = GetBinding(expr.relation_name, error); bool is_struct_ref = false; if (!binding) { - auto binding_name = GetMatchingBinding(expr.relation_name); - if (binding_name.empty()) { + binding = GetMatchingBinding(expr.relation_name); + if (!binding) { error.Throw(); } - binding = bindings[binding_name].get(); is_struct_ref = true; } @@ -389,22 +539,28 @@ void BindContext::GenerateAllColumnExpressions(StarExpression &expr, } auto &struct_children = StructType::GetChildTypes(col_type); vector column_names(3); - column_names[0] = binding->alias; + column_names[0] = binding->alias.GetAlias(); column_names[1] = expr.relation_name; for (auto &child : struct_children) { - if (CheckExclusionList(expr, child.first, new_select_list, excluded_columns)) { + QualifiedColumnName qualified_name(child.first); + if (CheckExclusionList(expr, qualified_name, exclusion_info)) { continue; } column_names[2] = child.first; - new_select_list.push_back(make_uniq(column_names)); + auto new_expr = make_uniq(column_names); + HandleRename(expr, qualified_name, *new_expr); + new_select_list.push_back(std::move(new_expr)); } } else { for (auto &column_name : binding->names) { - if (CheckExclusionList(expr, column_name, new_select_list, excluded_columns)) { + QualifiedColumnName qualified_name(binding->alias, column_name); + if (CheckExclusionList(expr, qualified_name, exclusion_info)) { continue; } - - new_select_list.push_back(make_uniq(column_name, binding->alias)); + auto new_expr = + CreateColumnReference(binding->alias, column_name, ColumnBindType::DO_NOT_EXPAND_GENERATED_COLUMNS); + HandleRename(expr, qualified_name, *new_expr); + new_select_list.push_back(std::move(new_expr)); } } } @@ -413,13 +569,14 @@ void BindContext::GenerateAllColumnExpressions(StarExpression &expr, expr.replace_list.clear(); } for (auto &excluded : expr.exclude_list) { - if (excluded_columns.find(excluded) == excluded_columns.end()) { - throw BinderException("Column \"%s\" in EXCLUDE list not found in %s", excluded, + if (exclusion_info.excluded_qualified_columns.find(excluded) == + exclusion_info.excluded_qualified_columns.end()) { + throw BinderException("Column \"%s\" in EXCLUDE list not found in %s", excluded.ToString(), expr.relation_name.empty() ? "FROM clause" : expr.relation_name.c_str()); } } for (auto &entry : expr.replace_list) { - if (excluded_columns.find(entry.first) == excluded_columns.end()) { + if (exclusion_info.excluded_columns.find(entry.first) == exclusion_info.excluded_columns.end()) { throw BinderException("Column \"%s\" in REPLACE list not found in %s", entry.first, expr.relation_name.empty() ? "FROM clause" : expr.relation_name.c_str()); } @@ -428,7 +585,7 @@ void BindContext::GenerateAllColumnExpressions(StarExpression &expr, void BindContext::GetTypesAndNames(vector &result_names, vector &result_types) { for (auto &binding_entry : bindings_list) { - auto &binding = binding_entry.get(); + auto &binding = *binding_entry; D_ASSERT(binding.names.size() == binding.types.size()); for (idx_t i = 0; i < binding.names.size(); i++) { result_names.push_back(binding.names[i]); @@ -437,24 +594,27 @@ void BindContext::GetTypesAndNames(vector &result_names, vector binding) { - if (bindings.find(alias) != bindings.end()) { - throw BinderException("Duplicate alias \"%s\" in query!", alias); - } - bindings_list.push_back(*binding); - bindings[alias] = std::move(binding); +void BindContext::AddBinding(unique_ptr binding) { + bindings_list.push_back(std::move(binding)); } void BindContext::AddBaseTable(idx_t index, const string &alias, const vector &names, const vector &types, vector &bound_column_ids, - StandardEntry *entry, bool add_row_id) { - AddBinding(alias, make_uniq(alias, types, names, bound_column_ids, entry, index, add_row_id)); + StandardEntry &entry, bool add_row_id) { + AddBinding(make_uniq(alias, types, names, bound_column_ids, &entry, index, add_row_id)); +} + +void BindContext::AddBaseTable(idx_t index, const string &alias, const vector &names, + const vector &types, vector &bound_column_ids, + const string &table_name) { + AddBinding(make_uniq(alias.empty() ? table_name : alias, types, names, bound_column_ids, nullptr, + index, true)); } void BindContext::AddTableFunction(idx_t index, const string &alias, const vector &names, const vector &types, vector &bound_column_ids, - StandardEntry *entry) { - AddBinding(alias, make_uniq(alias, types, names, bound_column_ids, entry, index)); + optional_ptr entry) { + AddBinding(make_uniq(alias, types, names, bound_column_ids, entry, index)); } static string AddColumnNameToBinding(const string &base_name, case_insensitive_set_t ¤t_names) { @@ -493,13 +653,13 @@ void BindContext::AddSubquery(idx_t index, const string &alias, SubqueryRef &ref void BindContext::AddEntryBinding(idx_t index, const string &alias, const vector &names, const vector &types, StandardEntry &entry) { - AddBinding(alias, make_uniq(alias, types, names, index, entry)); + AddBinding(make_uniq(alias, types, names, index, entry)); } void BindContext::AddView(idx_t index, const string &alias, SubqueryRef &ref, BoundQueryNode &subquery, - ViewCatalogEntry *view) { + ViewCatalogEntry &view) { auto names = AliasColumnNames(alias, subquery.names, ref.column_name_alias); - AddEntryBinding(index, alias, names, subquery.types, view->Cast()); + AddEntryBinding(index, alias, names, subquery.types, view.Cast()); } void BindContext::AddSubquery(idx_t index, const string &alias, TableFunctionRef &ref, BoundQueryNode &subquery) { @@ -509,36 +669,31 @@ void BindContext::AddSubquery(idx_t index, const string &alias, TableFunctionRef void BindContext::AddGenericBinding(idx_t index, const string &alias, const vector &names, const vector &types) { - AddBinding(alias, make_uniq(BindingType::BASE, alias, types, names, index)); + AddBinding(make_uniq(BindingType::BASE, BindingAlias(alias), types, names, index)); } void BindContext::AddCTEBinding(idx_t index, const string &alias, const vector &names, const vector &types) { - auto binding = make_shared_ptr(BindingType::BASE, alias, types, names, index); + auto binding = make_shared_ptr(BindingType::BASE, BindingAlias(alias), types, names, index); if (cte_bindings.find(alias) != cte_bindings.end()) { - throw BinderException("Duplicate alias \"%s\" in query!", alias); + throw BinderException("Duplicate CTE binding \"%s\" in query!", alias); } cte_bindings[alias] = std::move(binding); cte_references[alias] = make_shared_ptr(0); } void BindContext::AddContext(BindContext other) { - for (auto &binding : other.bindings) { - if (bindings.find(binding.first) != bindings.end()) { - throw BinderException("Duplicate alias \"%s\" in query!", binding.first); - } - bindings[binding.first] = std::move(binding.second); - } for (auto &binding : other.bindings_list) { - bindings_list.push_back(binding); + AddBinding(std::move(binding)); } for (auto &entry : other.using_columns) { for (auto &alias : entry.second) { #ifdef DEBUG for (auto &other_alias : using_columns[entry.first]) { for (auto &col : alias.get().bindings) { - D_ASSERT(other_alias.get().bindings.find(col) == other_alias.get().bindings.end()); + D_ASSERT(std::find(other_alias.get().bindings.begin(), other_alias.get().bindings.end(), col) == + other_alias.get().bindings.end()); } } #endif @@ -547,19 +702,19 @@ void BindContext::AddContext(BindContext other) { } } -void BindContext::RemoveContext(vector> &other_bindings_list) { - for (auto &other_binding : other_bindings_list) { - auto it = std::remove_if(bindings_list.begin(), bindings_list.end(), [other_binding](reference x) { - return x.get().alias == other_binding.get().alias; - }); - bindings_list.erase(it, bindings_list.end()); +vector BindContext::GetBindingAliases() { + vector result; + for (auto &binding : bindings_list) { + result.push_back(BindingAlias(binding->alias)); } + return result; +} - for (auto &other_binding : other_bindings_list) { - auto &alias = other_binding.get().alias; - if (bindings.find(alias) != bindings.end()) { - bindings.erase(alias); - } +void BindContext::RemoveContext(const vector &aliases) { + for (auto &alias : aliases) { + auto it = std::remove_if(bindings_list.begin(), bindings_list.end(), + [&](unique_ptr &x) { return x->alias == alias; }); + bindings_list.erase(it, bindings_list.end()); } } diff --git a/src/duckdb/src/planner/binder.cpp b/src/duckdb/src/planner/binder.cpp index 9f0abf398..ec4794895 100644 --- a/src/duckdb/src/planner/binder.cpp +++ b/src/duckdb/src/planner/binder.cpp @@ -59,7 +59,7 @@ Binder::Binder(ClientContext &context, shared_ptr parent_p, BinderType b : context(context), bind_context(*this), parent(std::move(parent_p)), bound_tables(0), binder_type(binder_type), entry_retriever(context) { if (parent) { - entry_retriever.SetCallback(parent->entry_retriever.GetCallback()); + entry_retriever.Inherit(parent->entry_retriever); // We have to inherit macro and lambda parameter bindings and from the parent binder, if there is a parent. macro_binding = parent->macro_binding; @@ -237,7 +237,7 @@ static bool ParsedExpressionIsAggregate(Binder &binder, const ParsedExpression & if (expr.GetExpressionClass() == ExpressionClass::FUNCTION) { auto &function = expr.Cast(); QueryErrorContext error_context; - auto entry = binder.GetCatalogEntry(CatalogType::SCALAR_FUNCTION_ENTRY, function.catalog, function.schema, + auto entry = binder.GetCatalogEntry(CatalogType::AGGREGATE_FUNCTION_ENTRY, function.catalog, function.schema, function.function_name, OnEntryNotFound::RETURN_NULL, error_context); if (entry && entry->type == CatalogType::AGGREGATE_FUNCTION_ENTRY) { return true; @@ -584,51 +584,30 @@ void Binder::AddCorrelatedColumn(const CorrelatedColumnInfo &info) { } } -bool Binder::HasMatchingBinding(const string &table_name, const string &column_name, ErrorData &error) { +optional_ptr Binder::GetMatchingBinding(const string &table_name, const string &column_name, + ErrorData &error) { string empty_schema; - return HasMatchingBinding(empty_schema, table_name, column_name, error); + return GetMatchingBinding(empty_schema, table_name, column_name, error); } -bool Binder::HasMatchingBinding(const string &schema_name, const string &table_name, const string &column_name, - ErrorData &error) { +optional_ptr Binder::GetMatchingBinding(const string &schema_name, const string &table_name, + const string &column_name, ErrorData &error) { string empty_catalog; - return HasMatchingBinding(empty_catalog, schema_name, table_name, column_name, error); + return GetMatchingBinding(empty_catalog, schema_name, table_name, column_name, error); } -bool Binder::HasMatchingBinding(const string &catalog_name, const string &schema_name, const string &table_name, - const string &column_name, ErrorData &error) { +optional_ptr Binder::GetMatchingBinding(const string &catalog_name, const string &schema_name, + const string &table_name, const string &column_name, + ErrorData &error) { optional_ptr binding; D_ASSERT(!lambda_bindings); - if (macro_binding && table_name == macro_binding->alias) { + if (macro_binding && table_name == macro_binding->GetAlias()) { binding = optional_ptr(macro_binding.get()); } else { - binding = bind_context.GetBinding(table_name, error); + BindingAlias alias(catalog_name, schema_name, table_name); + binding = bind_context.GetBinding(alias, column_name, error); } - - if (!binding) { - return false; - } - if (!catalog_name.empty() || !schema_name.empty()) { - auto catalog_entry = binding->GetStandardEntry(); - if (!catalog_entry) { - return false; - } - if (!catalog_name.empty() && catalog_entry->catalog.GetName() != catalog_name) { - return false; - } - if (!schema_name.empty() && catalog_entry->schema.name != schema_name) { - return false; - } - if (catalog_entry->name != table_name) { - return false; - } - } - bool binding_found; - binding_found = binding->HasMatchingBinding(column_name); - if (!binding_found) { - error = binding->ColumnNotFoundError(column_name); - } - return binding_found; + return binding; } void Binder::SetBindingMode(BindingMode mode) { @@ -714,8 +693,7 @@ BoundStatement Binder::BindReturning(vector> return column_count++; } - binder->bind_context.AddBaseTable(update_table_index, alias.empty() ? table.name : alias, names, types, - bound_columns, &table, false); + binder->bind_context.AddBaseTable(update_table_index, alias, names, types, bound_columns, table, false); ReturningBinder returning_binder(*binder, context); vector> projection_expressions; 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 2051bb1e9..c58214a00 100644 --- a/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp @@ -4,6 +4,7 @@ #include "duckdb/execution/expression_executor.hpp" #include "duckdb/function/function_binder.hpp" #include "duckdb/function/scalar/generic_functions.hpp" +#include "duckdb/function/scalar/generic_common.hpp" #include "duckdb/main/config.hpp" #include "duckdb/parser/expression/constant_expression.hpp" #include "duckdb/parser/expression/function_expression.hpp" 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 03a6fdbda..473bd2139 100644 --- a/src/duckdb/src/planner/binder/expression/bind_columnref_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_columnref_expression.cpp @@ -60,7 +60,7 @@ unique_ptr ExpressionBinder::QualifyColumnName(const string &c // we are referencing a USING column // check if we can refer to one of the base columns directly unique_ptr expression; - if (!using_binding->primary_binding.empty()) { + if (using_binding->primary_binding.IsSet()) { // we can! just assign the table name and re-bind return binder.bind_context.CreateColumnReference(using_binding->primary_binding, column_name); } else { @@ -81,26 +81,25 @@ unique_ptr ExpressionBinder::QualifyColumnName(const string &c } // find a table binding that contains this column name - string table_name = binder.bind_context.GetMatchingBinding(column_name); + auto table_binding = binder.bind_context.GetMatchingBinding(column_name); // 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_name.empty()) { + if (table_binding) { throw BinderException("Conflicting column names for column " + column_name + "!"); } } // bind as a macro column if (is_macro_column) { - D_ASSERT(!binder.macro_binding->alias.empty()); - return make_uniq(column_name, binder.macro_binding->alias); + return binder.bind_context.CreateColumnReference(binder.macro_binding->alias, column_name); } // bind as a regular column - if (!table_name.empty()) { - return binder.bind_context.CreateColumnReference(table_name, column_name); + if (table_binding) { + return binder.bind_context.CreateColumnReference(table_binding->alias, column_name); } // it's not, find candidates and error @@ -116,7 +115,6 @@ void ExpressionBinder::QualifyColumnNames(unique_ptr &expr, bool next_within_function_expression = false; switch (expr->type) { case ExpressionType::COLUMN_REF: { - auto &col_ref = expr->Cast(); // don't qualify lambda parameters @@ -220,6 +218,11 @@ void ExpressionBinder::QualifyColumnNames(Binder &binder, unique_ptr &expr) { + vector> lambda_params; + expression_binder.QualifyColumnNames(expr, lambda_params); +} + unique_ptr ExpressionBinder::CreateStructExtract(unique_ptr base, const string &field_name) { @@ -231,59 +234,57 @@ unique_ptr ExpressionBinder::CreateStructExtract(unique_ptr ExpressionBinder::CreateStructPack(ColumnRefExpression &col_ref) { - - D_ASSERT(col_ref.column_names.size() <= 3); + if (col_ref.column_names.size() > 3) { + return nullptr; + } + D_ASSERT(!col_ref.column_names.empty()); // get a matching binding ErrorData error; - auto &table_name = col_ref.column_names.back(); - auto binding = binder.bind_context.GetBinding(table_name, error); - - if (!binding) { - return nullptr; + optional_ptr binding; + switch (col_ref.column_names.size()) { + case 1: { + // single entry - this must be the table name + BindingAlias alias(col_ref.column_names[0]); + binding = binder.bind_context.GetBinding(alias, error); + break; } - - if (col_ref.column_names.size() >= 2) { - // "schema_name.table_name" - auto catalog_entry = binding->GetStandardEntry(); - if (!catalog_entry) { - return nullptr; - } - - if (catalog_entry->name != table_name) { - return nullptr; - } - - if (col_ref.column_names.size() == 2) { - auto &qualifier = col_ref.column_names[0]; - if (catalog_entry->catalog.GetName() != qualifier && catalog_entry->schema.name != qualifier) { - return nullptr; - } - - } else if (col_ref.column_names.size() == 3) { - auto &catalog_name = col_ref.column_names[0]; - auto &schema_name = col_ref.column_names[1]; - if (catalog_entry->catalog.GetName() != catalog_name || catalog_entry->schema.name != schema_name) { - return nullptr; - } - - } else { - throw InternalException("Expected 2 or 3 column names for CreateStructPack"); + case 2: { + // two entries - this can either be "catalog.table" or "schema.table" - try both + BindingAlias alias(col_ref.column_names[0], col_ref.column_names[1]); + binding = binder.bind_context.GetBinding(alias, error); + if (!binding) { + alias = BindingAlias(col_ref.column_names[0], INVALID_SCHEMA, col_ref.column_names[1]); + binding = binder.bind_context.GetBinding(alias, error); } + break; + } + case 3: { + // three entries - this must be "catalog.schema.table" + BindingAlias alias(col_ref.column_names[0], col_ref.column_names[1], col_ref.column_names[2]); + binding = binder.bind_context.GetBinding(alias, error); + break; + } + default: + throw InternalException("Expected 1, 2 or 3 column names for CreateStructPack"); + } + if (!binding) { + return nullptr; } // We found the table, now create the struct_pack expression vector> child_expressions; child_expressions.reserve(binding->names.size()); for (const auto &column_name : binding->names) { - child_expressions.push_back(make_uniq(column_name, table_name)); + child_expressions.push_back(binder.bind_context.CreateColumnReference( + binding->alias, column_name, ColumnBindType::DO_NOT_EXPAND_GENERATED_COLUMNS)); } return make_uniq("struct_pack", std::move(child_expressions)); } -unique_ptr ExpressionBinder::QualifyColumnNameWithManyDots(ColumnRefExpression &col_ref, - ErrorData &error) { - +unique_ptr ExpressionBinder::QualifyColumnNameWithManyDotsInternal(ColumnRefExpression &col_ref, + ErrorData &error, + idx_t &struct_extract_start) { // two or more dots (i.e. "part1.part2.part3.part4...") // -> part1 is a catalog, part2 is a schema, part3 is a table, part4 is a column name, part 5 and beyond are // struct fields @@ -299,50 +300,56 @@ unique_ptr ExpressionBinder::QualifyColumnNameWithManyDots(Col // -> 3. resolve "part1" as a table // -> 4. resolve "part1" as a column - unique_ptr result_expr; - idx_t struct_extract_start; - // first check if part1 is a catalog - if (col_ref.column_names.size() > 3 && - binder.HasMatchingBinding(col_ref.column_names[0], col_ref.column_names[1], col_ref.column_names[2], - col_ref.column_names[3], error)) { - // part1 is a catalog - the column reference is "catalog.schema.table.column" - result_expr = binder.bind_context.CreateColumnReference(col_ref.column_names[0], col_ref.column_names[1], - col_ref.column_names[2], col_ref.column_names[3]); - struct_extract_start = 4; - - } else if (binder.HasMatchingBinding(col_ref.column_names[0], INVALID_SCHEMA, col_ref.column_names[1], - col_ref.column_names[2], error)) { + optional_ptr binding; + if (col_ref.column_names.size() > 3) { + binding = binder.GetMatchingBinding(col_ref.column_names[0], col_ref.column_names[1], col_ref.column_names[2], + col_ref.column_names[3], error); + if (binding) { + // part1 is a catalog - the column reference is "catalog.schema.table.column" + struct_extract_start = 4; + return binder.bind_context.CreateColumnReference(binding->alias, col_ref.column_names[3]); + } + } + binding = binder.GetMatchingBinding(col_ref.column_names[0], INVALID_SCHEMA, col_ref.column_names[1], + col_ref.column_names[2], error); + if (binding) { // part1 is a catalog - the column reference is "catalog.table.column" - result_expr = binder.bind_context.CreateColumnReference(col_ref.column_names[0], INVALID_SCHEMA, - col_ref.column_names[1], col_ref.column_names[2]); struct_extract_start = 3; - - } else if (binder.HasMatchingBinding(col_ref.column_names[0], col_ref.column_names[1], col_ref.column_names[2], - error)) { + return binder.bind_context.CreateColumnReference(binding->alias, col_ref.column_names[2]); + } + binding = + binder.GetMatchingBinding(col_ref.column_names[0], col_ref.column_names[1], col_ref.column_names[2], error); + if (binding) { // part1 is a schema - the column reference is "schema.table.column" // any additional fields are turned into struct_extract calls - result_expr = binder.bind_context.CreateColumnReference(col_ref.column_names[0], col_ref.column_names[1], - col_ref.column_names[2]); struct_extract_start = 3; - - } else if (binder.HasMatchingBinding(col_ref.column_names[0], col_ref.column_names[1], error)) { + return binder.bind_context.CreateColumnReference(binding->alias, col_ref.column_names[2]); + } + binding = binder.GetMatchingBinding(col_ref.column_names[0], col_ref.column_names[1], error); + if (binding) { // part1 is a table // the column reference is "table.column" // any additional fields are turned into struct_extract calls - result_expr = binder.bind_context.CreateColumnReference(col_ref.column_names[0], col_ref.column_names[1]); struct_extract_start = 2; - - } else { - // part1 could be a column - ErrorData col_error; - result_expr = QualifyColumnName(col_ref.column_names[0], col_error); - if (!result_expr) { - // it is not! Try creating an implicit struct_pack - return CreateStructPack(col_ref); - } + return binder.bind_context.CreateColumnReference(binding->alias, col_ref.column_names[1]); + } + // part1 could be a column + ErrorData col_error; + auto result_expr = QualifyColumnName(col_ref.column_names[0], col_error); + if (result_expr) { // it is! add the struct extract calls struct_extract_start = 1; + return result_expr; + } + return CreateStructPack(col_ref); +} +unique_ptr ExpressionBinder::QualifyColumnNameWithManyDots(ColumnRefExpression &col_ref, + ErrorData &error) { + idx_t struct_extract_start = col_ref.column_names.size(); + auto result_expr = QualifyColumnNameWithManyDotsInternal(col_ref, error, struct_extract_start); + if (!result_expr) { + return nullptr; } // create a struct extract with all remaining column names @@ -387,9 +394,10 @@ unique_ptr ExpressionBinder::QualifyColumnName(ColumnRefExpres // -> part1 is a column, part2 is a property of that column (i.e. struct_extract) // first check if part1 is a table, and part2 is a standard column name - if (binder.HasMatchingBinding(col_ref.column_names[0], col_ref.column_names[1], error)) { + auto binding = binder.GetMatchingBinding(col_ref.column_names[0], col_ref.column_names[1], error); + if (binding) { // it is! return the column reference directly - return binder.bind_context.CreateColumnReference(col_ref.column_names[0], col_ref.column_names[1]); + return binder.bind_context.CreateColumnReference(binding->alias, col_ref.GetColumnName()); } // otherwise check if we can turn this into a struct extract @@ -461,7 +469,7 @@ BindResult ExpressionBinder::BindExpression(ColumnRefExpression &col_ref_p, idx_ D_ASSERT(col_ref.IsQualified()); auto &table_name = col_ref.GetTableName(); - if (binder.macro_binding && table_name == binder.macro_binding->alias) { + if (binder.macro_binding && table_name == binder.macro_binding->GetAlias()) { result = binder.macro_binding->Bind(col_ref, depth); } else { result = binder.bind_context.BindColumn(col_ref, depth); diff --git a/src/duckdb/src/planner/binder/expression/bind_operator_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_operator_expression.cpp index 572e0bb2b..7738d9fbc 100644 --- a/src/duckdb/src/planner/binder/expression/bind_operator_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_operator_expression.cpp @@ -1,9 +1,9 @@ #include "duckdb/parser/expression/function_expression.hpp" #include "duckdb/parser/expression/operator_expression.hpp" +#include "duckdb/planner/binder.hpp" #include "duckdb/planner/expression/bound_case_expression.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" #include "duckdb/planner/expression/bound_comparison_expression.hpp" -#include "duckdb/planner/binder.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_operator_expression.hpp" #include "duckdb/planner/expression/bound_parameter_expression.hpp" @@ -135,13 +135,16 @@ BindResult ExpressionBinder::BindExpression(OperatorExpression &op, idx_t depth) auto &name_exp = BoundExpression::GetExpression(*op.children[1]); const auto &extract_expr_type = extract_exp->return_type; if (extract_expr_type.id() != LogicalTypeId::STRUCT && extract_expr_type.id() != LogicalTypeId::UNION && - extract_expr_type.id() != LogicalTypeId::SQLNULL && !extract_expr_type.IsJSONType()) { + extract_expr_type.id() != LogicalTypeId::MAP && extract_expr_type.id() != LogicalTypeId::SQLNULL && + !extract_expr_type.IsJSONType()) { return BindResult(StringUtil::Format( - "Cannot extract field %s from expression \"%s\" because it is not a struct, union, or json", + "Cannot extract field %s from expression \"%s\" because it is not a struct, union, map, or json", name_exp->ToString(), extract_exp->ToString())); } if (extract_expr_type.id() == LogicalTypeId::UNION) { function_name = "union_extract"; + } else if (extract_expr_type.id() == LogicalTypeId::MAP) { + function_name = "map_extract"; } else if (extract_expr_type.IsJSONType()) { function_name = "json_extract"; // Make sure we only extract fields, not array elements, by adding $. syntax diff --git a/src/duckdb/src/planner/binder/expression/bind_star_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_star_expression.cpp index e25c69c16..ddf7dd5ba 100644 --- a/src/duckdb/src/planner/binder/expression/bind_star_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_star_expression.cpp @@ -134,8 +134,61 @@ static string ReplaceColumnsAlias(const string &alias, const string &column_name return result; } +void TryTransformStarLike(unique_ptr &root) { + // detect "* LIKE [literal]" and similar expressions + if (root->expression_class != ExpressionClass::FUNCTION) { + return; + } + auto &function = root->Cast(); + if (function.children.size() != 2) { + return; + } + auto &left = function.children[0]; + // expression must have a star on the LHS, and a literal on the RHS + if (left->expression_class != ExpressionClass::STAR) { + return; + } + auto &star = left->Cast(); + if (star.columns) { + // COLUMNS(*) has different semantics + return; + } + unordered_set supported_ops {"~~", "!~~", "~~~", "!~~~", "~~*", "!~~*", "regexp_full_match"}; + if (supported_ops.count(function.function_name) == 0) { + // unsupported op for * expression + throw BinderException(*root, "Function \"%s\" cannot be applied to a star expression", function.function_name); + } + auto &right = function.children[1]; + if (right->expression_class != ExpressionClass::CONSTANT) { + throw BinderException(*root, "Pattern applied to a star expression must be a constant"); + } + if (!star.replace_list.empty()) { + throw BinderException(*root, "Replace list cannot be combined with a filtering operation"); + } + // generate a columns expression + // "* LIKE '%literal%' + // -> COLUMNS(list_filter(*, x -> x LIKE '%literal%')) + auto star_expr = std::move(left); + + auto lhs = make_uniq("__lambda_col"); + function.children[0] = lhs->Copy(); + + auto lambda = make_uniq(std::move(lhs), std::move(root)); + vector> filter_children; + filter_children.push_back(std::move(star_expr)); + filter_children.push_back(std::move(lambda)); + auto list_filter = make_uniq("list_filter", std::move(filter_children)); + + auto columns_expr = make_uniq(); + columns_expr->columns = true; + columns_expr->expr = std::move(list_filter); + root = std::move(columns_expr); +} + void Binder::ExpandStarExpression(unique_ptr expr, vector> &new_select_list) { + TryTransformStarLike(expr); + StarExpression *star = nullptr; if (!FindStarExpression(expr, &star, true, false)) { // no star expression: add it as-is diff --git a/src/duckdb/src/planner/binder/expression/bind_unnest_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_unnest_expression.cpp index 139003c3d..0f9ecc8ba 100644 --- a/src/duckdb/src/planner/binder/expression/bind_unnest_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_unnest_expression.cpp @@ -21,7 +21,7 @@ unique_ptr CreateBoundStructExtract(ClientContext &context, unique_p vector> arguments; arguments.push_back(std::move(expr)); arguments.push_back(make_uniq(Value(key))); - auto extract_function = StructExtractFun::KeyExtractFunction(); + auto extract_function = GetKeyExtractFunction(); auto bind_info = extract_function.bind(context, extract_function, arguments); auto return_type = extract_function.return_type; auto result = make_uniq(return_type, std::move(extract_function), std::move(arguments), @@ -34,7 +34,7 @@ unique_ptr CreateBoundStructExtractIndex(ClientContext &context, uni vector> arguments; arguments.push_back(std::move(expr)); arguments.push_back(make_uniq(Value::BIGINT(int64_t(key)))); - auto extract_function = StructExtractFun::IndexExtractFunction(); + auto extract_function = GetIndexExtractFunction(); auto bind_info = extract_function.bind(context, extract_function, arguments); auto return_type = extract_function.return_type; auto result = make_uniq(return_type, std::move(extract_function), std::move(arguments), diff --git a/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp b/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp index d58b3868e..93e0b60c5 100644 --- a/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp +++ b/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp @@ -1,7 +1,7 @@ #include "duckdb/common/limits.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/execution/expression_executor.hpp" -#include "duckdb/function/aggregate/distributive_functions.hpp" +#include "duckdb/function/aggregate/distributive_function_utils.hpp" #include "duckdb/function/function_binder.hpp" #include "duckdb/main/config.hpp" #include "duckdb/parser/expression/columnref_expression.hpp" @@ -492,7 +492,7 @@ unique_ptr Binder::BindSelectNode(SelectNode &statement, unique_ // but also push a first(x) aggregate in case x is selected (uncollated) info.collated_groups[i] = result->aggregates.size(); - auto first_fun = FirstFun::GetFunction(bound_expr_ref.return_type); + auto first_fun = FirstFunctionGetter::GetFunction(bound_expr_ref.return_type); vector> first_children; // FIXME: would be better to just refer to this expression, but for now we copy first_children.push_back(bound_expr_ref.Copy()); @@ -518,7 +518,7 @@ unique_ptr Binder::BindSelectNode(SelectNode &statement, unique_ // bind the HAVING clause, if any if (statement.having) { HavingBinder having_binder(*this, context, *result, info, statement.aggregate_handling); - ExpressionBinder::QualifyColumnNames(*this, statement.having); + ExpressionBinder::QualifyColumnNames(having_binder, statement.having); result->having = having_binder.Bind(statement.having); } diff --git a/src/duckdb/src/planner/binder/query_node/bind_setop_node.cpp b/src/duckdb/src/planner/binder/query_node/bind_setop_node.cpp index 66ffede4d..82d6c754b 100644 --- a/src/duckdb/src/planner/binder/query_node/bind_setop_node.cpp +++ b/src/duckdb/src/planner/binder/query_node/bind_setop_node.cpp @@ -88,14 +88,18 @@ static void BuildUnionByNameInfo(ClientContext &context, BoundSetOperationNode & // We throw a binder exception if two same name in the SELECT list for (idx_t i = 0; i < left_node.names.size(); ++i) { if (left_names_map.find(left_node.names[i]) != left_names_map.end()) { - throw BinderException("UNION(ALL) BY NAME operation doesn't support same name in SELECT list"); + throw BinderException("UNION (ALL) BY NAME operation doesn't support duplicate names in the SELECT list - " + "the name \"%s\" occurs multiple times in the left-hand side", + left_node.names[i]); } left_names_map[left_node.names[i]] = i; } for (idx_t i = 0; i < right_node.names.size(); ++i) { if (right_names_map.find(right_node.names[i]) != right_names_map.end()) { - throw BinderException("UNION(ALL) BY NAME operation doesn't support same name in SELECT list"); + throw BinderException("UNION (ALL) BY NAME operation doesn't support duplicate names in the SELECT list - " + "the name \"%s\" occurs multiple times in the right-hand side", + right_node.names[i]); } if (left_names_map.find(right_node.names[i]) == left_names_map.end()) { result.names.push_back(right_node.names[i]); @@ -182,6 +186,16 @@ static void BuildUnionByNameInfo(ClientContext &context, BoundSetOperationNode & } } +static void GatherSetOpBinders(BoundQueryNode &node, Binder &binder, vector> &binders) { + if (node.type != QueryNodeType::SET_OPERATION_NODE) { + binders.push_back(binder); + return; + } + auto &setop_node = node.Cast(); + GatherSetOpBinders(*setop_node.left, *setop_node.left_binder, binders); + GatherSetOpBinders(*setop_node.right, *setop_node.right_binder, binders); +} + unique_ptr Binder::BindNode(SetOperationNode &statement) { auto result = make_uniq(); result->setop_type = statement.setop_type; @@ -247,7 +261,10 @@ unique_ptr Binder::BindNode(SetOperationNode &statement) { GatherAliases(*result, bind_state, reorder_idx); } // now we perform the actual resolution of the ORDER BY/DISTINCT expressions - OrderBinder order_binder({*result->left_binder, *result->right_binder}, bind_state); + vector> binders; + GatherSetOpBinders(*result->left, *result->left_binder, binders); + GatherSetOpBinders(*result->right, *result->right_binder, binders); + OrderBinder order_binder(binders, bind_state); PrepareModifiers(order_binder, statement, *result); } 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 d020d5399..807fa6c7b 100644 --- a/src/duckdb/src/planner/binder/query_node/plan_subquery.cpp +++ b/src/duckdb/src/planner/binder/query_node/plan_subquery.cpp @@ -1,4 +1,5 @@ #include "duckdb/function/aggregate/distributive_functions.hpp" +#include "duckdb/function/aggregate/distributive_function_utils.hpp" #include "duckdb/main/client_config.hpp" #include "duckdb/planner/binder.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" @@ -17,7 +18,7 @@ #include "duckdb/common/enums/logical_operator_type.hpp" #include "duckdb/planner/operator/logical_dependent_join.hpp" #include "duckdb/planner/subquery/recursive_dependent_join_planner.hpp" -#include "duckdb/core_functions/scalar/generic_functions.hpp" +#include "duckdb/function/scalar/generic_functions.hpp" namespace duckdb { @@ -87,8 +88,9 @@ static unique_ptr PlanUncorrelatedSubquery(Binder &binder, BoundSubq first_children.push_back(std::move(bound)); FunctionBinder function_binder(binder.context); - auto first_agg = function_binder.BindAggregateFunction( - FirstFun::GetFunction(expr.return_type), std::move(first_children), nullptr, AggregateType::NON_DISTINCT); + auto first_agg = + function_binder.BindAggregateFunction(FirstFunctionGetter::GetFunction(expr.return_type), + std::move(first_children), nullptr, AggregateType::NON_DISTINCT); expressions.push_back(std::move(first_agg)); if (error_on_multiple_rows) { diff --git a/src/duckdb/src/planner/binder/statement/bind_copy.cpp b/src/duckdb/src/planner/binder/statement/bind_copy.cpp index d95db2e0a..916a21ffd 100644 --- a/src/duckdb/src/planner/binder/statement/bind_copy.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_copy.cpp @@ -29,12 +29,6 @@ static bool GetBooleanArg(ClientContext &context, const vector &arg) { } BoundStatement Binder::BindCopyTo(CopyStatement &stmt, CopyToType copy_to_type) { - // COPY TO a file - auto &config = DBConfig::GetConfig(context); - if (!config.options.enable_external_access) { - throw PermissionException("COPY TO is disabled by configuration"); - } - // lookup the format in the catalog auto ©_function = Catalog::GetEntry(context, INVALID_CATALOG, DEFAULT_SCHEMA, stmt.info->format); @@ -272,10 +266,6 @@ BoundStatement Binder::BindCopyTo(CopyStatement &stmt, CopyToType copy_to_type) } BoundStatement Binder::BindCopyFrom(CopyStatement &stmt) { - auto &config = DBConfig::GetConfig(context); - if (!config.options.enable_external_access) { - throw PermissionException("COPY FROM is disabled by configuration"); - } BoundStatement result; result.types = {LogicalType::BIGINT}; result.names = {"Count"}; @@ -284,7 +274,7 @@ BoundStatement Binder::BindCopyFrom(CopyStatement &stmt) { throw ParserException("COPY FROM requires a table name to be specified"); } // COPY FROM a file - // generate an insert statement for the the to-be-inserted table + // generate an insert statement for the to-be-inserted table InsertStatement insert; insert.table = stmt.info->table; insert.schema = stmt.info->schema; diff --git a/src/duckdb/src/planner/binder/statement/bind_create.cpp b/src/duckdb/src/planner/binder/statement/bind_create.cpp index a35d6e13c..3803e63ec 100644 --- a/src/duckdb/src/planner/binder/statement/bind_create.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_create.cpp @@ -1,48 +1,45 @@ #include "duckdb/catalog/catalog.hpp" -#include "duckdb/catalog/catalog_search_path.hpp" #include "duckdb/catalog/catalog_entry/duck_table_entry.hpp" #include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/type_catalog_entry.hpp" -#include "duckdb/main/secret/secret_manager.hpp" +#include "duckdb/catalog/catalog_search_path.hpp" +#include "duckdb/catalog/duck_catalog.hpp" +#include "duckdb/function/scalar_macro_function.hpp" +#include "duckdb/function/table/table_scan.hpp" +#include "duckdb/main/attached_database.hpp" #include "duckdb/main/client_context.hpp" +#include "duckdb/main/client_data.hpp" #include "duckdb/main/database.hpp" +#include "duckdb/main/database_manager.hpp" +#include "duckdb/main/secret/secret_manager.hpp" +#include "duckdb/parser/constraints/foreign_key_constraint.hpp" +#include "duckdb/parser/constraints/list.hpp" +#include "duckdb/parser/constraints/unique_constraint.hpp" #include "duckdb/parser/expression/constant_expression.hpp" #include "duckdb/parser/expression/function_expression.hpp" #include "duckdb/parser/expression/subquery_expression.hpp" -#include "duckdb/planner/expression/bound_cast_expression.hpp" -#include "duckdb/planner/expression/bound_columnref_expression.hpp" #include "duckdb/parser/parsed_data/create_index_info.hpp" #include "duckdb/parser/parsed_data/create_macro_info.hpp" -#include "duckdb/parser/parsed_data/create_view_info.hpp" -#include "duckdb/parser/tableref/table_function_ref.hpp" #include "duckdb/parser/parsed_data/create_secret_info.hpp" +#include "duckdb/parser/parsed_data/create_view_info.hpp" #include "duckdb/parser/parsed_expression_iterator.hpp" #include "duckdb/parser/statement/create_statement.hpp" +#include "duckdb/parser/tableref/basetableref.hpp" +#include "duckdb/parser/tableref/table_function_ref.hpp" #include "duckdb/planner/binder.hpp" #include "duckdb/planner/bound_query_node.hpp" +#include "duckdb/planner/expression/bound_cast_expression.hpp" +#include "duckdb/planner/expression/bound_columnref_expression.hpp" #include "duckdb/planner/expression_binder/index_binder.hpp" #include "duckdb/planner/expression_binder/select_binder.hpp" #include "duckdb/planner/operator/logical_create.hpp" -#include "duckdb/planner/operator/logical_create_index.hpp" #include "duckdb/planner/operator/logical_create_table.hpp" #include "duckdb/planner/operator/logical_get.hpp" #include "duckdb/planner/operator/logical_projection.hpp" #include "duckdb/planner/parsed_data/bound_create_table_info.hpp" #include "duckdb/planner/query_node/bound_select_node.hpp" #include "duckdb/planner/tableref/bound_basetableref.hpp" -#include "duckdb/parser/constraints/foreign_key_constraint.hpp" -#include "duckdb/function/scalar_macro_function.hpp" -#include "duckdb/storage/data_table.hpp" #include "duckdb/storage/storage_extension.hpp" -#include "duckdb/main/client_data.hpp" -#include "duckdb/parser/constraints/unique_constraint.hpp" -#include "duckdb/parser/constraints/list.hpp" -#include "duckdb/main/database_manager.hpp" -#include "duckdb/main/attached_database.hpp" -#include "duckdb/catalog/duck_catalog.hpp" -#include "duckdb/function/table/table_scan.hpp" -#include "duckdb/parser/tableref/basetableref.hpp" -#include "duckdb/planner/expression_binder/select_bind_state.hpp" namespace duckdb { @@ -147,8 +144,7 @@ void Binder::BindCreateViewInfo(CreateViewInfo &base) { auto &catalog = Catalog::GetCatalog(context, base.catalog); auto &db_config = DBConfig::GetConfig(context); - auto should_create_dependencies = db_config.options.enable_view_dependencies; - + bool should_create_dependencies = db_config.GetSetting(context); if (should_create_dependencies) { view_binder->SetCatalogLookupCallback([&dependencies, &catalog](CatalogEntry &entry) { if (&catalog != &entry.ParentCatalog()) { @@ -219,7 +215,7 @@ SchemaCatalogEntry &Binder::BindCreateFunctionInfo(CreateInfo &info) { BoundSelectNode sel_node; BoundGroupInformation group_info; SelectBinder binder(*this, context, sel_node, group_info); - auto should_create_dependencies = db_config.options.enable_macro_dependencies; + bool should_create_dependencies = db_config.GetSetting(context); if (should_create_dependencies) { binder.SetCatalogLookupCallback([&dependencies, &catalog](CatalogEntry &entry) { @@ -574,46 +570,9 @@ static bool AnyConstraintReferencesGeneratedColumn(CreateTableInfo &table_info) unique_ptr DuckCatalog::BindCreateIndex(Binder &binder, CreateStatement &stmt, TableCatalogEntry &table, unique_ptr plan) { D_ASSERT(plan->type == LogicalOperatorType::LOGICAL_GET); - auto &base = stmt.info->Cast(); - - auto &get = plan->Cast(); - // bind the index expressions - IndexBinder index_binder(binder, binder.context); - auto &dependencies = base.dependencies; - auto &catalog = Catalog::GetCatalog(binder.context, base.catalog); - index_binder.SetCatalogLookupCallback([&dependencies, &catalog](CatalogEntry &entry) { - if (&catalog != &entry.ParentCatalog()) { - // Don't register any cross-catalog dependencies - return; - } - dependencies.AddDependency(entry); - }); - vector> expressions; - expressions.reserve(base.expressions.size()); - for (auto &expr : base.expressions) { - expressions.push_back(index_binder.Bind(expr)); - } - auto create_index_info = unique_ptr_cast(std::move(stmt.info)); - auto &column_ids = get.GetColumnIds(); - for (auto &column_id : column_ids) { - if (column_id == COLUMN_IDENTIFIER_ROW_ID) { - throw BinderException("Cannot create an index on the rowid!"); - } - create_index_info->scan_types.push_back(get.returned_types[column_id]); - } - create_index_info->scan_types.emplace_back(LogicalType::ROW_TYPE); - create_index_info->names = get.names; - create_index_info->column_ids = column_ids; - create_index_info->schema = table.schema.name; - auto &bind_data = get.bind_data->Cast(); - bind_data.is_create_index = true; - get.AddColumnId(COLUMN_IDENTIFIER_ROW_ID); - - // the logical CREATE INDEX also needs all fields to scan the referenced table - auto result = make_uniq(std::move(create_index_info), std::move(expressions), table); - result->children.push_back(std::move(plan)); - return std::move(result); + IndexBinder index_binder(binder, binder.context); + return index_binder.BindCreateIndex(binder.context, std::move(create_index_info), table, std::move(plan), nullptr); } BoundStatement Binder::Bind(CreateStatement &stmt) { @@ -659,18 +618,17 @@ BoundStatement Binder::Bind(CreateStatement &stmt) { break; } case CatalogType::INDEX_ENTRY: { - auto &base = stmt.info->Cast(); - - // visit the table reference - auto table_ref = make_uniq(); - table_ref->catalog_name = base.catalog; - table_ref->schema_name = base.schema; - table_ref->table_name = base.table; + auto &create_index_info = stmt.info->Cast(); + // Plan the table scan. + TableDescription table_description(create_index_info.catalog, create_index_info.schema, + create_index_info.table); + auto table_ref = make_uniq(table_description); auto bound_table = Bind(*table_ref); if (bound_table->type != TableReferenceType::BASE_TABLE) { - throw BinderException("Can only create an index over a base table!"); + throw BinderException("can only create an index on a base table"); } + auto &table_binding = bound_table->Cast(); auto &table = table_binding.table; if (table.temporary) { @@ -683,6 +641,7 @@ BoundStatement Binder::Bind(CreateStatement &stmt) { if (plan->type != LogicalOperatorType::LOGICAL_GET) { throw BinderException("Cannot create index on a view!"); } + result.plan = table.catalog.BindCreateIndex(*this, stmt, table, std::move(plan)); 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 7ffbaf236..670bdf586 100644 --- a/src/duckdb/src/planner/binder/statement/bind_create_table.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_create_table.cpp @@ -11,7 +11,6 @@ #include "duckdb/catalog/dependency_manager.hpp" #include "duckdb/function/table/table_scan.hpp" #include "duckdb/planner/operator/logical_get.hpp" -#include "duckdb/parser/parsed_expression_iterator.hpp" #include "duckdb/common/string.hpp" #include "duckdb/common/queue.hpp" #include "duckdb/parser/expression/list.hpp" @@ -21,8 +20,6 @@ #include "duckdb/parser/parsed_data/create_index_info.hpp" #include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" -#include - namespace duckdb { static void CreateColumnDependencyManager(BoundCreateTableInfo &info) { @@ -35,19 +32,6 @@ static void CreateColumnDependencyManager(BoundCreateTableInfo &info) { } } -static unique_ptr BindCheckConstraint(Binder &binder, const string &table_name, - const ColumnList &columns, const unique_ptr &cond) { - auto bound_constraint = make_uniq(); - // check constraint: bind the expression - CheckBinder check_binder(binder, binder.context, table_name, columns, bound_constraint->bound_columns); - auto &check = cond->Cast(); - // create a copy of the unbound expression because the binding destroys the constraint - auto unbound_expression = check.expression->Copy(); - // now bind the constraint and create a new BoundCheckConstraint - bound_constraint->expression = check_binder.Bind(unbound_expression); - return std::move(bound_constraint); -} - vector> Binder::BindConstraints(ClientContext &context, const vector> &constraints, const string &table_name, const ColumnList &columns) { @@ -62,76 +46,8 @@ vector> Binder::BindConstraints(const TableCatalogEn vector> Binder::BindConstraints(const vector> &constraints, const string &table_name, const ColumnList &columns) { vector> bound_constraints; - for (auto &constr : constraints) { - switch (constr->type) { - case ConstraintType::CHECK: { - bound_constraints.push_back(BindCheckConstraint(*this, table_name, columns, constr)); - break; - } - case ConstraintType::NOT_NULL: { - auto ¬_null = constr->Cast(); - auto &col = columns.GetColumn(LogicalIndex(not_null.index)); - bound_constraints.push_back(make_uniq(PhysicalIndex(col.StorageOid()))); - break; - } - case ConstraintType::UNIQUE: { - auto &unique = constr->Cast(); - // have to resolve columns of the unique constraint - vector keys; - logical_index_set_t key_set; - if (unique.HasIndex()) { - D_ASSERT(unique.GetIndex().index < columns.LogicalColumnCount()); - // unique constraint is given by single index - unique.SetColumnName(columns.GetColumn(unique.GetIndex()).Name()); - keys.push_back(unique.GetIndex()); - key_set.insert(unique.GetIndex()); - } else { - // unique constraint is given by list of names - // have to resolve names - for (auto &keyname : unique.GetColumnNames()) { - if (!columns.ColumnExists(keyname)) { - throw ParserException("column \"%s\" named in key does not exist", keyname); - } - auto &column = columns.GetColumn(keyname); - auto column_index = column.Logical(); - if (key_set.find(column_index) != key_set.end()) { - throw ParserException("column \"%s\" appears twice in " - "primary key constraint", - keyname); - } - keys.push_back(column_index); - key_set.insert(column_index); - } - } - bound_constraints.push_back( - make_uniq(std::move(keys), std::move(key_set), unique.IsPrimaryKey())); - break; - } - case ConstraintType::FOREIGN_KEY: { - auto &fk = constr->Cast(); - D_ASSERT((fk.info.type == ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE && !fk.info.pk_keys.empty()) || - (fk.info.type == ForeignKeyType::FK_TYPE_PRIMARY_KEY_TABLE && !fk.info.pk_keys.empty()) || - fk.info.type == ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE); - physical_index_set_t fk_key_set, pk_key_set; - for (auto &pk_key : fk.info.pk_keys) { - if (pk_key_set.find(pk_key) != pk_key_set.end()) { - throw BinderException("Duplicate primary key referenced in FOREIGN KEY constraint"); - } - pk_key_set.insert(pk_key); - } - for (auto &fk_key : fk.info.fk_keys) { - if (fk_key_set.find(fk_key) != fk_key_set.end()) { - throw BinderException("Duplicate key specified in FOREIGN KEY constraint"); - } - fk_key_set.insert(fk_key); - } - bound_constraints.push_back( - make_uniq(fk.info, std::move(pk_key_set), std::move(fk_key_set))); - break; - } - default: - throw NotImplementedException("unrecognized constraint type in bind"); - } + for (const auto &constr : constraints) { + bound_constraints.push_back(BindConstraint(*constr, table_name, columns)); } return bound_constraints; } @@ -140,30 +56,26 @@ vector> Binder::BindNewConstraints(vector primary_keys; - for (idx_t c = 0; c < constraints.size(); c++) { - auto &constr = constraints[c]; - switch (constr->type) { + physical_index_set_t not_null_columns; + vector primary_keys; + + for (const auto &bound_constr : bound_constraints) { + switch (bound_constr->type) { case ConstraintType::NOT_NULL: { - auto ¬_null = constr->Cast(); - auto &col = columns.GetColumn(LogicalIndex(not_null.index)); - bound_constraints.push_back(make_uniq(PhysicalIndex(col.StorageOid()))); + auto ¬_null = bound_constr->Cast(); not_null_columns.insert(not_null.index); break; } case ConstraintType::UNIQUE: { - auto &unique = constr->Cast(); - auto &bound_unique = bound_constraints[c]->Cast(); - if (unique.IsPrimaryKey()) { - // we can only have one primary key per table + const auto &unique = bound_constr->Cast(); + if (unique.is_primary_key) { if (has_primary_key) { throw ParserException("table \"%s\" has more than one primary key", table_name); } has_primary_key = true; - primary_keys = bound_unique.keys; + primary_keys = unique.keys; } break; } @@ -171,21 +83,127 @@ vector> Binder::BindNewConstraints(vector(column_index)); - bound_constraints.push_back(make_uniq(physical_index)); + + auto logical_index = columns.PhysicalToLogical(column_index); + constraints.push_back(make_uniq(logical_index)); + bound_constraints.push_back(make_uniq(column_index)); } } + return bound_constraints; } +unique_ptr BindCheckConstraint(Binder &binder, Constraint &constraint, const string &table, + const ColumnList &columns) { + auto bound_constraint = make_uniq(); + auto &bound_check = bound_constraint->Cast(); + + // Bind the CHECK expression. + CheckBinder check_binder(binder, binder.context, table, columns, bound_check.bound_columns); + auto &check = constraint.Cast(); + + // Create a copy of the unbound expression because binding can invalidate it. + auto unbound_expression = check.expression->Copy(); + + // Bind the constraint and reset the original expression. + bound_check.expression = check_binder.Bind(check.expression); + check.expression = std::move(unbound_expression); + return std::move(bound_constraint); +} + +unique_ptr Binder::BindUniqueConstraint(Constraint &constraint, const string &table, + const ColumnList &columns) { + auto &unique = constraint.Cast(); + + // Resolve the columns. + vector indexes; + physical_index_set_t index_set; + + // HasIndex refers to a column index, not an index(-structure). + // If set, then the UNIQUE constraint is defined on a single column. + if (unique.HasIndex()) { + auto &col = columns.GetColumn(unique.GetIndex()); + unique.SetColumnName(col.Name()); + indexes.push_back(col.Physical()); + index_set.insert(col.Physical()); + return make_uniq(std::move(indexes), std::move(index_set), unique.IsPrimaryKey()); + } + + // The UNIQUE constraint is defined on a list of columns. + for (auto &col_name : unique.GetColumnNames()) { + if (!columns.ColumnExists(col_name)) { + throw CatalogException("table \"%s\" does not have a column named \"%s\"", table, col_name); + } + auto &col = columns.GetColumn(col_name); + if (col.Generated()) { + throw BinderException("cannot create a PRIMARY KEY on a generated column: %s", col.GetName()); + } + + auto physical_index = col.Physical(); + if (index_set.find(physical_index) != index_set.end()) { + throw ParserException("column \"%s\" appears twice in primary key constraint", col_name); + } + indexes.push_back(physical_index); + index_set.insert(physical_index); + } + + return make_uniq(std::move(indexes), std::move(index_set), unique.IsPrimaryKey()); +} + +unique_ptr BindForeignKey(Constraint &constraint) { + auto &fk = constraint.Cast(); + D_ASSERT((fk.info.type == ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE && !fk.info.pk_keys.empty()) || + (fk.info.type == ForeignKeyType::FK_TYPE_PRIMARY_KEY_TABLE && !fk.info.pk_keys.empty()) || + fk.info.type == ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE); + + physical_index_set_t pk_key_set; + for (auto &pk_key : fk.info.pk_keys) { + if (pk_key_set.find(pk_key) != pk_key_set.end()) { + throw ParserException("duplicate primary key referenced in FOREIGN KEY constraint"); + } + pk_key_set.insert(pk_key); + } + + physical_index_set_t fk_key_set; + for (auto &fk_key : fk.info.fk_keys) { + if (fk_key_set.find(fk_key) != fk_key_set.end()) { + throw ParserException("duplicate key specified in FOREIGN KEY constraint"); + } + fk_key_set.insert(fk_key); + } + + return make_uniq(fk.info, std::move(pk_key_set), std::move(fk_key_set)); +} + +unique_ptr Binder::BindConstraint(Constraint &constraint, const string &table, + const ColumnList &columns) { + switch (constraint.type) { + case ConstraintType::CHECK: { + return BindCheckConstraint(*this, constraint, table, columns); + } + case ConstraintType::NOT_NULL: { + auto ¬_null = constraint.Cast(); + auto &col = columns.GetColumn(not_null.index); + return make_uniq(col.Physical()); + } + case ConstraintType::UNIQUE: { + return BindUniqueConstraint(constraint, table, columns); + } + case ConstraintType::FOREIGN_KEY: { + return BindForeignKey(constraint); + } + default: + throw NotImplementedException("unrecognized constraint type in bind"); + } +} + void Binder::BindGeneratedColumns(BoundCreateTableInfo &info) { auto &base = info.base->Cast(); @@ -319,10 +337,30 @@ unique_ptr Binder::BindCreateTableInfo(unique_ptr sql_types.size()) { + throw BinderException("Target table has more colum names than query result."); + } else if (target_col_names.size() < sql_types.size()) { + // filled the target_col_names with the name of query names + for (idx_t i = target_col_names.size(); i < sql_types.size(); i++) { + target_col_names.push_back(names[i]); + } + } + ColumnList new_colums; + for (idx_t i = 0; i < target_col_names.size(); i++) { + new_colums.AddColumn(ColumnDefinition(target_col_names[i], sql_types[i])); + } + base.columns = std::move(new_colums); + } else { + for (idx_t i = 0; i < names.size(); i++) { + base.columns.AddColumn(ColumnDefinition(names[i], sql_types[i])); + } } } else { SetCatalogLookupCallback([&dependencies, &schema](CatalogEntry &entry) { diff --git a/src/duckdb/src/planner/binder/statement/bind_export.cpp b/src/duckdb/src/planner/binder/statement/bind_export.cpp index 924df011f..68b5b80d2 100644 --- a/src/duckdb/src/planner/binder/statement/bind_export.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_export.cpp @@ -159,10 +159,6 @@ unique_ptr Binder::UnionOperators(vector alter_info) { + auto &table_info = alter_info->Cast(); + auto &constraint_info = table_info.Cast(); + auto &table = entry.Cast(); + auto &column_list = table.GetColumns(); + + auto bound_constraint = BindUniqueConstraint(*constraint_info.constraint, table_info.name, column_list); + auto &bound_unique = bound_constraint->Cast(); + + // Create the CreateIndexInfo. + auto create_index_info = make_uniq(); + create_index_info->table = table_info.name; + create_index_info->index_type = ART::TYPE_NAME; + create_index_info->constraint_type = IndexConstraintType::PRIMARY; + + for (const auto &physical_index : bound_unique.keys) { + auto &col = column_list.GetColumn(physical_index); + unique_ptr parsed = make_uniq(col.GetName(), table_info.name); + create_index_info->expressions.push_back(parsed->Copy()); + create_index_info->parsed_expressions.push_back(parsed->Copy()); + } + + auto unique_constraint = constraint_info.constraint->Cast(); + auto index_name = unique_constraint.GetName(table_info.name); + create_index_info->index_name = index_name; + D_ASSERT(!create_index_info->index_name.empty()); + + // Plan the table scan. + TableDescription table_description(table_info.catalog, table_info.schema, table_info.name); + auto table_ref = make_uniq(table_description); + auto bound_table = Bind(*table_ref); + if (bound_table->type != TableReferenceType::BASE_TABLE) { + throw BinderException("can only add an index to a base table"); + } + auto plan = CreatePlan(*bound_table); + auto &get = plan->Cast(); + get.names = column_list.GetColumnNames(); + + IndexBinder index_binder(*this, context); + auto op = index_binder.BindCreateIndex(context, std::move(create_index_info), table, std::move(plan), + unique_ptr_cast(std::move(alter_info))); + result.plan = std::move(op); + return std::move(result); +} + BoundStatement Binder::Bind(AlterStatement &stmt) { BoundStatement result; result.names = {"Success"}; result.types = {LogicalType::BOOLEAN}; - BindSchemaOrCatalog(stmt.info->catalog, stmt.info->schema); optional_ptr entry; if (stmt.info->type == AlterType::SET_COLUMN_COMMENT) { - // for column comments we need to an extra step: they can alter a table or a view, we resolve that here. + // 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); + } else { - // All other AlterTypes + // For any other ALTER, we retrieve the catalog entry directly. entry = entry_retriever.GetEntry(stmt.info->GetCatalogType(), stmt.info->catalog, stmt.info->schema, stmt.info->name, stmt.info->if_not_found); } auto &properties = GetStatementProperties(); - if (entry) { - D_ASSERT(!entry->deleted); - auto &catalog = entry->ParentCatalog(); - if (catalog.IsSystemCatalog()) { - throw BinderException("Can not comment on System Catalog entries"); - } - if (!entry->temporary) { - // we can only alter temporary tables/views in read-only mode - properties.RegisterDBModify(catalog, context); - } - stmt.info->catalog = catalog.GetName(); - stmt.info->schema = entry->ParentSchema().name; - } - result.plan = make_uniq(LogicalOperatorType::LOGICAL_ALTER, std::move(stmt.info)); properties.return_type = StatementReturnType::NOTHING; - return result; + if (!entry) { + result.plan = make_uniq(LogicalOperatorType::LOGICAL_ALTER, std::move(stmt.info)); + return result; + } + + D_ASSERT(!entry->deleted); + auto &catalog = entry->ParentCatalog(); + if (catalog.IsSystemCatalog()) { + throw BinderException("Can not comment on System Catalog entries"); + } + if (!entry->temporary) { + // We can only alter temporary tables and views in read-only mode. + properties.RegisterDBModify(catalog, context); + } + stmt.info->catalog = catalog.GetName(); + stmt.info->schema = entry->ParentSchema().name; + + if (!stmt.info->IsAddPrimaryKey()) { + result.plan = make_uniq(LogicalOperatorType::LOGICAL_ALTER, std::move(stmt.info)); + return result; + } + + return BindAlterAddIndex(result, *entry, std::move(stmt.info)); } BoundStatement Binder::Bind(TransactionStatement &stmt) { auto &properties = GetStatementProperties(); - // transaction statements do not require a valid transaction + + // Transaction statements do not require a valid transaction. properties.requires_valid_transaction = stmt.info->type == TransactionType::BEGIN_TRANSACTION; BoundStatement result; diff --git a/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp b/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp index 40f2662d4..ba41b051e 100644 --- a/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp +++ b/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp @@ -15,6 +15,7 @@ #include "duckdb/planner/tableref/bound_cteref.hpp" #include "duckdb/planner/tableref/bound_dummytableref.hpp" #include "duckdb/planner/tableref/bound_subqueryref.hpp" +#include "duckdb/catalog/catalog_search_path.hpp" namespace duckdb { @@ -202,6 +203,17 @@ unique_ptr Binder::Bind(BaseTableRef &ref) { return replacement_scan_bind_result; } } + auto &config = DBConfig::GetConfig(context); + if (context.config.use_replacement_scans && config.options.enable_external_access && + ExtensionHelper::IsFullPath(full_path)) { + auto &fs = FileSystem::GetFileSystem(context); + if (fs.FileExists(full_path)) { + throw BinderException( + "No extension found that is capable of reading the file \"%s\"\n* If this file is a supported file " + "format you can explicitly use the reader functions, such as read_csv, read_json or read_parquet", + full_path); + } + } // could not find an alternative: bind again to get the error (void)entry_retriever.GetEntry(CatalogType::TABLE_ENTRY, ref.catalog_name, ref.schema_name, ref.table_name, @@ -220,7 +232,6 @@ unique_ptr Binder::Bind(BaseTableRef &ref) { unique_ptr bind_data; auto scan_function = table.GetScanFunction(context, bind_data); - auto alias = ref.alias.empty() ? ref.table_name : ref.alias; // TODO: bundle the type and name vector in a struct (e.g PackedColumnMetadata) vector table_types; vector table_names; @@ -234,12 +245,17 @@ unique_ptr Binder::Bind(BaseTableRef &ref) { return_types.push_back(col.Type()); return_names.push_back(col.Name()); } - table_names = BindContext::AliasColumnNames(alias, table_names, ref.column_name_alias); + table_names = BindContext::AliasColumnNames(ref.table_name, table_names, ref.column_name_alias); auto logical_get = make_uniq(table_index, scan_function, std::move(bind_data), std::move(return_types), std::move(return_names)); - bind_context.AddBaseTable(table_index, alias, table_names, table_types, logical_get->GetMutableColumnIds(), - logical_get->GetTable().get()); + auto table_entry = logical_get->GetTable(); + auto &col_ids = logical_get->GetMutableColumnIds(); + if (!table_entry) { + bind_context.AddBaseTable(table_index, ref.alias, table_names, table_types, col_ids, ref.table_name); + } else { + bind_context.AddBaseTable(table_index, ref.alias, table_names, table_types, col_ids, *table_entry); + } return make_uniq_base(table, std::move(logical_get)); } case CatalogType::VIEW_ENTRY: { @@ -251,14 +267,24 @@ unique_ptr Binder::Bind(BaseTableRef &ref) { auto view_binder = Binder::CreateBinder(context, this, BinderType::VIEW_BINDER); view_binder->can_contain_nulls = true; SubqueryRef subquery(unique_ptr_cast(view_catalog_entry.query->Copy())); - subquery.alias = ref.alias.empty() ? ref.table_name : ref.alias; + 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]); } - subquery.column_name_alias = BindContext::AliasColumnNames(subquery.alias, view_names, ref.column_name_alias); + 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 + vector view_search_path; + auto &catalog_name = view_catalog_entry.ParentCatalog().GetName(); + auto &schema_name = view_catalog_entry.ParentSchema().name; + view_search_path.emplace_back(catalog_name, schema_name); + if (schema_name != DEFAULT_SCHEMA) { + view_search_path.emplace_back(view_catalog_entry.ParentCatalog().GetName(), DEFAULT_SCHEMA); + } + view_binder->entry_retriever.SetSearchPath(std::move(view_search_path)); // bind the child subquery view_binder->AddBoundView(view_catalog_entry); auto bound_child = view_binder->Bind(subquery); @@ -287,7 +313,7 @@ unique_ptr Binder::Bind(BaseTableRef &ref) { } } bind_context.AddView(bound_subquery.subquery->GetRootIndex(), subquery.alias, subquery, - *bound_subquery.subquery, &view_catalog_entry); + *bound_subquery.subquery, view_catalog_entry); return bound_child; } default: diff --git a/src/duckdb/src/planner/binder/tableref/bind_joinref.cpp b/src/duckdb/src/planner/binder/tableref/bind_joinref.cpp index c07c6424f..257e275be 100644 --- a/src/duckdb/src/planner/binder/tableref/bind_joinref.cpp +++ b/src/duckdb/src/planner/binder/tableref/bind_joinref.cpp @@ -15,7 +15,7 @@ namespace duckdb { -static unique_ptr BindColumn(Binder &binder, ClientContext &context, const string &alias, +static unique_ptr BindColumn(Binder &binder, ClientContext &context, const BindingAlias &alias, const string &column_name) { auto expr = make_uniq_base(column_name, alias); ExpressionBinder expr_binder(binder, context); @@ -24,7 +24,7 @@ static unique_ptr BindColumn(Binder &binder, ClientContext &co } static unique_ptr AddCondition(ClientContext &context, Binder &left_binder, Binder &right_binder, - const string &left_alias, const string &right_alias, + const BindingAlias &left_alias, const BindingAlias &right_alias, const string &column_name, ExpressionType type) { ExpressionBinder expr_binder(left_binder, context); auto left = BindColumn(left_binder, context, left_alias, column_name); @@ -32,7 +32,7 @@ static unique_ptr AddCondition(ClientContext &context, Binder return make_uniq(type, std::move(left), std::move(right)); } -bool Binder::TryFindBinding(const string &using_column, const string &join_side, string &result) { +bool Binder::TryFindBinding(const string &using_column, const string &join_side, BindingAlias &result) { // for each using column, get the matching binding auto bindings = bind_context.GetMatchingBindings(using_column); if (bindings.empty()) { @@ -40,46 +40,48 @@ bool Binder::TryFindBinding(const string &using_column, const string &join_side, } // find the join binding for (auto &binding : bindings) { - if (!result.empty()) { + if (result.IsSet()) { string error = "Column name \""; error += using_column; error += "\" is ambiguous: it exists more than once on "; error += join_side; error += " side of join.\nCandidates:"; - for (auto &binding : bindings) { + for (auto &binding_ref : bindings) { + auto &other_binding = binding_ref.get(); error += "\n\t"; - error += binding; + error += other_binding.GetAlias(); error += "."; - error += bind_context.GetActualColumnName(binding, using_column); + error += bind_context.GetActualColumnName(other_binding, using_column); } throw BinderException(error); } else { - result = binding; + result = binding.get().alias; } } return true; } -string Binder::FindBinding(const string &using_column, const string &join_side) { - string result; +BindingAlias Binder::FindBinding(const string &using_column, const string &join_side) { + BindingAlias result; if (!TryFindBinding(using_column, join_side, result)) { throw BinderException("Column \"%s\" does not exist on %s side of join!", using_column, join_side); } return result; } -static void AddUsingBindings(UsingColumnSet &set, optional_ptr input_set, const string &input_binding) { +static void AddUsingBindings(UsingColumnSet &set, optional_ptr input_set, + const BindingAlias &input_binding) { if (input_set) { for (auto &entry : input_set->bindings) { - set.bindings.insert(entry); + set.bindings.push_back(entry); } } else { - set.bindings.insert(input_binding); + set.bindings.push_back(input_binding); } } -static void SetPrimaryBinding(UsingColumnSet &set, JoinType join_type, const string &left_binding, - const string &right_binding) { +static void SetPrimaryBinding(UsingColumnSet &set, JoinType join_type, const BindingAlias &left_binding, + const BindingAlias &right_binding) { switch (join_type) { case JoinType::LEFT: case JoinType::INNER: @@ -97,9 +99,9 @@ static void SetPrimaryBinding(UsingColumnSet &set, JoinType join_type, const str } } -string Binder::RetrieveUsingBinding(Binder ¤t_binder, optional_ptr current_set, - const string &using_column, const string &join_side) { - string binding; +BindingAlias Binder::RetrieveUsingBinding(Binder ¤t_binder, optional_ptr current_set, + const string &using_column, const string &join_side) { + BindingAlias binding; if (!current_set) { binding = current_binder.FindBinding(using_column, join_side); } else { @@ -186,7 +188,7 @@ unique_ptr Binder::Bind(JoinRef &ref) { case_insensitive_set_t lhs_columns; auto &lhs_binding_list = left_binder.bind_context.GetBindingsList(); for (auto &binding : lhs_binding_list) { - for (auto &column_name : binding.get().names) { + for (auto &column_name : binding->names) { lhs_columns.insert(column_name); } } @@ -194,7 +196,7 @@ unique_ptr Binder::Bind(JoinRef &ref) { for (auto &column_name : lhs_columns) { auto right_using_binding = right_binder.bind_context.GetUsingBinding(column_name); - string right_binding; + BindingAlias right_binding; // loop over the set of lhs columns, and figure out if there is a table in the rhs with the same name if (!right_using_binding) { if (!right_binder.TryFindBinding(column_name, "right", right_binding)) { @@ -212,21 +214,21 @@ unique_ptr Binder::Bind(JoinRef &ref) { string left_candidates, right_candidates; auto &rhs_binding_list = right_binder.bind_context.GetBindingsList(); for (auto &binding_ref : lhs_binding_list) { - auto &binding = binding_ref.get(); + auto &binding = *binding_ref; for (auto &column_name : binding.names) { if (!left_candidates.empty()) { left_candidates += ", "; } - left_candidates += binding.alias + "." + column_name; + left_candidates += binding.GetAlias() + "." + column_name; } } for (auto &binding_ref : rhs_binding_list) { - auto &binding = binding_ref.get(); + auto &binding = *binding_ref; for (auto &column_name : binding.names) { if (!right_candidates.empty()) { right_candidates += ", "; } - right_candidates += binding.alias + "." + column_name; + right_candidates += binding.GetAlias() + "." + column_name; } } error_msg += "\n Left candidates: " + left_candidates; @@ -273,8 +275,8 @@ unique_ptr Binder::Bind(JoinRef &ref) { for (idx_t i = 0; i < extra_using_columns.size(); i++) { auto &using_column = extra_using_columns[i]; - string left_binding; - string right_binding; + BindingAlias left_binding; + BindingAlias right_binding; auto set = make_uniq(); auto &left_using_binding = left_using_bindings[i]; @@ -293,16 +295,14 @@ unique_ptr Binder::Bind(JoinRef &ref) { AddUsingBindings(*set, left_using_binding, left_binding); AddUsingBindings(*set, right_using_binding, right_binding); SetPrimaryBinding(*set, ref.type, left_binding, right_binding); - bind_context.TransferUsingBinding(left_binder.bind_context, left_using_binding, *set, left_binding, - using_column); - bind_context.TransferUsingBinding(right_binder.bind_context, right_using_binding, *set, right_binding, - using_column); + bind_context.TransferUsingBinding(left_binder.bind_context, left_using_binding, *set, using_column); + bind_context.TransferUsingBinding(right_binder.bind_context, right_using_binding, *set, using_column); AddUsingBindingSet(std::move(set)); } } - auto right_bindings_list_copy = right_binder.bind_context.GetBindingsList(); - auto left_bindings_list_copy = left_binder.bind_context.GetBindingsList(); + auto right_bindings = right_binder.bind_context.GetBindingAliases(); + auto left_bindings = left_binder.bind_context.GetBindingAliases(); bind_context.AddContext(std::move(left_binder.bind_context)); bind_context.AddContext(std::move(right_binder.bind_context)); @@ -338,7 +338,7 @@ unique_ptr Binder::Bind(JoinRef &ref) { } if (result->type == JoinType::SEMI || result->type == JoinType::ANTI || result->type == JoinType::MARK) { - bind_context.RemoveContext(right_bindings_list_copy); + bind_context.RemoveContext(right_bindings); if (result->type == JoinType::MARK) { auto mark_join_idx = GenerateTableIndex(); string mark_join_alias = "__internal_mark_join_ref" + to_string(mark_join_idx); @@ -348,7 +348,7 @@ unique_ptr Binder::Bind(JoinRef &ref) { } } if (result->type == JoinType::RIGHT_SEMI || result->type == JoinType::RIGHT_ANTI) { - bind_context.RemoveContext(left_bindings_list_copy); + bind_context.RemoveContext(left_bindings); } return std::move(result); diff --git a/src/duckdb/src/planner/binder/tableref/bind_showref.cpp b/src/duckdb/src/planner/binder/tableref/bind_showref.cpp index 9af266be4..168b68e7d 100644 --- a/src/duckdb/src/planner/binder/tableref/bind_showref.cpp +++ b/src/duckdb/src/planner/binder/tableref/bind_showref.cpp @@ -1,13 +1,86 @@ -#include "duckdb/planner/binder.hpp" -#include "duckdb/parser/tableref/showref.hpp" -#include "duckdb/planner/tableref/bound_table_function.hpp" -#include "duckdb/planner/operator/logical_column_data_get.hpp" #include "duckdb/function/pragma/pragma_functions.hpp" +#include "duckdb/function/table/system_functions.hpp" #include "duckdb/parser/parsed_data/create_view_info.hpp" +#include "duckdb/parser/tableref/showref.hpp" #include "duckdb/parser/tableref/subqueryref.hpp" +#include "duckdb/planner/binder.hpp" +#include "duckdb/planner/operator/logical_column_data_get.hpp" +#include "duckdb/planner/tableref/bound_table_function.hpp" +#include "duckdb/planner/operator/logical_get.hpp" +#include "duckdb/planner/operator/logical_projection.hpp" +#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" namespace duckdb { +struct BaseTableColumnInfo { + optional_ptr table; + optional_ptr column; +}; + +BaseTableColumnInfo FindBaseTableColumn(LogicalOperator &op, ColumnBinding binding) { + BaseTableColumnInfo result; + switch (op.type) { + case LogicalOperatorType::LOGICAL_GET: { + auto &get = op.Cast(); + if (get.table_index != binding.table_index) { + return result; + } + auto table = get.GetTable(); + if (!table) { + break; + } + if (!get.projection_ids.empty()) { + throw InternalException("Projection ids should not exist here"); + } + result.table = table; + auto base_column_id = get.GetColumnIds()[binding.column_index]; + result.column = &table->GetColumn(LogicalIndex(base_column_id)); + return result; + } + case LogicalOperatorType::LOGICAL_PROJECTION: { + auto &projection = op.Cast(); + if (binding.table_index != projection.table_index) { + break; + } + auto &expr = projection.expressions[binding.column_index]; + if (expr->type == ExpressionType::BOUND_COLUMN_REF) { + // if the projection at this index only has a column reference we can directly trace it to the base table + auto &bound_colref = expr->Cast(); + return FindBaseTableColumn(*projection.children[0], bound_colref.binding); + } + break; + } + case LogicalOperatorType::LOGICAL_LIMIT: + case LogicalOperatorType::LOGICAL_ORDER_BY: + case LogicalOperatorType::LOGICAL_TOP_N: + case LogicalOperatorType::LOGICAL_SAMPLE: + case LogicalOperatorType::LOGICAL_DISTINCT: + case LogicalOperatorType::LOGICAL_FILTER: + case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: + case LogicalOperatorType::LOGICAL_JOIN: + case LogicalOperatorType::LOGICAL_ANY_JOIN: + case LogicalOperatorType::LOGICAL_ASOF_JOIN: + case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: + // for any "pass-through" operators - search in children directly + for (auto &child : op.children) { + result = FindBaseTableColumn(*child, binding); + if (result.table) { + return result; + } + } + break; + default: + // unsupported operator + break; + } + return result; +} + +BaseTableColumnInfo FindBaseTableColumn(LogicalOperator &op, idx_t column_index) { + auto bindings = op.GetColumnBindings(); + return FindBaseTableColumn(op, bindings[column_index]); +} + unique_ptr Binder::BindShowQuery(ShowRef &ref) { // bind the child plan of the DESCRIBE statement auto child_binder = Binder::CreateBinder(context, this); @@ -24,21 +97,29 @@ unique_ptr Binder::BindShowQuery(ShowRef &ref) { ColumnDataAppendState append_state; collection->InitializeAppend(append_state); for (idx_t column_idx = 0; column_idx < plan.types.size(); column_idx++) { - auto type = plan.types[column_idx]; - auto &name = plan.names[column_idx]; + // check if we can trace the column to a base table so that we can figure out constraint information + auto result = FindBaseTableColumn(*plan.plan, column_idx); + if (result.table) { + // we can! emit the information from the base table directly + PragmaTableInfo::GetColumnInfo(*result.table, *result.column, output, output.size()); + } else { + // we cannot - read the type/name from the plan instead + auto type = plan.types[column_idx]; + auto &name = plan.names[column_idx]; - // "name", TypeId::VARCHAR - output.SetValue(0, output.size(), Value(name)); - // "type", TypeId::VARCHAR - output.SetValue(1, output.size(), Value(type.ToString())); - // "null", TypeId::VARCHAR - output.SetValue(2, output.size(), Value("YES")); - // "pk", TypeId::BOOL - output.SetValue(3, output.size(), Value()); - // "dflt_value", TypeId::VARCHAR - output.SetValue(4, output.size(), Value()); - // "extra", TypeId::VARCHAR - output.SetValue(5, output.size(), Value()); + // "name", TypeId::VARCHAR + output.SetValue(0, output.size(), Value(name)); + // "type", TypeId::VARCHAR + output.SetValue(1, output.size(), Value(type.ToString())); + // "null", TypeId::VARCHAR + output.SetValue(2, output.size(), Value("YES")); + // "pk", TypeId::BOOL + output.SetValue(3, output.size(), Value()); + // "dflt_value", TypeId::VARCHAR + output.SetValue(4, output.size(), Value()); + // "extra", TypeId::VARCHAR + output.SetValue(5, output.size(), Value()); + } output.SetCardinality(output.size() + 1); if (output.size() == STANDARD_VECTOR_SIZE) { diff --git a/src/duckdb/src/planner/binding_alias.cpp b/src/duckdb/src/planner/binding_alias.cpp new file mode 100644 index 000000000..62f60dfa1 --- /dev/null +++ b/src/duckdb/src/planner/binding_alias.cpp @@ -0,0 +1,69 @@ +#include "duckdb/planner/binding_alias.hpp" +#include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" +#include "duckdb/catalog/catalog.hpp" + +namespace duckdb { + +BindingAlias::BindingAlias() { +} + +BindingAlias::BindingAlias(string alias_p) : alias(std::move(alias_p)) { +} + +BindingAlias::BindingAlias(string schema_p, string alias_p) : schema(std::move(schema_p)), alias(std::move(alias_p)) { +} + +BindingAlias::BindingAlias(const StandardEntry &entry) + : catalog(entry.ParentCatalog().GetName()), schema(entry.schema.name), alias(entry.name) { +} + +BindingAlias::BindingAlias(string catalog_p, string schema_p, string alias_p) + : catalog(std::move(catalog_p)), schema(std::move(schema_p)), alias(std::move(alias_p)) { +} + +bool BindingAlias::IsSet() const { + return !alias.empty(); +} + +const string &BindingAlias::GetAlias() const { + if (!IsSet()) { + throw InternalException("Calling BindingAlias::GetAlias on a non-set alias"); + } + return alias; +} + +string BindingAlias::ToString() const { + string result; + if (!catalog.empty()) { + result += KeywordHelper::WriteOptionallyQuoted(catalog) + "."; + } + if (!schema.empty()) { + result += KeywordHelper::WriteOptionallyQuoted(schema) + "."; + } + result += KeywordHelper::WriteOptionallyQuoted(alias); + return result; +} + +bool BindingAlias::Matches(const BindingAlias &other) const { + // we match based on the specificity of the other entry + // i.e. "tbl" matches "catalog.schema.tbl" + // but "schema2.tbl" does not match "schema.tbl" + if (!other.catalog.empty()) { + if (!StringUtil::CIEquals(catalog, other.catalog)) { + return false; + } + } + if (!other.schema.empty()) { + if (!StringUtil::CIEquals(schema, other.schema)) { + return false; + } + } + return StringUtil::CIEquals(alias, other.alias); +} + +bool BindingAlias::operator==(const BindingAlias &other) const { + return StringUtil::CIEquals(catalog, other.catalog) && StringUtil::CIEquals(schema, other.schema) && + StringUtil::CIEquals(alias, other.alias); +} + +} // namespace duckdb diff --git a/src/duckdb/src/planner/expression.cpp b/src/duckdb/src/planner/expression.cpp index 9fa426b8a..3e9539b0c 100644 --- a/src/duckdb/src/planner/expression.cpp +++ b/src/duckdb/src/planner/expression.cpp @@ -58,6 +58,12 @@ bool Expression::IsConsistent() const { return is_consistent; } +bool Expression::CanThrow() const { + bool can_throw = false; + ExpressionIterator::EnumerateChildren(*this, [&](const Expression &child) { can_throw |= child.CanThrow(); }); + return can_throw; +} + bool Expression::PropagatesNullValues() const { if (type == ExpressionType::OPERATOR_IS_NULL || type == ExpressionType::OPERATOR_IS_NOT_NULL || type == ExpressionType::COMPARE_NOT_DISTINCT_FROM || type == ExpressionType::COMPARE_DISTINCT_FROM || diff --git a/src/duckdb/src/planner/expression/bound_cast_expression.cpp b/src/duckdb/src/planner/expression/bound_cast_expression.cpp index 1c8dc9518..2cd3869d5 100644 --- a/src/duckdb/src/planner/expression/bound_cast_expression.cpp +++ b/src/duckdb/src/planner/expression/bound_cast_expression.cpp @@ -2,6 +2,7 @@ #include "duckdb/planner/expression/bound_default_expression.hpp" #include "duckdb/planner/expression/bound_parameter_expression.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" +#include "duckdb/planner/expression_iterator.hpp" #include "duckdb/function/cast_rules.hpp" #include "duckdb/function/cast/cast_function_set.hpp" #include "duckdb/main/config.hpp" @@ -217,4 +218,15 @@ unique_ptr BoundCastExpression::Copy() const { return std::move(copy); } +bool BoundCastExpression::CanThrow() const { + const auto child_type = child->return_type; + if (return_type.id() != child_type.id() && + LogicalType::ForceMaxLogicalType(return_type, child_type) == child_type.id()) { + return true; + } + bool changes_type = false; + ExpressionIterator::EnumerateChildren(*this, [&](const Expression &child) { changes_type |= child.CanThrow(); }); + return changes_type; +} + } // namespace duckdb diff --git a/src/duckdb/src/planner/expression/bound_function_expression.cpp b/src/duckdb/src/planner/expression/bound_function_expression.cpp index f31df2719..aa00288ae 100644 --- a/src/duckdb/src/planner/expression/bound_function_expression.cpp +++ b/src/duckdb/src/planner/expression/bound_function_expression.cpp @@ -5,7 +5,7 @@ #include "duckdb/function/function_serialization.hpp" #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/common/serializer/deserializer.hpp" -#include "duckdb/core_functions/lambda_functions.hpp" +#include "duckdb/function/lambda_functions.hpp" namespace duckdb { diff --git a/src/duckdb/src/planner/expression_binder/having_binder.cpp b/src/duckdb/src/planner/expression_binder/having_binder.cpp index 27b0124bc..6f0c96a06 100644 --- a/src/duckdb/src/planner/expression_binder/having_binder.cpp +++ b/src/duckdb/src/planner/expression_binder/having_binder.cpp @@ -22,6 +22,22 @@ BindResult HavingBinder::BindLambdaReference(LambdaRefExpression &expr, idx_t de return (*lambda_bindings)[expr.lambda_idx].Bind(lambda_ref, depth); } +unique_ptr HavingBinder::QualifyColumnName(ColumnRefExpression &colref, ErrorData &error) { + auto qualified_colref = ExpressionBinder::QualifyColumnName(colref, error); + if (!qualified_colref) { + return nullptr; + } + + auto group_index = TryBindGroup(*qualified_colref); + if (group_index != DConstants::INVALID_INDEX) { + return qualified_colref; + } + if (column_alias_binder.QualifyColumnAlias(colref)) { + return nullptr; + } + return qualified_colref; +} + BindResult HavingBinder::BindColumnRef(unique_ptr &expr_ptr, idx_t depth, bool root_expression) { // Keep the original column name to return a meaningful error message. diff --git a/src/duckdb/src/planner/expression_binder/index_binder.cpp b/src/duckdb/src/planner/expression_binder/index_binder.cpp index e0138ecb3..69b27cb66 100644 --- a/src/duckdb/src/planner/expression_binder/index_binder.cpp +++ b/src/duckdb/src/planner/expression_binder/index_binder.cpp @@ -8,6 +8,9 @@ #include "duckdb/execution/index/unbound_index.hpp" #include "duckdb/main/config.hpp" #include "duckdb/main/database.hpp" +#include "duckdb/planner/operator/logical_get.hpp" +#include "duckdb/function/table/table_scan.hpp" +#include "duckdb/planner/operator/logical_create_index.hpp" namespace duckdb { @@ -45,6 +48,51 @@ unique_ptr IndexBinder::BindIndex(const UnboundIndex &unbound_index) return index_type->create_instance(input); } +unique_ptr IndexBinder::BindCreateIndex(ClientContext &context, + unique_ptr create_index_info, + TableCatalogEntry &table_entry, + unique_ptr plan, + unique_ptr alter_table_info) { + // Add the dependencies. + auto &dependencies = create_index_info->dependencies; + auto &catalog = Catalog::GetCatalog(context, create_index_info->catalog); + SetCatalogLookupCallback([&dependencies, &catalog](CatalogEntry &entry) { + if (&catalog != &entry.ParentCatalog()) { + return; + } + dependencies.AddDependency(entry); + }); + + // Bind the index expressions. + vector> expressions; + for (auto &expr : create_index_info->expressions) { + expressions.push_back(Bind(expr)); + } + + auto &get = plan->Cast(); + auto &column_ids = get.GetColumnIds(); + for (auto &column_id : column_ids) { + if (column_id == COLUMN_IDENTIFIER_ROW_ID) { + throw BinderException("cannot create an index on the rowid"); + } + create_index_info->scan_types.push_back(get.returned_types[column_id]); + } + + create_index_info->scan_types.emplace_back(LogicalType::ROW_TYPE); + create_index_info->names = get.names; + create_index_info->column_ids = column_ids; + create_index_info->schema = table_entry.schema.name; + + auto &bind_data = get.bind_data->Cast(); + bind_data.is_create_index = true; + get.AddColumnId(COLUMN_IDENTIFIER_ROW_ID); + + auto result = make_uniq(std::move(create_index_info), std::move(expressions), table_entry, + std::move(alter_table_info)); + result->children.push_back(std::move(plan)); + return std::move(result); +} + BindResult IndexBinder::BindExpression(unique_ptr &expr_ptr, idx_t depth, bool root_expression) { auto &expr = *expr_ptr; switch (expr.expression_class) { diff --git a/src/duckdb/src/planner/filter/null_filter.cpp b/src/duckdb/src/planner/filter/null_filter.cpp index a451c8a74..422b789d9 100644 --- a/src/duckdb/src/planner/filter/null_filter.cpp +++ b/src/duckdb/src/planner/filter/null_filter.cpp @@ -1,5 +1,4 @@ #include "duckdb/planner/filter/null_filter.hpp" - #include "duckdb/planner/expression/bound_operator_expression.hpp" #include "duckdb/storage/statistics/base_statistics.hpp" diff --git a/src/duckdb/src/planner/filter/optional_filter.cpp b/src/duckdb/src/planner/filter/optional_filter.cpp new file mode 100644 index 000000000..75bd9445d --- /dev/null +++ b/src/duckdb/src/planner/filter/optional_filter.cpp @@ -0,0 +1,28 @@ +#include "duckdb/planner/table_filter.hpp" +#include "duckdb/planner/filter/optional_filter.hpp" +#include "duckdb/planner/expression.hpp" + +namespace duckdb { + +OptionalFilter::OptionalFilter() : TableFilter(TableFilterType::OPTIONAL_FILTER) { +} + +FilterPropagateResult OptionalFilter::CheckStatistics(BaseStatistics &stats) { + return child_filter->CheckStatistics(stats); +} + +string OptionalFilter::ToString(const string &column_name) { + return string("optional: ") + child_filter->ToString(column_name); +} + +unique_ptr OptionalFilter::ToExpression(const Expression &column) const { + return child_filter->ToExpression(column); +} + +unique_ptr OptionalFilter::Copy() const { + auto copy = make_uniq(); + copy->child_filter = child_filter->Copy(); + return duckdb::unique_ptr_cast(std::move(copy)); +} + +} // namespace duckdb diff --git a/src/duckdb/src/planner/filter/struct_filter.cpp b/src/duckdb/src/planner/filter/struct_filter.cpp index 2c9c3541f..15c09803e 100644 --- a/src/duckdb/src/planner/filter/struct_filter.cpp +++ b/src/duckdb/src/planner/filter/struct_filter.cpp @@ -42,8 +42,8 @@ unique_ptr StructFilter::ToExpression(const Expression &column) cons vector> arguments; arguments.push_back(column.Copy()); arguments.push_back(make_uniq(Value::BIGINT(NumericCast(child_idx)))); - auto child = make_uniq(child_type, StructExtractFun::IndexExtractFunction(), - std::move(arguments), StructExtractFun::GetBindData(child_idx)); + auto child = make_uniq(child_type, GetIndexExtractFunction(), std::move(arguments), + GetBindData(child_idx)); return child_filter->ToExpression(*child); } } // namespace duckdb diff --git a/src/duckdb/src/planner/logical_operator.cpp b/src/duckdb/src/planner/logical_operator.cpp index 17cd2d982..c8e73a1fe 100644 --- a/src/duckdb/src/planner/logical_operator.cpp +++ b/src/duckdb/src/planner/logical_operator.cpp @@ -1,5 +1,6 @@ #include "duckdb/planner/logical_operator.hpp" +#include "duckdb/common/enum_util.hpp" #include "duckdb/common/printer.hpp" #include "duckdb/common/serializer/binary_deserializer.hpp" #include "duckdb/common/serializer/binary_serializer.hpp" @@ -8,6 +9,9 @@ #include "duckdb/common/tree_renderer.hpp" #include "duckdb/parser/parser.hpp" #include "duckdb/planner/operator/list.hpp" +#include "duckdb/planner/operator/logical_filter.hpp" +#include "duckdb/planner/operator/logical_join.hpp" +#include "duckdb/planner/operator/logical_order.hpp" namespace duckdb { @@ -73,7 +77,6 @@ InsertionOrderPreservingMap LogicalOperator::ParamsToString() const { } void LogicalOperator::ResolveOperatorTypes() { - types.clear(); // first resolve child types for (auto &child : children) { diff --git a/src/duckdb/src/planner/logical_operator_visitor.cpp b/src/duckdb/src/planner/logical_operator_visitor.cpp index 367fb5f20..7ebf3151e 100644 --- a/src/duckdb/src/planner/logical_operator_visitor.cpp +++ b/src/duckdb/src/planner/logical_operator_visitor.cpp @@ -12,9 +12,75 @@ void LogicalOperatorVisitor::VisitOperator(LogicalOperator &op) { } void LogicalOperatorVisitor::VisitOperatorChildren(LogicalOperator &op) { - for (auto &child : op.children) { - VisitOperator(*child); + if (op.HasProjectionMap()) { + VisitOperatorWithProjectionMapChildren(op); + } else { + for (auto &child : op.children) { + VisitOperator(*child); + } + } +} + +void LogicalOperatorVisitor::VisitOperatorWithProjectionMapChildren(LogicalOperator &op) { + D_ASSERT(op.HasProjectionMap()); + switch (op.type) { + case LogicalOperatorType::LOGICAL_ANY_JOIN: + case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: + case LogicalOperatorType::LOGICAL_DELIM_JOIN: + case LogicalOperatorType::LOGICAL_ASOF_JOIN: { + auto &join = op.Cast(); + VisitChildOfOperatorWithProjectionMap(*op.children[0], join.left_projection_map); + VisitChildOfOperatorWithProjectionMap(*op.children[1], join.right_projection_map); + break; + } + case LogicalOperatorType::LOGICAL_ORDER_BY: { + auto &order = op.Cast(); + VisitChildOfOperatorWithProjectionMap(*op.children[0], order.projection_map); + break; + } + case LogicalOperatorType::LOGICAL_FILTER: { + auto &filter = op.Cast(); + VisitChildOfOperatorWithProjectionMap(*op.children[0], filter.projection_map); + break; + } + default: + throw NotImplementedException("VisitOperatorWithProjectionMapChildren for %s", EnumUtil::ToString(op.type)); + } +} + +void LogicalOperatorVisitor::VisitChildOfOperatorWithProjectionMap(LogicalOperator &child, + vector &projection_map) { + const auto child_bindings_before = child.GetColumnBindings(); + VisitOperator(child); + if (projection_map.empty()) { + return; // Nothing to fix here + } + // Child binding order may have changed due to 'fun'. + const auto child_bindings_after = child.GetColumnBindings(); + if (child_bindings_before == child_bindings_after) { + return; // Nothing changed + } + // The desired order is 'projection_map' applied to 'child_bindings_before' + // We create 'new_projection_map', which ensures this order even if 'child_bindings_after' is different + vector new_projection_map; + new_projection_map.reserve(projection_map.size()); + for (const auto proj_idx_before : projection_map) { + auto &desired_binding = child_bindings_before[proj_idx_before]; + idx_t proj_idx_after; + for (proj_idx_after = 0; proj_idx_after < child_bindings_after.size(); proj_idx_after++) { + if (child_bindings_after[proj_idx_after] == desired_binding) { + break; + } + } + if (proj_idx_after == child_bindings_after.size()) { + // VisitOperator has removed this binding, e.g., by replacing one binding with another + // Inside here we don't know how it has been replaced, and projection maps are positional: bail + new_projection_map.clear(); + break; + } + new_projection_map.push_back(proj_idx_after); } + projection_map = std::move(new_projection_map); } void LogicalOperatorVisitor::EnumerateExpressions(LogicalOperator &op, diff --git a/src/duckdb/src/planner/operator/logical_comparison_join.cpp b/src/duckdb/src/planner/operator/logical_comparison_join.cpp index f844b1824..48efe6259 100644 --- a/src/duckdb/src/planner/operator/logical_comparison_join.cpp +++ b/src/duckdb/src/planner/operator/logical_comparison_join.cpp @@ -28,4 +28,27 @@ InsertionOrderPreservingMap LogicalComparisonJoin::ParamsToString() cons return result; } +bool LogicalComparisonJoin::HasEquality(idx_t &range_count) const { + for (size_t c = 0; c < conditions.size(); ++c) { + auto &cond = conditions[c]; + switch (cond.comparison) { + case ExpressionType::COMPARE_EQUAL: + case ExpressionType::COMPARE_NOT_DISTINCT_FROM: + return true; + case ExpressionType::COMPARE_LESSTHAN: + case ExpressionType::COMPARE_GREATERTHAN: + case ExpressionType::COMPARE_LESSTHANOREQUALTO: + case ExpressionType::COMPARE_GREATERTHANOREQUALTO: + ++range_count; + break; + case ExpressionType::COMPARE_NOTEQUAL: + case ExpressionType::COMPARE_DISTINCT_FROM: + break; + default: + throw NotImplementedException("Unimplemented comparison join"); + } + } + return false; +} + } // namespace duckdb diff --git a/src/duckdb/src/planner/operator/logical_create_index.cpp b/src/duckdb/src/planner/operator/logical_create_index.cpp index 65e36069a..e1bc0f0ee 100644 --- a/src/duckdb/src/planner/operator/logical_create_index.cpp +++ b/src/duckdb/src/planner/operator/logical_create_index.cpp @@ -7,13 +7,14 @@ namespace duckdb { LogicalCreateIndex::LogicalCreateIndex(unique_ptr info_p, vector> expressions_p, - TableCatalogEntry &table_p) - : LogicalOperator(LogicalOperatorType::LOGICAL_CREATE_INDEX), info(std::move(info_p)), table(table_p) { + TableCatalogEntry &table_p, unique_ptr alter_table_info) + : LogicalOperator(LogicalOperatorType::LOGICAL_CREATE_INDEX), info(std::move(info_p)), table(table_p), + alter_table_info(std::move(alter_table_info)) { for (auto &expr : expressions_p) { - this->unbound_expressions.push_back(expr->Copy()); + unbound_expressions.push_back(expr->Copy()); } - this->expressions = std::move(expressions_p); + expressions = std::move(expressions_p); if (info->column_ids.empty()) { throw BinderException("CREATE INDEX does not refer to any columns in the base table!"); @@ -21,23 +22,26 @@ LogicalCreateIndex::LogicalCreateIndex(unique_ptr info_p, vecto } LogicalCreateIndex::LogicalCreateIndex(ClientContext &context, unique_ptr info_p, - vector> expressions_p) + vector> expressions_p, + unique_ptr alter_table_info) : LogicalOperator(LogicalOperatorType::LOGICAL_CREATE_INDEX), - info(unique_ptr_cast(std::move(info_p))), table(BindTable(context, *info)) { + info(unique_ptr_cast(std::move(info_p))), table(BindTable(context, *info)), + alter_table_info(unique_ptr_cast(std::move(alter_table_info))) { + for (auto &expr : expressions_p) { - this->unbound_expressions.push_back(expr->Copy()); + unbound_expressions.push_back(expr->Copy()); } - this->expressions = std::move(expressions_p); + expressions = std::move(expressions_p); } void LogicalCreateIndex::ResolveTypes() { types.emplace_back(LogicalType::BIGINT); } -TableCatalogEntry &LogicalCreateIndex::BindTable(ClientContext &context, CreateIndexInfo &info) { - auto &catalog = info.catalog; - auto &schema = info.schema; - auto &table_name = info.table; +TableCatalogEntry &LogicalCreateIndex::BindTable(ClientContext &context, CreateIndexInfo &info_p) { + auto &catalog = info_p.catalog; + auto &schema = info_p.schema; + auto &table_name = info_p.table; return Catalog::GetEntry(context, catalog, schema, table_name); } diff --git a/src/duckdb/src/planner/operator/logical_get.cpp b/src/duckdb/src/planner/operator/logical_get.cpp index d6e9fda93..9883b685e 100644 --- a/src/duckdb/src/planner/operator/logical_get.cpp +++ b/src/duckdb/src/planner/operator/logical_get.cpp @@ -48,6 +48,10 @@ InsertionOrderPreservingMap LogicalGet::ParamsToString() const { } result["Filters"] = filters_info; + if (extra_info.sample_options) { + result["Sample Method"] = "System: " + extra_info.sample_options->sample_size.ToString() + "%"; + } + if (!extra_info.file_filters.empty()) { result["File Filters"] = extra_info.file_filters; if (extra_info.filtered_files.IsValid() && extra_info.total_files.IsValid()) { diff --git a/src/duckdb/src/planner/operator/logical_order.cpp b/src/duckdb/src/planner/operator/logical_order.cpp index 78a0c357b..bf904c3f3 100644 --- a/src/duckdb/src/planner/operator/logical_order.cpp +++ b/src/duckdb/src/planner/operator/logical_order.cpp @@ -8,15 +8,10 @@ LogicalOrder::LogicalOrder(vector orders) vector LogicalOrder::GetColumnBindings() { auto child_bindings = children[0]->GetColumnBindings(); - if (projections.empty()) { + if (!HasProjectionMap()) { return child_bindings; } - - vector result; - for (auto &col_idx : projections) { - result.push_back(child_bindings[col_idx]); - } - return result; + return MapBindings(child_bindings, projection_map); } InsertionOrderPreservingMap LogicalOrder::ParamsToString() const { @@ -35,12 +30,10 @@ InsertionOrderPreservingMap LogicalOrder::ParamsToString() const { void LogicalOrder::ResolveTypes() { const auto child_types = children[0]->types; - if (projections.empty()) { + if (!HasProjectionMap()) { types = child_types; } else { - for (auto &col_idx : projections) { - types.push_back(child_types[col_idx]); - } + types = MapTypes(child_types, projection_map); } } diff --git a/src/duckdb/src/planner/planner.cpp b/src/duckdb/src/planner/planner.cpp index 99a5934ae..909228ced 100644 --- a/src/duckdb/src/planner/planner.cpp +++ b/src/duckdb/src/planner/planner.cpp @@ -160,7 +160,7 @@ void Planner::VerifyPlan(ClientContext &context, unique_ptr &op auto &config = DBConfig::GetConfig(context); #ifdef DUCKDB_ALTERNATIVE_VERIFY { - auto &serialize_comp = config.options.serialization_compatibility; + auto &serialize_comp = config.GetSetting(context); auto latest_version = SerializationCompatibility::Latest(); if (serialize_comp.manually_set && serialize_comp.serialization_version != latest_version.serialization_version) { diff --git a/src/duckdb/src/planner/subquery/flatten_dependent_join.cpp b/src/duckdb/src/planner/subquery/flatten_dependent_join.cpp index ac36e9eae..bbd98b2cf 100644 --- a/src/duckdb/src/planner/subquery/flatten_dependent_join.cpp +++ b/src/duckdb/src/planner/subquery/flatten_dependent_join.cpp @@ -3,6 +3,7 @@ #include "duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp" #include "duckdb/common/operator/add.hpp" #include "duckdb/function/aggregate/distributive_functions.hpp" +#include "duckdb/function/aggregate/distributive_function_utils.hpp" #include "duckdb/planner/binder.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" #include "duckdb/planner/expression/list.hpp" @@ -240,7 +241,7 @@ unique_ptr FlattenDependentJoins::PushDownDependentJoinInternal delim_data_offset = aggr.groups.size(); for (idx_t i = 0; i < correlated_columns.size(); i++) { auto &col = correlated_columns[i]; - auto first_aggregate = FirstFun::GetFunction(col.type); + auto first_aggregate = FirstFunctionGetter::GetFunction(col.type); auto colref = make_uniq( col.name, col.type, ColumnBinding(base_binding.table_index, base_binding.column_index + i)); vector> aggr_children; @@ -300,7 +301,8 @@ unique_ptr FlattenDependentJoins::PushDownDependentJoinInternal D_ASSERT(aggr.expressions[i]->GetExpressionClass() == ExpressionClass::BOUND_AGGREGATE); auto &bound = aggr.expressions[i]->Cast(); vector arguments; - if (bound.function == CountFun::GetFunction() || bound.function == CountStarFun::GetFunction()) { + if (bound.function == CountFunctionBase::GetFunction() || + bound.function == CountStarFun::GetFunction()) { // have to replace this ColumnBinding with the CASE expression replacement_map[ColumnBinding(aggr.aggregate_index, i)] = i; } diff --git a/src/duckdb/src/planner/table_binding.cpp b/src/duckdb/src/planner/table_binding.cpp index 7b9e65bc6..ab8c88bbd 100644 --- a/src/duckdb/src/planner/table_binding.cpp +++ b/src/duckdb/src/planner/table_binding.cpp @@ -15,20 +15,25 @@ namespace duckdb { -Binding::Binding(BindingType binding_type, const string &alias, vector coltypes, vector colnames, +Binding::Binding(BindingType binding_type, BindingAlias alias_p, vector coltypes, vector colnames, idx_t index) - : binding_type(binding_type), alias(alias), index(index), types(std::move(coltypes)), names(std::move(colnames)) { + : binding_type(binding_type), alias(std::move(alias_p)), index(index), types(std::move(coltypes)), + names(std::move(colnames)) { D_ASSERT(types.size() == names.size()); for (idx_t i = 0; i < names.size(); i++) { auto &name = names[i]; D_ASSERT(!name.empty()); if (name_map.find(name) != name_map.end()) { - throw BinderException("table \"%s\" has duplicate column name \"%s\"", alias, name); + throw BinderException("table \"%s\" has duplicate column name \"%s\"", alias.GetAlias(), name); } name_map[name] = i; } } +string Binding::GetAlias() const { + return alias.GetAlias(); +} + bool Binding::TryGetBindingIndex(const string &column_name, column_t &result) { auto entry = name_map.find(column_name); if (entry == name_map.end()) { @@ -53,8 +58,8 @@ bool Binding::HasMatchingBinding(const string &column_name) { } ErrorData Binding::ColumnNotFoundError(const string &column_name) const { - return ErrorData(ExceptionType::BINDER, - StringUtil::Format("Values list \"%s\" does not have a column named \"%s\"", alias, column_name)); + return ErrorData(ExceptionType::BINDER, StringUtil::Format("Values list \"%s\" does not have a column named \"%s\"", + GetAlias(), column_name)); } BindResult Binding::Bind(ColumnRefExpression &colref, idx_t depth) { @@ -78,9 +83,29 @@ optional_ptr Binding::GetStandardEntry() { return nullptr; } +BindingAlias Binding::GetAlias(const string &explicit_alias, const StandardEntry &entry) { + if (!explicit_alias.empty()) { + return BindingAlias(explicit_alias); + } + // no explicit alias provided - generate from entry + return BindingAlias(entry); +} + +BindingAlias Binding::GetAlias(const string &explicit_alias, optional_ptr entry) { + if (!explicit_alias.empty()) { + return BindingAlias(explicit_alias); + } + if (!entry) { + throw InternalException("Binding::GetAlias called - but neither an alias nor an entry was provided"); + } + // no explicit alias provided - generate from entry + return BindingAlias(*entry); +} + EntryBinding::EntryBinding(const string &alias, vector types_p, vector names_p, idx_t index, StandardEntry &entry) - : Binding(BindingType::CATALOG_ENTRY, alias, std::move(types_p), std::move(names_p), index), entry(entry) { + : Binding(BindingType::CATALOG_ENTRY, GetAlias(alias, entry), std::move(types_p), std::move(names_p), index), + entry(entry) { } optional_ptr EntryBinding::GetStandardEntry() { @@ -90,7 +115,7 @@ optional_ptr EntryBinding::GetStandardEntry() { TableBinding::TableBinding(const string &alias, vector types_p, vector names_p, vector &bound_column_ids, optional_ptr entry, idx_t index, bool add_row_id) - : Binding(BindingType::TABLE, alias, std::move(types_p), std::move(names_p), index), + : Binding(BindingType::TABLE, GetAlias(alias, entry), std::move(types_p), std::move(names_p), index), bound_column_ids(bound_column_ids), entry(entry) { if (add_row_id) { if (name_map.find("rowid") == name_map.end()) { @@ -111,18 +136,24 @@ static void ReplaceAliases(ParsedExpression &expr, const ColumnList &list, col_names = {alias}; } ParsedExpressionIterator::EnumerateChildren( - expr, [&](const ParsedExpression &child) { ReplaceAliases((ParsedExpression &)child, list, alias_map); }); + expr, [&](ParsedExpression &child) { ReplaceAliases(child, list, alias_map); }); } -static void BakeTableName(ParsedExpression &expr, const string &table_name) { +static void BakeTableName(ParsedExpression &expr, const BindingAlias &binding_alias) { if (expr.type == ExpressionType::COLUMN_REF) { auto &colref = expr.Cast(); D_ASSERT(!colref.IsQualified()); auto &col_names = colref.column_names; - col_names.insert(col_names.begin(), table_name); + col_names.insert(col_names.begin(), binding_alias.GetAlias()); + if (!binding_alias.GetSchema().empty()) { + col_names.insert(col_names.begin(), binding_alias.GetSchema()); + } + if (!binding_alias.GetCatalog().empty()) { + col_names.insert(col_names.begin(), binding_alias.GetCatalog()); + } } - ParsedExpressionIterator::EnumerateChildren( - expr, [&](const ParsedExpression &child) { BakeTableName((ParsedExpression &)child, table_name); }); + ParsedExpressionIterator::EnumerateChildren(expr, + [&](ParsedExpression &child) { BakeTableName(child, binding_alias); }); } unique_ptr TableBinding::ExpandGeneratedColumn(const string &column_name) { @@ -219,13 +250,13 @@ optional_ptr TableBinding::GetStandardEntry() { } ErrorData TableBinding::ColumnNotFoundError(const string &column_name) const { - return ErrorData(ExceptionType::BINDER, - StringUtil::Format("Table \"%s\" does not have a column named \"%s\"", alias, column_name)); + return ErrorData(ExceptionType::BINDER, StringUtil::Format("Table \"%s\" does not have a column named \"%s\"", + alias.GetAlias(), column_name)); } DummyBinding::DummyBinding(vector types, vector names, string dummy_name) - : Binding(BindingType::DUMMY, DummyBinding::DUMMY_NAME + dummy_name, std::move(types), std::move(names), - DConstants::INVALID_INDEX), + : Binding(BindingType::DUMMY, BindingAlias(DummyBinding::DUMMY_NAME + dummy_name), std::move(types), + std::move(names), DConstants::INVALID_INDEX), dummy_name(std::move(dummy_name)) { } diff --git a/src/duckdb/src/storage/buffer/block_handle.cpp b/src/duckdb/src/storage/buffer/block_handle.cpp index 9523b2962..8a24834a8 100644 --- a/src/duckdb/src/storage/buffer/block_handle.cpp +++ b/src/duckdb/src/storage/buffer/block_handle.cpp @@ -36,7 +36,7 @@ BlockHandle::~BlockHandle() { // NOLINT: allow internal exceptions 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(buffer->type); + buffer_manager.GetBufferPool().IncrementDeadNodes(*this); } // no references remain to this block: erase diff --git a/src/duckdb/src/storage/buffer/block_manager.cpp b/src/duckdb/src/storage/buffer/block_manager.cpp index 22cb54d13..2f7839179 100644 --- a/src/duckdb/src/storage/buffer/block_manager.cpp +++ b/src/duckdb/src/storage/buffer/block_manager.cpp @@ -64,7 +64,7 @@ shared_ptr BlockManager::ConvertToPersistent(block_id_t block_id, s // potentially purge the queue auto purge_queue = buffer_manager.GetBufferPool().AddToEvictionQueue(new_block); if (purge_queue) { - buffer_manager.GetBufferPool().PurgeQueue(new_block->buffer->type); + buffer_manager.GetBufferPool().PurgeQueue(*new_block); } return new_block; diff --git a/src/duckdb/src/storage/buffer/buffer_pool.cpp b/src/duckdb/src/storage/buffer/buffer_pool.cpp index 30d6b648b..4acfc3cd9 100644 --- a/src/duckdb/src/storage/buffer/buffer_pool.cpp +++ b/src/duckdb/src/storage/buffer/buffer_pool.cpp @@ -41,7 +41,8 @@ typedef duckdb_moodycamel::ConcurrentQueue eviction_queue_t; struct EvictionQueue { public: - EvictionQueue() : evict_queue_insertions(0), total_dead_nodes(0) { + explicit EvictionQueue(const FileBufferType file_buffer_type_p) + : file_buffer_type(file_buffer_type_p), evict_queue_insertions(0), total_dead_nodes(0) { } public: @@ -69,6 +70,8 @@ struct EvictionQueue { void PurgeIteration(const idx_t purge_size); public: + //! The type of the buffers in this queue + const FileBufferType file_buffer_type; //! The concurrent queue eviction_queue_t q; @@ -196,20 +199,24 @@ void EvictionQueue::PurgeIteration(const idx_t purge_size) { BufferPool::BufferPool(idx_t maximum_memory, bool track_eviction_timestamps, idx_t allocator_bulk_deallocation_flush_threshold) - : maximum_memory(maximum_memory), + : eviction_queue_sizes({BLOCK_QUEUE_SIZE, MANAGED_BUFFER_QUEUE_SIZE, TINY_BUFFER_QUEUE_SIZE}), + maximum_memory(maximum_memory), allocator_bulk_deallocation_flush_threshold(allocator_bulk_deallocation_flush_threshold), track_eviction_timestamps(track_eviction_timestamps), temporary_memory_manager(make_uniq()) { - queues.reserve(FILE_BUFFER_TYPE_COUNT); - for (idx_t i = 0; i < FILE_BUFFER_TYPE_COUNT; i++) { - queues.push_back(make_uniq()); + for (uint8_t type_idx = 0; type_idx < FILE_BUFFER_TYPE_COUNT; type_idx++) { + const auto type = static_cast(type_idx + 1); + const auto &type_queue_size = eviction_queue_sizes[type_idx]; + for (idx_t queue_idx = 0; queue_idx < type_queue_size; queue_idx++) { + queues.push_back(make_uniq(type)); + } } } BufferPool::~BufferPool() { } bool BufferPool::AddToEvictionQueue(shared_ptr &handle) { - auto &queue = GetEvictionQueueForType(handle->buffer->type); + auto &queue = GetEvictionQueueForBlockHandle(*handle); // The block handle is locked during this operation (Unpin), // or the block handle is still a local variable (ConvertToPersistent) @@ -227,16 +234,36 @@ bool BufferPool::AddToEvictionQueue(shared_ptr &handle) { queue.IncrementDeadNodes(); } - // Get the eviction queue for the buffer type and add it + // Get the eviction queue for the block and add it return queue.AddToEvictionQueue(BufferEvictionNode(weak_ptr(handle), ts)); } -EvictionQueue &BufferPool::GetEvictionQueueForType(FileBufferType type) { - return *queues[uint8_t(type) - 1]; +EvictionQueue &BufferPool::GetEvictionQueueForBlockHandle(const BlockHandle &handle) { + const auto &handle_buffer_type = handle.buffer->type; + + // Get offset into eviction queues for this FileBufferType + idx_t queue_index = 0; + for (uint8_t type_idx = 0; type_idx < FILE_BUFFER_TYPE_COUNT; type_idx++) { + const auto queue_buffer_type = static_cast(type_idx + 1); + if (handle_buffer_type == queue_buffer_type) { + break; + } + const auto &type_queue_size = eviction_queue_sizes[type_idx]; + queue_index += type_queue_size; + } + + const auto &queue_size = eviction_queue_sizes[static_cast(handle_buffer_type) - 1]; + // Adjust if eviction_queue_idx is set (idx == 0 -> add at back, idx >= queue_size -> add at front) + if (handle.eviction_queue_idx.IsValid() && handle.eviction_queue_idx.GetIndex() < queue_size) { + queue_index += queue_size - handle.eviction_queue_idx.GetIndex() - 1; + } + + D_ASSERT(queues[queue_index]->file_buffer_type == handle_buffer_type); + return *queues[queue_index]; } -void BufferPool::IncrementDeadNodes(FileBufferType type) { - GetEvictionQueueForType(type).IncrementDeadNodes(); +void BufferPool::IncrementDeadNodes(const BlockHandle &handle) { + GetEvictionQueueForBlockHandle(handle).IncrementDeadNodes(); } void BufferPool::UpdateUsedMemory(MemoryTag tag, int64_t size) { @@ -261,23 +288,14 @@ TemporaryMemoryManager &BufferPool::GetTemporaryMemoryManager() { BufferPool::EvictionResult BufferPool::EvictBlocks(MemoryTag tag, idx_t extra_memory, idx_t memory_limit, unique_ptr *buffer) { - // First, we try to evict persistent table data - auto block_result = - EvictBlocksInternal(GetEvictionQueueForType(FileBufferType::BLOCK), tag, extra_memory, memory_limit, buffer); - if (block_result.success) { - return block_result; - } - - // If that does not succeed, we try to evict temporary data - auto managed_buffer_result = EvictBlocksInternal(GetEvictionQueueForType(FileBufferType::MANAGED_BUFFER), tag, - extra_memory, memory_limit, buffer); - if (managed_buffer_result.success) { - return managed_buffer_result; + 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 + } } - - // Finally, we try to evict tiny buffers - return EvictBlocksInternal(GetEvictionQueueForType(FileBufferType::TINY_BUFFER), tag, extra_memory, memory_limit, - buffer); + // 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"); } BufferPool::EvictionResult BufferPool::EvictBlocksInternal(EvictionQueue &queue, MemoryTag tag, idx_t extra_memory, @@ -382,8 +400,8 @@ void EvictionQueue::IterateUnloadableBlocks(FN fn) { } } -void BufferPool::PurgeQueue(FileBufferType type) { - GetEvictionQueueForType(type).Purge(); +void BufferPool::PurgeQueue(const BlockHandle &block) { + GetEvictionQueueForBlockHandle(block).Purge(); } void BufferPool::SetLimit(idx_t limit, const char *exception_postscript) { diff --git a/src/duckdb/src/storage/buffer_manager.cpp b/src/duckdb/src/storage/buffer_manager.cpp index c758fae84..1ff33caa4 100644 --- a/src/duckdb/src/storage/buffer_manager.cpp +++ b/src/duckdb/src/storage/buffer_manager.cpp @@ -13,6 +13,10 @@ shared_ptr BufferManager::RegisterTransientMemory(const idx_t size, } shared_ptr BufferManager::RegisterSmallMemory(const idx_t size) { + return RegisterSmallMemory(MemoryTag::BASE_TABLE, size); +} + +shared_ptr BufferManager::RegisterSmallMemory(MemoryTag tag, const idx_t size) { throw NotImplementedException("This type of BufferManager can not create 'small-memory' blocks"); } diff --git a/src/duckdb/src/storage/checkpoint_manager.cpp b/src/duckdb/src/storage/checkpoint_manager.cpp index cd46862ee..43dfd3cb4 100644 --- a/src/duckdb/src/storage/checkpoint_manager.cpp +++ b/src/duckdb/src/storage/checkpoint_manager.cpp @@ -30,6 +30,7 @@ #include "duckdb/storage/table/column_checkpoint_state.hpp" #include "duckdb/transaction/meta_transaction.hpp" #include "duckdb/transaction/transaction_manager.hpp" +#include "duckdb/catalog/dependency_manager.hpp" namespace duckdb { @@ -149,6 +150,15 @@ void SingleFileCheckpointWriter::CreateCheckpoint() { // 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 &duck_catalog = catalog.Cast(); + auto &dependency_manager = duck_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 @@ -169,7 +179,6 @@ void SingleFileCheckpointWriter::CreateCheckpoint() { ] } */ - auto catalog_entries = GetCatalogEntries(schemas); SerializationOptions serialization_options; serialization_options.serialization_compatibility = config.options.serialization_compatibility; @@ -538,6 +547,10 @@ void CheckpointReader::ReadTable(CatalogTransaction transaction, Deserializer &d auto &schema = catalog.GetSchema(transaction, info->schema); auto bound_info = Binder::BindCreateTableCheckpoint(std::move(info), schema); + for (auto &dep : bound_info->Base().dependencies.Set()) { + bound_info->dependencies.AddDependency(dep); + } + // now read the actual table data and place it into the CreateTableInfo ReadTableData(transaction, deserializer, *bound_info); diff --git a/src/duckdb/src/storage/data_table.cpp b/src/duckdb/src/storage/data_table.cpp index 3e7b63da2..bf1e14246 100644 --- a/src/duckdb/src/storage/data_table.cpp +++ b/src/duckdb/src/storage/data_table.cpp @@ -18,7 +18,6 @@ #include "duckdb/storage/table/row_group.hpp" #include "duckdb/storage/table/standard_column_data.hpp" #include "duckdb/transaction/duck_transaction.hpp" -#include "duckdb/transaction/transaction_manager.hpp" #include "duckdb/main/attached_database.hpp" #include "duckdb/common/types/conflict_manager.hpp" #include "duckdb/common/types/constraint_conflict_info.hpp" @@ -50,8 +49,8 @@ DataTable::DataTable(AttachedDatabase &db, shared_ptr table_io_m column_definitions(std::move(column_definitions_p)), is_root(true) { // initialize the table with the existing data from disk, if any auto types = GetTypes(); - this->row_groups = - make_shared_ptr(info, TableIOManager::Get(*this).GetBlockManagerForRowData(), types, 0); + auto &io_manager = TableIOManager::Get(*this); + this->row_groups = make_shared_ptr(info, io_manager, types, 0); if (data && data->row_group_count > 0) { this->row_groups->Initialize(*data); } else { @@ -134,24 +133,27 @@ DataTable::DataTable(ClientContext &context, DataTable &parent, idx_t removed_co parent.is_root = false; } -// Alter column to add new constraint -DataTable::DataTable(ClientContext &context, DataTable &parent, unique_ptr constraint) +DataTable::DataTable(ClientContext &context, DataTable &parent, BoundConstraint &constraint) : db(parent.db), info(parent.info), row_groups(parent.row_groups), is_root(true) { + // ALTER COLUMN to add a new constraint. + + // Clone the storage info vector or the table. + for (const auto &index_info : parent.info->index_storage_infos) { + info->index_storage_infos.push_back(IndexStorageInfo(index_info.name)); + } + info->InitializeIndexes(context); + auto &local_storage = LocalStorage::Get(context, db); lock_guard parent_lock(parent.append_lock); for (auto &column_def : parent.column_definitions) { column_definitions.emplace_back(column_def.Copy()); } - info->InitializeIndexes(context); - - // Verify the new constraint against current persistent/local data - VerifyNewConstraint(local_storage, parent, *constraint); - - // Get the local data ownership from old dt + if (constraint.type != ConstraintType::UNIQUE) { + VerifyNewConstraint(local_storage, parent, constraint); + } local_storage.MoveStorage(parent, *this); - // this table replaces the previous table, hence the parent is no longer the root DataTable parent.is_root = false; } @@ -223,34 +225,29 @@ TableIOManager &TableIOManager::Get(DataTable &table) { //===--------------------------------------------------------------------===// // Scan //===--------------------------------------------------------------------===// -void DataTable::InitializeScan(TableScanState &state, const vector &column_ids, - TableFilterSet *table_filters) { - if (!state.checkpoint_lock) { - state.checkpoint_lock = make_shared_ptr(info->checkpoint_lock.GetSharedLock()); - } - state.Initialize(column_ids, table_filters); - row_groups->InitializeScan(state.table_state, column_ids, table_filters); -} - void DataTable::InitializeScan(DuckTransaction &transaction, TableScanState &state, const vector &column_ids, TableFilterSet *table_filters) { state.checkpoint_lock = transaction.SharedLockTable(*info); auto &local_storage = LocalStorage::Get(transaction); - InitializeScan(state, column_ids, table_filters); + state.Initialize(column_ids, table_filters); + row_groups->InitializeScan(state.table_state, column_ids, table_filters); local_storage.InitializeScan(*this, state.local_state, table_filters); } -void DataTable::InitializeScanWithOffset(TableScanState &state, const vector &column_ids, idx_t start_row, - idx_t end_row) { - if (!state.checkpoint_lock) { - state.checkpoint_lock = make_shared_ptr(info->checkpoint_lock.GetSharedLock()); - } +void DataTable::InitializeScanWithOffset(DuckTransaction &transaction, TableScanState &state, + const vector &column_ids, idx_t start_row, idx_t end_row) { + state.checkpoint_lock = transaction.SharedLockTable(*info); state.Initialize(column_ids); row_groups->InitializeScanWithOffset(state.table_state, column_ids, start_row, end_row); } -idx_t DataTable::MaxThreads(ClientContext &context) { - idx_t parallel_scan_vector_count = Storage::ROW_GROUP_VECTOR_COUNT; +idx_t DataTable::GetRowGroupSize() const { + return row_groups->GetRowGroupSize(); +} + +idx_t DataTable::MaxThreads(ClientContext &context) const { + idx_t row_group_size = GetRowGroupSize(); + idx_t parallel_scan_vector_count = row_group_size / STANDARD_VECTOR_SIZE; if (ClientConfig::GetConfig(context).verify_parallelism) { parallel_scan_vector_count = 1; } @@ -424,7 +421,8 @@ static void VerifyCheckConstraint(ClientContext &context, TableCatalogEntry &tab } catch (std::exception &ex) { ErrorData error(ex); throw ConstraintException("CHECK constraint failed: %s (Error: %s)", table.name, error.RawMessage()); - } catch (...) { // LCOV_EXCL_START + } catch (...) { + // LCOV_EXCL_START throw ConstraintException("CHECK constraint failed: %s (Unknown Error)", table.name); } // LCOV_EXCL_STOP UnifiedVectorFormat vdata; @@ -759,14 +757,14 @@ void DataTable::VerifyAppendConstraints(ConstraintState &state, ClientContext &c auto &constraint = state.bound_constraints[i]; switch (base_constraint->type) { case ConstraintType::NOT_NULL: { - auto &bound_not_null = *reinterpret_cast(constraint.get()); - auto ¬_null = *reinterpret_cast(base_constraint.get()); + auto &bound_not_null = constraint->Cast(); + auto ¬_null = base_constraint->Cast(); auto &col = table.GetColumns().GetColumn(LogicalIndex(not_null.index)); VerifyNotNullConstraint(table, chunk.data[bound_not_null.index.index], chunk.size(), col.Name()); break; } case ConstraintType::CHECK: { - auto &check = *reinterpret_cast(constraint.get()); + auto &check = constraint->Cast(); VerifyCheckConstraint(context, table, *check.expression, chunk); break; } @@ -775,7 +773,7 @@ void DataTable::VerifyAppendConstraints(ConstraintState &state, ClientContext &c break; } case ConstraintType::FOREIGN_KEY: { - auto &bfk = *reinterpret_cast(constraint.get()); + auto &bfk = constraint->Cast(); if (bfk.info.type == ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE || bfk.info.type == ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE) { VerifyAppendForeignKeyConstraint(bfk, context, chunk); @@ -891,7 +889,8 @@ void DataTable::FinalizeAppend(DuckTransaction &transaction, TableAppendState &s row_groups->FinalizeAppend(transaction, state); } -void DataTable::ScanTableSegment(idx_t row_start, idx_t count, const std::function &function) { +void DataTable::ScanTableSegment(DuckTransaction &transaction, idx_t row_start, idx_t count, + const std::function &function) { if (count == 0) { return; } @@ -909,7 +908,7 @@ void DataTable::ScanTableSegment(idx_t row_start, idx_t count, const std::functi CreateIndexScanState state; - InitializeScanWithOffset(state, column_ids, row_start, row_start + count); + InitializeScanWithOffset(transaction, state, column_ids, row_start, row_start + count); auto row_start_aligned = state.table_state.row_group->start + state.table_state.vector_index * STANDARD_VECTOR_SIZE; idx_t current_row = row_start_aligned; @@ -951,7 +950,7 @@ void DataTable::MergeStorage(RowGroupCollection &data, TableIndexList &, row_groups->Verify(); } -void DataTable::WriteToLog(WriteAheadLog &log, idx_t row_start, idx_t count, +void DataTable::WriteToLog(DuckTransaction &transaction, WriteAheadLog &log, idx_t row_start, idx_t count, optional_ptr commit_state) { log.WriteSetTable(info->schema, info->table); if (commit_state) { @@ -973,7 +972,7 @@ void DataTable::WriteToLog(WriteAheadLog &log, idx_t row_start, idx_t count, } } } - ScanTableSegment(row_start, count, [&](DataChunk &chunk) { log.WriteInsert(chunk); }); + ScanTableSegment(transaction, row_start, count, [&](DataChunk &chunk) { log.WriteInsert(chunk); }); } void DataTable::CommitAppend(transaction_t commit_id, idx_t row_start, idx_t count) { @@ -987,7 +986,7 @@ void DataTable::RevertAppendInternal(idx_t start_row) { row_groups->RevertAppendInternal(start_row); } -void DataTable::RevertAppend(idx_t start_row, idx_t count) { +void DataTable::RevertAppend(DuckTransaction &transaction, idx_t start_row, idx_t count) { lock_guard lock(append_lock); // revert any appends to indexes @@ -996,7 +995,7 @@ void DataTable::RevertAppend(idx_t start_row, idx_t count) { row_t row_data[STANDARD_VECTOR_SIZE]; Vector row_identifiers(LogicalType::ROW_TYPE, data_ptr_cast(row_data)); idx_t scan_count = MinValue(count, row_groups->GetTotalRows() - start_row); - ScanTableSegment(start_row, scan_count, [&](DataChunk &chunk) { + ScanTableSegment(transaction, start_row, scan_count, [&](DataChunk &chunk) { for (idx_t i = 0; i < chunk.size(); i++) { row_data[i] = NumericCast(current_row_base + i); } @@ -1137,7 +1136,7 @@ void DataTable::VerifyDeleteConstraints(TableDeleteState &state, ClientContext & case ConstraintType::UNIQUE: break; case ConstraintType::FOREIGN_KEY: { - auto &bfk = *reinterpret_cast(constraint.get()); + auto &bfk = constraint->Cast(); if (bfk.info.type == ForeignKeyType::FK_TYPE_PRIMARY_KEY_TABLE || bfk.info.type == ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE) { VerifyDeleteForeignKeyConstraint(bfk, context, chunk); @@ -1270,8 +1269,8 @@ void DataTable::VerifyUpdateConstraints(ConstraintState &state, ClientContext &c auto &constraint = bound_constraints[constr_idx]; switch (constraint->type) { case ConstraintType::NOT_NULL: { - auto &bound_not_null = *reinterpret_cast(constraint.get()); - auto ¬_null = *reinterpret_cast(base_constraint.get()); + auto &bound_not_null = constraint->Cast(); + auto ¬_null = base_constraint->Cast(); // check if the constraint is in the list of column_ids for (idx_t col_idx = 0; col_idx < column_ids.size(); col_idx++) { if (column_ids[col_idx] == bound_not_null.index) { @@ -1284,7 +1283,7 @@ void DataTable::VerifyUpdateConstraints(ConstraintState &state, ClientContext &c break; } case ConstraintType::CHECK: { - auto &check = *reinterpret_cast(constraint.get()); + auto &check = constraint->Cast(); DataChunk mock_chunk; if (CreateMockChunk(table, column_ids, check.bound_columns, chunk, mock_chunk)) { @@ -1459,11 +1458,39 @@ void DataTable::CommitDropTable() { } //===--------------------------------------------------------------------===// -// GetColumnSegmentInfo +// Column Segment Info //===--------------------------------------------------------------------===// vector DataTable::GetColumnSegmentInfo() { auto lock = GetSharedCheckpointLock(); return row_groups->GetColumnSegmentInfo(); } +//===--------------------------------------------------------------------===// +// Index Constraint Creation +//===--------------------------------------------------------------------===// +void DataTable::AddIndex(const ColumnList &columns, const vector &column_indexes, + const IndexConstraintType type, const IndexStorageInfo &index_info) { + if (!IsRoot()) { + throw TransactionException("cannot add an index to a table that has been altered!"); + } + + // Fetch the column types and create bound column reference expressions. + vector physical_ids; + vector> expressions; + + for (const auto column_index : column_indexes) { + auto binding = ColumnBinding(0, physical_ids.size()); + auto &col = columns.GetColumn(column_index); + auto ref = make_uniq(col.Name(), col.Type(), binding); + expressions.push_back(std::move(ref)); + physical_ids.push_back(col.Physical().index); + } + + // Create an ART around the expressions. + auto &io_manager = TableIOManager::Get(*this); + auto art = make_uniq(index_info.name, type, physical_ids, io_manager, std::move(expressions), db, nullptr, + index_info); + info->indexes.AddIndex(std::move(art)); +} + } // namespace duckdb diff --git a/src/duckdb/src/storage/local_storage.cpp b/src/duckdb/src/storage/local_storage.cpp index 282eb349f..9e1ad45e7 100644 --- a/src/duckdb/src/storage/local_storage.cpp +++ b/src/duckdb/src/storage/local_storage.cpp @@ -19,8 +19,8 @@ LocalTableStorage::LocalTableStorage(ClientContext &context, DataTable &table) merged_storage(false) { auto types = table.GetTypes(); auto data_table_info = table.GetDataTableInfo(); - row_groups = make_shared_ptr( - data_table_info, TableIOManager::Get(table).GetBlockManagerForRowData(), types, MAX_ROW_ID, 0); + auto &io_manager = TableIOManager::Get(table); + row_groups = make_shared_ptr(data_table_info, io_manager, types, MAX_ROW_ID, 0); row_groups->InitializeEmpty(); data_table_info->GetIndexes().BindAndScan(context, *data_table_info, [&](ART &art) { @@ -110,7 +110,8 @@ void LocalTableStorage::WriteNewRowGroup() { } void LocalTableStorage::FlushBlocks() { - if (!merged_storage && row_groups->GetTotalRows() > Storage::ROW_GROUP_SIZE) { + const idx_t row_group_size = row_groups->GetRowGroupSize(); + if (!merged_storage && row_groups->GetTotalRows() > row_group_size) { optimistic_writer.WriteLastRowGroup(*row_groups); } optimistic_writer.FinalFlush(); @@ -446,13 +447,14 @@ void LocalStorage::Flush(DataTable &table, LocalTableStorage &storage, optional_ return; } idx_t append_count = storage.row_groups->GetTotalRows() - storage.deleted_rows; - table.InitializeIndexes(context); + const idx_t row_group_size = storage.row_groups->GetRowGroupSize(); + TableAppendState append_state; table.AppendLock(append_state); transaction.PushAppend(table, NumericCast(append_state.row_start), append_count); - if ((append_state.row_start == 0 || storage.row_groups->GetTotalRows() >= MERGE_THRESHOLD) && + if ((append_state.row_start == 0 || storage.row_groups->GetTotalRows() >= row_group_size) && storage.deleted_rows == 0) { // table is currently empty OR we are bulk appending: move over the storage directly // first flush any outstanding blocks diff --git a/src/duckdb/src/storage/serialization/serialize_logical_operator.cpp b/src/duckdb/src/storage/serialization/serialize_logical_operator.cpp index d8a4d83b5..e5df17d5a 100644 --- a/src/duckdb/src/storage/serialization/serialize_logical_operator.cpp +++ b/src/duckdb/src/storage/serialization/serialize_logical_operator.cpp @@ -330,12 +330,14 @@ void LogicalCreateIndex::Serialize(Serializer &serializer) const { LogicalOperator::Serialize(serializer); serializer.WritePropertyWithDefault>(200, "info", info); serializer.WritePropertyWithDefault>>(201, "unbound_expressions", unbound_expressions); + serializer.WritePropertyWithDefault>(202, "alter_table_info", alter_table_info); } unique_ptr LogicalCreateIndex::Deserialize(Deserializer &deserializer) { auto info = deserializer.ReadPropertyWithDefault>(200, "info"); auto unbound_expressions = deserializer.ReadPropertyWithDefault>>(201, "unbound_expressions"); - auto result = duckdb::unique_ptr(new LogicalCreateIndex(deserializer.Get(), std::move(info), std::move(unbound_expressions))); + auto alter_table_info = deserializer.ReadPropertyWithDefault>(202, "alter_table_info"); + auto result = duckdb::unique_ptr(new LogicalCreateIndex(deserializer.Get(), std::move(info), std::move(unbound_expressions), std::move(alter_table_info))); return std::move(result); } @@ -562,13 +564,13 @@ unique_ptr LogicalMaterializedCTE::Deserialize(Deserializer &de void LogicalOrder::Serialize(Serializer &serializer) const { LogicalOperator::Serialize(serializer); serializer.WritePropertyWithDefault>(200, "orders", orders); - serializer.WritePropertyWithDefault>(201, "projections", projections); + serializer.WritePropertyWithDefault>(201, "projections", projection_map); } unique_ptr LogicalOrder::Deserialize(Deserializer &deserializer) { auto orders = deserializer.ReadPropertyWithDefault>(200, "orders"); auto result = duckdb::unique_ptr(new LogicalOrder(std::move(orders))); - deserializer.ReadPropertyWithDefault>(201, "projections", result->projections); + deserializer.ReadPropertyWithDefault>(201, "projections", result->projection_map); 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 7e6f7174a..867382964 100644 --- a/src/duckdb/src/storage/serialization/serialize_nodes.cpp +++ b/src/duckdb/src/storage/serialization/serialize_nodes.cpp @@ -32,6 +32,7 @@ #include "duckdb/function/scalar/strftime_format.hpp" #include "duckdb/function/table/read_csv.hpp" #include "duckdb/common/types/interval.hpp" +#include "duckdb/parser/qualified_name.hpp" #include "duckdb/parser/parsed_data/exported_table_data.hpp" namespace duckdb { @@ -488,6 +489,22 @@ PivotColumnEntry PivotColumnEntry::Deserialize(Deserializer &deserializer) { return result; } +void QualifiedColumnName::Serialize(Serializer &serializer) const { + serializer.WritePropertyWithDefault(100, "catalog", catalog); + serializer.WritePropertyWithDefault(101, "schema", schema); + serializer.WritePropertyWithDefault(102, "table", table); + serializer.WritePropertyWithDefault(103, "column", column); +} + +QualifiedColumnName QualifiedColumnName::Deserialize(Deserializer &deserializer) { + QualifiedColumnName result; + deserializer.ReadPropertyWithDefault(100, "catalog", result.catalog); + deserializer.ReadPropertyWithDefault(101, "schema", result.schema); + deserializer.ReadPropertyWithDefault(102, "table", result.table); + deserializer.ReadPropertyWithDefault(103, "column", result.column); + return result; +} + void ReadCSVData::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault>(100, "files", files); serializer.WritePropertyWithDefault>(101, "csv_types", csv_types); @@ -544,15 +561,18 @@ void SampleOptions::Serialize(Serializer &serializer) const { serializer.WriteProperty(100, "sample_size", sample_size); serializer.WritePropertyWithDefault(101, "is_percentage", is_percentage); serializer.WriteProperty(102, "method", method); - serializer.WritePropertyWithDefault(103, "seed", seed); + serializer.WritePropertyWithDefault(103, "seed", GetSeed()); } unique_ptr SampleOptions::Deserialize(Deserializer &deserializer) { - auto result = duckdb::unique_ptr(new SampleOptions()); - deserializer.ReadProperty(100, "sample_size", result->sample_size); - deserializer.ReadPropertyWithDefault(101, "is_percentage", result->is_percentage); - deserializer.ReadProperty(102, "method", result->method); - deserializer.ReadPropertyWithDefault(103, "seed", result->seed); + auto sample_size = deserializer.ReadProperty(100, "sample_size"); + auto is_percentage = deserializer.ReadPropertyWithDefault(101, "is_percentage"); + auto method = deserializer.ReadProperty(102, "method"); + auto seed = deserializer.ReadPropertyWithDefault(103, "seed"); + auto result = duckdb::unique_ptr(new SampleOptions(seed)); + result->sample_size = sample_size; + result->is_percentage = is_percentage; + result->method = method; return result; } diff --git a/src/duckdb/src/storage/serialization/serialize_parse_info.cpp b/src/duckdb/src/storage/serialization/serialize_parse_info.cpp index e68acf36b..ccf98a0ce 100644 --- a/src/duckdb/src/storage/serialization/serialize_parse_info.cpp +++ b/src/duckdb/src/storage/serialization/serialize_parse_info.cpp @@ -130,6 +130,9 @@ unique_ptr AlterTableInfo::Deserialize(Deserializer &deserializer) { case AlterTableType::ADD_COLUMN: result = AddColumnInfo::Deserialize(deserializer); break; + case AlterTableType::ADD_CONSTRAINT: + result = AddConstraintInfo::Deserialize(deserializer); + break; case AlterTableType::ALTER_COLUMN_TYPE: result = ChangeColumnTypeInfo::Deserialize(deserializer); break; @@ -191,6 +194,17 @@ unique_ptr AddColumnInfo::Deserialize(Deserializer &deserializer return std::move(result); } +void AddConstraintInfo::Serialize(Serializer &serializer) const { + AlterTableInfo::Serialize(serializer); + serializer.WritePropertyWithDefault>(400, "constraint", constraint); +} + +unique_ptr AddConstraintInfo::Deserialize(Deserializer &deserializer) { + auto result = duckdb::unique_ptr(new AddConstraintInfo()); + deserializer.ReadPropertyWithDefault>(400, "constraint", result->constraint); + return std::move(result); +} + void AlterForeignKeyInfo::Serialize(Serializer &serializer) const { AlterTableInfo::Serialize(serializer); serializer.WritePropertyWithDefault(400, "fk_table", fk_table); diff --git a/src/duckdb/src/storage/serialization/serialize_parsed_expression.cpp b/src/duckdb/src/storage/serialization/serialize_parsed_expression.cpp index 146aa7feb..3ae8fe29b 100644 --- a/src/duckdb/src/storage/serialization/serialize_parsed_expression.cpp +++ b/src/duckdb/src/storage/serialization/serialize_parsed_expression.cpp @@ -288,21 +288,30 @@ unique_ptr PositionalReferenceExpression::Deserialize(Deserial void StarExpression::Serialize(Serializer &serializer) const { ParsedExpression::Serialize(serializer); serializer.WritePropertyWithDefault(200, "relation_name", relation_name); - serializer.WriteProperty(201, "exclude_list", exclude_list); + serializer.WriteProperty(201, "exclude_list", SerializedExcludeList()); serializer.WritePropertyWithDefault>>(202, "replace_list", replace_list); serializer.WritePropertyWithDefault(203, "columns", columns); serializer.WritePropertyWithDefault>(204, "expr", expr); serializer.WritePropertyWithDefault(205, "unpacked", unpacked, false); + serializer.WritePropertyWithDefault(206, "qualified_exclude_list", SerializedQualifiedExcludeList(), qualified_column_set_t()); + serializer.WritePropertyWithDefault>(207, "rename_list", rename_list, qualified_column_map_t()); } unique_ptr StarExpression::Deserialize(Deserializer &deserializer) { - auto result = duckdb::unique_ptr(new StarExpression()); - deserializer.ReadPropertyWithDefault(200, "relation_name", result->relation_name); - deserializer.ReadProperty(201, "exclude_list", result->exclude_list); - deserializer.ReadPropertyWithDefault>>(202, "replace_list", result->replace_list); - deserializer.ReadPropertyWithDefault(203, "columns", result->columns); - deserializer.ReadPropertyWithDefault>(204, "expr", result->expr); - deserializer.ReadPropertyWithExplicitDefault(205, "unpacked", result->unpacked, false); + auto relation_name = deserializer.ReadPropertyWithDefault(200, "relation_name"); + auto exclude_list = deserializer.ReadProperty(201, "exclude_list"); + auto replace_list = deserializer.ReadPropertyWithDefault>>(202, "replace_list"); + auto columns = deserializer.ReadPropertyWithDefault(203, "columns"); + auto expr = deserializer.ReadPropertyWithDefault>(204, "expr"); + auto unpacked = deserializer.ReadPropertyWithExplicitDefault(205, "unpacked", false); + auto qualified_exclude_list = deserializer.ReadPropertyWithExplicitDefault(206, "qualified_exclude_list", qualified_column_set_t()); + auto result = duckdb::unique_ptr(new StarExpression(exclude_list, qualified_exclude_list)); + result->relation_name = std::move(relation_name); + result->replace_list = std::move(replace_list); + result->columns = columns; + result->expr = std::move(expr); + result->unpacked = unpacked; + deserializer.ReadPropertyWithExplicitDefault>(207, "rename_list", result->rename_list, qualified_column_map_t()); return std::move(result); } diff --git a/src/duckdb/src/storage/serialization/serialize_table_filter.cpp b/src/duckdb/src/storage/serialization/serialize_table_filter.cpp index 550905eef..b15c2d0b0 100644 --- a/src/duckdb/src/storage/serialization/serialize_table_filter.cpp +++ b/src/duckdb/src/storage/serialization/serialize_table_filter.cpp @@ -10,6 +10,7 @@ #include "duckdb/planner/filter/constant_filter.hpp" #include "duckdb/planner/filter/conjunction_filter.hpp" #include "duckdb/planner/filter/struct_filter.hpp" +#include "duckdb/planner/filter/optional_filter.hpp" namespace duckdb { @@ -36,6 +37,9 @@ unique_ptr TableFilter::Deserialize(Deserializer &deserializer) { case TableFilterType::IS_NULL: result = IsNullFilter::Deserialize(deserializer); break; + case TableFilterType::OPTIONAL_FILTER: + result = OptionalFilter::Deserialize(deserializer); + break; case TableFilterType::STRUCT_EXTRACT: result = StructFilter::Deserialize(deserializer); break; @@ -98,6 +102,17 @@ unique_ptr IsNullFilter::Deserialize(Deserializer &deserializer) { return std::move(result); } +void OptionalFilter::Serialize(Serializer &serializer) const { + TableFilter::Serialize(serializer); + serializer.WritePropertyWithDefault>(200, "child_filter", child_filter); +} + +unique_ptr OptionalFilter::Deserialize(Deserializer &deserializer) { + auto result = duckdb::unique_ptr(new OptionalFilter()); + deserializer.ReadPropertyWithDefault>(200, "child_filter", result->child_filter); + return std::move(result); +} + void StructFilter::Serialize(Serializer &serializer) const { TableFilter::Serialize(serializer); serializer.WritePropertyWithDefault(200, "child_idx", child_idx); diff --git a/src/duckdb/src/storage/standard_buffer_manager.cpp b/src/duckdb/src/storage/standard_buffer_manager.cpp index da10afce2..e4087ff48 100644 --- a/src/duckdb/src/storage/standard_buffer_manager.cpp +++ b/src/duckdb/src/storage/standard_buffer_manager.cpp @@ -30,6 +30,9 @@ struct BufferAllocatorData : PrivateAllocatorData { unique_ptr StandardBufferManager::ConstructManagedBuffer(idx_t size, unique_ptr &&source, FileBufferType type) { unique_ptr result; + if (type == FileBufferType::BLOCK) { + throw InternalException("ConstructManagedBuffer cannot be used to construct blocks"); + } if (source) { auto tmp = std::move(source); D_ASSERT(tmp->AllocSize() == BufferManager::GetAllocSize(size)); @@ -123,24 +126,23 @@ shared_ptr StandardBufferManager::RegisterTransientMemory(const idx // Otherwise, any non-default block size would register as small memory, causing problems when // trying to convert that memory to consistent blocks later on. if (size < block_size) { - return RegisterSmallMemory(size); + return RegisterSmallMemory(MemoryTag::IN_MEMORY_TABLE, size); } auto buffer_handle = Allocate(MemoryTag::IN_MEMORY_TABLE, size, false); return buffer_handle.GetBlockHandle(); } -shared_ptr StandardBufferManager::RegisterSmallMemory(const idx_t size) { +shared_ptr StandardBufferManager::RegisterSmallMemory(MemoryTag tag, const idx_t size) { D_ASSERT(size < GetBlockSize()); - auto reservation = EvictBlocksOrThrow(MemoryTag::BASE_TABLE, size, nullptr, "could not allocate block of size %s%s", + auto reservation = EvictBlocksOrThrow(tag, size, nullptr, "could not allocate block of size %s%s", StringUtil::BytesToHumanReadableString(size)); auto buffer = ConstructManagedBuffer(size, nullptr, FileBufferType::TINY_BUFFER); // Create a new block pointer for this block. - auto result = - make_shared_ptr(*temp_block_manager, ++temporary_id, MemoryTag::BASE_TABLE, std::move(buffer), - DestroyBufferUpon::BLOCK, size, std::move(reservation)); + auto result = make_shared_ptr(*temp_block_manager, ++temporary_id, tag, std::move(buffer), + DestroyBufferUpon::BLOCK, size, std::move(reservation)); #ifdef DUCKDB_DEBUG_DESTROY_BLOCKS // Initialize the memory with garbage data WriteGarbageIntoBuffer(*result->buffer); @@ -356,8 +358,8 @@ BufferHandle StandardBufferManager::Pin(shared_ptr &handle) { return buf; } -void StandardBufferManager::PurgeQueue(FileBufferType type) { - buffer_pool.PurgeQueue(type); +void StandardBufferManager::PurgeQueue(const BlockHandle &handle) { + buffer_pool.PurgeQueue(handle); } void StandardBufferManager::AddToEvictionQueue(shared_ptr &handle) { @@ -366,8 +368,15 @@ void StandardBufferManager::AddToEvictionQueue(shared_ptr &handle) void StandardBufferManager::VerifyZeroReaders(shared_ptr &handle) { #ifdef DUCKDB_DEBUG_DESTROY_BLOCKS - auto replacement_buffer = make_uniq(Allocator::Get(db), handle->buffer->type, - handle->memory_usage - Storage::DEFAULT_BLOCK_HEADER_SIZE); + unique_ptr replacement_buffer; + auto &allocator = Allocator::Get(db); + auto alloc_size = handle->memory_usage - Storage::DEFAULT_BLOCK_HEADER_SIZE; + if (handle->buffer->type == FileBufferType::BLOCK) { + auto block = reinterpret_cast(handle->buffer.get()); + replacement_buffer = make_uniq(allocator, block->id, alloc_size); + } else { + replacement_buffer = make_uniq(allocator, handle->buffer->type, alloc_size); + } memcpy(replacement_buffer->buffer, handle->buffer->buffer, handle->buffer->size); WriteGarbageIntoBuffer(*handle->buffer); handle->buffer = std::move(replacement_buffer); @@ -395,7 +404,7 @@ void StandardBufferManager::Unpin(shared_ptr &handle) { // We do not have to keep the handle locked while purging. if (purge) { - PurgeQueue(handle->buffer->type); + PurgeQueue(*handle); } } diff --git a/src/duckdb/src/storage/statistics/column_statistics.cpp b/src/duckdb/src/storage/statistics/column_statistics.cpp index 7a1de53d5..19784bc91 100644 --- a/src/duckdb/src/storage/statistics/column_statistics.cpp +++ b/src/duckdb/src/storage/statistics/column_statistics.cpp @@ -44,12 +44,12 @@ void ColumnStatistics::SetDistinct(unique_ptr distinct) { this->distinct_stats = std::move(distinct); } -void ColumnStatistics::UpdateDistinctStatistics(Vector &v, idx_t count) { +void ColumnStatistics::UpdateDistinctStatistics(Vector &v, idx_t count, Vector &hashes) { if (!distinct_stats) { return; } - // We sample for non-integral types to save cost, and because integers are more likely to be join keys - distinct_stats->Update(v, count); + // we use a sample to update the distinct statistics for performance reasons + distinct_stats->UpdateSample(v, count, hashes); } shared_ptr ColumnStatistics::Copy() const { diff --git a/src/duckdb/src/storage/statistics/distinct_statistics.cpp b/src/duckdb/src/storage/statistics/distinct_statistics.cpp index 6e5088cb3..ddadc997e 100644 --- a/src/duckdb/src/storage/statistics/distinct_statistics.cpp +++ b/src/duckdb/src/storage/statistics/distinct_statistics.cpp @@ -15,7 +15,6 @@ DistinctStatistics::DistinctStatistics(unique_ptr log, idx_t sample } unique_ptr DistinctStatistics::Copy() const { - lock_guard guard(lock); return make_uniq(log->Copy(), sample_count, total_count); } @@ -25,26 +24,28 @@ void DistinctStatistics::Merge(const DistinctStatistics &other) { total_count += other.total_count; } -void DistinctStatistics::Update(Vector &v, idx_t count, bool sample) { +void DistinctStatistics::UpdateSample(Vector &new_data, idx_t count, Vector &hashes) { total_count += count; - if (sample) { - const auto original_count = count; - const auto sample_rate = v.GetType().IsIntegral() ? INTEGRAL_SAMPLE_RATE : BASE_SAMPLE_RATE; - // Sample up to 'sample_rate' of STANDARD_VECTOR_SIZE of this vector (at least 1) - count = MaxValue(LossyNumericCast(sample_rate * static_cast(STANDARD_VECTOR_SIZE)), 1); - // But never more than the original count - count = MinValue(count, original_count); - } - sample_count += count; + const auto original_count = count; + const auto sample_rate = new_data.GetType().IsIntegral() ? INTEGRAL_SAMPLE_RATE : BASE_SAMPLE_RATE; + // Sample up to 'sample_rate' of STANDARD_VECTOR_SIZE of this vector (at least 1) + count = MaxValue(LossyNumericCast(sample_rate * static_cast(STANDARD_VECTOR_SIZE)), 1); + // But never more than the original count + count = MinValue(count, original_count); + + UpdateInternal(new_data, count, hashes); +} - lock_guard guard(lock); - Vector hash_vec(LogicalType::HASH, count); - VectorOperations::Hash(v, hash_vec, count); +void DistinctStatistics::Update(Vector &new_data, idx_t count, Vector &hashes) { + total_count += count; + UpdateInternal(new_data, count, hashes); +} - UnifiedVectorFormat vdata; - v.ToUnifiedFormat(count, vdata); +void DistinctStatistics::UpdateInternal(Vector &new_data, idx_t count, Vector &hashes) { + sample_count += count; + VectorOperations::Hash(new_data, hashes, count); - log->Update(v, hash_vec, count); + log->Update(new_data, hashes, count); } string DistinctStatistics::ToString() const { diff --git a/src/duckdb/src/storage/storage_manager.cpp b/src/duckdb/src/storage/storage_manager.cpp index 456cd2261..cef7f5031 100644 --- a/src/duckdb/src/storage/storage_manager.cpp +++ b/src/duckdb/src/storage/storage_manager.cpp @@ -109,23 +109,25 @@ bool StorageManager::InMemory() { return path == IN_MEMORY_PATH; } -void StorageManager::Initialize(const optional_idx block_alloc_size) { +void StorageManager::Initialize(StorageOptions options) { bool in_memory = InMemory(); if (in_memory && read_only) { throw CatalogException("Cannot launch in-memory database in read-only mode!"); } // Create or load the database from disk, if not in-memory mode. - LoadDatabase(block_alloc_size); + LoadDatabase(options); } /////////////////////////////////////////////////////////////////////////// class SingleFileTableIOManager : public TableIOManager { public: - explicit SingleFileTableIOManager(BlockManager &block_manager) : block_manager(block_manager) { + explicit SingleFileTableIOManager(BlockManager &block_manager, idx_t row_group_size) + : block_manager(block_manager), row_group_size(row_group_size) { } BlockManager &block_manager; + idx_t row_group_size; public: BlockManager &GetIndexBlockManager() override { @@ -137,32 +139,43 @@ class SingleFileTableIOManager : public TableIOManager { MetadataManager &GetMetadataManager() override { return block_manager.GetMetadataManager(); } + idx_t GetRowGroupSize() const override { + return row_group_size; + } }; SingleFileStorageManager::SingleFileStorageManager(AttachedDatabase &db, string path, bool read_only) : StorageManager(db, std::move(path), read_only) { } -void SingleFileStorageManager::LoadDatabase(const optional_idx block_alloc_size) { +void SingleFileStorageManager::LoadDatabase(StorageOptions storage_options) { if (InMemory()) { block_manager = make_uniq(BufferManager::GetBufferManager(db), DEFAULT_BLOCK_ALLOC_SIZE); - table_io_manager = make_uniq(*block_manager); + table_io_manager = make_uniq(*block_manager, DEFAULT_ROW_GROUP_SIZE); return; } auto &fs = FileSystem::Get(db); auto &config = DBConfig::Get(db); - if (!config.options.enable_external_access) { - if (!db.IsInitialDatabase()) { - throw PermissionException("Attaching on-disk databases is disabled through configuration"); - } - } StorageManagerOptions options; options.read_only = read_only; options.use_direct_io = config.options.use_direct_io; options.debug_initialize = config.options.debug_initialize; + idx_t row_group_size = DEFAULT_ROW_GROUP_SIZE; + if (storage_options.row_group_size.IsValid()) { + row_group_size = storage_options.row_group_size.GetIndex(); + if (row_group_size == 0) { + throw NotImplementedException("Invalid row group size: %llu - row group size must be bigger than 0", + row_group_size); + } + if (row_group_size % STANDARD_VECTOR_SIZE != 0) { + throw NotImplementedException( + "Invalid row group size: %llu - row group size must be divisible by the vector size (%llu)", + row_group_size, STANDARD_VECTOR_SIZE); + } + } // Check if the database file already exists. // Note: a file can also exist if there was a ROLLBACK on a previous transaction creating that file. if (!read_only && !fs.FileExists(path)) { @@ -178,9 +191,10 @@ void SingleFileStorageManager::LoadDatabase(const optional_idx block_alloc_size) } // Set the block allocation size for the new database file. - if (block_alloc_size.IsValid()) { + if (storage_options.block_alloc_size.IsValid()) { // Use the option provided by the user. - options.block_alloc_size = block_alloc_size; + Storage::VerifyBlockAllocSize(storage_options.block_alloc_size.GetIndex()); + 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; @@ -190,7 +204,7 @@ void SingleFileStorageManager::LoadDatabase(const optional_idx block_alloc_size) auto sf_block_manager = make_uniq(db, path, options); sf_block_manager->CreateNewDatabase(); block_manager = std::move(sf_block_manager); - table_io_manager = make_uniq(*block_manager); + table_io_manager = make_uniq(*block_manager, row_group_size); } else { // Either the file exists, or we are in read-only mode, so we @@ -202,12 +216,16 @@ void SingleFileStorageManager::LoadDatabase(const optional_idx block_alloc_size) auto sf_block_manager = make_uniq(db, path, options); sf_block_manager->LoadExistingDatabase(); block_manager = std::move(sf_block_manager); - table_io_manager = make_uniq(*block_manager); - - if (block_alloc_size.IsValid() && block_alloc_size.GetIndex() != block_manager->GetBlockAllocSize()) { - throw InvalidInputException( - "block size parameter does not match the file's block size, got %llu, expected %llu", - block_alloc_size.GetIndex(), block_manager->GetBlockAllocSize()); + table_io_manager = make_uniq(*block_manager, row_group_size); + + if (storage_options.block_alloc_size.IsValid()) { + // user-provided block alloc size + idx_t block_alloc_size = storage_options.block_alloc_size.GetIndex(); + if (block_alloc_size != block_manager->GetBlockAllocSize()) { + throw InvalidInputException( + "block size parameter does not match the file's block size, got %llu, expected %llu", + storage_options.block_alloc_size.GetIndex(), block_manager->GetBlockAllocSize()); + } } // load the db from storage diff --git a/src/duckdb/src/storage/table/column_segment.cpp b/src/duckdb/src/storage/table/column_segment.cpp index ae73eef9e..695a16005 100644 --- a/src/duckdb/src/storage/table/column_segment.cpp +++ b/src/duckdb/src/storage/table/column_segment.cpp @@ -392,6 +392,9 @@ static idx_t TemplatedNullSelection(UnifiedVectorFormat &vdata, SelectionVector idx_t ColumnSegment::FilterSelection(SelectionVector &sel, Vector &vector, UnifiedVectorFormat &vdata, const TableFilter &filter, idx_t scan_count, idx_t &approved_tuple_count) { switch (filter.filter_type) { + case TableFilterType::OPTIONAL_FILTER: { + return scan_count; + } case TableFilterType::CONJUNCTION_OR: { // similar to the CONJUNCTION_AND, but we need to take care of the SelectionVectors (OR all of them) idx_t count_total = 0; diff --git a/src/duckdb/src/storage/table/row_group.cpp b/src/duckdb/src/storage/table/row_group.cpp index f05edb99c..5ef82603a 100644 --- a/src/duckdb/src/storage/table/row_group.cpp +++ b/src/duckdb/src/storage/table/row_group.cpp @@ -21,6 +21,7 @@ #include "duckdb/common/serializer/binary_serializer.hpp" #include "duckdb/planner/filter/conjunction_filter.hpp" #include "duckdb/planner/filter/struct_filter.hpp" +#include "duckdb/planner/filter/optional_filter.hpp" #include "duckdb/execution/adaptive_filter.hpp" namespace duckdb { @@ -94,6 +95,10 @@ idx_t RowGroup::GetColumnCount() const { return columns.size(); } +idx_t RowGroup::GetRowGroupSize() const { + return collection.get().GetRowGroupSize(); +} + ColumnData &RowGroup::GetColumn(storage_t c) { D_ASSERT(c < columns.size()); if (!is_loaded) { @@ -416,6 +421,10 @@ static idx_t GetFilterScanCount(ColumnScanState &state, TableFilter &filter) { } return max_count; } + case TableFilterType::OPTIONAL_FILTER: { + auto &zone_filter = filter.Cast(); + return GetFilterScanCount(state, *zone_filter.child_filter); + } case TableFilterType::IS_NULL: case TableFilterType::IS_NOT_NULL: case TableFilterType::CONSTANT_COMPARISON: @@ -441,6 +450,8 @@ bool RowGroup::CheckZonemapSegments(CollectionScanState &state) { if (prune_result != FilterPropagateResult::FILTER_ALWAYS_FALSE) { continue; } + + // check zone map segment. idx_t target_row = GetFilterScanCount(state.column_scans[column_idx], filter); if (target_row >= state.max_row) { target_row = state.max_row; @@ -481,6 +492,13 @@ void RowGroup::TemplatedScan(TransactionData transaction, CollectionScanState &s idx_t current_row = state.vector_index * STANDARD_VECTOR_SIZE; auto max_count = MinValue(STANDARD_VECTOR_SIZE, state.max_row_group_row - current_row); + // check the sampling info if we have to sample this chunk + if (state.GetSamplingInfo().do_system_sample && + state.random.NextRandom() > state.GetSamplingInfo().sample_rate) { + NextVector(state); + continue; + } + //! first check the zonemap if we have to scan this partition if (!CheckZonemapSegments(state)) { continue; @@ -769,10 +787,11 @@ void RowGroup::FetchRow(TransactionData transaction, ColumnFetchState &state, co } void RowGroup::AppendVersionInfo(TransactionData transaction, idx_t count) { + const idx_t row_group_size = GetRowGroupSize(); idx_t row_group_start = this->count.load(); idx_t row_group_end = row_group_start + count; - if (row_group_end > Storage::ROW_GROUP_SIZE) { - row_group_end = Storage::ROW_GROUP_SIZE; + if (row_group_end > row_group_size) { + row_group_end = row_group_size; } // create the version_info if it doesn't exist yet auto &vinfo = GetOrCreateVersionInfo(); diff --git a/src/duckdb/src/storage/table/row_group_collection.cpp b/src/duckdb/src/storage/table/row_group_collection.cpp index 4dfb19492..961a09595 100644 --- a/src/duckdb/src/storage/table/row_group_collection.cpp +++ b/src/duckdb/src/storage/table/row_group_collection.cpp @@ -53,10 +53,17 @@ unique_ptr RowGroupSegmentTree::LoadSegment() { //===--------------------------------------------------------------------===// // Row Group Collection //===--------------------------------------------------------------------===// +RowGroupCollection::RowGroupCollection(shared_ptr info_p, TableIOManager &io_manager, + vector types_p, idx_t row_start, idx_t total_rows) + : RowGroupCollection(std::move(info_p), io_manager.GetBlockManagerForRowData(), std::move(types_p), row_start, + total_rows, io_manager.GetRowGroupSize()) { +} + RowGroupCollection::RowGroupCollection(shared_ptr info_p, BlockManager &block_manager, - vector types_p, idx_t row_start_p, idx_t total_rows_p) - : block_manager(block_manager), total_rows(total_rows_p), info(std::move(info_p)), types(std::move(types_p)), - row_start(row_start_p), allocation_size(0) { + vector types_p, idx_t row_start_p, idx_t total_rows_p, + idx_t row_group_size_p) + : block_manager(block_manager), row_group_size(row_group_size_p), total_rows(total_rows_p), info(std::move(info_p)), + types(std::move(types_p)), row_start(row_start_p), allocation_size(0) { row_groups = make_shared_ptr(*this); } @@ -303,7 +310,8 @@ void RowGroupCollection::Fetch(TransactionData transaction, DataChunk &result, c // Append //===--------------------------------------------------------------------===// TableAppendState::TableAppendState() - : row_group_append_state(*this), total_append_count(0), start_row_group(nullptr), transaction(0, 0) { + : row_group_append_state(*this), total_append_count(0), start_row_group(nullptr), transaction(0, 0), + hashes(LogicalType::HASH) { } TableAppendState::~TableAppendState() { @@ -345,6 +353,7 @@ void RowGroupCollection::InitializeAppend(TableAppendState &state) { } bool RowGroupCollection::Append(DataChunk &chunk, TableAppendState &state) { + const idx_t row_group_size = GetRowGroupSize(); D_ASSERT(chunk.ColumnCount() == types.size()); chunk.Verify(); @@ -356,7 +365,7 @@ bool RowGroupCollection::Append(DataChunk &chunk, TableAppendState &state) { auto current_row_group = state.row_group_append_state.row_group; // check how much we can fit into the current row_group idx_t append_count = - MinValue(remaining, Storage::ROW_GROUP_SIZE - state.row_group_append_state.offset_in_row_group); + MinValue(remaining, row_group_size - state.row_group_append_state.offset_in_row_group); if (append_count > 0) { auto previous_allocation_size = current_row_group->GetAllocationSize(); current_row_group->Append(state.row_group_append_state, chunk, append_count); @@ -390,16 +399,19 @@ bool RowGroupCollection::Append(DataChunk &chunk, TableAppendState &state) { state.current_row += row_t(total_append_count); auto local_stats_lock = state.stats.GetLock(); for (idx_t col_idx = 0; col_idx < types.size(); col_idx++) { - state.stats.GetStats(*local_stats_lock, col_idx).UpdateDistinctStatistics(chunk.data[col_idx], chunk.size()); + auto &column_stats = state.stats.GetStats(*local_stats_lock, col_idx); + column_stats.UpdateDistinctStatistics(chunk.data[col_idx], chunk.size(), state.hashes); } return new_row_group; } void RowGroupCollection::FinalizeAppend(TransactionData transaction, TableAppendState &state) { + const idx_t row_group_size = GetRowGroupSize(); + auto remaining = state.total_append_count; auto row_group = state.start_row_group; while (remaining > 0) { - auto append_count = MinValue(remaining, Storage::ROW_GROUP_SIZE - row_group->count); + auto append_count = MinValue(remaining, row_group_size - row_group->count); row_group->AppendVersionInfo(transaction, append_count); remaining -= append_count; row_group = row_groups->GetNextSegment(row_group); @@ -758,6 +770,7 @@ class VacuumTask : public BaseCheckpointTask { void ExecuteTask() override { auto &collection = checkpoint_state.collection; + const idx_t row_group_size = collection.GetRowGroupSize(); auto &types = collection.GetTypes(); // create the new set of target row groups (initially empty) vector> new_row_groups; @@ -765,7 +778,7 @@ class VacuumTask : public BaseCheckpointTask { idx_t row_group_rows = merge_rows; idx_t start = row_start; for (idx_t target_idx = 0; target_idx < target_count; target_idx++) { - idx_t current_row_group_rows = MinValue(row_group_rows, Storage::ROW_GROUP_SIZE); + idx_t current_row_group_rows = MinValue(row_group_rows, row_group_size); auto new_row_group = make_uniq(collection, start, current_row_group_rows); new_row_group->InitializeEmpty(types); new_row_groups.push_back(std::move(new_row_group)); @@ -815,13 +828,12 @@ class VacuumTask : public BaseCheckpointTask { scan_chunk.Flatten(); idx_t remaining = scan_chunk.size(); while (remaining > 0) { - idx_t append_count = - MinValue(remaining, Storage::ROW_GROUP_SIZE - append_counts[current_append_idx]); + idx_t append_count = MinValue(remaining, row_group_size - append_counts[current_append_idx]); new_row_groups[current_append_idx]->Append(append_state.row_group_append_state, scan_chunk, append_count); append_counts[current_append_idx] += append_count; remaining -= append_count; - const bool row_group_full = append_counts[current_append_idx] == Storage::ROW_GROUP_SIZE; + const bool row_group_full = append_counts[current_append_idx] == row_group_size; const bool last_row_group = current_append_idx + 1 >= new_row_groups.size(); if (remaining > 0 || (row_group_full && !last_row_group)) { // move to the next row group @@ -917,8 +929,9 @@ bool RowGroupCollection::ScheduleVacuumTasks(CollectionCheckpointState &checkpoi // hence we target_count should be less than merge_count for a marge to be worth it // we greedily prefer to merge to the lowest target_count // i.e. we prefer to merge 2 row groups into 1, than 3 row groups into 2 + const idx_t row_group_size = GetRowGroupSize(); for (target_count = 1; target_count <= MAX_MERGE_COUNT; target_count++) { - auto total_target_size = target_count * Storage::ROW_GROUP_SIZE; + auto total_target_size = target_count * row_group_size; merge_count = 0; merge_rows = 0; for (next_idx = segment_idx; next_idx < checkpoint_state.segments.size(); next_idx++) { @@ -1050,8 +1063,8 @@ shared_ptr RowGroupCollection::AddColumn(ClientContext &cont idx_t new_column_idx = types.size(); auto new_types = types; new_types.push_back(new_column.GetType()); - auto result = - make_shared_ptr(info, block_manager, std::move(new_types), row_start, total_rows.load()); + auto result = make_shared_ptr(info, block_manager, std::move(new_types), row_start, + total_rows.load(), row_group_size); DataChunk dummy_chunk; Vector default_vector(new_column.GetType()); @@ -1077,8 +1090,8 @@ shared_ptr RowGroupCollection::RemoveColumn(idx_t col_idx) { auto new_types = types; new_types.erase_at(col_idx); - auto result = - make_shared_ptr(info, block_manager, std::move(new_types), row_start, total_rows.load()); + auto result = make_shared_ptr(info, block_manager, std::move(new_types), row_start, + total_rows.load(), row_group_size); result->stats.InitializeRemoveColumn(stats, col_idx); for (auto ¤t_row_group : row_groups->Segments()) { @@ -1095,8 +1108,8 @@ shared_ptr RowGroupCollection::AlterType(ClientContext &cont auto new_types = types; new_types[changed_idx] = target_type; - auto result = - make_shared_ptr(info, block_manager, std::move(new_types), row_start, total_rows.load()); + auto result = make_shared_ptr(info, block_manager, std::move(new_types), row_start, + total_rows.load(), row_group_size); result->stats.InitializeAlterType(stats, changed_idx, target_type); vector scan_types; @@ -1134,33 +1147,38 @@ void RowGroupCollection::VerifyNewConstraint(DataTable &parent, const BoundConst if (total_rows == 0) { return; } - // scan the original table, check if there's any null value + + // Scan the original table for NULL values. auto ¬_null_constraint = constraint.Cast(); vector scan_types; auto physical_index = not_null_constraint.index.index; D_ASSERT(physical_index < types.size()); + scan_types.push_back(types[physical_index]); DataChunk scan_chunk; scan_chunk.Initialize(GetAllocator(), scan_types); + vector column_ids; + column_ids.push_back(physical_index); + + // Use SCAN_COMMITTED to scan the latest data. CreateIndexScanState state; - vector cids; - cids.push_back(physical_index); - // Use ScanCommitted to scan the latest committed data - state.Initialize(cids, nullptr); - InitializeScan(state.table_state, cids, nullptr); + auto scan_type = TableScanType::TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED; + state.Initialize(column_ids, nullptr); + InitializeScan(state.table_state, column_ids, nullptr); InitializeCreateIndexScan(state); + while (true) { scan_chunk.Reset(); - state.table_state.ScanCommitted(scan_chunk, state.segment_lock, - TableScanType::TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED); + state.table_state.ScanCommitted(scan_chunk, state.segment_lock, scan_type); if (scan_chunk.size() == 0) { break; } - // Check constraint + + // Verify the NOT NULL constraint. if (VectorOperations::HasNull(scan_chunk.data[0], scan_chunk.size())) { - throw ConstraintException("NOT NULL constraint failed: %s.%s", info->GetTableName(), - parent.Columns()[physical_index].GetName()); + auto name = parent.Columns()[physical_index].GetName(); + throw ConstraintException("NOT NULL constraint failed: %s.%s", info->GetTableName(), name); } } } diff --git a/src/duckdb/src/storage/table/row_version_manager.cpp b/src/duckdb/src/storage/table/row_version_manager.cpp index 4a166f059..a3b47a56e 100644 --- a/src/duckdb/src/storage/table/row_version_manager.cpp +++ b/src/duckdb/src/storage/table/row_version_manager.cpp @@ -14,9 +14,9 @@ void RowVersionManager::SetStart(idx_t new_start) { lock_guard l(version_lock); this->start = new_start; idx_t current_start = start; - for (idx_t i = 0; i < Storage::ROW_GROUP_VECTOR_COUNT; i++) { - if (vector_info[i]) { - vector_info[i]->start = current_start; + for (auto &info : vector_info) { + if (info) { + info->start = current_start; } current_start += STANDARD_VECTOR_SIZE; } @@ -26,7 +26,7 @@ idx_t RowVersionManager::GetCommittedDeletedCount(idx_t count) { lock_guard l(version_lock); idx_t deleted_count = 0; for (idx_t r = 0, i = 0; r < count; r += STANDARD_VECTOR_SIZE, i++) { - if (!vector_info[i]) { + if (i >= vector_info.size() || !vector_info[i]) { continue; } idx_t max_count = MinValue(STANDARD_VECTOR_SIZE, count - r); @@ -39,6 +39,9 @@ idx_t RowVersionManager::GetCommittedDeletedCount(idx_t count) { } optional_ptr RowVersionManager::GetChunkInfo(idx_t vector_idx) { + if (vector_idx >= vector_info.size()) { + return nullptr; + } return vector_info[vector_idx].get(); } @@ -72,12 +75,27 @@ bool RowVersionManager::Fetch(TransactionData transaction, idx_t row) { return info->Fetch(transaction, UnsafeNumericCast(row - vector_index * STANDARD_VECTOR_SIZE)); } +void RowVersionManager::FillVectorInfo(idx_t vector_idx) { + if (vector_idx < vector_info.size()) { + return; + } + vector_info.reserve(vector_idx + 1); + for (idx_t i = vector_info.size(); i <= vector_idx; i++) { + vector_info.emplace_back(); + } +} + void RowVersionManager::AppendVersionInfo(TransactionData transaction, idx_t count, idx_t row_group_start, idx_t row_group_end) { lock_guard lock(version_lock); has_changes = true; idx_t start_vector_idx = row_group_start / STANDARD_VECTOR_SIZE; idx_t end_vector_idx = (row_group_end - 1) / STANDARD_VECTOR_SIZE; + + // fill-up vector_info + FillVectorInfo(end_vector_idx); + + // insert the version info nodes for (idx_t vector_idx = start_vector_idx; vector_idx <= end_vector_idx; vector_idx++) { idx_t vector_start = vector_idx == start_vector_idx ? row_group_start - start_vector_idx * STANDARD_VECTOR_SIZE : 0; @@ -143,7 +161,7 @@ void RowVersionManager::CleanupAppend(transaction_t lowest_active_transaction, i // not written fully - skip continue; } - if (!vector_info[vector_idx]) { + if (vector_idx >= vector_info.size() || !vector_info[vector_idx]) { // already vacuumed - skip continue; } @@ -160,12 +178,14 @@ void RowVersionManager::CleanupAppend(transaction_t lowest_active_transaction, i void RowVersionManager::RevertAppend(idx_t start_row) { lock_guard lock(version_lock); idx_t start_vector_idx = (start_row + (STANDARD_VECTOR_SIZE - 1)) / STANDARD_VECTOR_SIZE; - for (idx_t vector_idx = start_vector_idx; vector_idx < Storage::ROW_GROUP_VECTOR_COUNT; vector_idx++) { + for (idx_t vector_idx = start_vector_idx; vector_idx < vector_info.size(); vector_idx++) { vector_info[vector_idx].reset(); } } ChunkVectorInfo &RowVersionManager::GetVectorInfo(idx_t vector_idx) { + FillVectorInfo(vector_idx); + if (!vector_info[vector_idx]) { // no info yet: create it vector_info[vector_idx] = make_uniq(start + vector_idx * STANDARD_VECTOR_SIZE); @@ -206,7 +226,7 @@ vector RowVersionManager::Checkpoint(MetadataManager &manager) } // first count how many ChunkInfo's we need to deserialize vector>> to_serialize; - for (idx_t vector_idx = 0; vector_idx < Storage::ROW_GROUP_VECTOR_COUNT; vector_idx++) { + for (idx_t vector_idx = 0; vector_idx < vector_info.size(); vector_idx++) { auto chunk_info = vector_info[vector_idx].get(); if (!chunk_info) { continue; @@ -248,10 +268,13 @@ shared_ptr RowVersionManager::Deserialize(MetaBlockPointer de D_ASSERT(chunk_count > 0); for (idx_t i = 0; i < chunk_count; i++) { idx_t vector_index = source.Read(); - if (vector_index >= Storage::ROW_GROUP_VECTOR_COUNT) { - throw InternalException( - "In DeserializeDeletes, vector_index is out of range for the row group. Corrupted file?"); + if (vector_index * STANDARD_VECTOR_SIZE >= Storage::MAX_ROW_GROUP_SIZE) { + throw IOException("In DeserializeDeletes, vector_index %llu is out of range for the max row group size of " + "%llu. Corrupted file?", + vector_index, Storage::MAX_ROW_GROUP_SIZE); } + + version_info->FillVectorInfo(vector_index); version_info->vector_info[vector_index] = ChunkInfo::Read(source); } version_info->has_changes = false; diff --git a/src/duckdb/src/storage/table/scan_state.cpp b/src/duckdb/src/storage/table/scan_state.cpp index 5eb0adf74..dc4213d03 100644 --- a/src/duckdb/src/storage/table/scan_state.cpp +++ b/src/duckdb/src/storage/table/scan_state.cpp @@ -16,11 +16,16 @@ TableScanState::TableScanState() : table_state(*this), local_state(*this) { TableScanState::~TableScanState() { } -void TableScanState::Initialize(vector column_ids_p, optional_ptr table_filters) { +void TableScanState::Initialize(vector column_ids_p, optional_ptr table_filters, + optional_ptr table_sampling) { this->column_ids = std::move(column_ids_p); if (table_filters) { filters.Initialize(*table_filters, column_ids); } + if (table_sampling) { + sampling_info.do_system_sample = table_sampling->method == SampleMethod::SYSTEM_SAMPLE; + sampling_info.sample_rate = table_sampling->sample_size.GetValue() / 100.0; + } } const vector &TableScanState::GetColumnIds() { @@ -35,6 +40,10 @@ ScanFilterInfo &TableScanState::GetFilterInfo() { return filters; } +ScanSamplingInfo &TableScanState::GetSamplingInfo() { + return sampling_info; +} + ScanFilter::ScanFilter(idx_t index, const vector &column_ids, TableFilter &filter) : scan_column_index(index), table_column_index(column_ids[index]), filter(filter), always_true(false) { } @@ -143,6 +152,10 @@ ScanFilterInfo &CollectionScanState::GetFilterInfo() { return parent.GetFilterInfo(); } +ScanSamplingInfo &CollectionScanState::GetSamplingInfo() { + return parent.GetSamplingInfo(); +} + TableScanOptions &CollectionScanState::GetOptions() { return parent.options; } @@ -153,7 +166,7 @@ ParallelCollectionScanState::ParallelCollectionScanState() CollectionScanState::CollectionScanState(TableScanState &parent_p) : row_group(nullptr), vector_index(0), max_row_group_row(0), row_groups(nullptr), max_row(0), batch_index(0), - valid_sel(STANDARD_VECTOR_SIZE), parent(parent_p) { + valid_sel(STANDARD_VECTOR_SIZE), random(-1), parent(parent_p) { } bool CollectionScanState::Scan(DuckTransaction &transaction, DataChunk &result) { diff --git a/src/duckdb/src/storage/table/update_segment.cpp b/src/duckdb/src/storage/table/update_segment.cpp index 1c7518b2c..ddee92ceb 100644 --- a/src/duckdb/src/storage/table/update_segment.cpp +++ b/src/duckdb/src/storage/table/update_segment.cpp @@ -6,6 +6,7 @@ #include "duckdb/storage/table/column_data.hpp" #include "duckdb/transaction/duck_transaction.hpp" #include "duckdb/transaction/update_info.hpp" +#include "duckdb/transaction/undo_buffer.hpp" #include @@ -46,6 +47,7 @@ UpdateSegment::~UpdateSegment() { Value UpdateInfo::GetValue(idx_t index) { auto &type = segment->column_data.type; + auto tuple_data = GetValues(); switch (type.id()) { case LogicalTypeId::VALIDITY: return Value::BOOLEAN(reinterpret_cast(tuple_data)[index]); @@ -64,17 +66,53 @@ string UpdateInfo::ToString() { auto &type = segment->column_data.type; string result = "Update Info [" + type.ToString() + ", Count: " + to_string(N) + ", Transaction Id: " + to_string(version_number) + "]\n"; + auto tuples = GetTuples(); for (idx_t i = 0; i < N; i++) { result += to_string(tuples[i]) + ": " + GetValue(i).ToString() + "\n"; } - if (next) { - result += "\nChild Segment: " + next->ToString(); + if (HasNext()) { + auto next_pin = next.Pin(); + result += "\nChild Segment: " + Get(next_pin).ToString(); } return result; } +sel_t *UpdateInfo::GetTuples() { + return reinterpret_cast(data_ptr_cast(this) + sizeof(UpdateInfo)); +} + +data_ptr_t UpdateInfo::GetValues() { + return reinterpret_cast(data_ptr_cast(this) + sizeof(UpdateInfo) + sizeof(sel_t) * max); +} + +UpdateInfo &UpdateInfo::Get(UndoBufferReference &entry) { + auto update_info = reinterpret_cast(entry.Ptr()); + return *update_info; +} + +bool UpdateInfo::HasPrev() const { + return prev.entry; +} + +bool UpdateInfo::HasNext() const { + return next.entry; +} + +idx_t UpdateInfo::GetAllocSize(idx_t type_size) { + return AlignValue(sizeof(UpdateInfo) + (sizeof(sel_t) + type_size) * STANDARD_VECTOR_SIZE); +} + +void UpdateInfo::Initialize(UpdateInfo &info, transaction_t transaction_id) { + info.max = STANDARD_VECTOR_SIZE; + info.version_number = transaction_id; + info.segment = nullptr; + info.prev.entry = nullptr; + info.next.entry = nullptr; +} + void UpdateInfo::Verify() { #ifdef DEBUG + auto tuples = GetTuples(); for (idx_t i = 1; i < N; i++) { D_ASSERT(tuples[i] > tuples[i - 1] && tuples[i] < STANDARD_VECTOR_SIZE); } @@ -84,40 +122,42 @@ void UpdateInfo::Verify() { //===--------------------------------------------------------------------===// // Update Fetch //===--------------------------------------------------------------------===// -static void MergeValidityInfo(UpdateInfo *current, ValidityMask &result_mask) { - auto info_data = reinterpret_cast(current->tuple_data); - for (idx_t i = 0; i < current->N; i++) { - result_mask.Set(current->tuples[i], info_data[i]); +static void MergeValidityInfo(UpdateInfo ¤t, ValidityMask &result_mask) { + auto tuples = current.GetTuples(); + auto info_data = current.GetData(); + for (idx_t i = 0; i < current.N; i++) { + result_mask.Set(tuples[i], info_data[i]); } } -static void UpdateMergeValidity(transaction_t start_time, transaction_t transaction_id, UpdateInfo *info, +static void UpdateMergeValidity(transaction_t start_time, transaction_t transaction_id, UpdateInfo &info, Vector &result) { auto &result_mask = FlatVector::Validity(result); UpdateInfo::UpdatesForTransaction(info, start_time, transaction_id, - [&](UpdateInfo *current) { MergeValidityInfo(current, result_mask); }); + [&](UpdateInfo ¤t) { MergeValidityInfo(current, result_mask); }); } template -static void MergeUpdateInfo(UpdateInfo *current, T *result_data) { - auto info_data = reinterpret_cast(current->tuple_data); - if (current->N == STANDARD_VECTOR_SIZE) { +static void MergeUpdateInfo(UpdateInfo ¤t, T *result_data) { + auto tuples = current.GetTuples(); + auto info_data = current.GetData(); + if (current.N == STANDARD_VECTOR_SIZE) { // special case: update touches ALL tuples of this vector // in this case we can just memcpy the data // since the layout of the update info is guaranteed to be [0, 1, 2, 3, ...] - memcpy(result_data, info_data, sizeof(T) * current->N); + memcpy(result_data, info_data, sizeof(T) * current.N); } else { - for (idx_t i = 0; i < current->N; i++) { - result_data[current->tuples[i]] = info_data[i]; + for (idx_t i = 0; i < current.N; i++) { + result_data[tuples[i]] = info_data[i]; } } } template -static void UpdateMergeFetch(transaction_t start_time, transaction_t transaction_id, UpdateInfo *info, Vector &result) { +static void UpdateMergeFetch(transaction_t start_time, transaction_t transaction_id, UpdateInfo &info, Vector &result) { auto result_data = FlatVector::GetData(result); UpdateInfo::UpdatesForTransaction(info, start_time, transaction_id, - [&](UpdateInfo *current) { MergeUpdateInfo(current, result_data); }); + [&](UpdateInfo ¤t) { MergeUpdateInfo(current, result_data); }); } static UpdateSegment::fetch_update_function_t GetFetchUpdateFunction(PhysicalType type) { @@ -158,31 +198,44 @@ static UpdateSegment::fetch_update_function_t GetFetchUpdateFunction(PhysicalTyp } } -void UpdateSegment::FetchUpdates(TransactionData transaction, idx_t vector_index, Vector &result) { - auto lock_handle = lock.GetSharedLock(); +UndoBufferPointer UpdateSegment::GetUpdateNode(idx_t vector_idx) const { if (!root) { - return; + return UndoBufferPointer(); } - if (!root->info[vector_index]) { + if (vector_idx >= root->info.size()) { + return UndoBufferPointer(); + } + return root->info[vector_idx]; +} + +void UpdateSegment::FetchUpdates(TransactionData transaction, idx_t vector_index, Vector &result) { + auto lock_handle = lock.GetSharedLock(); + auto node = GetUpdateNode(vector_index); + if (!node.IsSet()) { return; } // FIXME: normalify if this is not the case... need to pass in count? D_ASSERT(result.GetVectorType() == VectorType::FLAT_VECTOR); + auto pin = node.Pin(); + fetch_update_function(transaction.start_time, transaction.transaction_id, UpdateInfo::Get(pin), result); +} + +UpdateNode::UpdateNode(BufferManager &manager) : allocator(manager) { +} - fetch_update_function(transaction.start_time, transaction.transaction_id, root->info[vector_index]->info.get(), - result); +UpdateNode::~UpdateNode() { } //===--------------------------------------------------------------------===// // Fetch Committed //===--------------------------------------------------------------------===// -static void FetchCommittedValidity(UpdateInfo *info, Vector &result) { +static void FetchCommittedValidity(UpdateInfo &info, Vector &result) { auto &result_mask = FlatVector::Validity(result); MergeValidityInfo(info, result_mask); } template -static void TemplatedFetchCommitted(UpdateInfo *info, Vector &result) { +static void TemplatedFetchCommitted(UpdateInfo &info, Vector &result) { auto result_data = FlatVector::GetData(result); MergeUpdateInfo(info, result_data); } @@ -227,27 +280,25 @@ static UpdateSegment::fetch_committed_function_t GetFetchCommittedFunction(Physi void UpdateSegment::FetchCommitted(idx_t vector_index, Vector &result) { auto lock_handle = lock.GetSharedLock(); - - if (!root) { - return; - } - if (!root->info[vector_index]) { + auto node = GetUpdateNode(vector_index); + if (!node.IsSet()) { return; } // FIXME: normalify if this is not the case... need to pass in count? D_ASSERT(result.GetVectorType() == VectorType::FLAT_VECTOR); - - fetch_committed_function(root->info[vector_index]->info.get(), result); + auto pin = node.Pin(); + fetch_committed_function(UpdateInfo::Get(pin), result); } //===--------------------------------------------------------------------===// // Fetch Range //===--------------------------------------------------------------------===// -static void MergeUpdateInfoRangeValidity(UpdateInfo *current, idx_t start, idx_t end, idx_t result_offset, +static void MergeUpdateInfoRangeValidity(UpdateInfo ¤t, idx_t start, idx_t end, idx_t result_offset, ValidityMask &result_mask) { - auto info_data = reinterpret_cast(current->tuple_data); - for (idx_t i = 0; i < current->N; i++) { - auto tuple_idx = current->tuples[i]; + auto tuples = current.GetTuples(); + auto info_data = current.GetData(); + for (idx_t i = 0; i < current.N; i++) { + auto tuple_idx = tuples[i]; if (tuple_idx < start) { continue; } else if (tuple_idx >= end) { @@ -258,16 +309,17 @@ static void MergeUpdateInfoRangeValidity(UpdateInfo *current, idx_t start, idx_t } } -static void FetchCommittedRangeValidity(UpdateInfo *info, idx_t start, idx_t end, idx_t result_offset, Vector &result) { +static void FetchCommittedRangeValidity(UpdateInfo &info, idx_t start, idx_t end, idx_t result_offset, Vector &result) { auto &result_mask = FlatVector::Validity(result); MergeUpdateInfoRangeValidity(info, start, end, result_offset, result_mask); } template -static void MergeUpdateInfoRange(UpdateInfo *current, idx_t start, idx_t end, idx_t result_offset, T *result_data) { - auto info_data = reinterpret_cast(current->tuple_data); - for (idx_t i = 0; i < current->N; i++) { - auto tuple_idx = current->tuples[i]; +static void MergeUpdateInfoRange(UpdateInfo ¤t, idx_t start, idx_t end, idx_t result_offset, T *result_data) { + auto tuples = current.GetTuples(); + auto info_data = current.GetData(); + for (idx_t i = 0; i < current.N; i++) { + auto tuple_idx = tuples[i]; if (tuple_idx < start) { continue; } else if (tuple_idx >= end) { @@ -279,7 +331,7 @@ static void MergeUpdateInfoRange(UpdateInfo *current, idx_t start, idx_t end, id } template -static void TemplatedFetchCommittedRange(UpdateInfo *info, idx_t start, idx_t end, idx_t result_offset, +static void TemplatedFetchCommittedRange(UpdateInfo &info, idx_t start, idx_t end, idx_t result_offset, Vector &result) { auto result_data = FlatVector::GetData(result); MergeUpdateInfoRange(info, start, end, result_offset, result_data); @@ -334,37 +386,38 @@ void UpdateSegment::FetchCommittedRange(idx_t start_row, idx_t count, Vector &re idx_t start_vector = start_row / STANDARD_VECTOR_SIZE; idx_t end_vector = (end_row - 1) / STANDARD_VECTOR_SIZE; D_ASSERT(start_vector <= end_vector); - D_ASSERT(end_vector < Storage::ROW_GROUP_VECTOR_COUNT); for (idx_t vector_idx = start_vector; vector_idx <= end_vector; vector_idx++) { - if (!root->info[vector_idx]) { + auto entry = GetUpdateNode(vector_idx); + if (!entry.IsSet()) { continue; } + auto pin = entry.Pin(); idx_t start_in_vector = vector_idx == start_vector ? start_row - start_vector * STANDARD_VECTOR_SIZE : 0; idx_t end_in_vector = vector_idx == end_vector ? end_row - end_vector * STANDARD_VECTOR_SIZE : STANDARD_VECTOR_SIZE; D_ASSERT(start_in_vector < end_in_vector); D_ASSERT(end_in_vector > 0 && end_in_vector <= STANDARD_VECTOR_SIZE); idx_t result_offset = ((vector_idx * STANDARD_VECTOR_SIZE) + start_in_vector) - start_row; - fetch_committed_range(root->info[vector_idx]->info.get(), start_in_vector, end_in_vector, result_offset, - result); + fetch_committed_range(UpdateInfo::Get(pin), start_in_vector, end_in_vector, result_offset, result); } } //===--------------------------------------------------------------------===// // Fetch Row //===--------------------------------------------------------------------===// -static void FetchRowValidity(transaction_t start_time, transaction_t transaction_id, UpdateInfo *info, idx_t row_idx, +static void FetchRowValidity(transaction_t start_time, transaction_t transaction_id, UpdateInfo &info, idx_t row_idx, Vector &result, idx_t result_idx) { auto &result_mask = FlatVector::Validity(result); - UpdateInfo::UpdatesForTransaction(info, start_time, transaction_id, [&](UpdateInfo *current) { - auto info_data = reinterpret_cast(current->tuple_data); + UpdateInfo::UpdatesForTransaction(info, start_time, transaction_id, [&](UpdateInfo ¤t) { + auto info_data = current.GetData(); + auto tuples = current.GetTuples(); // FIXME: we could do a binary search in here - for (idx_t i = 0; i < current->N; i++) { - if (current->tuples[i] == row_idx) { + for (idx_t i = 0; i < current.N; i++) { + if (tuples[i] == row_idx) { result_mask.Set(result_idx, info_data[i]); break; - } else if (current->tuples[i] > row_idx) { + } else if (tuples[i] > row_idx) { break; } } @@ -372,17 +425,18 @@ static void FetchRowValidity(transaction_t start_time, transaction_t transaction } template -static void TemplatedFetchRow(transaction_t start_time, transaction_t transaction_id, UpdateInfo *info, idx_t row_idx, +static void TemplatedFetchRow(transaction_t start_time, transaction_t transaction_id, UpdateInfo &info, idx_t row_idx, Vector &result, idx_t result_idx) { auto result_data = FlatVector::GetData(result); - UpdateInfo::UpdatesForTransaction(info, start_time, transaction_id, [&](UpdateInfo *current) { - auto info_data = (T *)current->tuple_data; + UpdateInfo::UpdatesForTransaction(info, start_time, transaction_id, [&](UpdateInfo ¤t) { + auto info_data = current.GetData(); + auto tuples = current.GetTuples(); // FIXME: we could do a binary search in here - for (idx_t i = 0; i < current->N; i++) { - if (current->tuples[i] == row_idx) { + for (idx_t i = 0; i < current.N; i++) { + if (tuples[i] == row_idx) { result_data[result_idx] = info_data[i]; break; - } else if (current->tuples[i] > row_idx) { + } else if (tuples[i] > row_idx) { break; } } @@ -428,16 +482,15 @@ static UpdateSegment::fetch_row_function_t GetFetchRowFunction(PhysicalType type } void UpdateSegment::FetchRow(TransactionData transaction, idx_t row_id, Vector &result, idx_t result_idx) { - if (!root) { - return; - } idx_t vector_index = (row_id - column_data.start) / STANDARD_VECTOR_SIZE; - if (!root->info[vector_index]) { + auto entry = GetUpdateNode(vector_index); + if (!entry.IsSet()) { return; } idx_t row_in_vector = (row_id - column_data.start) - vector_index * STANDARD_VECTOR_SIZE; - fetch_row_function(transaction.start_time, transaction.transaction_id, root->info[vector_index]->info.get(), - row_in_vector, result, result_idx); + auto pin = entry.Pin(); + fetch_row_function(transaction.start_time, transaction.transaction_id, UpdateInfo::Get(pin), row_in_vector, result, + result_idx); } //===--------------------------------------------------------------------===// @@ -445,12 +498,14 @@ void UpdateSegment::FetchRow(TransactionData transaction, idx_t row_id, Vector & //===--------------------------------------------------------------------===// template static void RollbackUpdate(UpdateInfo &base_info, UpdateInfo &rollback_info) { - auto base_data = (T *)base_info.tuple_data; - auto rollback_data = (T *)rollback_info.tuple_data; + auto base_data = base_info.GetData(); + auto base_tuples = base_info.GetTuples(); + auto rollback_data = rollback_info.GetData(); + auto rollback_tuples = rollback_info.GetTuples(); idx_t base_offset = 0; for (idx_t i = 0; i < rollback_info.N; i++) { - auto id = rollback_info.tuples[i]; - while (base_info.tuples[base_offset] < id) { + auto id = rollback_tuples[i]; + while (base_tuples[base_offset] < id) { base_offset++; D_ASSERT(base_offset < base_info.N); } @@ -501,10 +556,12 @@ void UpdateSegment::RollbackUpdate(UpdateInfo &info) { auto lock_handle = lock.GetExclusiveLock(); // move the data from the UpdateInfo back into the base info - if (!root->info[info.vector_index]) { + auto entry = GetUpdateNode(info.vector_index); + if (!entry.IsSet()) { return; } - rollback_update_function(*root->info[info.vector_index]->info, info); + auto pin = entry.Pin(); + rollback_update_function(UpdateInfo::Get(pin), info); // clean up the update chain CleanupUpdateInternal(*lock_handle, info); @@ -514,11 +571,18 @@ void UpdateSegment::RollbackUpdate(UpdateInfo &info) { // Cleanup Update //===--------------------------------------------------------------------===// void UpdateSegment::CleanupUpdateInternal(const StorageLockKey &lock, UpdateInfo &info) { - D_ASSERT(info.prev); + D_ASSERT(info.HasPrev()); auto prev = info.prev; - prev->next = info.next; - if (prev->next) { - prev->next->prev = prev; + { + auto pin = prev.Pin(); + auto &prev_info = UpdateInfo::Get(pin); + prev_info.next = info.next; + } + if (info.HasNext()) { + auto next = info.next; + auto next_pin = next.Pin(); + auto &next_info = UpdateInfo::Get(next_pin); + next_info.prev = prev; } } @@ -531,38 +595,40 @@ void UpdateSegment::CleanupUpdate(UpdateInfo &info) { //===--------------------------------------------------------------------===// // Check for conflicts in update //===--------------------------------------------------------------------===// -static void CheckForConflicts(UpdateInfo *info, TransactionData transaction, row_t *ids, const SelectionVector &sel, - idx_t count, row_t offset, UpdateInfo *&node) { - if (!info) { - return; - } - if (info->version_number == transaction.transaction_id) { - // this UpdateInfo belongs to the current transaction, set it in the node - node = info; - } else if (info->version_number > transaction.start_time) { - // potential conflict, check that tuple ids do not conflict - // as both ids and info->tuples are sorted, this is similar to a merge join - idx_t i = 0, j = 0; - while (true) { - auto id = ids[sel.get_index(i)] - offset; - if (id == info->tuples[j]) { - throw TransactionException("Conflict on update!"); - } else if (id < info->tuples[j]) { - // id < the current tuple in info, move to next id - i++; - if (i == count) { - break; - } - } else { - // id > the current tuple, move to next tuple in info - j++; - if (j == info->N) { - break; +static void CheckForConflicts(UndoBufferPointer next_ptr, TransactionData transaction, row_t *ids, + const SelectionVector &sel, idx_t count, row_t offset, UndoBufferReference &node_ref) { + while (next_ptr.IsSet()) { + auto pin = next_ptr.Pin(); + auto &info = UpdateInfo::Get(pin); + if (info.version_number == transaction.transaction_id) { + // this UpdateInfo belongs to the current transaction, set it in the node + node_ref = std::move(pin); + } else if (info.version_number > transaction.start_time) { + // potential conflict, check that tuple ids do not conflict + // as both ids and info->tuples are sorted, this is similar to a merge join + idx_t i = 0, j = 0; + auto tuples = info.GetTuples(); + while (true) { + auto id = ids[sel.get_index(i)] - offset; + if (id == tuples[j]) { + throw TransactionException("Conflict on update!"); + } else if (id < tuples[j]) { + // id < the current tuple in info, move to next id + i++; + if (i == count) { + break; + } + } else { + // id > the current tuple, move to next tuple in info + j++; + if (j == info.N) { + break; + } } } } + next_ptr = info.next; } - CheckForConflicts(info->next, transaction, ids, sel, count, offset, node); } //===--------------------------------------------------------------------===// @@ -572,43 +638,45 @@ void UpdateSegment::InitializeUpdateInfo(UpdateInfo &info, row_t *ids, const Sel idx_t vector_index, idx_t vector_offset) { info.segment = this; info.vector_index = vector_index; - info.prev = nullptr; - info.next = nullptr; + info.prev = UndoBufferPointer(); + info.next = UndoBufferPointer(); // set up the tuple ids info.N = UnsafeNumericCast(count); + auto tuples = info.GetTuples(); for (idx_t i = 0; i < count; i++) { auto idx = sel.get_index(i); auto id = ids[idx]; D_ASSERT(idx_t(id) >= vector_offset && idx_t(id) < vector_offset + STANDARD_VECTOR_SIZE); - info.tuples[i] = NumericCast(NumericCast(id) - vector_offset); + tuples[i] = NumericCast(NumericCast(id) - vector_offset); }; } -static void InitializeUpdateValidity(UpdateInfo *base_info, Vector &base_data, UpdateInfo *update_info, Vector &update, +static void InitializeUpdateValidity(UpdateInfo &base_info, Vector &base_data, UpdateInfo &update_info, Vector &update, const SelectionVector &sel) { auto &update_mask = FlatVector::Validity(update); - auto tuple_data = reinterpret_cast(update_info->tuple_data); + auto tuple_data = update_info.GetData(); if (!update_mask.AllValid()) { - for (idx_t i = 0; i < update_info->N; i++) { + for (idx_t i = 0; i < update_info.N; i++) { auto idx = sel.get_index(i); tuple_data[i] = update_mask.RowIsValidUnsafe(idx); } } else { - for (idx_t i = 0; i < update_info->N; i++) { + for (idx_t i = 0; i < update_info.N; i++) { tuple_data[i] = true; } } auto &base_mask = FlatVector::Validity(base_data); - auto base_tuple_data = reinterpret_cast(base_info->tuple_data); + auto base_tuple_data = base_info.GetData(); + auto base_tuples = base_info.GetTuples(); if (!base_mask.AllValid()) { - for (idx_t i = 0; i < base_info->N; i++) { - base_tuple_data[i] = base_mask.RowIsValidUnsafe(base_info->tuples[i]); + for (idx_t i = 0; i < base_info.N; i++) { + base_tuple_data[i] = base_mask.RowIsValidUnsafe(base_tuples[i]); } } else { - for (idx_t i = 0; i < base_info->N; i++) { + for (idx_t i = 0; i < base_info.N; i++) { base_tuple_data[i] = true; } } @@ -616,36 +684,37 @@ static void InitializeUpdateValidity(UpdateInfo *base_info, Vector &base_data, U struct UpdateSelectElement { template - static T Operation(UpdateSegment *segment, T element) { + static T Operation(UpdateSegment &segment, T element) { return element; } }; template <> -string_t UpdateSelectElement::Operation(UpdateSegment *segment, string_t element) { - return element.IsInlined() ? element : segment->GetStringHeap().AddBlob(element); +string_t UpdateSelectElement::Operation(UpdateSegment &segment, string_t element) { + return element.IsInlined() ? element : segment.GetStringHeap().AddBlob(element); } template -static void InitializeUpdateData(UpdateInfo *base_info, Vector &base_data, UpdateInfo *update_info, Vector &update, +static void InitializeUpdateData(UpdateInfo &base_info, Vector &base_data, UpdateInfo &update_info, Vector &update, const SelectionVector &sel) { auto update_data = FlatVector::GetData(update); - auto tuple_data = (T *)update_info->tuple_data; + auto tuple_data = update_info.GetData(); - for (idx_t i = 0; i < update_info->N; i++) { + for (idx_t i = 0; i < update_info.N; i++) { auto idx = sel.get_index(i); tuple_data[i] = update_data[idx]; } auto base_array_data = FlatVector::GetData(base_data); auto &base_validity = FlatVector::Validity(base_data); - auto base_tuple_data = (T *)base_info->tuple_data; - for (idx_t i = 0; i < base_info->N; i++) { - auto base_idx = base_info->tuples[i]; + auto base_tuple_data = base_info.GetData(); + auto base_tuples = base_info.GetTuples(); + for (idx_t i = 0; i < base_info.N; i++) { + auto base_idx = base_tuples[i]; if (!base_validity.RowIsValid(base_idx)) { continue; } - base_tuple_data[i] = UpdateSelectElement::Operation(base_info->segment, base_array_data[base_idx]); + base_tuple_data[i] = UpdateSelectElement::Operation(*base_info.segment, base_array_data[base_idx]); } } @@ -741,9 +810,9 @@ struct ExtractValidityEntry { }; template -static void MergeUpdateLoopInternal(UpdateInfo *base_info, V *base_table_data, UpdateInfo *update_info, +static void MergeUpdateLoopInternal(UpdateInfo &base_info, V *base_table_data, UpdateInfo &update_info, V *update_vector_data, row_t *ids, idx_t count, const SelectionVector &sel) { - auto base_id = base_info->segment->column_data.start + base_info->vector_index * STANDARD_VECTOR_SIZE; + auto base_id = base_info.segment->column_data.start + base_info.vector_index * STANDARD_VECTOR_SIZE; #ifdef DEBUG // all of these should be sorted, otherwise the below algorithm does not work for (idx_t i = 1; i < count; i++) { @@ -759,8 +828,10 @@ static void MergeUpdateLoopInternal(UpdateInfo *base_info, V *base_table_data, U // and potentially, this transaction already has updates present (update_info) // we need to merge these all together so that the latest updates get merged into base_info // and the "old" values (fetched from EITHER base_info OR from base_data) get placed into update_info - auto base_info_data = (T *)base_info->tuple_data; - auto update_info_data = (T *)update_info->tuple_data; + auto base_info_data = base_info.GetData(); + auto base_tuples = base_info.GetTuples(); + auto update_info_data = update_info.GetData(); + auto update_tuples = update_info.GetTuples(); // we first do the merging of the old values // what we are trying to do here is update the "update_info" of this transaction with all the old data we require @@ -779,45 +850,45 @@ static void MergeUpdateLoopInternal(UpdateInfo *base_info, V *base_table_data, U // we have to merge the info for "ids[i]" auto update_id = UnsafeNumericCast(ids[idx]) - base_id; - while (update_info_offset < update_info->N && update_info->tuples[update_info_offset] < update_id) { + while (update_info_offset < update_info.N && update_tuples[update_info_offset] < update_id) { // old id comes before the current id: write it result_values[result_offset] = update_info_data[update_info_offset]; - result_ids[result_offset++] = update_info->tuples[update_info_offset]; + result_ids[result_offset++] = update_tuples[update_info_offset]; update_info_offset++; } // write the new id - if (update_info_offset < update_info->N && update_info->tuples[update_info_offset] == update_id) { + if (update_info_offset < update_info.N && update_tuples[update_info_offset] == update_id) { // we have an id that is equivalent in the current update info: write the update info result_values[result_offset] = update_info_data[update_info_offset]; - result_ids[result_offset++] = update_info->tuples[update_info_offset]; + result_ids[result_offset++] = update_tuples[update_info_offset]; update_info_offset++; continue; } /// now check if we have the current update_id in the base_info, or if we should fetch it from the base data - while (base_info_offset < base_info->N && base_info->tuples[base_info_offset] < update_id) { + while (base_info_offset < base_info.N && base_tuples[base_info_offset] < update_id) { base_info_offset++; } - if (base_info_offset < base_info->N && base_info->tuples[base_info_offset] == update_id) { + if (base_info_offset < base_info.N && base_tuples[base_info_offset] == update_id) { // it is! we have to move the tuple from base_info->ids[base_info_offset] to update_info result_values[result_offset] = base_info_data[base_info_offset]; } else { // it is not! we have to move base_table_data[update_id] to update_info result_values[result_offset] = UpdateSelectElement::Operation( - base_info->segment, OP::template Extract(base_table_data, update_id)); + *base_info.segment, OP::template Extract(base_table_data, update_id)); } result_ids[result_offset++] = UnsafeNumericCast(update_id); } // write any remaining entries from the old updates - while (update_info_offset < update_info->N) { + while (update_info_offset < update_info.N) { result_values[result_offset] = update_info_data[update_info_offset]; - result_ids[result_offset++] = update_info->tuples[update_info_offset]; + result_ids[result_offset++] = update_tuples[update_info_offset]; update_info_offset++; } // now copy them back - update_info->N = UnsafeNumericCast(result_offset); + update_info.N = UnsafeNumericCast(result_offset); memcpy(update_info_data, result_values, result_offset * sizeof(T)); - memcpy(update_info->tuples, result_ids, result_offset * sizeof(sel_t)); + memcpy(update_tuples, result_ids, result_offset * sizeof(sel_t)); // now we merge the new values into the base_info result_offset = 0; @@ -835,14 +906,14 @@ static void MergeUpdateLoopInternal(UpdateInfo *base_info, V *base_table_data, U auto merge = [&](idx_t id, idx_t aidx, idx_t bidx, idx_t count) { pick_new(id, aidx, count); }; - MergeLoop(ids, base_info->tuples, count, base_info->N, base_id, merge, pick_new, pick_old, sel); + MergeLoop(ids, base_tuples, count, base_info.N, base_id, merge, pick_new, pick_old, sel); - base_info->N = UnsafeNumericCast(result_offset); + base_info.N = UnsafeNumericCast(result_offset); memcpy(base_info_data, result_values, result_offset * sizeof(T)); - memcpy(base_info->tuples, result_ids, result_offset * sizeof(sel_t)); + memcpy(base_tuples, result_ids, result_offset * sizeof(sel_t)); } -static void MergeValidityLoop(UpdateInfo *base_info, Vector &base_data, UpdateInfo *update_info, Vector &update, +static void MergeValidityLoop(UpdateInfo &base_info, Vector &base_data, UpdateInfo &update_info, Vector &update, row_t *ids, idx_t count, const SelectionVector &sel) { auto &base_validity = FlatVector::Validity(base_data); auto &update_validity = FlatVector::Validity(update); @@ -851,7 +922,7 @@ static void MergeValidityLoop(UpdateInfo *base_info, Vector &base_data, UpdateIn } template -static void MergeUpdateLoop(UpdateInfo *base_info, Vector &base_data, UpdateInfo *update_info, Vector &update, +static void MergeUpdateLoop(UpdateInfo &base_info, Vector &base_data, UpdateInfo &update_info, Vector &update, row_t *ids, idx_t count, const SelectionVector &sel) { auto base_table_data = FlatVector::GetData(base_data); auto update_vector_data = FlatVector::GetData(update); @@ -1062,16 +1133,26 @@ static idx_t SortSelectionVector(SelectionVector &sel, idx_t count, row_t *ids) UpdateInfo *CreateEmptyUpdateInfo(TransactionData transaction, idx_t type_size, idx_t count, unsafe_unique_array &data) { - data = make_unsafe_uniq_array_uninitialized(sizeof(UpdateInfo) + - (sizeof(sel_t) + type_size) * STANDARD_VECTOR_SIZE); + data = make_unsafe_uniq_array_uninitialized(UpdateInfo::GetAllocSize(type_size)); auto update_info = reinterpret_cast(data.get()); - update_info->max = STANDARD_VECTOR_SIZE; - update_info->tuples = reinterpret_cast((data_ptr_cast(update_info)) + sizeof(UpdateInfo)); - update_info->tuple_data = (data_ptr_cast(update_info)) + sizeof(UpdateInfo) + sizeof(sel_t) * update_info->max; - update_info->version_number = transaction.transaction_id; + UpdateInfo::Initialize(*update_info, transaction.transaction_id); return update_info; } +void UpdateSegment::InitializeUpdateInfo(idx_t vector_idx) { + // create the versions for this segment, if there are none yet + if (!root) { + root = make_uniq(column_data.block_manager.buffer_manager); + } + if (vector_idx < root->info.size()) { + return; + } + root->info.reserve(vector_idx + 1); + for (idx_t i = root->info.size(); i <= vector_idx; i++) { + root->info.emplace_back(); + } +} + void UpdateSegment::Update(TransactionData transaction, idx_t column_index, Vector &update, row_t *ids, idx_t count, Vector &base_data) { // obtain an exclusive lock @@ -1096,45 +1177,35 @@ void UpdateSegment::Update(TransactionData transaction, idx_t column_index, Vect count = SortSelectionVector(sel, count, ids); D_ASSERT(count > 0); - // create the versions for this segment, if there are none yet - if (!root) { - root = make_uniq(); - } - // get the vector index based on the first id // we assert that all updates must be part of the same vector auto first_id = ids[sel.get_index(0)]; idx_t vector_index = (UnsafeNumericCast(first_id) - column_data.start) / STANDARD_VECTOR_SIZE; idx_t vector_offset = column_data.start + vector_index * STANDARD_VECTOR_SIZE; + InitializeUpdateInfo(vector_index); D_ASSERT(idx_t(first_id) >= column_data.start); - D_ASSERT(vector_index < Storage::ROW_GROUP_VECTOR_COUNT); - - // first check the version chain - UpdateInfo *node = nullptr; - if (root->info[vector_index]) { + if (root->info[vector_index].IsSet()) { // there is already a version here, check if there are any conflicts and search for the node that belongs to // this transaction in the version chain - auto base_info = root->info[vector_index]->info.get(); - CheckForConflicts(base_info->next, transaction, ids, sel, count, UnsafeNumericCast(vector_offset), node); - - // there are no conflicts - // first, check if this thread has already done any updates - auto node = base_info->next; - while (node) { - if (node->version_number == transaction.transaction_id) { - // it has! use this node - break; - } - node = node->next; - } + auto root_pointer = root->info[vector_index]; + auto root_pin = root_pointer.Pin(); + auto &base_info = UpdateInfo::Get(root_pin); + + UndoBufferReference node_ref; + CheckForConflicts(base_info.next, transaction, ids, sel, count, UnsafeNumericCast(vector_offset), + node_ref); + + // there are no conflicts - continue with the update unsafe_unique_array update_info_data; - if (!node) { + optional_ptr node; + if (!node_ref.IsSet()) { // no updates made yet by this transaction: initially the update info to empty if (transaction.transaction) { auto &dtransaction = transaction.transaction->Cast(); - node = dtransaction.CreateUpdateInfo(type_size, count); + node_ref = dtransaction.CreateUpdateInfo(type_size, count); + node = &UpdateInfo::Get(node_ref); } else { node = CreateEmptyUpdateInfo(transaction, type_size, count, update_info_data); } @@ -1144,39 +1215,44 @@ void UpdateSegment::Update(TransactionData transaction, idx_t column_index, Vect node->column_index = column_index; // insert the new node into the chain - node->next = base_info->next; - if (node->next) { - node->next->prev = node; + node->next = base_info.next; + if (node->next.IsSet()) { + auto next_pin = node->next.Pin(); + auto &next_info = UpdateInfo::Get(next_pin); + next_info.prev = node_ref.GetBufferPointer(); } - node->prev = base_info; - base_info->next = transaction.transaction ? node : nullptr; + node->prev = root_pointer; + base_info.next = transaction.transaction ? node_ref.GetBufferPointer() : UndoBufferPointer(); + } else { + // we already had updates made to this transaction + node = &UpdateInfo::Get(node_ref); } - base_info->Verify(); + base_info.Verify(); node->Verify(); // now we are going to perform the merge - merge_update_function(base_info, base_data, node, update, ids, count, sel); + merge_update_function(base_info, base_data, *node, update, ids, count, sel); - base_info->Verify(); + base_info.Verify(); node->Verify(); } else { // there is no version info yet: create the top level update info and fill it with the updates - auto result = make_uniq(); + // allocate space for the UpdateInfo in the allocator + idx_t alloc_size = UpdateInfo::GetAllocSize(type_size); + auto handle = root->allocator.Allocate(alloc_size); + auto &update_info = UpdateInfo::Get(handle); + UpdateInfo::Initialize(update_info, TRANSACTION_ID_START - 1); + update_info.column_index = column_index; - result->info = make_uniq(); - result->tuples = make_unsafe_uniq_array_uninitialized(STANDARD_VECTOR_SIZE); - result->tuple_data = make_unsafe_uniq_array_uninitialized(STANDARD_VECTOR_SIZE * type_size); - result->info->tuples = result->tuples.get(); - result->info->tuple_data = result->tuple_data.get(); - result->info->version_number = TRANSACTION_ID_START - 1; - result->info->column_index = column_index; - InitializeUpdateInfo(*result->info, ids, sel, count, vector_index, vector_offset); + InitializeUpdateInfo(update_info, ids, sel, count, vector_index, vector_offset); // now create the transaction level update info in the undo log unsafe_unique_array update_info_data; - UpdateInfo *transaction_node; + UndoBufferReference node_ref; + optional_ptr transaction_node; if (transaction.transaction) { - transaction_node = transaction.transaction->CreateUpdateInfo(type_size, count); + node_ref = transaction.transaction->CreateUpdateInfo(type_size, count); + transaction_node = &UpdateInfo::Get(node_ref); } else { transaction_node = CreateEmptyUpdateInfo(transaction, type_size, count, update_info_data); } @@ -1184,18 +1260,18 @@ void UpdateSegment::Update(TransactionData transaction, idx_t column_index, Vect InitializeUpdateInfo(*transaction_node, ids, sel, count, vector_index, vector_offset); // we write the updates in the update node data, and write the updates in the info - initialize_update_function(transaction_node, base_data, result->info.get(), update, sel); + initialize_update_function(*transaction_node, base_data, update_info, update, sel); - result->info->next = transaction.transaction ? transaction_node : nullptr; - result->info->prev = nullptr; - transaction_node->next = nullptr; - transaction_node->prev = result->info.get(); + update_info.next = transaction.transaction ? node_ref.GetBufferPointer() : UndoBufferPointer(); + update_info.prev = UndoBufferPointer(); + transaction_node->next = UndoBufferPointer(); + transaction_node->prev = handle.GetBufferPointer(); transaction_node->column_index = column_index; transaction_node->Verify(); - result->info->Verify(); + update_info.Verify(); - root->info[vector_index] = std::move(result); + root->info[vector_index] = handle.GetBufferPointer(); } } @@ -1204,33 +1280,34 @@ bool UpdateSegment::HasUpdates() const { } bool UpdateSegment::HasUpdates(idx_t vector_index) const { - if (!HasUpdates()) { - return false; - } - return root->info[vector_index].get(); + auto read_lock = lock.GetSharedLock(); + return GetUpdateNode(vector_index).IsSet(); } bool UpdateSegment::HasUncommittedUpdates(idx_t vector_index) { - if (!HasUpdates(vector_index)) { + auto read_lock = lock.GetSharedLock(); + auto entry = GetUpdateNode(vector_index); + if (!entry.IsSet()) { return false; } - auto read_lock = lock.GetSharedLock(); - auto entry = root->info[vector_index].get(); - if (entry->info->next) { + auto pin = entry.Pin(); + auto &info = UpdateInfo::Get(pin); + if (info.HasNext()) { return true; } return false; } bool UpdateSegment::HasUpdates(idx_t start_row_index, idx_t end_row_index) { - if (!HasUpdates()) { + auto read_lock = lock.GetSharedLock(); + if (!root) { return false; } - auto read_lock = lock.GetSharedLock(); idx_t base_vector_index = start_row_index / STANDARD_VECTOR_SIZE; idx_t end_vector_index = end_row_index / STANDARD_VECTOR_SIZE; for (idx_t i = base_vector_index; i <= end_vector_index; i++) { - if (root->info[i]) { + auto entry = GetUpdateNode(i); + if (entry.IsSet()) { return true; } } diff --git a/src/duckdb/src/storage/table_index_list.cpp b/src/duckdb/src/storage/table_index_list.cpp index c505d0a05..426568ae0 100644 --- a/src/duckdb/src/storage/table_index_list.cpp +++ b/src/duckdb/src/storage/table_index_list.cpp @@ -22,7 +22,6 @@ void TableIndexList::RemoveIndex(const string &name) { for (idx_t index_idx = 0; index_idx < indexes.size(); index_idx++) { auto &index_entry = indexes[index_idx]; - if (index_entry->GetIndexName() == name) { indexes.erase_at(index_idx); break; @@ -94,8 +93,7 @@ void TableIndexList::InitializeIndexes(ClientContext &context, DataTableInfo &ta // Add the table to the binder // We're not interested in the column_ids here, so just pass a dummy vector vector dummy_column_ids; - binder->bind_context.AddBaseTable(0, table_info.GetTableName(), column_names, column_types, - dummy_column_ids, &table); + binder->bind_context.AddBaseTable(0, string(), column_names, column_types, dummy_column_ids, table); // Create an IndexBinder to bind the index IndexBinder idx_binder(*binder, context); diff --git a/src/duckdb/src/storage/temporary_file_manager.cpp b/src/duckdb/src/storage/temporary_file_manager.cpp index 845f295e0..6aa5a3464 100644 --- a/src/duckdb/src/storage/temporary_file_manager.cpp +++ b/src/duckdb/src/storage/temporary_file_manager.cpp @@ -1,26 +1,104 @@ #include "duckdb/storage/temporary_file_manager.hpp" + +#include "duckdb/common/chrono.hpp" +#include "duckdb/common/enum_util.hpp" +#include "duckdb/parallel/task_scheduler.hpp" #include "duckdb/storage/buffer/temporary_file_information.hpp" #include "duckdb/storage/standard_buffer_manager.hpp" +#include "zstd.h" namespace duckdb { //===--------------------------------------------------------------------===// -// BlockIndexManager +// TemporaryBufferSize //===--------------------------------------------------------------------===// +static bool TemporaryBufferSizeIsValid(const TemporaryBufferSize size) { + switch (size) { + case TemporaryBufferSize::S32K: + case TemporaryBufferSize::S64K: + case TemporaryBufferSize::S96K: + case TemporaryBufferSize::S128K: + case TemporaryBufferSize::S160K: + case TemporaryBufferSize::S192K: + case TemporaryBufferSize::S224K: + case TemporaryBufferSize::DEFAULT: + return true; + default: + return false; + } +} -BlockIndexManager::BlockIndexManager(TemporaryFileManager &manager) : max_index(0), manager(&manager) { +static TemporaryBufferSize SizeToTemporaryBufferSize(const idx_t size) { + D_ASSERT(size != 0 && size % TEMPORARY_BUFFER_SIZE_GRANULARITY == 0); + const auto res = static_cast(size); + D_ASSERT(TemporaryBufferSizeIsValid(res)); + return res; +} + +static idx_t TemporaryBufferSizeToSize(const TemporaryBufferSize size) { + D_ASSERT(TemporaryBufferSizeIsValid(size)); + return static_cast(size); +} + +static TemporaryBufferSize RoundUpSizeToTemporaryBufferSize(const idx_t size) { + return SizeToTemporaryBufferSize(AlignValue(size)); +} + +static const vector TemporaryBufferSizes() { + return {TemporaryBufferSize::S32K, TemporaryBufferSize::S64K, TemporaryBufferSize::S96K, + TemporaryBufferSize::S128K, TemporaryBufferSize::S160K, TemporaryBufferSize::S192K, + TemporaryBufferSize::S224K, TemporaryBufferSize::DEFAULT}; +} + +static TemporaryBufferSize MinimumCompressedTemporaryBufferSize() { + return TemporaryBufferSize::S32K; } +static TemporaryBufferSize MaximumCompressedTemporaryBufferSize() { + return TemporaryBufferSize::S224K; +} + +//===--------------------------------------------------------------------===// +// TemporaryFileIdentifier/TemporaryFileIndex +//===--------------------------------------------------------------------===// +TemporaryFileIdentifier::TemporaryFileIdentifier() : size(TemporaryBufferSize::INVALID) { +} + +TemporaryFileIdentifier::TemporaryFileIdentifier(TemporaryBufferSize size_p, idx_t file_index_p) + : size(size_p), file_index(file_index_p) { +} + +bool TemporaryFileIdentifier::IsValid() const { + return size != TemporaryBufferSize::INVALID && file_index.IsValid(); +} + +TemporaryFileIndex::TemporaryFileIndex() { +} + +TemporaryFileIndex::TemporaryFileIndex(TemporaryFileIdentifier identifier_p, idx_t block_index_p) + : identifier(identifier_p), block_index(block_index_p) { +} + +bool TemporaryFileIndex::IsValid() const { + return identifier.IsValid() && block_index.IsValid(); +} + +//===--------------------------------------------------------------------===// +// BlockIndexManager +//===--------------------------------------------------------------------===// BlockIndexManager::BlockIndexManager() : max_index(0), manager(nullptr) { } -idx_t BlockIndexManager::GetNewBlockIndex() { - auto index = GetNewBlockIndexInternal(); +BlockIndexManager::BlockIndexManager(TemporaryFileManager &manager) : max_index(0), manager(&manager) { +} + +idx_t BlockIndexManager::GetNewBlockIndex(const TemporaryBufferSize size) { + auto index = GetNewBlockIndexInternal(size); indexes_in_use.insert(index); return index; } -bool BlockIndexManager::RemoveIndex(idx_t index) { +bool BlockIndexManager::RemoveIndex(idx_t index, const TemporaryBufferSize size) { // remove this block from the set of blocks auto entry = indexes_in_use.find(index); if (entry == indexes_in_use.end()) { @@ -35,9 +113,9 @@ bool BlockIndexManager::RemoveIndex(idx_t index) { if (max_index_in_use < max_index) { // max index in use is lower than the max_index // reduce the max_index - SetMaxIndex(max_index_in_use); + SetMaxIndex(max_index_in_use, size); // we can remove any free_indexes that are larger than the current max_index - while (!free_indexes.empty()) { + while (HasFreeBlocks()) { auto max_entry = *free_indexes.rbegin(); if (max_entry < max_index) { break; @@ -49,28 +127,41 @@ bool BlockIndexManager::RemoveIndex(idx_t index) { return false; } -idx_t BlockIndexManager::GetMaxIndex() { +idx_t BlockIndexManager::GetMaxIndex() const { return max_index; } -bool BlockIndexManager::HasFreeBlocks() { +bool BlockIndexManager::HasFreeBlocks() const { return !free_indexes.empty(); } -void BlockIndexManager::SetMaxIndex(idx_t new_index) { - static constexpr idx_t TEMP_FILE_BLOCK_SIZE = DEFAULT_BLOCK_ALLOC_SIZE; +idx_t BlockIndexManager::GetNewBlockIndexInternal(const TemporaryBufferSize size) { + if (!HasFreeBlocks()) { + auto new_index = max_index; + SetMaxIndex(max_index + 1, size); + return new_index; + } + auto entry = free_indexes.begin(); + auto index = *entry; + free_indexes.erase(entry); + return index; +} + +void BlockIndexManager::SetMaxIndex(const idx_t new_index, const TemporaryBufferSize size) { + const auto temp_file_block_size = + size == TemporaryBufferSize::DEFAULT ? DEFAULT_BLOCK_ALLOC_SIZE : TemporaryBufferSizeToSize(size); if (!manager) { max_index = new_index; } else { auto old = max_index; if (new_index < old) { max_index = new_index; - auto difference = old - new_index; - auto size_on_disk = difference * TEMP_FILE_BLOCK_SIZE; + const auto difference = old - new_index; + const auto size_on_disk = difference * temp_file_block_size; manager->DecreaseSizeOnDisk(size_on_disk); } else if (new_index > old) { - auto difference = new_index - old; - auto size_on_disk = difference * TEMP_FILE_BLOCK_SIZE; + const auto difference = new_index - old; + const auto size_on_disk = difference * temp_file_block_size; manager->IncreaseSizeOnDisk(size_on_disk); // Increase can throw, so this is only updated after it was successfully updated max_index = new_index; @@ -78,27 +169,13 @@ void BlockIndexManager::SetMaxIndex(idx_t new_index) { } } -idx_t BlockIndexManager::GetNewBlockIndexInternal() { - if (free_indexes.empty()) { - auto new_index = max_index; - SetMaxIndex(max_index + 1); - return new_index; - } - auto entry = free_indexes.begin(); - auto index = *entry; - free_indexes.erase(entry); - return index; -} - //===--------------------------------------------------------------------===// // TemporaryFileHandle //===--------------------------------------------------------------------===// - -TemporaryFileHandle::TemporaryFileHandle(idx_t temp_file_count, DatabaseInstance &db, const string &temp_directory, - idx_t index, TemporaryFileManager &manager) - : max_allowed_index((1 << temp_file_count) * MAX_ALLOWED_INDEX_BASE), db(db), file_index(index), - path(FileSystem::GetFileSystem(db).JoinPath(temp_directory, "duckdb_temp_storage-" + to_string(index) + ".tmp")), - index_manager(manager) { +TemporaryFileHandle::TemporaryFileHandle(TemporaryFileManager &manager, TemporaryFileIdentifier identifier_p, + idx_t temp_file_count) + : db(manager.db), identifier(identifier_p), max_allowed_index((1 << temp_file_count) * MAX_ALLOWED_INDEX_BASE), + path(manager.CreateTemporaryFileName(identifier)), index_manager(manager) { } TemporaryFileHandle::TemporaryFileLock::TemporaryFileLock(mutex &mutex) : lock(mutex) { @@ -113,21 +190,51 @@ TemporaryFileIndex TemporaryFileHandle::TryGetBlockIndex() { // open the file handle if it does not yet exist CreateFileIfNotExists(lock); // fetch a new block index to write to - auto block_index = index_manager.GetNewBlockIndex(); - return TemporaryFileIndex(file_index, block_index); + auto block_index = index_manager.GetNewBlockIndex(identifier.size); + return TemporaryFileIndex(identifier, block_index); } -void TemporaryFileHandle::WriteTemporaryFile(FileBuffer &buffer, TemporaryFileIndex index) { - // We group DEFAULT_BLOCK_ALLOC_SIZE blocks into the same file. - D_ASSERT(buffer.size == BufferManager::GetBufferManager(db).GetBlockSize()); - buffer.Write(*handle, GetPositionInFile(index.block_index)); +unique_ptr TemporaryFileHandle::ReadTemporaryBuffer(idx_t block_index, + unique_ptr reusable_buffer) const { + auto &buffer_manager = BufferManager::GetBufferManager(db); + if (identifier.size == TemporaryBufferSize::DEFAULT) { + return StandardBufferManager::ReadTemporaryBufferInternal( + buffer_manager, *handle, GetPositionInFile(block_index), buffer_manager.GetBlockSize(), + std::move(reusable_buffer)); + } + + // Read compressed buffer + auto compressed_buffer = Allocator::Get(db).Allocate(TemporaryBufferSizeToSize(identifier.size)); + handle->Read(compressed_buffer.get(), compressed_buffer.GetSize(), GetPositionInFile(block_index)); + + // Decompress into buffer + auto buffer = buffer_manager.ConstructManagedBuffer(buffer_manager.GetBlockSize(), std::move(reusable_buffer)); + + const auto compressed_size = Load(compressed_buffer.get()); + D_ASSERT(!duckdb_zstd::ZSTD_isError(compressed_size)); +#ifdef DEBUG + const auto decompressed_size = +#endif + duckdb_zstd::ZSTD_decompress(buffer->InternalBuffer(), buffer->AllocSize(), + compressed_buffer.get() + sizeof(idx_t), compressed_size); +#ifdef DEBUG + D_ASSERT(!duckdb_zstd::ZSTD_isError(decompressed_size)); +#endif + + D_ASSERT(decompressed_size == buffer->AllocSize()); + return buffer; } -unique_ptr TemporaryFileHandle::ReadTemporaryBuffer(idx_t block_index, - unique_ptr reusable_buffer) { - return StandardBufferManager::ReadTemporaryBufferInternal( - BufferManager::GetBufferManager(db), *handle, GetPositionInFile(block_index), - BufferManager::GetBufferManager(db).GetBlockSize(), std::move(reusable_buffer)); +void TemporaryFileHandle::WriteTemporaryBuffer(FileBuffer &buffer, const idx_t block_index, + AllocatedData &compressed_buffer) const { + // We group DEFAULT_BLOCK_ALLOC_SIZE blocks into the same file. + D_ASSERT(buffer.size == BufferManager::GetBufferManager(db).GetBlockSize()); + if (identifier.size == TemporaryBufferSize::DEFAULT) { + buffer.Write(*handle, GetPositionInFile(block_index)); + } else { + handle->Write(compressed_buffer.get(), TemporaryBufferSizeToSize(identifier.size), + GetPositionInFile(block_index)); + } } void TemporaryFileHandle::EraseBlockIndex(block_id_t block_index) { @@ -169,7 +276,7 @@ void TemporaryFileHandle::CreateFileIfNotExists(TemporaryFileLock &) { void TemporaryFileHandle::RemoveTempBlockIndex(TemporaryFileLock &, idx_t index) { // remove the block index from the index manager - if (index_manager.RemoveIndex(index)) { + if (index_manager.RemoveIndex(index, identifier.size)) { // the max_index that is currently in use has decreased // as a result we can truncate the file #ifndef WIN32 // this ended up causing issues when sorting @@ -180,113 +287,165 @@ void TemporaryFileHandle::RemoveTempBlockIndex(TemporaryFileLock &, idx_t index) } } -idx_t TemporaryFileHandle::GetPositionInFile(idx_t index) { - return index * BufferManager::GetBufferManager(db).GetBlockAllocSize(); +idx_t TemporaryFileHandle::GetPositionInFile(const idx_t index) const { + return index * static_cast(identifier.size); } //===--------------------------------------------------------------------===// -// TemporaryDirectoryHandle +// TemporaryFileMap //===--------------------------------------------------------------------===// +TemporaryFileMap::TemporaryFileMap(TemporaryFileManager &manager_p) : manager(manager_p) { +} -TemporaryDirectoryHandle::TemporaryDirectoryHandle(DatabaseInstance &db, string path_p, optional_idx max_swap_space) - : db(db), temp_directory(std::move(path_p)), temp_file(make_uniq(db, temp_directory)) { - auto &fs = FileSystem::GetFileSystem(db); - D_ASSERT(!temp_directory.empty()); - if (!fs.DirectoryExists(temp_directory)) { - fs.CreateDirectory(temp_directory); - created_directory = true; - } - temp_file->SetMaxSwapSpace(max_swap_space); +void TemporaryFileMap::Clear() { + files.clear(); } -TemporaryDirectoryHandle::~TemporaryDirectoryHandle() { - // first release any temporary files - temp_file.reset(); - // then delete the temporary file directory - auto &fs = FileSystem::GetFileSystem(db); - if (!temp_directory.empty()) { - bool delete_directory = created_directory; - vector files_to_delete; - if (!created_directory) { - bool deleted_everything = true; - fs.ListFiles(temp_directory, [&](const string &path, bool isdir) { - if (isdir) { - deleted_everything = false; - return; - } - if (!StringUtil::StartsWith(path, "duckdb_temp_")) { - deleted_everything = false; - return; - } - files_to_delete.push_back(path); - }); - } - if (delete_directory) { - // we want to remove all files in the directory - fs.RemoveDirectory(temp_directory); - } else { - for (auto &file : files_to_delete) { - fs.RemoveFile(fs.JoinPath(temp_directory, file)); - } - } - } +TemporaryFileMap::temporary_file_map_t &TemporaryFileMap::GetMapForSize(const TemporaryBufferSize size) { + D_ASSERT(TemporaryBufferSizeIsValid(size)); + return files[size]; } -TemporaryFileManager &TemporaryDirectoryHandle::GetTempFile() { - return *temp_file; +optional_ptr TemporaryFileMap::GetFile(const TemporaryFileIdentifier &identifier) { + D_ASSERT(identifier.IsValid()); + auto &map = GetMapForSize(identifier.size); + const auto it = map.find(identifier.file_index.GetIndex()); + return it == map.end() ? nullptr : it->second.get(); +} + +TemporaryFileHandle &TemporaryFileMap::CreateFile(const TemporaryFileIdentifier &identifier) { + D_ASSERT(identifier.IsValid()); + D_ASSERT(!GetFile(identifier)); + auto &map = GetMapForSize(identifier.size); + const auto res = + map.emplace(identifier.file_index.GetIndex(), make_uniq(manager, identifier, map.size())); + D_ASSERT(res.second); + return *res.first->second; +} + +void TemporaryFileMap::EraseFile(const TemporaryFileIdentifier &identifier) { + D_ASSERT(identifier.IsValid()); + D_ASSERT(GetFile(identifier)); + GetMapForSize(identifier.size).erase(identifier.file_index.GetIndex()); } //===--------------------------------------------------------------------===// -// TemporaryFileIndex +// TemporaryFileCompressionLevel/TemporaryFileCompressionAdaptivity //===--------------------------------------------------------------------===// +TemporaryFileCompressionAdaptivity::TemporaryFileCompressionAdaptivity() : last_uncompressed_write_ns(INITIAL_NS) { + for (idx_t i = 0; i < LEVELS; i++) { + last_compressed_writes_ns[i] = INITIAL_NS; + } +} -TemporaryFileIndex::TemporaryFileIndex(idx_t file_index, idx_t block_index) - : file_index(file_index), block_index(block_index) { +int64_t TemporaryFileCompressionAdaptivity::GetCurrentTimeNanos() { + return duration_cast(high_resolution_clock::now().time_since_epoch()).count(); } -bool TemporaryFileIndex::IsValid() const { - return block_index != DConstants::INVALID_INDEX; +TemporaryCompressionLevel TemporaryFileCompressionAdaptivity::IndexToLevel(const idx_t index) { + return static_cast(NumericCast(index) * 2 - 5); } -//===--------------------------------------------------------------------===// -// TemporaryFileManager -//===--------------------------------------------------------------------===// +idx_t TemporaryFileCompressionAdaptivity::LevelToIndex(const TemporaryCompressionLevel level) { + return NumericCast((static_cast(level) + 5) / 2); +} -static idx_t GetDefaultMax(const string &path) { - D_ASSERT(!path.empty()); - auto disk_space = FileSystem::GetAvailableDiskSpace(path); - // Use the available disk space - // We have made sure that the file exists before we call this, it shouldn't fail - if (!disk_space.IsValid()) { - // But if it does (i.e because the system call is not implemented) - // we don't cap the available swap space - return DConstants::INVALID_INDEX - 1; +TemporaryCompressionLevel TemporaryFileCompressionAdaptivity::MinimumCompressionLevel() { + return IndexToLevel(0); +} + +TemporaryCompressionLevel TemporaryFileCompressionAdaptivity::MaximumCompressionLevel() { + return IndexToLevel(LEVELS - 1); +} + +TemporaryCompressionLevel TemporaryFileCompressionAdaptivity::GetCompressionLevel() { + idx_t min_compression_idx = 0; + TemporaryCompressionLevel level; + + double ratio; + bool should_compress; + + bool should_deviate; + bool deviate_uncompressed; + { + lock_guard guard(random_engine.lock); + + auto min_compressed_time = last_compressed_writes_ns[min_compression_idx]; + for (idx_t compression_idx = 1; compression_idx < LEVELS; compression_idx++) { + const auto time = last_compressed_writes_ns[compression_idx]; + if (time < min_compressed_time) { + min_compression_idx = compression_idx; + min_compressed_time = time; + } + } + level = IndexToLevel(min_compression_idx); + + ratio = static_cast(min_compressed_time) / static_cast(last_uncompressed_write_ns); + should_compress = ratio < DURATION_RATIO_THRESHOLD; + + should_deviate = random_engine.NextRandom() < COMPRESSION_DEVIATION; + deviate_uncompressed = random_engine.NextRandom() < 0.5; // Coin flip to deviate with just uncompressed } - // Only use 90% of the available disk space - return static_cast(static_cast(disk_space.GetIndex()) * 0.9); + + TemporaryCompressionLevel result; + if (!should_deviate) { + result = should_compress ? level : TemporaryCompressionLevel::UNCOMPRESSED; // Don't deviate + } else if (!should_compress) { + result = MinimumCompressionLevel(); // Deviate from uncompressed -> go to fastest level + } else if (deviate_uncompressed) { + result = TemporaryCompressionLevel::UNCOMPRESSED; + } else if (level == MaximumCompressionLevel()) { + result = IndexToLevel(min_compression_idx - 1); // At highest level, go down one + } else if (ratio < 1.0) { // Compressed writes are faster, try increasing the compression level + result = IndexToLevel(min_compression_idx + 1); + } else { // Compressed writes are slower, try decreasing the compression level + result = level == MinimumCompressionLevel() + ? TemporaryCompressionLevel::UNCOMPRESSED // Already lowest level, go to uncompressed + : IndexToLevel(min_compression_idx - 1); + } + return result; +} + +void TemporaryFileCompressionAdaptivity::Update(const TemporaryCompressionLevel level, const int64_t time_before_ns) { + const auto duration = GetCurrentTimeNanos() - time_before_ns; + auto &last_write_ns = level == TemporaryCompressionLevel::UNCOMPRESSED + ? last_uncompressed_write_ns + : last_compressed_writes_ns[LevelToIndex(level)]; + lock_guard guard(random_engine.lock); + last_write_ns = (last_write_ns * (WEIGHT - 1) + duration) / WEIGHT; } +//===--------------------------------------------------------------------===// +// TemporaryFileManager +//===--------------------------------------------------------------------===// TemporaryFileManager::TemporaryFileManager(DatabaseInstance &db, const string &temp_directory_p) - : db(db), temp_directory(temp_directory_p), size_on_disk(0), max_swap_space(0) { + : db(db), temp_directory(temp_directory_p), files(*this), size_on_disk(0), max_swap_space(0) { } TemporaryFileManager::~TemporaryFileManager() { - files.clear(); + files.Clear(); } -TemporaryFileManager::TemporaryManagerLock::TemporaryManagerLock(mutex &mutex) : lock(mutex) { +TemporaryFileManager::TemporaryFileManagerLock::TemporaryFileManagerLock(mutex &mutex) : lock(mutex) { } void TemporaryFileManager::WriteTemporaryBuffer(block_id_t block_id, FileBuffer &buffer) { // We group DEFAULT_BLOCK_ALLOC_SIZE blocks into the same file. D_ASSERT(buffer.size == BufferManager::GetBufferManager(db).GetBlockSize()); - TemporaryFileIndex index; - TemporaryFileHandle *handle = nullptr; + const auto adaptivity_idx = TaskScheduler::GetEstimatedCPUId() % COMPRESSION_ADAPTIVITIES; + auto &compression_adaptivity = compression_adaptivities[adaptivity_idx]; + + const auto time_before_ns = TemporaryFileCompressionAdaptivity::GetCurrentTimeNanos(); + AllocatedData compressed_buffer; + const auto compression_result = CompressBuffer(compression_adaptivity, buffer, compressed_buffer); + + TemporaryFileIndex index; + optional_ptr handle; { - TemporaryManagerLock lock(manager_lock); + TemporaryFileManagerLock lock(manager_lock); // first check if we can write to an open existing file - for (auto &entry : files) { + for (auto &entry : files.GetMapForSize(compression_result.size)) { auto &temp_file = entry.second; index = temp_file->TryGetBlockIndex(); if (index.IsValid()) { @@ -296,19 +455,51 @@ void TemporaryFileManager::WriteTemporaryBuffer(block_id_t block_id, FileBuffer } if (!handle) { // no existing handle to write to; we need to create & open a new file - auto new_file_index = index_manager.GetNewBlockIndex(); - auto new_file = make_uniq(files.size(), db, temp_directory, new_file_index, *this); - handle = new_file.get(); - files[new_file_index] = std::move(new_file); - - index = handle->TryGetBlockIndex(); + auto &size = compression_result.size; + const TemporaryFileIdentifier identifier(size, index_managers[size].GetNewBlockIndex(size)); + auto &new_file = files.CreateFile(identifier); + index = new_file.TryGetBlockIndex(); + handle = &new_file; } D_ASSERT(used_blocks.find(block_id) == used_blocks.end()); used_blocks[block_id] = index; } D_ASSERT(handle); D_ASSERT(index.IsValid()); - handle->WriteTemporaryFile(buffer, index); + + handle->WriteTemporaryBuffer(buffer, index.block_index.GetIndex(), compressed_buffer); + + compression_adaptivity.Update(compression_result.level, time_before_ns); +} + +TemporaryFileManager::CompressionResult +TemporaryFileManager::CompressBuffer(TemporaryFileCompressionAdaptivity &compression_adaptivity, FileBuffer &buffer, + AllocatedData &compressed_buffer) { + if (buffer.AllocSize() <= TemporaryBufferSizeToSize(MinimumCompressedTemporaryBufferSize())) { + // Buffer size is less or equal to the minimum compressed size - no point compressing + return {TemporaryBufferSize::DEFAULT, TemporaryCompressionLevel::UNCOMPRESSED}; + } + + const auto level = compression_adaptivity.GetCompressionLevel(); + if (level == TemporaryCompressionLevel::UNCOMPRESSED) { + return {TemporaryBufferSize::DEFAULT, TemporaryCompressionLevel::UNCOMPRESSED}; + } + + const auto compression_level = static_cast(level); + D_ASSERT(compression_level >= duckdb_zstd::ZSTD_minCLevel() && compression_level <= duckdb_zstd::ZSTD_maxCLevel()); + const auto zstd_bound = duckdb_zstd::ZSTD_compressBound(buffer.AllocSize()); + compressed_buffer = Allocator::Get(db).Allocate(sizeof(idx_t) + zstd_bound); + const auto zstd_size = duckdb_zstd::ZSTD_compress(compressed_buffer.get() + sizeof(idx_t), zstd_bound, + buffer.InternalBuffer(), buffer.AllocSize(), compression_level); + D_ASSERT(!duckdb_zstd::ZSTD_isError(zstd_size)); + Store(zstd_size, compressed_buffer.get()); + const auto compressed_size = sizeof(idx_t) + zstd_size; + + if (compressed_size > TemporaryBufferSizeToSize(MaximumCompressedTemporaryBufferSize())) { + return {TemporaryBufferSize::DEFAULT, level}; // Use default size if compression ratio is bad + } + + return {RoundUpSizeToTemporaryBufferSize(compressed_size), level}; } bool TemporaryFileManager::HasTemporaryBuffer(block_id_t block_id) { @@ -316,7 +507,7 @@ bool TemporaryFileManager::HasTemporaryBuffer(block_id_t block_id) { return used_blocks.find(block_id) != used_blocks.end(); } -idx_t TemporaryFileManager::GetTotalUsedSpaceInBytes() { +idx_t TemporaryFileManager::GetTotalUsedSpaceInBytes() const { return size_on_disk.load(); } @@ -324,6 +515,20 @@ optional_idx TemporaryFileManager::GetMaxSwapSpace() const { return max_swap_space; } +static idx_t GetDefaultMax(const string &path) { + D_ASSERT(!path.empty()); + auto disk_space = FileSystem::GetAvailableDiskSpace(path); + // Use the available disk space + // We have made sure that the file exists before we call this, it shouldn't fail + if (!disk_space.IsValid()) { + // But if it does (i.e because the system call is not implemented) + // we don't cap the available swap space + return DConstants::INVALID_INDEX - 1; + } + // Only use 90% of the available disk space + return static_cast(static_cast(disk_space.GetIndex()) * 0.9); +} + void TemporaryFileManager::SetMaxSwapSpace(optional_idx limit) { idx_t new_limit; if (limit.IsValid()) { @@ -332,7 +537,7 @@ void TemporaryFileManager::SetMaxSwapSpace(optional_idx limit) { new_limit = GetDefaultMax(temp_directory); } - auto current_size_on_disk = size_on_disk.load(); + auto current_size_on_disk = GetTotalUsedSpaceInBytes(); if (current_size_on_disk > new_limit) { auto used = StringUtil::BytesToHumanReadableString(current_size_on_disk); auto max = StringUtil::BytesToHumanReadableString(new_limit); @@ -347,7 +552,7 @@ To get usage information of the temp_directory, use 'CALL duckdb_temporary_files } void TemporaryFileManager::IncreaseSizeOnDisk(idx_t bytes) { - auto current_size_on_disk = size_on_disk.load(); + auto current_size_on_disk = GetTotalUsedSpaceInBytes(); if (current_size_on_disk + bytes > max_swap_space) { auto used = StringUtil::BytesToHumanReadableString(current_size_on_disk); auto max = StringUtil::BytesToHumanReadableString(max_swap_space); @@ -368,63 +573,125 @@ void TemporaryFileManager::DecreaseSizeOnDisk(idx_t bytes) { unique_ptr TemporaryFileManager::ReadTemporaryBuffer(block_id_t id, unique_ptr reusable_buffer) { TemporaryFileIndex index; - TemporaryFileHandle *handle; + optional_ptr handle; { - TemporaryManagerLock lock(manager_lock); + TemporaryFileManagerLock lock(manager_lock); index = GetTempBlockIndex(lock, id); - handle = GetFileHandle(lock, index.file_index); + handle = GetFileHandle(lock, index.identifier); } - auto buffer = handle->ReadTemporaryBuffer(index.block_index, std::move(reusable_buffer)); + + auto buffer = handle->ReadTemporaryBuffer(index.block_index.GetIndex(), std::move(reusable_buffer)); { // remove the block (and potentially erase the temp file) - TemporaryManagerLock lock(manager_lock); - EraseUsedBlock(lock, id, handle, index); + TemporaryFileManagerLock lock(manager_lock); + EraseUsedBlock(lock, id, *handle, index); } return buffer; } void TemporaryFileManager::DeleteTemporaryBuffer(block_id_t id) { - TemporaryManagerLock lock(manager_lock); + TemporaryFileManagerLock lock(manager_lock); auto index = GetTempBlockIndex(lock, id); - auto handle = GetFileHandle(lock, index.file_index); - EraseUsedBlock(lock, id, handle, index); + auto handle = GetFileHandle(lock, index.identifier); + EraseUsedBlock(lock, id, *handle, index); } vector TemporaryFileManager::GetTemporaryFiles() { lock_guard lock(manager_lock); vector result; - for (auto &file : files) { - result.push_back(file.second->GetTemporaryFile()); + for (auto &size : TemporaryBufferSizes()) { + for (const auto &file : files.GetMapForSize(size)) { + result.push_back(file.second->GetTemporaryFile()); + } } return result; } -void TemporaryFileManager::EraseUsedBlock(TemporaryManagerLock &lock, block_id_t id, TemporaryFileHandle *handle, +void TemporaryFileManager::EraseUsedBlock(TemporaryFileManagerLock &lock, block_id_t id, TemporaryFileHandle &handle, TemporaryFileIndex index) { auto entry = used_blocks.find(id); if (entry == used_blocks.end()) { throw InternalException("EraseUsedBlock - Block %llu not found in used blocks", id); } used_blocks.erase(entry); - handle->EraseBlockIndex(NumericCast(index.block_index)); - if (handle->DeleteIfEmpty()) { - EraseFileHandle(lock, index.file_index); + handle.EraseBlockIndex(NumericCast(index.block_index.GetIndex())); + if (handle.DeleteIfEmpty()) { + EraseFileHandle(lock, index.identifier); } } -// FIXME: returning a raw pointer??? -TemporaryFileHandle *TemporaryFileManager::GetFileHandle(TemporaryManagerLock &, idx_t index) { - return files[index].get(); +string TemporaryFileManager::CreateTemporaryFileName(const TemporaryFileIdentifier &identifier) const { + return FileSystem::GetFileSystem(db).JoinPath( + temp_directory, StringUtil::Format("duckdb_temp_storage_%s-%llu.tmp", EnumUtil::ToString(identifier.size), + identifier.file_index.GetIndex())); } -TemporaryFileIndex TemporaryFileManager::GetTempBlockIndex(TemporaryManagerLock &, block_id_t id) { +optional_ptr TemporaryFileManager::GetFileHandle(TemporaryFileManagerLock &, + const TemporaryFileIdentifier &identifier) { + D_ASSERT(identifier.IsValid()); + return files.GetFile(identifier); +} + +TemporaryFileIndex TemporaryFileManager::GetTempBlockIndex(TemporaryFileManagerLock &, block_id_t id) { D_ASSERT(used_blocks.find(id) != used_blocks.end()); return used_blocks[id]; } -void TemporaryFileManager::EraseFileHandle(TemporaryManagerLock &, idx_t file_index) { - files.erase(file_index); - index_manager.RemoveIndex(file_index); +void TemporaryFileManager::EraseFileHandle(TemporaryFileManagerLock &, const TemporaryFileIdentifier &identifier) { + D_ASSERT(identifier.IsValid()); + files.EraseFile(identifier); + index_managers[identifier.size].RemoveIndex(identifier.file_index.GetIndex(), identifier.size); +} + +//===--------------------------------------------------------------------===// +// TemporaryDirectoryHandle +//===--------------------------------------------------------------------===// +TemporaryDirectoryHandle::TemporaryDirectoryHandle(DatabaseInstance &db, string path_p, optional_idx max_swap_space) + : db(db), temp_directory(std::move(path_p)), temp_file(make_uniq(db, temp_directory)) { + auto &fs = FileSystem::GetFileSystem(db); + D_ASSERT(!temp_directory.empty()); + if (!fs.DirectoryExists(temp_directory)) { + fs.CreateDirectory(temp_directory); + created_directory = true; + } + temp_file->SetMaxSwapSpace(max_swap_space); +} + +TemporaryDirectoryHandle::~TemporaryDirectoryHandle() { + // first release any temporary files + temp_file.reset(); + // then delete the temporary file directory + auto &fs = FileSystem::GetFileSystem(db); + if (!temp_directory.empty()) { + bool delete_directory = created_directory; + vector files_to_delete; + if (!created_directory) { + bool deleted_everything = true; + fs.ListFiles(temp_directory, [&](const string &path, bool isdir) { + if (isdir) { + deleted_everything = false; + return; + } + if (!StringUtil::StartsWith(path, "duckdb_temp_")) { + deleted_everything = false; + return; + } + files_to_delete.push_back(path); + }); + } + if (delete_directory) { + // we want to remove all files in the directory + fs.RemoveDirectory(temp_directory); + } else { + for (auto &file : files_to_delete) { + fs.RemoveFile(fs.JoinPath(temp_directory, file)); + } + } + } +} + +TemporaryFileManager &TemporaryDirectoryHandle::GetTempFile() const { + return *temp_file; } } // namespace duckdb diff --git a/src/duckdb/src/storage/wal_replay.cpp b/src/duckdb/src/storage/wal_replay.cpp index 6d77b071f..ab43e265c 100644 --- a/src/duckdb/src/storage/wal_replay.cpp +++ b/src/duckdb/src/storage/wal_replay.cpp @@ -370,12 +370,98 @@ void WriteAheadLogDeserializer::ReplayDropTable() { catalog.DropEntry(context, info); } +void ReplayWithoutIndex(ClientContext &context, Catalog &catalog, AlterInfo &info, const bool only_deserialize) { + if (only_deserialize) { + return; + } + catalog.Alter(context, info); +} + +void ReplayIndexData(AttachedDatabase &db, BinaryDeserializer &deserializer, IndexStorageInfo &info, + const bool deserialize_only) { + D_ASSERT(info.IsValid() && !info.name.empty()); + + auto &storage_manager = db.GetStorageManager(); + auto &single_file_sm = storage_manager.Cast(); + auto &block_manager = single_file_sm.block_manager; + auto &buffer_manager = block_manager->buffer_manager; + + deserializer.ReadList(103, "index_storage", [&](Deserializer::List &list, idx_t i) { + auto &data_info = info.allocator_infos[i]; + + // Read the data into buffer handles and convert them to blocks on disk. + for (idx_t j = 0; j < data_info.allocation_sizes.size(); j++) { + + // Read the data into a buffer handle. + auto buffer_handle = buffer_manager.Allocate(MemoryTag::ART_INDEX, block_manager->GetBlockSize(), false); + auto block_handle = buffer_handle.GetBlockHandle(); + auto data_ptr = buffer_handle.Ptr(); + + list.ReadElement(data_ptr, data_info.allocation_sizes[j]); + + // Convert the buffer handle to a persistent block and store the block id. + if (!deserialize_only) { + auto block_id = block_manager->GetFreeBlockId(); + block_manager->ConvertToPersistent(block_id, std::move(block_handle)); + data_info.block_pointers[j].block_id = block_id; + } + } + }); +} + void WriteAheadLogDeserializer::ReplayAlter() { auto info = deserializer.ReadProperty>(101, "info"); auto &alter_info = info->Cast(); + if (!alter_info.IsAddPrimaryKey()) { + return ReplayWithoutIndex(context, catalog, alter_info, DeserializeOnly()); + } + + auto index_storage_info = deserializer.ReadProperty(102, "index_storage_info"); + ReplayIndexData(db, deserializer, index_storage_info, DeserializeOnly()); if (DeserializeOnly()) { return; } + + auto &table_info = alter_info.Cast(); + auto &constraint_info = table_info.Cast(); + auto &unique_info = constraint_info.constraint->Cast(); + + auto &table = + catalog.GetEntry(context, table_info.schema, table_info.name).Cast(); + auto &column_list = table.GetColumns(); + + // Add the table to the bind context to bind the parsed expressions. + auto binder = Binder::CreateBinder(context); + vector column_types; + vector column_names; + for (auto &col : column_list.Logical()) { + column_types.push_back(col.Type()); + column_names.push_back(col.Name()); + } + + // Create a binder to bind the parsed expressions. + vector column_ids; + binder->bind_context.AddBaseTable(0, string(), column_names, column_types, column_ids, table); + IndexBinder idx_binder(*binder, context); + + // Bind the parsed expressions to create unbound expressions. + vector> unbound_expressions; + auto logical_indexes = unique_info.GetLogicalIndexes(column_list); + for (const auto &logical_index : logical_indexes) { + auto &col = column_list.GetColumn(logical_index); + unique_ptr parsed = make_uniq(col.GetName(), table_info.name); + unbound_expressions.push_back(idx_binder.Bind(parsed)); + } + + auto &storage = table.GetStorage(); + CreateIndexInput input(TableIOManager::Get(storage), storage.db, IndexConstraintType::PRIMARY, + index_storage_info.name, column_ids, unbound_expressions, index_storage_info, + index_storage_info.options); + + auto index_type = context.db->config.GetIndexTypes().FindByName(ART::TYPE_NAME); + auto index_instance = index_type->create_instance(input); + storage.AddIndex(std::move(index_instance)); + catalog.Alter(context, alter_info); } @@ -539,40 +625,15 @@ void WriteAheadLogDeserializer::ReplayDropTableMacro() { void WriteAheadLogDeserializer::ReplayCreateIndex() { auto create_info = deserializer.ReadProperty>(101, "index_catalog_entry"); auto index_info = deserializer.ReadProperty(102, "index_storage_info"); - D_ASSERT(index_info.IsValid() && !index_info.name.empty()); - - auto &storage_manager = db.GetStorageManager(); - auto &single_file_sm = storage_manager.Cast(); - auto &block_manager = single_file_sm.block_manager; - auto &buffer_manager = block_manager->buffer_manager; - - deserializer.ReadList(103, "index_storage", [&](Deserializer::List &list, idx_t i) { - auto &data_info = index_info.allocator_infos[i]; - - // read the data into buffer handles and convert them to blocks on disk - // then, update the block pointer - for (idx_t j = 0; j < data_info.allocation_sizes.size(); j++) { - - // read the data into a buffer handle - auto buffer_handle = buffer_manager.Allocate(MemoryTag::ART_INDEX, block_manager->GetBlockSize(), false); - auto block_handle = buffer_handle.GetBlockHandle(); - auto data_ptr = buffer_handle.Ptr(); - - list.ReadElement(data_ptr, data_info.allocation_sizes[j]); - - // now convert the buffer handle to a persistent block and remember the block id - auto block_id = block_manager->GetFreeBlockId(); - block_manager->ConvertToPersistent(block_id, std::move(block_handle)); - data_info.block_pointers[j].block_id = block_id; - } - }); + ReplayIndexData(db, deserializer, index_info, DeserializeOnly()); if (DeserializeOnly()) { return; } + auto &info = create_info->Cast(); - // Ensure the index type exists + // Ensure that the index type exists. if (info.index_type.empty()) { info.index_type = ART::TYPE_NAME; } @@ -582,11 +643,11 @@ void WriteAheadLogDeserializer::ReplayCreateIndex() { throw InternalException("Index type \"%s\" not recognized", info.index_type); } - // create the index in the catalog + // Create the index in the catalog. auto &table = catalog.GetEntry(context, create_info->schema, info.table).Cast(); auto &index = table.schema.CreateIndex(context, info, table)->Cast(); - // add the table to the bind context to bind the parsed expressions + // Add the table to the bind context to bind the parsed expressions. auto binder = Binder::CreateBinder(context); vector column_types; vector column_names; @@ -595,26 +656,23 @@ void WriteAheadLogDeserializer::ReplayCreateIndex() { column_names.push_back(col.Name()); } - // create a binder to bind the parsed expressions + // Create a binder to bind the parsed expressions. vector column_ids; - binder->bind_context.AddBaseTable(0, info.table, column_names, column_types, column_ids, &table); + binder->bind_context.AddBaseTable(0, string(), column_names, column_types, column_ids, table); IndexBinder idx_binder(*binder, context); - // bind the parsed expressions to create unbound expressions + // Bind the parsed expressions to create unbound expressions. vector> unbound_expressions; - unbound_expressions.reserve(index.parsed_expressions.size()); for (auto &expr : index.parsed_expressions) { auto copy = expr->Copy(); unbound_expressions.push_back(idx_binder.Bind(copy)); } - auto &data_table = table.GetStorage(); - - CreateIndexInput input(TableIOManager::Get(data_table), data_table.db, info.constraint_type, info.index_name, + auto &storage = table.GetStorage(); + CreateIndexInput input(TableIOManager::Get(storage), storage.db, info.constraint_type, info.index_name, info.column_ids, unbound_expressions, index_info, info.options); - auto index_instance = index_type->create_instance(input); - data_table.AddIndex(std::move(index_instance)); + storage.AddIndex(std::move(index_instance)); } void WriteAheadLogDeserializer::ReplayDropIndex() { @@ -699,7 +757,7 @@ void WriteAheadLogDeserializer::ReplayRowGroupData() { } auto &storage = state.current_table->GetStorage(); auto &table_info = storage.GetDataTableInfo(); - RowGroupCollection new_row_groups(table_info, block_manager, storage.GetTypes(), 0); + RowGroupCollection new_row_groups(table_info, table_info->GetIOManager(), storage.GetTypes(), 0); new_row_groups.Initialize(data); TableIndexList index_list; storage.MergeStorage(new_row_groups, index_list, nullptr); diff --git a/src/duckdb/src/storage/write_ahead_log.cpp b/src/duckdb/src/storage/write_ahead_log.cpp index ba9db9eee..c9eb7a4fc 100644 --- a/src/duckdb/src/storage/write_ahead_log.cpp +++ b/src/duckdb/src/storage/write_ahead_log.cpp @@ -1,21 +1,24 @@ #include "duckdb/storage/write_ahead_log.hpp" #include "duckdb/catalog/catalog_entry/duck_index_entry.hpp" +#include "duckdb/catalog/catalog_entry/duck_table_entry.hpp" #include "duckdb/catalog/catalog_entry/scalar_macro_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/type_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/view_catalog_entry.hpp" +#include "duckdb/common/checksum.hpp" #include "duckdb/common/serializer/binary_serializer.hpp" +#include "duckdb/common/serializer/memory_stream.hpp" +#include "duckdb/execution/index/bound_index.hpp" #include "duckdb/main/database.hpp" +#include "duckdb/parser/constraints/unique_constraint.hpp" #include "duckdb/parser/parsed_data/alter_table_info.hpp" +#include "duckdb/storage/data_table.hpp" #include "duckdb/storage/index.hpp" -#include "duckdb/execution/index/bound_index.hpp" +#include "duckdb/storage/table/column_data.hpp" #include "duckdb/storage/table/data_table_info.hpp" #include "duckdb/storage/table_io_manager.hpp" -#include "duckdb/common/checksum.hpp" -#include "duckdb/common/serializer/memory_stream.hpp" -#include "duckdb/storage/table/column_data.hpp" namespace duckdb { @@ -259,44 +262,42 @@ void WriteAheadLog::WriteDropTableMacro(const TableMacroCatalogEntry &entry) { // Indexes //===--------------------------------------------------------------------===// -void SerializeIndexToWAL(WriteAheadLogSerializer &serializer, Index &index, - const case_insensitive_map_t &options) { - - // We will never write an index to the WAL that is not bound - D_ASSERT(index.IsBound()); - const auto index_storage_info = index.Cast().GetStorageInfo(options, true); - serializer.WriteProperty(102, "index_storage_info", index_storage_info); - - serializer.WriteList(103, "index_storage", index_storage_info.buffers.size(), [&](Serializer::List &list, idx_t i) { - auto &buffers = index_storage_info.buffers[i]; - for (auto buffer : buffers) { - list.WriteElement(buffer.buffer_ptr, buffer.allocation_size); - } - }); -} - -void WriteAheadLog::WriteCreateIndex(const IndexCatalogEntry &entry) { - WriteAheadLogSerializer serializer(*this, WALType::CREATE_INDEX); - serializer.WriteProperty(101, "index_catalog_entry", &entry); - - auto db_options = database.GetDatabase().config.options; +void SerializeIndex(AttachedDatabase &db, WriteAheadLogSerializer &serializer, TableIndexList &list, + const string &name) { + const auto &db_options = db.GetDatabase().config.options; auto v1_0_0_storage = db_options.serialization_compatibility.serialization_version < 3; case_insensitive_map_t options; if (!v1_0_0_storage) { options.emplace("v1_0_0_storage", v1_0_0_storage); } - // now serialize the index data to the persistent storage and write the index metadata - auto &duck_index_entry = entry.Cast(); - auto &table_idx_list = duck_index_entry.GetDataTableInfo().GetIndexes(); - - table_idx_list.Scan([&](Index &index) { - if (duck_index_entry.name == index.GetIndexName()) { - SerializeIndexToWAL(serializer, index, options); + list.Scan([&](Index &index) { + if (name == index.GetIndexName()) { + // We never write an unbound index to the WAL. + D_ASSERT(index.IsBound()); + + const auto &info = index.Cast().GetStorageInfo(options, true); + serializer.WriteProperty(102, "index_storage_info", info); + serializer.WriteList(103, "index_storage", info.buffers.size(), [&](Serializer::List &list, idx_t i) { + auto &buffers = info.buffers[i]; + for (auto buffer : buffers) { + list.WriteElement(buffer.buffer_ptr, buffer.allocation_size); + } + }); return true; } return false; }); +} + +void WriteAheadLog::WriteCreateIndex(const IndexCatalogEntry &entry) { + WriteAheadLogSerializer serializer(*this, WALType::CREATE_INDEX); + serializer.WriteProperty(101, "index_catalog_entry", &entry); + + // Serialize the index data to the persistent storage and write the metadata. + auto &index_entry = entry.Cast(); + auto &list = index_entry.GetDataTableInfo().GetIndexes(); + SerializeIndex(database, serializer, list, index_entry.name); serializer.End(); } @@ -400,9 +401,25 @@ void WriteAheadLog::WriteUpdate(DataChunk &chunk, const vector &column //===--------------------------------------------------------------------===// // Write ALTER Statement //===--------------------------------------------------------------------===// -void WriteAheadLog::WriteAlter(const AlterInfo &info) { +void WriteAheadLog::WriteAlter(CatalogEntry &entry, const AlterInfo &info) { WriteAheadLogSerializer serializer(*this, WALType::ALTER_INFO); serializer.WriteProperty(101, "info", &info); + + if (!info.IsAddPrimaryKey()) { + return serializer.End(); + } + + auto &table_info = info.Cast(); + auto &constraint_info = table_info.Cast(); + auto &unique = constraint_info.constraint->Cast(); + + auto &table_entry = entry.Cast(); + auto &parent = table_entry.Parent().Cast(); + auto &parent_info = parent.GetStorage().GetDataTableInfo(); + auto &list = parent_info->GetIndexes(); + + auto name = unique.GetName(parent.name); + SerializeIndex(database, serializer, list, name); serializer.End(); } diff --git a/src/duckdb/src/transaction/cleanup_state.cpp b/src/duckdb/src/transaction/cleanup_state.cpp index 2b2c33bb9..f9a17f265 100644 --- a/src/duckdb/src/transaction/cleanup_state.cpp +++ b/src/duckdb/src/transaction/cleanup_state.cpp @@ -54,7 +54,6 @@ void CleanupState::CleanupEntry(UndoFlags type, data_ptr_t data) { void CleanupState::CleanupUpdate(UpdateInfo &info) { // remove the update info from the update chain - // first obtain an exclusive lock on the segment info.segment->CleanupUpdate(info); } diff --git a/src/duckdb/src/transaction/commit_state.cpp b/src/duckdb/src/transaction/commit_state.cpp index 821522cb6..b6be289ee 100644 --- a/src/duckdb/src/transaction/commit_state.cpp +++ b/src/duckdb/src/transaction/commit_state.cpp @@ -19,7 +19,8 @@ namespace duckdb { -CommitState::CommitState(transaction_t commit_id) : commit_id(commit_id) { +CommitState::CommitState(DuckTransaction &transaction_p, transaction_t commit_id) + : transaction(transaction_p), commit_id(commit_id) { } void CommitState::CommitEntryDrop(CatalogEntry &entry, data_ptr_t dataptr) { @@ -197,7 +198,7 @@ void CommitState::RevertCommit(UndoFlags type, data_ptr_t data) { case UndoFlags::INSERT_TUPLE: { auto info = reinterpret_cast(data); // revert this append - info->table->RevertAppend(info->start_row, info->count); + info->table->RevertAppend(transaction, info->start_row, info->count); break; } case UndoFlags::DELETE_TUPLE: { diff --git a/src/duckdb/src/transaction/duck_transaction.cpp b/src/duckdb/src/transaction/duck_transaction.cpp index d47aee655..273f256b6 100644 --- a/src/duckdb/src/transaction/duck_transaction.cpp +++ b/src/duckdb/src/transaction/duck_transaction.cpp @@ -32,8 +32,8 @@ TransactionData::TransactionData(transaction_t transaction_id_p, transaction_t s DuckTransaction::DuckTransaction(DuckTransactionManager &manager, ClientContext &context_p, transaction_t start_time, transaction_t transaction_id, idx_t catalog_version_p) : Transaction(manager, context_p), start_time(start_time), transaction_id(transaction_id), commit_id(0), - highest_active_query(0), catalog_version(catalog_version_p), transaction_manager(manager), undo_buffer(context_p), - storage(make_uniq(context_p, *this)) { + highest_active_query(0), catalog_version(catalog_version_p), transaction_manager(manager), + undo_buffer(*this, context_p), storage(make_uniq(context_p, *this)) { } DuckTransaction::~DuckTransaction() { @@ -61,17 +61,18 @@ void DuckTransaction::PushCatalogEntry(CatalogEntry &entry, data_ptr_t extra_dat alloc_size += extra_data_size + sizeof(idx_t); } - auto baseptr = undo_buffer.CreateEntry(UndoFlags::CATALOG_ENTRY, alloc_size); + auto undo_entry = undo_buffer.CreateEntry(UndoFlags::CATALOG_ENTRY, alloc_size); + auto ptr = undo_entry.Ptr(); // store the pointer to the catalog entry - Store(&entry, baseptr); + Store(&entry, ptr); if (extra_data_size > 0) { // copy the extra data behind the catalog entry pointer (if any) - baseptr += sizeof(CatalogEntry *); + ptr += sizeof(CatalogEntry *); // first store the extra data size - Store(extra_data_size, baseptr); - baseptr += sizeof(idx_t); + Store(extra_data_size, ptr); + ptr += sizeof(idx_t); // then copy over the actual data - memcpy(baseptr, extra_data, extra_data_size); + memcpy(ptr, extra_data, extra_data_size); } } @@ -91,7 +92,8 @@ void DuckTransaction::PushDelete(DataTable &table, RowVersionManager &info, idx_ alloc_size += sizeof(uint16_t) * count; } - auto delete_info = reinterpret_cast(undo_buffer.CreateEntry(UndoFlags::DELETE_TUPLE, alloc_size)); + auto undo_entry = undo_buffer.CreateEntry(UndoFlags::DELETE_TUPLE, alloc_size); + auto delete_info = reinterpret_cast(undo_entry.Ptr()); delete_info->version_info = &info; delete_info->vector_idx = vector_idx; delete_info->table = &table; @@ -108,30 +110,27 @@ void DuckTransaction::PushDelete(DataTable &table, RowVersionManager &info, idx_ } void DuckTransaction::PushAppend(DataTable &table, idx_t start_row, idx_t row_count) { - auto append_info = - reinterpret_cast(undo_buffer.CreateEntry(UndoFlags::INSERT_TUPLE, sizeof(AppendInfo))); + auto undo_entry = undo_buffer.CreateEntry(UndoFlags::INSERT_TUPLE, sizeof(AppendInfo)); + auto append_info = reinterpret_cast(undo_entry.Ptr()); append_info->table = &table; append_info->start_row = start_row; append_info->count = row_count; } -UpdateInfo *DuckTransaction::CreateUpdateInfo(idx_t type_size, idx_t entries) { - data_ptr_t base_info = undo_buffer.CreateEntry( - UndoFlags::UPDATE_TUPLE, sizeof(UpdateInfo) + (sizeof(sel_t) + type_size) * STANDARD_VECTOR_SIZE); - auto update_info = reinterpret_cast(base_info); - update_info->max = STANDARD_VECTOR_SIZE; - update_info->tuples = reinterpret_cast(base_info + sizeof(UpdateInfo)); - update_info->tuple_data = base_info + sizeof(UpdateInfo) + sizeof(sel_t) * update_info->max; - update_info->version_number = transaction_id; - return update_info; +UndoBufferReference DuckTransaction::CreateUpdateInfo(idx_t type_size, idx_t entries) { + idx_t alloc_size = UpdateInfo::GetAllocSize(type_size); + auto undo_entry = undo_buffer.CreateEntry(UndoFlags::UPDATE_TUPLE, alloc_size); + auto &update_info = UpdateInfo::Get(undo_entry); + UpdateInfo::Initialize(update_info, transaction_id); + return undo_entry; } void DuckTransaction::PushSequenceUsage(SequenceCatalogEntry &sequence, const SequenceData &data) { lock_guard l(sequence_lock); auto entry = sequence_usage.find(sequence); if (entry == sequence_usage.end()) { - auto sequence_ptr = undo_buffer.CreateEntry(UndoFlags::SEQUENCE_VALUE, sizeof(SequenceValue)); - auto sequence_info = reinterpret_cast(sequence_ptr); + auto undo_entry = undo_buffer.CreateEntry(UndoFlags::SEQUENCE_VALUE, sizeof(SequenceValue)); + auto sequence_info = reinterpret_cast(undo_entry.Ptr()); sequence_info->entry = &sequence; sequence_info->usage_count = data.usage_count; sequence_info->counter = data.counter; @@ -248,9 +247,14 @@ ErrorData DuckTransaction::Commit(AttachedDatabase &db, transaction_t new_commit } } -void DuckTransaction::Rollback() noexcept { - storage->Rollback(); - undo_buffer.Rollback(); +ErrorData DuckTransaction::Rollback() { + try { + storage->Rollback(); + undo_buffer.Rollback(); + return ErrorData(); + } catch (std::exception &ex) { + return ErrorData(ex); + } } void DuckTransaction::Cleanup(transaction_t lowest_active_transaction) { diff --git a/src/duckdb/src/transaction/duck_transaction_manager.cpp b/src/duckdb/src/transaction/duck_transaction_manager.cpp index 83558ffa7..42c9d7d09 100644 --- a/src/duckdb/src/transaction/duck_transaction_manager.cpp +++ b/src/duckdb/src/transaction/duck_transaction_manager.cpp @@ -262,7 +262,11 @@ ErrorData DuckTransactionManager::CommitTransaction(ClientContext &context, Tran // commit unsuccessful: rollback the transaction instead checkpoint_decision = CheckpointDecision(error.Message()); transaction.commit_id = 0; - transaction.Rollback(); + auto rollback_error = transaction.Rollback(); + if (rollback_error.HasError()) { + throw FatalException("Failed to rollback transaction. Cannot continue operation.\nError: %s", + rollback_error.Message()); + } } else { // check if catalog changes were made if (transaction.catalog_version >= TRANSACTION_ID_START) { @@ -302,11 +306,15 @@ void DuckTransactionManager::RollbackTransaction(Transaction &transaction_p) { lock_guard lock(transaction_lock); // rollback the transaction - transaction.Rollback(); + auto error = transaction.Rollback(); // remove the transaction id from the list of active transactions // potentially resulting in garbage collection RemoveTransaction(transaction); + + if (error.HasError()) { + throw FatalException("Failed to rollback transaction. Cannot continue operation.\nError: %s", error.Message()); + } } void DuckTransactionManager::RemoveTransaction(DuckTransaction &transaction) noexcept { diff --git a/src/duckdb/src/transaction/rollback_state.cpp b/src/duckdb/src/transaction/rollback_state.cpp index f7d1410c7..335c35eff 100644 --- a/src/duckdb/src/transaction/rollback_state.cpp +++ b/src/duckdb/src/transaction/rollback_state.cpp @@ -13,10 +13,13 @@ namespace duckdb { +RollbackState::RollbackState(DuckTransaction &transaction_p) : transaction(transaction_p) { +} + void RollbackState::RollbackEntry(UndoFlags type, data_ptr_t data) { switch (type) { case UndoFlags::CATALOG_ENTRY: { - // undo this catalog entry + // Load and undo the catalog entry. auto catalog_entry = Load(data); D_ASSERT(catalog_entry->set); catalog_entry->set->Undo(*catalog_entry); @@ -25,7 +28,7 @@ void RollbackState::RollbackEntry(UndoFlags type, data_ptr_t data) { case UndoFlags::INSERT_TUPLE: { auto info = reinterpret_cast(data); // revert the append in the base table - info->table->RevertAppend(info->start_row, info->count); + info->table->RevertAppend(transaction, info->start_row, info->count); break; } case UndoFlags::DELETE_TUPLE: { diff --git a/src/duckdb/src/transaction/transaction_context.cpp b/src/duckdb/src/transaction/transaction_context.cpp index 9fc36814c..67f8cfec4 100644 --- a/src/duckdb/src/transaction/transaction_context.cpp +++ b/src/duckdb/src/transaction/transaction_context.cpp @@ -74,11 +74,19 @@ void TransactionContext::Rollback(optional_ptr error) { } auto transaction = std::move(current_transaction); ClearTransaction(); - transaction->Rollback(); + ErrorData rollback_error; + try { + transaction->Rollback(); + } catch (std::exception &ex) { + rollback_error = ErrorData(ex); + } // Notify any registered state of transaction rollback for (auto const &s : context.registered_state->States()) { s->TransactionRollback(*transaction, context, error); } + if (rollback_error.HasError()) { + rollback_error.Throw(); + } } void TransactionContext::ClearTransaction() { diff --git a/src/duckdb/src/transaction/undo_buffer.cpp b/src/duckdb/src/transaction/undo_buffer.cpp index 1e61bd9cc..cacf2b1a7 100644 --- a/src/duckdb/src/transaction/undo_buffer.cpp +++ b/src/duckdb/src/transaction/undo_buffer.cpp @@ -13,32 +13,36 @@ #include "duckdb/execution/index/bound_index.hpp" #include "duckdb/transaction/wal_write_state.hpp" #include "duckdb/transaction/delete_info.hpp" +#include "duckdb/storage/buffer_manager.hpp" namespace duckdb { constexpr uint32_t UNDO_ENTRY_HEADER_SIZE = sizeof(UndoFlags) + sizeof(uint32_t); -UndoBuffer::UndoBuffer(ClientContext &context_p) : allocator(BufferAllocator::Get(context_p)) { +UndoBuffer::UndoBuffer(DuckTransaction &transaction_p, ClientContext &context_p) + : transaction(transaction_p), allocator(BufferManager::GetBufferManager(context_p)) { } -data_ptr_t UndoBuffer::CreateEntry(UndoFlags type, idx_t len) { - D_ASSERT(len <= NumericLimits::Maximum()); - len = AlignValue(len); - idx_t needed_space = len + UNDO_ENTRY_HEADER_SIZE; - auto data = allocator.Allocate(needed_space); +UndoBufferReference UndoBuffer::CreateEntry(UndoFlags type, idx_t len) { + idx_t alloc_len = AlignValue(len + UNDO_ENTRY_HEADER_SIZE); + auto handle = allocator.Allocate(alloc_len); + auto data = handle.Ptr(); + // write the undo entry metadata Store(type, data); data += sizeof(UndoFlags); - Store(UnsafeNumericCast(len), data); - data += sizeof(uint32_t); - return data; + Store(UnsafeNumericCast(alloc_len - UNDO_ENTRY_HEADER_SIZE), data); + // increment the position of the header past the undo entry metadata + handle.position += UNDO_ENTRY_HEADER_SIZE; + return handle; } template void UndoBuffer::IterateEntries(UndoBuffer::IteratorState &state, T &&callback) { // iterate in insertion order: start with the tail - state.current = allocator.GetTail(); + state.current = allocator.tail.get(); while (state.current) { - state.start = state.current->data.get(); - state.end = state.start + state.current->current_position; + state.handle = allocator.buffer_manager.Pin(state.current->block); + state.start = state.handle.Ptr(); + state.end = state.start + state.current->position; while (state.start < state.end) { UndoFlags type = Load(state.start); state.start += sizeof(UndoFlags); @@ -55,11 +59,11 @@ void UndoBuffer::IterateEntries(UndoBuffer::IteratorState &state, T &&callback) template void UndoBuffer::IterateEntries(UndoBuffer::IteratorState &state, UndoBuffer::IteratorState &end_state, T &&callback) { // iterate in insertion order: start with the tail - state.current = allocator.GetTail(); + state.current = allocator.tail.get(); while (state.current) { - state.start = state.current->data.get(); - state.end = - state.current == end_state.current ? end_state.start : state.start + state.current->current_position; + state.handle = allocator.buffer_manager.Pin(state.current->block); + state.start = state.handle.Ptr(); + state.end = state.current == end_state.current ? end_state.start : state.start + state.current->position; while (state.start < state.end) { auto type = Load(state.start); state.start += sizeof(UndoFlags); @@ -79,10 +83,11 @@ void UndoBuffer::IterateEntries(UndoBuffer::IteratorState &state, UndoBuffer::It template void UndoBuffer::ReverseIterateEntries(T &&callback) { // iterate in reverse insertion order: start with the head - auto current = allocator.GetHead(); + auto current = allocator.head.get(); while (current) { - data_ptr_t start = current->data.get(); - data_ptr_t end = start + current->current_position; + auto handle = allocator.buffer_manager.Pin(current->block); + data_ptr_t start = handle.Ptr(); + data_ptr_t end = start + current->position; // create a vector with all nodes in this chunk vector> nodes; while (start < end) { @@ -103,7 +108,7 @@ void UndoBuffer::ReverseIterateEntries(T &&callback) { bool UndoBuffer::ChangesMade() { // we need to search for any index creation entries - return !allocator.IsEmpty(); + return allocator.head.get(); } UndoBufferProperties UndoBuffer::GetProperties() { @@ -111,9 +116,9 @@ UndoBufferProperties UndoBuffer::GetProperties() { if (!ChangesMade()) { return properties; } - auto node = allocator.GetHead(); + auto node = allocator.head.get(); while (node) { - properties.estimated_size += node->current_position; + properties.estimated_size += node->position; node = node->next.get(); } @@ -178,25 +183,25 @@ void UndoBuffer::Cleanup(transaction_t lowest_active_transaction) { } void UndoBuffer::WriteToWAL(WriteAheadLog &wal, optional_ptr commit_state) { - WALWriteState state(wal, commit_state); + WALWriteState state(transaction, wal, commit_state); UndoBuffer::IteratorState iterator_state; IterateEntries(iterator_state, [&](UndoFlags type, data_ptr_t data) { state.CommitEntry(type, data); }); } void UndoBuffer::Commit(UndoBuffer::IteratorState &iterator_state, transaction_t commit_id) { - CommitState state(commit_id); + CommitState state(transaction, commit_id); IterateEntries(iterator_state, [&](UndoFlags type, data_ptr_t data) { state.CommitEntry(type, data); }); } void UndoBuffer::RevertCommit(UndoBuffer::IteratorState &end_state, transaction_t transaction_id) { - CommitState state(transaction_id); + CommitState state(transaction, transaction_id); UndoBuffer::IteratorState start_state; IterateEntries(start_state, end_state, [&](UndoFlags type, data_ptr_t data) { state.RevertCommit(type, data); }); } -void UndoBuffer::Rollback() noexcept { +void UndoBuffer::Rollback() { // rollback needs to be performed in reverse - RollbackState state; + RollbackState state(transaction); ReverseIterateEntries([&](UndoFlags type, data_ptr_t data) { state.RollbackEntry(type, data); }); } } // namespace duckdb diff --git a/src/duckdb/src/transaction/undo_buffer_allocator.cpp b/src/duckdb/src/transaction/undo_buffer_allocator.cpp new file mode 100644 index 000000000..20e3bdf19 --- /dev/null +++ b/src/duckdb/src/transaction/undo_buffer_allocator.cpp @@ -0,0 +1,72 @@ +#include "duckdb/transaction/undo_buffer_allocator.hpp" +#include "duckdb/storage/buffer_manager.hpp" + +namespace duckdb { + +UndoBufferEntry::~UndoBufferEntry() { + if (next) { + auto current_next = std::move(next); + while (current_next) { + current_next = std::move(current_next->next); + } + } +} +UndoBufferPointer UndoBufferReference::GetBufferPointer() { + return UndoBufferPointer(*entry, position); +} + +UndoBufferReference UndoBufferPointer::Pin() const { + if (!entry) { + throw InternalException("UndoBufferPointer::Pin called but no entry was found"); + } + D_ASSERT(entry->capacity >= position); + auto handle = entry->buffer_manager.Pin(entry->block); + return UndoBufferReference(*entry, std::move(handle), position); +} + +UndoBufferAllocator::UndoBufferAllocator(BufferManager &buffer_manager) : buffer_manager(buffer_manager) { +} + +UndoBufferReference UndoBufferAllocator::Allocate(idx_t alloc_len) { + D_ASSERT(!head || head->position <= head->capacity); + BufferHandle handle; + if (!head || head->position + alloc_len > head->capacity) { + // no space in current head - allocate a new block + auto block_size = buffer_manager.GetBlockSize(); + ; + idx_t capacity; + if (!head && alloc_len <= 4096) { + capacity = 4096; + } else { + capacity = block_size; + } + if (capacity < alloc_len) { + capacity = NextPowerOfTwo(alloc_len); + } + auto entry = make_uniq(buffer_manager); + if (capacity < block_size) { + entry->block = buffer_manager.RegisterSmallMemory(MemoryTag::TRANSACTION, capacity); + handle = buffer_manager.Pin(entry->block); + } else { + handle = buffer_manager.Allocate(MemoryTag::TRANSACTION, capacity, false); + entry->block = handle.GetBlockHandle(); + } + entry->capacity = capacity; + entry->position = 0; + // add block to the chain + if (head) { + head->prev = entry.get(); + entry->next = std::move(head); + } else { + tail = entry.get(); + } + head = std::move(entry); + } else { + handle = buffer_manager.Pin(head->block); + } + idx_t current_position = head->position; + head->position += alloc_len; + return UndoBufferReference(*head, std::move(handle), current_position); +} + +} // namespace duckdb diff --git a/src/duckdb/src/transaction/wal_write_state.cpp b/src/duckdb/src/transaction/wal_write_state.cpp index b700005ef..8bb1702a3 100644 --- a/src/duckdb/src/transaction/wal_write_state.cpp +++ b/src/duckdb/src/transaction/wal_write_state.cpp @@ -22,8 +22,9 @@ namespace duckdb { -WALWriteState::WALWriteState(WriteAheadLog &log, optional_ptr commit_state) - : log(log), commit_state(commit_state), current_table_info(nullptr) { +WALWriteState::WALWriteState(DuckTransaction &transaction_p, WriteAheadLog &log, + optional_ptr commit_state) + : transaction(transaction_p), log(log), commit_state(commit_state), current_table_info(nullptr) { } void WALWriteState::SwitchTable(DataTableInfo *table_info, UndoFlags new_op) { @@ -63,7 +64,7 @@ void WALWriteState::WriteCatalogEntry(CatalogEntry &entry, data_ptr_t dataptr) { deserializer.End(); auto &alter_info = parse_info->Cast(); - log.WriteAlter(alter_info); + log.WriteAlter(entry, alter_info); } else { switch (parent.type) { case CatalogType::TABLE_ENTRY: @@ -217,19 +218,20 @@ void WALWriteState::WriteUpdate(UpdateInfo &info) { // write the row ids into the chunk auto row_ids = FlatVector::GetData(update_chunk->data[1]); idx_t start = column_data.start + info.vector_index * STANDARD_VECTOR_SIZE; + auto tuples = info.GetTuples(); for (idx_t i = 0; i < info.N; i++) { - row_ids[info.tuples[i]] = UnsafeNumericCast(start + info.tuples[i]); + row_ids[tuples[i]] = UnsafeNumericCast(start + tuples[i]); } if (column_data.type.id() == LogicalTypeId::VALIDITY) { // zero-initialize the booleans // FIXME: this is only required because of NullValue in Vector::Serialize... auto booleans = FlatVector::GetData(update_chunk->data[0]); for (idx_t i = 0; i < info.N; i++) { - auto idx = info.tuples[i]; + auto idx = tuples[i]; booleans[idx] = false; } } - SelectionVector sel(info.tuples); + SelectionVector sel(tuples); update_chunk->Slice(sel, info.N); // construct the column index path @@ -259,7 +261,7 @@ void WALWriteState::CommitEntry(UndoFlags type, data_ptr_t data) { // append: auto info = reinterpret_cast(data); if (!info->table->IsTemporary()) { - info->table->WriteToLog(log, info->start_row, info->count, commit_state.get()); + info->table->WriteToLog(transaction, log, info->start_row, info->count, commit_state.get()); } break; } 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 a5aa55c36..2fbf2cf75 100644 --- a/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp +++ b/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp @@ -317,6 +317,7 @@ typedef struct PGAStar { PGNode *expr; /* optional: the expression (regex or list) to select columns */ PGList *except_list; /* optional: EXCLUDE list */ PGList *replace_list; /* optional: REPLACE list */ + PGList *rename_list; /* optional: RENAME list */ bool columns; /* whether or not this is a columns list */ bool unpacked; /* whether or not the columns list is unpacked */ int location; @@ -1574,7 +1575,8 @@ typedef struct PGVariableSetStmt { */ typedef struct PGVariableShowStmt { PGNodeTag type; - char *name; + PGRangeVar *relation; /* relation to describe (if any) */ + char *set; /* set to describe (e.g. set when using SHOW ALL TABLES) */ int is_summary; // whether or not this is a DESCRIBE or a SUMMARIZE } PGVariableShowStmt; @@ -2101,7 +2103,7 @@ typedef struct PGIntervalConstant { typedef struct PGSampleSize { PGNodeTag type; bool is_percentage; /* whether or not the sample size is expressed in row numbers or a percentage */ - PGValue sample_size; /* sample size */ + PGNode *sample_size; /* sample size */ } PGSampleSize; typedef struct PGSampleOptions { 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 8da0cbf89..598fd18d5 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 @@ -1277,7 +1277,7 @@ static PGNode *makeStringConstCast(char *str, int location, PGTypeName *tpname); static PGNode *makeIntervalNode(char *str, int location, PGList *typmods); static PGNode *makeIntervalNode(int val, int location, PGList *typmods); static PGNode *makeIntervalNode(PGNode *arg, int location, PGList *typmods); -static PGNode *makeSampleSize(PGValue *sample_size, bool is_percentage); +static PGNode *makeSampleSize(PGNode *sample_size, bool is_percentage); static PGNode *makeSampleOptions(PGNode *sample_size, char *method, int *seed, int location); static PGNode *makeIntConst(int val, int location); static PGNode *makeFloatConst(char *str, int location); @@ -1624,18 +1624,18 @@ union yyalloc #endif /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 873 +#define YYFINAL 874 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 72916 +#define YYLAST 74581 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 529 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 474 +#define YYNNTS 483 /* YYNRULES -- Number of rules. */ -#define YYNRULES 2155 +#define YYNRULES 2175 /* YYNRULES -- Number of states. */ -#define YYNSTATES 3579 +#define YYNSTATES 3614 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 @@ -1650,16 +1650,16 @@ static const yytype_uint16 yytranslate[] = 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 524, 525, 513, 2, 2, + 2, 2, 2, 2, 2, 526, 525, 513, 2, 2, 518, 519, 511, 509, 522, 510, 520, 512, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 528, 521, - 505, 507, 506, 523, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 523, 521, + 505, 507, 506, 524, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 516, 2, 517, 514, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 526, 2, 527, 2, 2, 2, 2, + 2, 2, 2, 527, 2, 528, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -1794,179 +1794,181 @@ static const yytype_uint16 yyprhs[] = 2138, 2141, 2143, 2149, 2151, 2152, 2155, 2158, 2159, 2161, 2162, 2166, 2172, 2174, 2178, 2183, 2187, 2189, 2191, 2192, 2195, 2198, 2199, 2202, 2205, 2207, 2209, 2211, 2212, 2215, - 2220, 2226, 2231, 2234, 2238, 2241, 2244, 2247, 2250, 2252, - 2255, 2259, 2260, 2262, 2263, 2269, 2271, 2276, 2283, 2286, - 2288, 2289, 2294, 2295, 2297, 2299, 2302, 2305, 2308, 2310, - 2312, 2315, 2318, 2320, 2322, 2324, 2326, 2328, 2330, 2334, - 2338, 2339, 2341, 2345, 2347, 2350, 2352, 2354, 2356, 2358, - 2360, 2363, 2368, 2373, 2379, 2381, 2383, 2386, 2387, 2390, - 2391, 2393, 2397, 2399, 2400, 2402, 2405, 2409, 2412, 2417, - 2420, 2424, 2427, 2428, 2430, 2433, 2434, 2439, 2445, 2447, - 2450, 2453, 2454, 2456, 2460, 2462, 2465, 2469, 2473, 2477, - 2481, 2485, 2489, 2491, 2496, 2506, 2516, 2520, 2521, 2524, - 2527, 2528, 2534, 2538, 2540, 2542, 2546, 2552, 2556, 2558, - 2561, 2563, 2567, 2573, 2575, 2578, 2582, 2587, 2593, 2598, - 2604, 2609, 2616, 2622, 2627, 2633, 2639, 2645, 2648, 2653, - 2655, 2657, 2658, 2660, 2665, 2671, 2676, 2677, 2680, 2683, - 2686, 2688, 2690, 2692, 2694, 2695, 2700, 2703, 2705, 2708, - 2711, 2716, 2719, 2726, 2729, 2731, 2735, 2740, 2741, 2744, - 2745, 2748, 2749, 2751, 2755, 2759, 2762, 2763, 2766, 2771, - 2773, 2775, 2777, 2778, 2781, 2785, 2791, 2798, 2801, 2805, - 2807, 2813, 2819, 2825, 2829, 2833, 2837, 2842, 2843, 2845, - 2847, 2849, 2851, 2853, 2856, 2861, 2863, 2865, 2867, 2869, - 2872, 2876, 2877, 2879, 2881, 2883, 2885, 2887, 2890, 2893, - 2896, 2899, 2902, 2904, 2908, 2909, 2911, 2913, 2915, 2917, - 2923, 2926, 2928, 2930, 2932, 2934, 2939, 2941, 2944, 2947, - 2949, 2953, 2957, 2960, 2962, 2963, 2969, 2972, 2978, 2981, - 2983, 2987, 2991, 2992, 2994, 2996, 2998, 3000, 3002, 3004, - 3006, 3008, 3010, 3012, 3014, 3016, 3018, 3020, 3022, 3024, - 3026, 3028, 3030, 3032, 3034, 3036, 3038, 3040, 3042, 3044, - 3046, 3048, 3050, 3052, 3054, 3056, 3058, 3060, 3062, 3064, - 3066, 3068, 3070, 3074, 3078, 3082, 3086, 3090, 3094, 3098, - 3099, 3101, 3105, 3109, 3115, 3118, 3121, 3125, 3129, 3133, - 3137, 3141, 3145, 3149, 3153, 3157, 3161, 3165, 3169, 3173, - 3177, 3181, 3184, 3187, 3191, 3195, 3198, 3201, 3205, 3209, - 3215, 3220, 3227, 3231, 3237, 3242, 3249, 3254, 3261, 3267, - 3275, 3279, 3282, 3287, 3291, 3294, 3298, 3302, 3306, 3310, - 3315, 3319, 3324, 3328, 3333, 3339, 3346, 3353, 3361, 3368, - 3376, 3383, 3391, 3395, 3400, 3405, 3412, 3414, 3420, 3425, - 3429, 3435, 3437, 3441, 3444, 3447, 3451, 3455, 3459, 3463, - 3467, 3471, 3475, 3479, 3483, 3487, 3491, 3495, 3499, 3503, - 3507, 3510, 3513, 3519, 3526, 3533, 3541, 3543, 3546, 3548, - 3550, 3552, 3555, 3558, 3563, 3567, 3569, 3571, 3573, 3575, - 3577, 3579, 3581, 3583, 3585, 3587, 3590, 3595, 3598, 3601, - 3605, 3609, 3614, 3618, 3625, 3633, 3643, 3651, 3659, 3665, - 3667, 3669, 3671, 3677, 3684, 3691, 3696, 3701, 3706, 3711, - 3718, 3724, 3730, 3736, 3741, 3748, 3753, 3755, 3763, 3773, - 3779, 3780, 3786, 3791, 3792, 3794, 3795, 3798, 3799, 3801, - 3805, 3809, 3812, 3815, 3816, 3823, 3825, 3826, 3830, 3831, - 3835, 3839, 3843, 3844, 3846, 3851, 3854, 3857, 3860, 3863, - 3866, 3870, 3873, 3876, 3880, 3881, 3886, 3890, 3892, 3898, - 3902, 3904, 3908, 3910, 3913, 3917, 3919, 3923, 3925, 3928, - 3930, 3931, 3933, 3935, 3937, 3939, 3941, 3943, 3945, 3947, - 3949, 3951, 3953, 3955, 3957, 3959, 3961, 3963, 3965, 3967, - 3969, 3971, 3976, 3978, 3983, 3985, 3990, 3992, 3995, 3997, - 4000, 4002, 4005, 4007, 4011, 4013, 4017, 4019, 4022, 4024, - 4028, 4030, 4033, 4035, 4036, 4038, 4042, 4044, 4048, 4052, - 4054, 4058, 4062, 4063, 4065, 4067, 4069, 4071, 4073, 4075, - 4077, 4079, 4081, 4083, 4085, 4087, 4089, 4091, 4093, 4098, - 4102, 4105, 4109, 4110, 4114, 4118, 4121, 4124, 4126, 4127, - 4130, 4133, 4137, 4140, 4142, 4144, 4148, 4150, 4152, 4158, - 4160, 4163, 4168, 4171, 4172, 4174, 4175, 4177, 4181, 4183, - 4185, 4188, 4192, 4198, 4206, 4214, 4216, 4217, 4218, 4221, - 4222, 4225, 4229, 4233, 4237, 4243, 4251, 4259, 4260, 4263, - 4265, 4266, 4268, 4269, 4271, 4275, 4277, 4280, 4284, 4287, - 4289, 4294, 4297, 4299, 4300, 4304, 4306, 4310, 4312, 4315, - 4320, 4323, 4324, 4326, 4330, 4332, 4336, 4338, 4341, 4343, - 4347, 4349, 4351, 4354, 4356, 4358, 4361, 4363, 4365, 4368, - 4376, 4379, 4385, 4389, 4393, 4395, 4397, 4399, 4401, 4403, - 4405, 4407, 4409, 4411, 4413, 4415, 4417, 4419, 4421, 4424, - 4427, 4431, 4435, 4436, 4438, 4440, 4442, 4448, 4452, 4453, - 4455, 4457, 4459, 4461, 4463, 4465, 4470, 4478, 4485, 4488, - 4489, 4491, 4493, 4495, 4497, 4511, 4528, 4530, 4533, 4534, - 4536, 4537, 4539, 4540, 4543, 4544, 4546, 4547, 4554, 4563, - 4570, 4579, 4586, 4595, 4599, 4602, 4604, 4605, 4612, 4619, - 4621, 4623, 4625, 4627, 4629, 4631, 4634, 4636, 4638, 4640, - 4642, 4644, 4649, 4656, 4660, 4663, 4668, 4672, 4678, 4680, - 4681, 4683, 4685, 4686, 4688, 4690, 4692, 4694, 4696, 4698, - 4700, 4702, 4704, 4706, 4708, 4710, 4712, 4714, 4716, 4718, - 4720, 4722, 4724, 4726, 4728, 4730, 4732, 4734, 4736, 4738, - 4740, 4742, 4744, 4746, 4748, 4750, 4752, 4754, 4756, 4758, - 4760, 4764, 4766, 4768, 4770, 4772, 4774, 4776, 4779, 4781, - 4783, 4786, 4790, 4794, 4798, 4802, 4804, 4808, 4812, 4815, - 4819, 4823, 4825, 4827, 4829, 4833, 4839, 4841, 4843, 4845, - 4847, 4851, 4854, 4859, 4866, 4873, 4874, 4876, 4878, 4880, - 4881, 4884, 4887, 4892, 4899, 4905, 4910, 4917, 4919, 4921, - 4923, 4925, 4927, 4929, 4930, 4932, 4936, 4938, 4939, 4947, - 4951, 4953, 4956, 4960, 4963, 4964, 4967, 4968, 4971, 4976, - 4982, 4991, 4994, 4998, 5004, 5006, 5007, 5010, 5011, 5014, - 5018, 5022, 5026, 5030, 5032, 5034, 5036, 5039, 5043, 5046, - 5049, 5052, 5055, 5059, 5064, 5068, 5070, 5072, 5074, 5076, - 5078, 5080, 5081, 5083, 5087, 5089, 5093, 5096, 5106, 5119, - 5131, 5144, 5159, 5163, 5168, 5173, 5174, 5182, 5193, 5203, - 5206, 5210, 5211, 5216, 5218, 5220, 5222, 5224, 5226, 5228, - 5230, 5232, 5234, 5236, 5238, 5240, 5242, 5244, 5246, 5248, - 5250, 5252, 5254, 5256, 5258, 5260, 5262, 5264, 5266, 5268, - 5270, 5272, 5274, 5276, 5278, 5280, 5282, 5284, 5286, 5288, - 5290, 5292, 5294, 5296, 5298, 5300, 5302, 5304, 5306, 5308, - 5310, 5312, 5314, 5316, 5318, 5320, 5322, 5324, 5326, 5328, - 5330, 5332, 5334, 5336, 5338, 5340, 5342, 5344, 5346, 5348, - 5350, 5352, 5354, 5356, 5358, 5360, 5362, 5364, 5366, 5368, - 5370, 5372, 5374, 5376, 5378, 5380, 5382, 5384, 5386, 5388, - 5390, 5392, 5394, 5396, 5398, 5400, 5402, 5404, 5406, 5408, - 5410, 5412, 5414, 5416, 5418, 5420, 5422, 5424, 5426, 5428, - 5430, 5432, 5434, 5436, 5438, 5440, 5442, 5444, 5446, 5448, - 5450, 5452, 5454, 5456, 5458, 5460, 5462, 5464, 5466, 5468, - 5470, 5472, 5474, 5476, 5478, 5480, 5482, 5484, 5486, 5488, - 5490, 5492, 5494, 5496, 5498, 5500, 5502, 5504, 5506, 5508, - 5510, 5512, 5514, 5516, 5518, 5520, 5522, 5524, 5526, 5528, - 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 + 2220, 2226, 2231, 2234, 2238, 2240, 2242, 2244, 2247, 2250, + 2252, 2255, 2259, 2260, 2262, 2263, 2269, 2271, 2276, 2283, + 2286, 2288, 2289, 2294, 2295, 2297, 2299, 2302, 2305, 2308, + 2310, 2312, 2315, 2318, 2320, 2322, 2324, 2326, 2328, 2330, + 2334, 2338, 2339, 2341, 2345, 2347, 2350, 2352, 2354, 2356, + 2358, 2360, 2363, 2368, 2373, 2379, 2381, 2383, 2386, 2387, + 2390, 2391, 2393, 2397, 2399, 2400, 2402, 2405, 2409, 2412, + 2417, 2420, 2424, 2427, 2428, 2430, 2433, 2434, 2439, 2445, + 2447, 2450, 2453, 2454, 2456, 2460, 2462, 2465, 2468, 2472, + 2476, 2480, 2484, 2488, 2492, 2496, 2500, 2504, 2506, 2511, + 2516, 2526, 2536, 2540, 2541, 2544, 2547, 2548, 2554, 2558, + 2560, 2562, 2566, 2572, 2576, 2578, 2581, 2583, 2587, 2593, + 2595, 2598, 2602, 2607, 2613, 2618, 2624, 2629, 2636, 2642, + 2647, 2653, 2659, 2665, 2668, 2673, 2675, 2677, 2678, 2680, + 2685, 2691, 2696, 2697, 2700, 2703, 2706, 2708, 2710, 2712, + 2714, 2715, 2720, 2723, 2725, 2728, 2731, 2736, 2739, 2746, + 2749, 2751, 2755, 2760, 2761, 2764, 2765, 2768, 2769, 2771, + 2775, 2779, 2782, 2783, 2786, 2791, 2793, 2795, 2797, 2798, + 2801, 2805, 2811, 2818, 2821, 2825, 2827, 2833, 2839, 2845, + 2849, 2853, 2857, 2862, 2863, 2865, 2867, 2869, 2871, 2873, + 2876, 2881, 2883, 2885, 2887, 2889, 2892, 2896, 2897, 2899, + 2901, 2903, 2905, 2907, 2910, 2913, 2916, 2919, 2922, 2924, + 2928, 2929, 2931, 2933, 2935, 2937, 2943, 2946, 2948, 2950, + 2952, 2954, 2959, 2961, 2964, 2967, 2969, 2973, 2977, 2980, + 2982, 2983, 2989, 2992, 2998, 3001, 3003, 3007, 3011, 3012, + 3014, 3016, 3018, 3020, 3022, 3024, 3026, 3028, 3030, 3032, + 3034, 3036, 3038, 3040, 3042, 3044, 3046, 3048, 3050, 3052, + 3054, 3056, 3058, 3060, 3062, 3064, 3066, 3068, 3070, 3072, + 3074, 3076, 3078, 3080, 3082, 3084, 3086, 3088, 3090, 3094, + 3098, 3102, 3106, 3110, 3114, 3118, 3119, 3121, 3125, 3129, + 3135, 3138, 3141, 3145, 3149, 3153, 3157, 3161, 3165, 3169, + 3173, 3177, 3181, 3185, 3189, 3193, 3197, 3201, 3204, 3207, + 3211, 3215, 3218, 3221, 3225, 3229, 3235, 3240, 3247, 3251, + 3257, 3262, 3269, 3274, 3281, 3287, 3295, 3299, 3302, 3307, + 3311, 3314, 3318, 3322, 3326, 3330, 3335, 3339, 3344, 3348, + 3353, 3359, 3366, 3373, 3381, 3388, 3396, 3403, 3411, 3415, + 3420, 3425, 3432, 3434, 3440, 3445, 3450, 3457, 3459, 3463, + 3466, 3469, 3473, 3477, 3481, 3485, 3489, 3493, 3497, 3501, + 3505, 3509, 3513, 3517, 3521, 3525, 3529, 3532, 3535, 3541, + 3548, 3555, 3563, 3565, 3568, 3570, 3572, 3574, 3577, 3580, + 3585, 3589, 3591, 3593, 3595, 3597, 3600, 3602, 3604, 3606, + 3608, 3610, 3612, 3614, 3617, 3622, 3625, 3629, 3633, 3638, + 3642, 3649, 3657, 3667, 3675, 3683, 3689, 3691, 3693, 3695, + 3701, 3708, 3715, 3720, 3725, 3730, 3735, 3742, 3748, 3754, + 3760, 3765, 3772, 3777, 3779, 3787, 3797, 3803, 3804, 3810, + 3815, 3816, 3818, 3819, 3822, 3823, 3825, 3829, 3833, 3836, + 3839, 3840, 3847, 3849, 3850, 3854, 3855, 3859, 3863, 3867, + 3868, 3870, 3875, 3878, 3881, 3884, 3887, 3890, 3894, 3897, + 3900, 3904, 3905, 3910, 3914, 3916, 3922, 3926, 3928, 3932, + 3934, 3937, 3941, 3943, 3947, 3949, 3952, 3954, 3955, 3957, + 3959, 3961, 3963, 3965, 3967, 3969, 3971, 3973, 3975, 3977, + 3979, 3981, 3983, 3985, 3987, 3989, 3991, 3993, 3995, 4000, + 4002, 4007, 4009, 4014, 4016, 4019, 4021, 4024, 4026, 4029, + 4031, 4035, 4037, 4041, 4043, 4046, 4048, 4052, 4054, 4057, + 4059, 4060, 4062, 4066, 4068, 4072, 4076, 4078, 4082, 4086, + 4087, 4089, 4091, 4093, 4095, 4097, 4099, 4101, 4103, 4105, + 4107, 4109, 4111, 4113, 4115, 4117, 4122, 4126, 4129, 4133, + 4134, 4138, 4142, 4145, 4148, 4150, 4151, 4154, 4157, 4161, + 4164, 4166, 4168, 4172, 4174, 4176, 4182, 4184, 4187, 4192, + 4195, 4196, 4198, 4199, 4201, 4205, 4207, 4209, 4212, 4216, + 4222, 4230, 4238, 4240, 4241, 4242, 4245, 4246, 4249, 4253, + 4257, 4261, 4267, 4275, 4283, 4284, 4287, 4289, 4290, 4292, + 4293, 4295, 4299, 4301, 4304, 4308, 4311, 4313, 4317, 4322, + 4325, 4327, 4331, 4333, 4337, 4339, 4342, 4344, 4345, 4349, + 4351, 4355, 4357, 4360, 4365, 4368, 4369, 4373, 4375, 4379, + 4381, 4384, 4389, 4392, 4393, 4395, 4399, 4401, 4405, 4407, + 4410, 4412, 4416, 4418, 4420, 4423, 4425, 4427, 4430, 4432, + 4434, 4437, 4445, 4448, 4454, 4458, 4462, 4464, 4466, 4468, + 4470, 4472, 4474, 4476, 4478, 4480, 4482, 4484, 4486, 4488, + 4490, 4493, 4496, 4500, 4504, 4505, 4507, 4509, 4511, 4517, + 4521, 4522, 4524, 4526, 4528, 4530, 4532, 4534, 4539, 4547, + 4554, 4557, 4558, 4560, 4562, 4564, 4566, 4580, 4597, 4599, + 4602, 4603, 4605, 4606, 4608, 4609, 4612, 4613, 4615, 4616, + 4623, 4632, 4639, 4648, 4655, 4664, 4668, 4671, 4673, 4674, + 4681, 4688, 4690, 4692, 4694, 4696, 4698, 4700, 4703, 4705, + 4707, 4709, 4711, 4713, 4718, 4725, 4729, 4732, 4737, 4741, + 4747, 4749, 4750, 4752, 4754, 4755, 4757, 4759, 4761, 4763, + 4765, 4767, 4769, 4771, 4773, 4775, 4777, 4779, 4781, 4783, + 4785, 4787, 4789, 4791, 4793, 4795, 4797, 4799, 4801, 4803, + 4805, 4807, 4809, 4811, 4813, 4815, 4817, 4819, 4821, 4823, + 4825, 4827, 4829, 4833, 4835, 4837, 4839, 4841, 4843, 4845, + 4848, 4850, 4852, 4855, 4859, 4863, 4867, 4871, 4873, 4877, + 4881, 4884, 4888, 4892, 4894, 4896, 4898, 4902, 4908, 4910, + 4912, 4914, 4916, 4920, 4923, 4928, 4935, 4942, 4943, 4945, + 4947, 4949, 4950, 4953, 4956, 4961, 4968, 4974, 4979, 4986, + 4988, 4990, 4992, 4994, 4996, 4998, 4999, 5001, 5005, 5007, + 5008, 5016, 5020, 5022, 5025, 5029, 5032, 5033, 5036, 5037, + 5040, 5045, 5051, 5060, 5063, 5067, 5073, 5075, 5076, 5079, + 5080, 5083, 5087, 5091, 5095, 5099, 5101, 5103, 5105, 5108, + 5112, 5115, 5118, 5121, 5124, 5128, 5133, 5137, 5139, 5141, + 5143, 5145, 5147, 5149, 5150, 5152, 5156, 5159, 5169, 5182, + 5194, 5207, 5222, 5226, 5231, 5236, 5237, 5245, 5256, 5266, + 5269, 5273, 5274, 5279, 5281, 5283, 5285, 5287, 5289, 5291, + 5293, 5295, 5297, 5299, 5301, 5303, 5305, 5307, 5309, 5311, + 5313, 5315, 5317, 5319, 5321, 5323, 5325, 5327, 5329, 5331, + 5333, 5335, 5337, 5339, 5341, 5343, 5345, 5347, 5349, 5351, + 5353, 5355, 5357, 5359, 5361, 5363, 5365, 5367, 5369, 5371, + 5373, 5375, 5377, 5379, 5381, 5383, 5385, 5387, 5389, 5391, + 5393, 5395, 5397, 5399, 5401, 5403, 5405, 5407, 5409, 5411, + 5413, 5415, 5417, 5419, 5421, 5423, 5425, 5427, 5429, 5431, + 5433, 5435, 5437, 5439, 5441, 5443, 5445, 5447, 5449, 5451, + 5453, 5455, 5457, 5459, 5461, 5463, 5465, 5467, 5469, 5471, + 5473, 5475, 5477, 5479, 5481, 5483, 5485, 5487, 5489, 5491, + 5493, 5495, 5497, 5499, 5501, 5503, 5505, 5507, 5509, 5511, + 5513, 5515, 5517, 5519, 5521, 5523, 5525, 5527, 5529, 5531, + 5533, 5535, 5537, 5539, 5541, 5543, 5545, 5547, 5549, 5551, + 5553, 5555, 5557, 5559, 5561, 5563, 5565, 5567, 5569, 5571, + 5573, 5575, 5577, 5579, 5581, 5583, 5585, 5587, 5589, 5591, + 5593, 5595, 5597, 5599, 5601, 5603, 5605, 5607, 5609, 5611, + 5613, 5615, 5617, 5619, 5621, 5623, 5625, 5627, 5629, 5631, + 5633, 5635, 5637, 5639, 5641, 5643, 5645, 5647, 5649, 5651, + 5653, 5655, 5657, 5659, 5661, 5663, 5665, 5667, 5669, 5671, + 5673, 5675, 5677, 5679, 5681, 5683, 5685, 5687, 5689, 5691, + 5693, 5695, 5697, 5699, 5701, 5703, 5705, 5707, 5709, 5711, + 5713, 5715, 5717, 5719, 5721, 5723, 5725, 5727, 5729, 5731, + 5733, 5735, 5737, 5739, 5741, 5743, 5745, 5747, 5749, 5751, + 5753, 5755, 5757, 5759, 5761, 5763, 5765, 5767, 5769, 5771, + 5773, 5775, 5777, 5779, 5781, 5783, 5785, 5787, 5789, 5791, + 5793, 5795, 5797, 5799, 5801, 5803, 5805, 5807, 5809, 5811, + 5813, 5815, 5817, 5819, 5821, 5823, 5825, 5827, 5829, 5831, + 5833, 5835, 5837, 5839, 5841, 5843, 5845, 5847, 5849, 5851, + 5853, 5855, 5857, 5859, 5861, 5863, 5865, 5867, 5869, 5871, + 5873, 5875, 5877, 5879, 5881, 5883, 5885, 5887, 5889, 5891, + 5893, 5895, 5897, 5899, 5901, 5903, 5905, 5907, 5909, 5911, + 5913, 5915, 5917, 5919, 5921, 5923, 5925, 5927, 5929, 5931, + 5933, 5935, 5937, 5939, 5941, 5943, 5945, 5947, 5949, 5951, + 5953, 5955, 5957, 5959, 5961, 5963, 5965, 5967, 5969, 5971, + 5973, 5975, 5977, 5979, 5981, 5983, 5985, 5987, 5989, 5991, + 5993, 5995, 5997, 5999, 6001, 6003, 6005, 6007, 6009, 6011, + 6013, 6015, 6017, 6019, 6021, 6023, 6025, 6027, 6029, 6031, + 6033, 6035, 6037, 6039, 6041, 6043, 6045, 6047, 6049, 6051, + 6053, 6055, 6057, 6059, 6061, 6063, 6065, 6067, 6069, 6071, + 6073, 6075, 6077, 6079, 6081, 6083, 6085, 6087, 6089, 6091, + 6093, 6095, 6097, 6099, 6101, 6103, 6105, 6107, 6109, 6111, + 6113, 6115, 6117, 6119, 6121, 6123, 6125, 6127, 6129, 6131, + 6133, 6135, 6137, 6139, 6141, 6143, 6145, 6147, 6149, 6151, + 6153, 6155, 6157, 6159, 6161, 6163, 6165, 6167, 6169, 6171, + 6173, 6175, 6177, 6179, 6181, 6183, 6185, 6187, 6189, 6191, + 6193, 6195, 6197, 6199, 6201, 6203, 6205, 6207, 6209, 6211, + 6213, 6215, 6217, 6219, 6221, 6223, 6225, 6227, 6229, 6231, + 6233, 6235, 6237, 6239, 6241, 6243, 6245, 6247, 6249, 6251, + 6253, 6255, 6257, 6259, 6261, 6263, 6265, 6267, 6269, 6271, + 6273, 6275, 6277, 6279, 6281, 6283, 6285, 6287, 6289, 6291, + 6293, 6295, 6297, 6299, 6301, 6303, 6305, 6307, 6309, 6311, + 6313, 6315, 6317, 6319, 6321, 6323, 6325, 6327, 6329, 6331, + 6333, 6335, 6337, 6339, 6341, 6343, 6345, 6347, 6349, 6351, + 6353, 6355, 6357, 6359, 6361, 6363, 6365, 6367, 6369, 6371, + 6373, 6375, 6377, 6379, 6381, 6383, 6385, 6387, 6389, 6391, + 6393, 6395, 6397, 6399, 6401, 6403, 6405, 6407, 6409, 6411, + 6413, 6415, 6417, 6419, 6421, 6423, 6425, 6427, 6429, 6431, + 6433, 6435, 6437, 6439, 6441, 6443, 6445, 6447, 6449, 6451, + 6453, 6455, 6457, 6459, 6461, 6463, 6465, 6467, 6469, 6471, + 6473, 6475, 6477, 6479, 6481, 6483, 6485, 6487, 6489, 6491, + 6493, 6495, 6497, 6499, 6501, 6503, 6505, 6507, 6509, 6511, + 6513, 6515, 6517, 6519, 6521, 6523 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int16 yyrhs[] = { 530, 0, -1, 531, -1, 531, 521, 532, -1, 532, - -1, 938, -1, 591, -1, 533, -1, 976, -1, 977, - -1, 990, -1, 939, -1, 941, -1, 668, -1, 993, - -1, 658, -1, 928, -1, 582, -1, 580, -1, 604, - -1, 576, -1, 544, -1, 972, -1, 978, -1, 598, - -1, 652, -1, 587, -1, 946, -1, 944, -1, 945, - -1, 931, -1, 555, -1, 963, -1, 579, -1, 925, + -1, 948, -1, 591, -1, 533, -1, 986, -1, 987, + -1, 999, -1, 949, -1, 951, -1, 668, -1, 1002, + -1, 658, -1, 938, -1, 582, -1, 580, -1, 604, + -1, 576, -1, 544, -1, 982, -1, 988, -1, 598, + -1, 652, -1, 587, -1, 956, -1, 954, -1, 955, + -1, 941, -1, 555, -1, 973, -1, 579, -1, 935, -1, 553, -1, 686, -1, 600, -1, 586, -1, 667, - -1, 603, -1, 967, -1, 981, -1, 957, -1, 984, - -1, 991, -1, -1, 32, 419, 773, 541, -1, 32, - 419, 192, 152, 773, 541, -1, 32, 203, 545, 541, + -1, 603, -1, 977, -1, 991, -1, 967, -1, 994, + -1, 1000, -1, -1, 32, 419, 775, 541, -1, 32, + 419, 192, 152, 775, 541, -1, 32, 203, 545, 541, -1, 32, 203, 192, 152, 545, 541, -1, 32, 384, 545, 541, -1, 32, 384, 192, 152, 545, 541, -1, 32, 470, 545, 541, -1, 32, 470, 192, 152, 545, - 541, -1, 536, -1, 534, 536, -1, 389, 117, 822, + 541, -1, 536, -1, 534, 536, -1, 389, 117, 824, -1, 137, 117, -1, 359, -1, 359, 593, 594, -1, 389, 595, -1, 389, 176, 651, -1, 540, -1, 537, 522, 540, -1, 26, 631, -1, 26, 192, 275, 152, @@ -1980,72 +1982,72 @@ static const yytype_int16 yyrhs[] = 546, 534, -1, 32, 554, 546, 137, 191, -1, 32, 554, 546, 137, 191, 192, 152, -1, 137, 554, 192, 152, 546, 656, -1, 137, 554, 546, 656, -1, 32, - 554, 546, 543, 442, 786, 782, 539, -1, 32, 554, - 546, 542, -1, 26, 621, -1, 32, 93, 913, 605, - -1, 460, 93, 913, -1, 137, 93, 192, 152, 913, - 656, -1, 137, 93, 913, 656, -1, 389, 245, -1, + 554, 546, 543, 442, 787, 784, 539, -1, 32, 554, + 546, 542, -1, 26, 621, -1, 32, 93, 923, 605, + -1, 460, 93, 923, -1, 137, 93, 192, 152, 923, + 656, -1, 137, 93, 923, 656, -1, 389, 245, -1, 389, 451, -1, 389, 619, -1, 357, 619, -1, 542, - -1, 457, 822, -1, -1, 615, -1, 389, 615, -1, + -1, 457, 824, -1, -1, 615, -1, 389, 615, -1, 26, 615, -1, 137, 629, -1, 538, -1, 541, 522, 538, -1, 294, 518, 537, 519, -1, 389, 107, -1, - 389, -1, -1, 111, 913, -1, 111, 326, 913, -1, + 389, -1, -1, 111, 923, -1, 111, 326, 923, -1, 111, 30, -1, 111, 326, 30, -1, 547, -1, 546, - 549, -1, 3, -1, 996, -1, 997, -1, 546, -1, + 549, -1, 3, -1, 1005, -1, 1006, -1, 546, -1, 5, -1, 5, -1, 550, -1, 549, 550, -1, 520, - 551, -1, 552, -1, 3, -1, 1000, -1, 996, -1, - 1002, -1, 32, 373, 913, 353, 431, 913, -1, 32, - 419, 773, 353, 431, 913, -1, 32, 419, 192, 152, - 773, 353, 431, 913, -1, 32, 384, 545, 353, 431, - 913, -1, 32, 384, 192, 152, 545, 353, 431, 913, - -1, 32, 470, 545, 353, 431, 913, -1, 32, 470, - 192, 152, 545, 353, 431, 913, -1, 32, 203, 545, - 353, 431, 913, -1, 32, 203, 192, 152, 545, 353, - 431, 913, -1, 32, 419, 773, 353, 554, 913, 431, - 913, -1, 32, 419, 192, 152, 773, 353, 554, 913, - 431, 913, -1, 32, 419, 773, 353, 93, 913, 431, - 913, -1, 32, 419, 192, 152, 773, 353, 93, 913, - 431, 913, -1, 82, -1, -1, 560, 213, 563, 220, + 551, -1, 552, -1, 3, -1, 1009, -1, 1005, -1, + 1011, -1, 32, 373, 923, 353, 431, 923, -1, 32, + 419, 775, 353, 431, 923, -1, 32, 419, 192, 152, + 775, 353, 431, 923, -1, 32, 384, 545, 353, 431, + 923, -1, 32, 384, 192, 152, 545, 353, 431, 923, + -1, 32, 470, 545, 353, 431, 923, -1, 32, 470, + 192, 152, 545, 353, 431, 923, -1, 32, 203, 545, + 353, 431, 923, -1, 32, 203, 192, 152, 545, 353, + 431, 923, -1, 32, 419, 775, 353, 554, 923, 431, + 923, -1, 32, 419, 192, 152, 775, 353, 554, 923, + 431, 923, -1, 32, 419, 775, 353, 93, 923, 431, + 923, -1, 32, 419, 192, 152, 775, 353, 93, 923, + 431, 923, -1, 82, -1, -1, 560, 213, 563, 220, 557, 558, 556, 564, 566, -1, 686, -1, 304, 567, 462, 686, -1, 518, 571, 519, 686, -1, 518, 571, 519, 304, 567, 462, 686, -1, 117, 463, -1, 545, -1, 545, 40, 546, -1, 59, 266, -1, 59, 321, - -1, -1, 518, 574, 519, 779, -1, 290, 93, 913, - -1, -1, 698, -1, -1, 546, 894, -1, 575, 507, - 822, -1, 518, 568, 519, 507, 822, -1, 295, 355, + -1, -1, 518, 574, 519, 781, -1, 290, 93, 923, + -1, -1, 698, -1, -1, 546, 897, -1, 575, 507, + 824, -1, 518, 568, 519, 507, 824, -1, 295, 355, -1, 295, 193, -1, -1, 290, 91, 559, 133, 454, - 389, 573, 779, -1, 290, 91, 559, 133, 276, -1, - -1, 546, 569, 570, 714, 715, -1, 833, 569, 570, - 714, 715, -1, 518, 822, 519, 569, 570, 714, 715, - -1, 361, 900, -1, -1, 456, -1, 418, -1, 575, - -1, 568, 522, 575, -1, 80, 920, -1, -1, 920, + 389, 573, 781, -1, 290, 91, 559, 133, 276, -1, + -1, 546, 569, 570, 714, 715, -1, 836, 569, 570, + 714, 715, -1, 518, 824, 519, 569, 570, 714, 715, + -1, 361, 903, -1, -1, 456, -1, 418, -1, 575, + -1, 568, 522, 575, -1, 80, 930, -1, -1, 930, -1, -1, 561, -1, 571, 522, 561, -1, 562, -1, 572, 522, 562, -1, 572, -1, 572, 522, -1, 565, - -1, 574, 522, 565, -1, 546, 894, -1, 100, 442, + -1, 574, 522, 565, -1, 546, 897, -1, 100, 442, 545, 40, 144, 687, -1, 100, 442, 545, 40, 144, - 518, 577, 519, -1, 100, 442, 545, 40, 786, -1, + 518, 577, 519, -1, 100, 442, 545, 40, 788, -1, 578, -1, -1, 548, -1, 578, 522, 548, -1, 323, - 546, -1, 323, 546, 507, 962, -1, 323, 546, 518, - 872, 519, -1, 100, 650, 384, 545, 581, -1, 100, + 546, -1, 323, 546, 507, 972, -1, 323, 546, 518, + 875, 519, -1, 100, 650, 384, 545, 581, -1, 100, 650, 384, 192, 275, 152, 545, 581, -1, 100, 295, 355, 650, 384, 545, 581, -1, 592, -1, -1, 100, 584, 380, 583, 585, 518, 685, 519, -1, 100, 584, 380, 192, 275, 152, 583, 585, 518, 685, 519, -1, 100, 295, 355, 584, 380, 583, 585, 518, 685, 519, -1, -1, 546, -1, -1, 425, -1, 314, -1, -1, - 199, 3, -1, 560, 454, 157, 639, -1, 151, 913, - 590, -1, 100, 650, 419, 995, 40, 151, 913, 590, - 994, -1, 100, 650, 419, 192, 275, 152, 995, 40, - 151, 913, 590, 994, -1, 822, -1, 923, 13, 822, + 199, 3, -1, 560, 454, 157, 639, -1, 151, 923, + 590, -1, 100, 650, 419, 1004, 40, 151, 923, 590, + 1003, -1, 100, 650, 419, 192, 275, 152, 1004, 40, + 151, 923, 590, 1003, -1, 824, -1, 933, 13, 824, -1, 588, -1, 589, 522, 588, -1, 518, 589, 519, -1, -1, 32, 384, 545, 592, -1, 32, 384, 192, 152, 545, 592, -1, 595, -1, 592, 595, -1, 480, -1, 504, -1, -1, 4, -1, 509, 4, -1, 510, - 4, -1, 597, -1, 40, 789, -1, 60, 594, -1, + 4, -1, 597, -1, 40, 791, -1, 60, 594, -1, 106, -1, 273, 106, -1, 202, 596, 594, -1, 251, 594, -1, 261, 594, -1, 273, 251, -1, 273, 261, - -1, 305, 59, 920, -1, 384, 266, 920, -1, 403, + -1, 305, 59, 930, -1, 384, 266, 930, -1, 403, 593, 594, -1, 359, -1, 359, 593, 594, -1, 59, - -1, -1, 916, -1, 509, 916, -1, 510, 916, -1, + -1, -1, 926, -1, 509, 926, -1, 510, 926, -1, 137, 584, 380, 546, 599, -1, 137, 584, 380, 192, 152, 546, 599, -1, -1, 172, 3, -1, 22, 601, -1, 52, 601, 602, -1, 403, 601, 602, -1, 86, @@ -2055,21 +2057,21 @@ static const yytype_int16 yyrhs[] = 626, 618, -1, 100, 650, 419, 192, 275, 152, 545, 518, 637, 519, 626, 618, -1, 100, 295, 355, 650, 419, 545, 518, 637, 519, 626, 618, -1, -1, 605, - 630, -1, 645, -1, 1002, -1, 864, -1, 594, -1, + 630, -1, 645, -1, 1011, -1, 867, -1, 594, -1, 548, -1, 274, -1, 518, 592, 519, -1, -1, 548, -1, 273, 25, -1, 360, -1, 63, -1, 389, 280, - -1, 389, 117, -1, 93, 913, 611, -1, 611, -1, - 625, -1, 80, 920, -1, 275, 280, -1, 280, -1, - 448, 636, -1, 329, 227, 636, -1, 74, 518, 822, - 519, 620, -1, 457, 88, 913, -1, 117, 823, -1, + -1, 389, 117, -1, 93, 923, 611, -1, 611, -1, + 625, -1, 80, 930, -1, 275, 280, -1, 280, -1, + 448, 636, -1, 329, 227, 636, -1, 74, 518, 824, + 519, 620, -1, 457, 88, 923, -1, 117, 825, -1, 347, 545, 639, 648, 617, -1, 472, -1, 409, -1, 612, -1, -1, 176, 651, 40, 191, 607, -1, 176, - 651, 40, 518, 822, 519, 613, -1, 40, 518, 822, + 651, 40, 518, 824, 519, 613, -1, 40, 518, 824, 519, 613, -1, 629, 608, -1, 290, 454, 609, -1, 616, -1, 641, -1, 616, 641, -1, 641, 616, -1, -1, 290, 86, 137, -1, 290, 86, 122, 369, -1, 290, 86, 328, 369, -1, -1, 518, 623, 519, -1, - 273, 205, -1, -1, 93, 913, 646, -1, 646, -1, + 273, 205, -1, -1, 93, 923, 646, -1, 646, -1, 85, -1, 94, -1, 118, -1, 191, -1, 204, -1, 405, -1, 408, -1, 30, -1, 642, -1, 623, 522, 642, -1, 457, 203, 633, -1, 119, -1, 275, 119, @@ -2078,7 +2080,7 @@ static const yytype_int16 yyrhs[] = -1, 628, 201, 622, -1, 628, 149, 622, -1, -1, 552, -1, 275, 119, -1, 119, -1, 207, 195, -1, 207, 120, -1, 275, 459, -1, 273, 205, -1, 546, - 786, 640, -1, 546, 785, 614, 640, -1, 635, -1, + 788, 640, -1, 546, 787, 614, 640, -1, 635, -1, 632, 522, 635, -1, 546, -1, 631, -1, 649, -1, 621, -1, 552, 507, 606, -1, 552, -1, 480, 627, -1, -1, 647, -1, 647, 522, -1, -1, 546, -1, @@ -2086,8 +2088,8 @@ static const yytype_int16 yyrhs[] = 122, 609, -1, 552, 507, 606, -1, 552, -1, 552, 520, 552, 507, 606, -1, 552, 520, 552, -1, 638, -1, 643, 522, 638, -1, 643, -1, 643, 522, -1, - 786, -1, 917, 921, 513, 442, -1, 390, 917, 921, - 513, 442, -1, 74, 518, 822, 519, 605, -1, 448, + 788, -1, 927, 931, 513, 442, -1, 390, 927, 931, + 513, 442, -1, 74, 518, 824, 519, 605, -1, 448, 518, 644, 519, 636, 605, -1, 448, 624, 605, -1, 329, 227, 518, 644, 519, 636, 605, -1, 329, 227, 624, 605, -1, 169, 227, 518, 644, 519, 347, 545, @@ -2097,16 +2099,16 @@ static const yytype_int16 yyrhs[] = 425, -1, 241, 423, -1, 178, 425, -1, 178, 423, -1, 451, -1, -1, 33, -1, 59, 117, -1, 137, 653, 192, 152, 655, 656, -1, 137, 653, 655, 656, - -1, 137, 654, 192, 152, 910, 656, -1, 137, 654, - 910, 656, -1, 137, 657, 913, 290, 920, 656, -1, - 137, 657, 192, 152, 913, 290, 920, 656, -1, 419, + -1, 137, 654, 192, 152, 920, 656, -1, 137, 654, + 920, 656, -1, 137, 657, 923, 290, 930, 656, -1, + 137, 657, 192, 152, 923, 290, 930, 656, -1, 419, -1, 384, -1, 174, -1, 246, -1, 246, 419, -1, 470, -1, 250, 470, -1, 203, -1, 169, 419, -1, 81, -1, 97, -1, 373, -1, 405, -1, 426, 377, 308, -1, 426, 377, 129, -1, 426, 377, 424, -1, 426, 377, 90, -1, 442, -1, 24, 252, -1, 146, 436, -1, 156, -1, 169, 107, 484, -1, 335, -1, - 387, -1, 920, -1, 655, 522, 920, -1, 63, -1, + 387, -1, 930, -1, 655, 522, 930, -1, 63, -1, 360, -1, -1, 320, -1, 370, -1, 436, -1, 100, 650, 665, 545, 662, -1, 100, 650, 665, 192, 275, 152, 545, 662, -1, 100, 295, 355, 650, 665, 545, @@ -2114,501 +2116,507 @@ static const yytype_int16 yyrhs[] = 665, 192, 275, 152, 545, 664, -1, 100, 295, 355, 650, 665, 545, 664, -1, 666, 40, 419, 688, -1, 666, 40, 419, 687, -1, 660, -1, 661, 522, 660, - -1, 659, -1, 661, -1, 666, 40, 822, -1, 663, + -1, 659, -1, 661, -1, 666, 40, 824, -1, 663, -1, 664, 522, 663, -1, 174, -1, 246, -1, 518, - 519, -1, 518, 872, 519, -1, 560, 454, 973, 389, - 573, 753, 974, 566, -1, 98, 681, 545, 639, 679, + 519, -1, 518, 875, 519, -1, 560, 454, 983, 389, + 573, 754, 984, 566, -1, 98, 681, 545, 639, 679, 670, 675, 684, 671, 593, 676, -1, 98, 518, 686, 519, 431, 675, 684, 593, 676, -1, 98, 172, 108, 546, 431, 546, 669, -1, -1, 518, 373, 519, -1, 518, 107, 519, -1, 172, -1, 431, -1, 673, 124, 548, -1, -1, 683, -1, 672, 522, 683, -1, 457, -1, -1, 40, -1, -1, 334, -1, -1, 680, -1, - 518, 685, 519, -1, 954, -1, 594, -1, 828, -1, - 511, -1, 518, 672, 519, -1, 829, -1, 830, -1, + 518, 685, 519, -1, 964, -1, 594, -1, 831, -1, + 511, -1, 518, 672, 519, -1, 832, -1, 833, -1, -1, 552, 677, -1, 480, 288, -1, -1, 680, 682, -1, -1, 55, -1, -1, 55, -1, 288, -1, 171, -1, 123, 674, 548, -1, 280, 674, 548, -1, 102, -1, 187, -1, 339, 674, 548, -1, 145, 674, 548, -1, 168, 339, 643, -1, 168, 339, 511, -1, 310, 59, 643, -1, 310, 59, 511, -1, 168, 275, 280, - 643, -1, 168, 280, 643, -1, 141, 548, -1, 954, + 643, -1, 168, 280, 643, -1, 141, 548, -1, 964, -1, 548, -1, 406, -1, 407, -1, 3, 520, 546, -1, 3, -1, 678, -1, 685, 522, 678, -1, 688, -1, 687, -1, 518, 688, 519, -1, 518, 687, 519, - -1, 518, 984, 519, -1, 691, -1, 689, 711, -1, - 689, 710, 744, 717, -1, 689, 710, 716, 745, -1, + -1, 518, 994, 519, -1, 691, -1, 689, 711, -1, + 689, 710, 745, 717, -1, 689, 710, 716, 746, -1, 698, 689, -1, 698, 689, 711, -1, 698, 689, 710, - 744, 717, -1, 698, 689, 710, 716, 745, -1, 691, - -1, 687, -1, 382, 708, 899, -1, -1, 382, 708, - 899, 702, 753, 779, 733, 742, 840, 743, 721, -1, - 382, 707, 901, 702, 753, 779, 733, 742, 840, 743, - 721, -1, 172, 754, 690, 702, 779, 733, 742, 840, - 743, 721, -1, 172, 754, 382, 707, 901, 702, 779, - 733, 742, 840, 743, 721, -1, 752, -1, 419, 773, + 745, 717, -1, 698, 689, 710, 716, 746, -1, 691, + -1, 687, -1, 382, 708, 902, -1, -1, 382, 708, + 902, 702, 754, 781, 734, 743, 843, 744, 722, -1, + 382, 707, 904, 702, 754, 781, 734, 743, 843, 744, + 722, -1, 172, 755, 690, 702, 781, 734, 743, 843, + 744, 722, -1, 172, 755, 382, 707, 904, 702, 781, + 734, 743, 843, 744, 722, -1, 753, -1, 419, 775, -1, 689, 447, 705, 706, 689, -1, 689, 447, 705, 689, -1, 689, 218, 705, 689, -1, 689, 147, 705, - 689, -1, 693, 756, 457, 901, -1, 693, 756, 457, - 901, 181, 59, 912, -1, 693, 756, 181, 59, 912, - -1, 693, 756, 290, 697, -1, 693, 756, 290, 697, - 181, 59, 912, -1, 693, 756, 290, 697, 457, 901, - -1, 693, 756, 290, 697, 457, 901, 181, 59, 912, - -1, 694, 756, 290, 901, 220, 266, 913, 692, 912, - -1, 694, 756, 290, 901, -1, 462, -1, 463, -1, - 315, -1, 317, -1, 452, -1, 316, -1, 823, -1, - 823, 199, 518, 688, 519, -1, 759, -1, 695, -1, + 689, -1, 693, 758, 457, 904, -1, 693, 758, 457, + 904, 181, 59, 922, -1, 693, 758, 181, 59, 922, + -1, 693, 758, 290, 697, -1, 693, 758, 290, 697, + 181, 59, 922, -1, 693, 758, 290, 697, 457, 904, + -1, 693, 758, 290, 697, 457, 904, 181, 59, 922, + -1, 694, 758, 290, 904, 220, 266, 923, 692, 922, + -1, 694, 758, 290, 904, -1, 462, -1, 463, -1, + 315, -1, 317, -1, 452, -1, 316, -1, 825, -1, + 825, 199, 518, 688, 519, -1, 761, -1, 695, -1, 696, 522, 695, -1, 696, -1, 696, 522, -1, 480, 699, -1, 504, 699, -1, 480, 345, 699, -1, 700, - -1, 699, 522, 700, -1, 913, 922, 40, 701, 518, - 927, 519, -1, 250, -1, 275, 250, -1, -1, 220, + -1, 699, 522, 700, -1, 923, 932, 40, 701, 518, + 937, 519, -1, 250, -1, 275, 250, -1, -1, 220, 703, -1, -1, 425, 704, 545, -1, 423, 704, 545, -1, 241, 425, 704, 545, -1, 241, 423, 704, 545, -1, 178, 425, 704, 545, -1, 178, 423, 704, 545, -1, 451, 704, 545, -1, 419, 545, -1, 545, -1, 419, -1, -1, 30, -1, 132, -1, -1, 59, 266, - -1, 132, -1, 132, 290, 518, 870, 519, -1, 30, + -1, 132, -1, 132, 290, 518, 873, 519, -1, 30, -1, -1, 193, 282, -1, 358, 282, -1, -1, 711, -1, -1, 296, 59, 712, -1, 296, 59, 30, 714, - 715, -1, 713, -1, 712, 522, 713, -1, 822, 457, - 864, 715, -1, 822, 714, 715, -1, 41, -1, 126, + 715, -1, 713, -1, 712, 522, 713, -1, 824, 457, + 867, 715, -1, 824, 714, 715, -1, 41, -1, 126, -1, -1, 503, 164, -1, 503, 231, -1, -1, 718, 719, -1, 719, 718, -1, 718, -1, 719, -1, 716, - -1, -1, 238, 727, -1, 238, 727, 522, 728, -1, - 162, 732, 729, 731, 291, -1, 162, 732, 731, 291, - -1, 287, 728, -1, 287, 729, 731, -1, 4, 513, - -1, 9, 513, -1, 4, 313, -1, 9, 313, -1, - 9, -1, 9, 369, -1, 457, 371, 723, -1, -1, - 546, -1, -1, 722, 518, 720, 519, 726, -1, 720, - -1, 720, 518, 546, 519, -1, 720, 518, 546, 522, - 9, 519, -1, 421, 723, -1, 724, -1, -1, 354, - 518, 9, 519, -1, -1, 822, -1, 30, -1, 822, - 513, -1, 4, 313, -1, 9, 313, -1, 822, -1, - 824, -1, 509, 730, -1, 510, 730, -1, 916, -1, + -1, -1, 238, 728, -1, 238, 728, 522, 729, -1, + 162, 733, 730, 732, 291, -1, 162, 733, 732, 291, + -1, 287, 729, -1, 287, 730, 732, -1, 4, -1, + 9, -1, 829, -1, 720, 513, -1, 720, 313, -1, + 720, -1, 720, 369, -1, 457, 371, 724, -1, -1, + 546, -1, -1, 723, 518, 721, 519, 727, -1, 721, + -1, 721, 518, 546, 519, -1, 721, 518, 546, 522, + 9, 519, -1, 421, 724, -1, 725, -1, -1, 354, + 518, 9, 519, -1, -1, 824, -1, 30, -1, 824, + 513, -1, 4, 313, -1, 9, 313, -1, 824, -1, + 826, -1, 509, 731, -1, 510, 731, -1, 926, -1, 4, -1, 368, -1, 369, -1, 164, -1, 272, -1, - 181, 59, 735, -1, 181, 59, 30, -1, -1, 736, - -1, 734, 522, 736, -1, 734, -1, 734, 522, -1, - 822, -1, 737, -1, 739, -1, 738, -1, 740, -1, - 518, 519, -1, 367, 518, 870, 519, -1, 103, 518, - 870, 519, -1, 182, 391, 518, 735, 519, -1, 182, - -1, 183, -1, 186, 822, -1, -1, 336, 822, -1, - -1, 746, -1, 167, 341, 291, -1, 744, -1, -1, - 747, -1, 746, 747, -1, 748, 749, 750, -1, 167, + 181, 59, 736, -1, 181, 59, 30, -1, -1, 737, + -1, 735, 522, 737, -1, 735, -1, 735, 522, -1, + 824, -1, 738, -1, 740, -1, 739, -1, 741, -1, + 518, 519, -1, 367, 518, 873, 519, -1, 103, 518, + 873, 519, -1, 182, 391, 518, 736, 519, -1, 182, + -1, 183, -1, 186, 824, -1, -1, 336, 824, -1, + -1, 747, -1, 167, 341, 291, -1, 745, -1, -1, + 748, -1, 747, 748, -1, 749, 750, 751, -1, 167, 454, -1, 167, 273, 227, 454, -1, 167, 392, -1, - 167, 227, 392, -1, 285, 909, -1, -1, 279, -1, - 396, 244, -1, -1, 463, 518, 870, 519, -1, 751, - 522, 518, 870, 519, -1, 751, -1, 751, 522, -1, - 172, 755, -1, -1, 756, -1, 754, 522, 756, -1, - 754, -1, 754, 522, -1, 773, 768, 725, -1, 774, - 769, 725, -1, 752, 767, 725, -1, 232, 774, 769, - -1, 687, 768, 725, -1, 232, 687, 768, -1, 766, - -1, 518, 766, 519, 767, -1, 756, 315, 518, 901, - 167, 762, 757, 519, 768, -1, 756, 452, 758, 518, - 763, 167, 765, 519, 768, -1, 181, 59, 911, -1, - -1, 200, 282, -1, 148, 282, -1, -1, 823, 199, - 518, 901, 519, -1, 823, 199, 547, -1, 825, -1, - 827, -1, 518, 868, 519, -1, 760, 199, 518, 901, - 519, -1, 760, 199, 547, -1, 761, -1, 762, 761, - -1, 547, -1, 518, 911, 519, -1, 763, 199, 518, - 901, 519, -1, 764, -1, 765, 764, -1, 518, 766, - 519, -1, 756, 101, 225, 756, -1, 756, 770, 225, - 756, 772, -1, 756, 225, 756, 772, -1, 756, 269, - 770, 225, 756, -1, 756, 269, 225, 756, -1, 756, - 42, 770, 225, 756, 772, -1, 756, 42, 225, 756, - 772, -1, 756, 322, 225, 756, -1, 756, 37, 225, - 756, 772, -1, 756, 383, 225, 756, 772, -1, 40, - 547, 518, 911, 519, -1, 40, 547, -1, 546, 518, - 911, 519, -1, 546, -1, 767, -1, -1, 767, -1, - 40, 518, 780, 519, -1, 40, 547, 518, 780, 519, - -1, 546, 518, 780, 519, -1, -1, 173, 771, -1, - 235, 771, -1, 364, 771, -1, 383, -1, 37, -1, - 209, -1, 300, -1, -1, 457, 518, 911, 519, -1, - 290, 822, -1, 545, -1, 545, 511, -1, 291, 545, - -1, 291, 518, 545, 519, -1, 833, 778, -1, 369, - 172, 518, 776, 519, 778, -1, 833, 777, -1, 775, - -1, 776, 522, 775, -1, 40, 518, 780, 519, -1, - -1, 504, 297, -1, -1, 477, 822, -1, -1, 781, - -1, 780, 522, 781, -1, 547, 786, 782, -1, 80, - 920, -1, -1, 546, 786, -1, 783, 522, 546, 786, - -1, 368, -1, 412, -1, 786, -1, -1, 789, 788, - -1, 390, 789, 788, -1, 789, 39, 516, 916, 517, - -1, 390, 789, 39, 516, 916, 517, -1, 789, 39, - -1, 390, 789, 39, -1, 787, -1, 784, 518, 783, - 519, 788, -1, 247, 518, 874, 519, 788, -1, 447, - 518, 783, 519, 788, -1, 3, 520, 3, -1, 787, - 520, 3, -1, 788, 516, 517, -1, 788, 516, 916, - 517, -1, -1, 791, -1, 793, -1, 795, -1, 799, - -1, 805, -1, 806, 821, -1, 806, 518, 916, 519, - -1, 793, -1, 796, -1, 800, -1, 805, -1, 919, - 792, -1, 518, 871, 519, -1, -1, 216, -1, 217, - -1, 397, -1, 54, -1, 342, -1, 165, 794, -1, - 136, 325, -1, 115, 792, -1, 112, 792, -1, 283, - 792, -1, 57, -1, 518, 916, 519, -1, -1, 797, - -1, 798, -1, 797, -1, 798, -1, 56, 804, 518, - 870, 519, -1, 56, 804, -1, 801, -1, 802, -1, - 801, -1, 802, -1, 803, 518, 916, 519, -1, 803, - -1, 72, 804, -1, 71, 804, -1, 464, -1, 268, - 72, 804, -1, 268, 71, 804, -1, 270, 804, -1, - 467, -1, -1, 430, 518, 916, 519, 807, -1, 430, - 807, -1, 429, 518, 916, 519, 807, -1, 429, 807, + 167, 227, 392, -1, 285, 919, -1, -1, 279, -1, + 396, 244, -1, -1, 463, 518, 873, 519, -1, 752, + 522, 518, 873, 519, -1, 752, -1, 752, 522, -1, + 172, 756, -1, -1, 758, -1, 755, 522, 758, -1, + 755, -1, 755, 522, -1, 547, 523, -1, 775, 770, + 726, -1, 757, 775, 726, -1, 776, 771, 726, -1, + 757, 776, 726, -1, 753, 769, 726, -1, 232, 776, + 771, -1, 687, 770, 726, -1, 757, 687, 726, -1, + 232, 687, 770, -1, 768, -1, 518, 768, 519, 769, + -1, 757, 518, 768, 519, -1, 758, 315, 518, 904, + 167, 764, 759, 519, 770, -1, 758, 452, 760, 518, + 765, 167, 767, 519, 770, -1, 181, 59, 921, -1, + -1, 200, 282, -1, 148, 282, -1, -1, 825, 199, + 518, 904, 519, -1, 825, 199, 547, -1, 827, -1, + 830, -1, 518, 871, 519, -1, 762, 199, 518, 904, + 519, -1, 762, 199, 547, -1, 763, -1, 764, 763, + -1, 547, -1, 518, 921, 519, -1, 765, 199, 518, + 904, 519, -1, 766, -1, 767, 766, -1, 518, 768, + 519, -1, 758, 101, 225, 758, -1, 758, 772, 225, + 758, 774, -1, 758, 225, 758, 774, -1, 758, 269, + 772, 225, 758, -1, 758, 269, 225, 758, -1, 758, + 42, 772, 225, 758, 774, -1, 758, 42, 225, 758, + 774, -1, 758, 322, 225, 758, -1, 758, 37, 225, + 758, 774, -1, 758, 383, 225, 758, 774, -1, 40, + 547, 518, 921, 519, -1, 40, 547, -1, 546, 518, + 921, 519, -1, 546, -1, 769, -1, -1, 769, -1, + 40, 518, 782, 519, -1, 40, 547, 518, 782, 519, + -1, 546, 518, 782, 519, -1, -1, 173, 773, -1, + 235, 773, -1, 364, 773, -1, 383, -1, 37, -1, + 209, -1, 300, -1, -1, 457, 518, 921, 519, -1, + 290, 824, -1, 545, -1, 545, 511, -1, 291, 545, + -1, 291, 518, 545, 519, -1, 836, 780, -1, 369, + 172, 518, 778, 519, 780, -1, 836, 779, -1, 777, + -1, 778, 522, 777, -1, 40, 518, 782, 519, -1, + -1, 504, 297, -1, -1, 477, 824, -1, -1, 783, + -1, 782, 522, 783, -1, 547, 788, 784, -1, 80, + 930, -1, -1, 546, 788, -1, 785, 522, 546, 788, + -1, 368, -1, 412, -1, 788, -1, -1, 791, 790, + -1, 390, 791, 790, -1, 791, 39, 516, 926, 517, + -1, 390, 791, 39, 516, 926, 517, -1, 791, 39, + -1, 390, 791, 39, -1, 789, -1, 786, 518, 785, + 519, 790, -1, 247, 518, 877, 519, 790, -1, 447, + 518, 785, 519, 790, -1, 3, 520, 3, -1, 789, + 520, 3, -1, 790, 516, 517, -1, 790, 516, 926, + 517, -1, -1, 793, -1, 795, -1, 797, -1, 801, + -1, 807, -1, 808, 823, -1, 808, 518, 926, 519, + -1, 795, -1, 798, -1, 802, -1, 807, -1, 929, + 794, -1, 518, 874, 519, -1, -1, 216, -1, 217, + -1, 397, -1, 54, -1, 342, -1, 165, 796, -1, + 136, 325, -1, 115, 794, -1, 112, 794, -1, 283, + 794, -1, 57, -1, 518, 926, 519, -1, -1, 799, + -1, 800, -1, 799, -1, 800, -1, 56, 806, 518, + 873, 519, -1, 56, 806, -1, 803, -1, 804, -1, + 803, -1, 804, -1, 805, 518, 926, 519, -1, 805, + -1, 72, 806, -1, 71, 806, -1, 464, -1, 268, + 72, 806, -1, 268, 71, 806, -1, 270, 806, -1, + 467, -1, -1, 430, 518, 926, 519, 809, -1, 430, + 809, -1, 429, 518, 926, 519, 809, -1, 429, 809, -1, 219, -1, 504, 429, 501, -1, 482, 429, 501, -1, -1, 498, -1, 499, -1, 263, -1, 264, -1, 109, -1, 110, -1, 189, -1, 190, -1, 259, -1, 260, -1, 378, -1, 379, -1, 257, -1, 258, -1, 253, -1, 254, -1, 474, -1, 475, -1, 337, -1, 338, -1, 113, -1, 114, -1, 69, -1, 68, -1, - 256, -1, 255, -1, 808, -1, 809, -1, 810, -1, - 811, -1, 812, -1, 813, -1, 814, -1, 815, -1, - 816, -1, 817, -1, 818, -1, 819, -1, 820, -1, - 808, 431, 809, -1, 810, 431, 811, -1, 810, 431, - 812, -1, 810, 431, 813, -1, 811, 431, 812, -1, - 811, 431, 813, -1, 812, 431, 813, -1, -1, 824, - -1, 822, 11, 786, -1, 822, 80, 920, -1, 822, - 46, 429, 501, 822, -1, 509, 822, -1, 510, 822, - -1, 822, 509, 822, -1, 822, 510, 822, -1, 822, - 511, 822, -1, 822, 512, 822, -1, 822, 15, 822, - -1, 822, 513, 822, -1, 822, 514, 822, -1, 822, - 16, 822, -1, 822, 505, 822, -1, 822, 506, 822, - -1, 822, 507, 822, -1, 822, 19, 822, -1, 822, - 20, 822, -1, 822, 21, 822, -1, 822, 863, 822, - -1, 863, 822, -1, 822, 863, -1, 822, 36, 822, - -1, 822, 295, 822, -1, 275, 822, -1, 502, 822, - -1, 822, 177, 822, -1, 822, 237, 822, -1, 822, - 237, 822, 145, 822, -1, 822, 502, 237, 822, -1, - 822, 502, 237, 822, 145, 822, -1, 822, 194, 822, - -1, 822, 194, 822, 145, 822, -1, 822, 502, 194, - 822, -1, 822, 502, 194, 822, 145, 822, -1, 822, - 394, 431, 822, -1, 822, 394, 431, 822, 145, 822, - -1, 822, 502, 394, 431, 822, -1, 822, 502, 394, - 431, 822, 145, 822, -1, 822, 222, 280, -1, 822, - 223, -1, 822, 222, 275, 280, -1, 822, 275, 280, - -1, 822, 278, -1, 822, 17, 822, -1, 822, 18, - 822, -1, 852, 302, 852, -1, 822, 222, 438, -1, - 822, 222, 275, 438, -1, 822, 222, 160, -1, 822, - 222, 275, 160, -1, 822, 222, 449, -1, 822, 222, - 275, 449, -1, 822, 222, 132, 172, 822, -1, 822, - 222, 275, 132, 172, 822, -1, 822, 222, 285, 518, - 874, 519, -1, 822, 222, 275, 285, 518, 874, 519, - -1, 822, 53, 898, 823, 36, 822, -1, 822, 502, - 53, 898, 823, 36, 822, -1, 822, 53, 416, 823, - 36, 822, -1, 822, 502, 53, 416, 823, 36, 822, - -1, 822, 199, 884, -1, 822, 502, 199, 884, -1, - 822, 865, 860, 687, -1, 822, 865, 860, 518, 822, - 519, -1, 117, -1, 511, 83, 518, 822, 519, -1, - 83, 518, 822, 519, -1, 511, 904, 908, -1, 546, - 520, 511, 904, 908, -1, 824, -1, 823, 11, 786, - -1, 509, 823, -1, 510, 823, -1, 823, 509, 823, - -1, 823, 510, 823, -1, 823, 511, 823, -1, 823, - 512, 823, -1, 823, 15, 823, -1, 823, 513, 823, - -1, 823, 514, 823, -1, 823, 16, 823, -1, 823, - 505, 823, -1, 823, 506, 823, -1, 823, 507, 823, - -1, 823, 19, 823, -1, 823, 20, 823, -1, 823, - 21, 823, -1, 823, 863, 823, -1, 863, 823, -1, - 823, 863, -1, 823, 222, 132, 172, 823, -1, 823, - 222, 275, 132, 172, 823, -1, 823, 222, 285, 518, - 874, 519, -1, 823, 222, 275, 285, 518, 874, 519, - -1, 825, -1, 826, 897, -1, 892, -1, 915, -1, - 687, -1, 687, 549, -1, 152, 687, -1, 741, 518, - 870, 519, -1, 518, 822, 519, -1, 827, -1, 852, - -1, 523, -1, 10, -1, 829, -1, 830, -1, 832, - -1, 885, -1, 828, -1, 836, -1, 39, 687, -1, - 39, 516, 871, 517, -1, 524, 9, -1, 525, 552, - -1, 516, 871, 517, -1, 526, 855, 527, -1, 247, - 526, 859, 527, -1, 914, 518, 519, -1, 914, 518, - 872, 710, 709, 519, -1, 914, 518, 466, 873, 710, - 709, 519, -1, 914, 518, 872, 522, 466, 873, 710, - 709, 519, -1, 914, 518, 30, 872, 710, 709, 519, - -1, 914, 518, 132, 872, 710, 709, 519, -1, 831, - 837, 838, 839, 843, -1, 834, -1, 831, -1, 834, - -1, 81, 167, 518, 822, 519, -1, 66, 518, 822, - 40, 786, 519, -1, 441, 518, 822, 40, 786, 519, - -1, 159, 518, 875, 519, -1, 303, 518, 877, 519, - -1, 321, 518, 879, 519, -1, 414, 518, 880, 519, - -1, 435, 518, 822, 40, 786, 519, -1, 437, 518, - 58, 883, 519, -1, 437, 518, 233, 883, 519, -1, - 437, 518, 432, 883, 519, -1, 437, 518, 883, 519, - -1, 281, 518, 822, 522, 822, 519, -1, 79, 518, - 870, 519, -1, 890, -1, 516, 822, 167, 835, 199, - 822, 517, -1, 516, 822, 167, 835, 199, 824, 192, - 822, 517, -1, 481, 181, 518, 711, 519, -1, -1, - 163, 518, 477, 822, 519, -1, 163, 518, 822, 519, - -1, -1, 155, -1, -1, 479, 841, -1, -1, 842, - -1, 841, 522, 842, -1, 546, 40, 844, -1, 301, - 844, -1, 301, 546, -1, -1, 518, 845, 846, 710, - 847, 519, -1, 546, -1, -1, 310, 59, 869, -1, - -1, 340, 848, 850, -1, 369, 848, 850, -1, 184, - 848, 850, -1, -1, 849, -1, 53, 849, 36, 849, - -1, 444, 324, -1, 444, 166, -1, 104, 368, -1, - 822, 324, -1, 822, 166, -1, 148, 104, 368, -1, - 148, 181, -1, 148, 428, -1, 148, 273, 298, -1, - -1, 368, 518, 870, 519, -1, 368, 518, 519, -1, - 851, -1, 518, 869, 522, 822, 519, -1, 547, 528, - 822, -1, 853, -1, 854, 522, 853, -1, 854, -1, - 854, 522, -1, 822, 528, 822, -1, 856, -1, 857, - 522, 856, -1, 857, -1, 857, 522, -1, 858, -1, - -1, 38, -1, 399, -1, 30, -1, 8, -1, 862, - -1, 509, -1, 510, -1, 511, -1, 512, -1, 15, - -1, 513, -1, 514, -1, 16, -1, 505, -1, 506, - -1, 507, -1, 19, -1, 20, -1, 21, -1, 8, - -1, 292, 518, 866, 519, -1, 861, -1, 292, 518, - 866, 519, -1, 861, -1, 292, 518, 866, 519, -1, - 237, -1, 502, 237, -1, 177, -1, 502, 177, -1, - 194, -1, 502, 194, -1, 861, -1, 546, 520, 866, - -1, 824, -1, 867, 522, 824, -1, 867, -1, 867, - 522, -1, 822, -1, 869, 522, 822, -1, 869, -1, - 869, 522, -1, 870, -1, -1, 873, -1, 872, 522, - 873, -1, 822, -1, 923, 13, 822, -1, 923, 14, - 822, -1, 786, -1, 874, 522, 786, -1, 876, 172, - 822, -1, -1, 3, -1, 808, -1, 809, -1, 810, + 256, -1, 255, -1, 810, -1, 811, -1, 812, -1, + 813, -1, 814, -1, 815, -1, 816, -1, 817, -1, + 818, -1, 819, -1, 820, -1, 821, -1, 822, -1, + 810, 431, 811, -1, 812, 431, 813, -1, 812, 431, + 814, -1, 812, 431, 815, -1, 813, 431, 814, -1, + 813, 431, 815, -1, 814, 431, 815, -1, -1, 826, + -1, 824, 11, 788, -1, 824, 80, 930, -1, 824, + 46, 429, 501, 824, -1, 509, 824, -1, 510, 824, + -1, 824, 509, 824, -1, 824, 510, 824, -1, 824, + 511, 824, -1, 824, 512, 824, -1, 824, 15, 824, + -1, 824, 513, 824, -1, 824, 514, 824, -1, 824, + 16, 824, -1, 824, 505, 824, -1, 824, 506, 824, + -1, 824, 507, 824, -1, 824, 19, 824, -1, 824, + 20, 824, -1, 824, 21, 824, -1, 824, 866, 824, + -1, 866, 824, -1, 824, 866, -1, 824, 36, 824, + -1, 824, 295, 824, -1, 275, 824, -1, 502, 824, + -1, 824, 177, 824, -1, 824, 237, 824, -1, 824, + 237, 824, 145, 824, -1, 824, 502, 237, 824, -1, + 824, 502, 237, 824, 145, 824, -1, 824, 194, 824, + -1, 824, 194, 824, 145, 824, -1, 824, 502, 194, + 824, -1, 824, 502, 194, 824, 145, 824, -1, 824, + 394, 431, 824, -1, 824, 394, 431, 824, 145, 824, + -1, 824, 502, 394, 431, 824, -1, 824, 502, 394, + 431, 824, 145, 824, -1, 824, 222, 280, -1, 824, + 223, -1, 824, 222, 275, 280, -1, 824, 275, 280, + -1, 824, 278, -1, 824, 17, 824, -1, 824, 18, + 824, -1, 855, 302, 855, -1, 824, 222, 438, -1, + 824, 222, 275, 438, -1, 824, 222, 160, -1, 824, + 222, 275, 160, -1, 824, 222, 449, -1, 824, 222, + 275, 449, -1, 824, 222, 132, 172, 824, -1, 824, + 222, 275, 132, 172, 824, -1, 824, 222, 285, 518, + 877, 519, -1, 824, 222, 275, 285, 518, 877, 519, + -1, 824, 53, 901, 825, 36, 824, -1, 824, 502, + 53, 901, 825, 36, 824, -1, 824, 53, 416, 825, + 36, 824, -1, 824, 502, 53, 416, 825, 36, 824, + -1, 824, 199, 887, -1, 824, 502, 199, 887, -1, + 824, 868, 863, 687, -1, 824, 868, 863, 518, 824, + 519, -1, 117, -1, 511, 83, 518, 824, 519, -1, + 83, 518, 824, 519, -1, 511, 910, 914, 918, -1, + 546, 520, 511, 910, 914, 918, -1, 826, -1, 825, + 11, 788, -1, 509, 825, -1, 510, 825, -1, 825, + 509, 825, -1, 825, 510, 825, -1, 825, 511, 825, + -1, 825, 512, 825, -1, 825, 15, 825, -1, 825, + 513, 825, -1, 825, 514, 825, -1, 825, 16, 825, + -1, 825, 505, 825, -1, 825, 506, 825, -1, 825, + 507, 825, -1, 825, 19, 825, -1, 825, 20, 825, + -1, 825, 21, 825, -1, 825, 866, 825, -1, 866, + 825, -1, 825, 866, -1, 825, 222, 132, 172, 825, + -1, 825, 222, 275, 132, 172, 825, -1, 825, 222, + 285, 518, 877, 519, -1, 825, 222, 275, 285, 518, + 877, 519, -1, 827, -1, 828, 900, -1, 895, -1, + 925, -1, 687, -1, 687, 549, -1, 152, 687, -1, + 742, 518, 873, 519, -1, 518, 824, 519, -1, 830, + -1, 855, -1, 524, -1, 10, -1, 525, 552, -1, + 829, -1, 832, -1, 833, -1, 835, -1, 888, -1, + 831, -1, 839, -1, 39, 687, -1, 39, 516, 874, + 517, -1, 526, 9, -1, 516, 874, 517, -1, 527, + 858, 528, -1, 247, 527, 862, 528, -1, 924, 518, + 519, -1, 924, 518, 875, 710, 709, 519, -1, 924, + 518, 466, 876, 710, 709, 519, -1, 924, 518, 875, + 522, 466, 876, 710, 709, 519, -1, 924, 518, 30, + 875, 710, 709, 519, -1, 924, 518, 132, 875, 710, + 709, 519, -1, 834, 840, 841, 842, 846, -1, 837, + -1, 834, -1, 837, -1, 81, 167, 518, 824, 519, + -1, 66, 518, 824, 40, 788, 519, -1, 441, 518, + 824, 40, 788, 519, -1, 159, 518, 878, 519, -1, + 303, 518, 880, 519, -1, 321, 518, 882, 519, -1, + 414, 518, 883, 519, -1, 435, 518, 824, 40, 788, + 519, -1, 437, 518, 58, 886, 519, -1, 437, 518, + 233, 886, 519, -1, 437, 518, 432, 886, 519, -1, + 437, 518, 886, 519, -1, 281, 518, 824, 522, 824, + 519, -1, 79, 518, 873, 519, -1, 893, -1, 516, + 824, 167, 838, 199, 824, 517, -1, 516, 824, 167, + 838, 199, 826, 192, 824, 517, -1, 481, 181, 518, + 711, 519, -1, -1, 163, 518, 477, 824, 519, -1, + 163, 518, 824, 519, -1, -1, 155, -1, -1, 479, + 844, -1, -1, 845, -1, 844, 522, 845, -1, 546, + 40, 847, -1, 301, 847, -1, 301, 546, -1, -1, + 518, 848, 849, 710, 850, 519, -1, 546, -1, -1, + 310, 59, 872, -1, -1, 340, 851, 853, -1, 369, + 851, 853, -1, 184, 851, 853, -1, -1, 852, -1, + 53, 852, 36, 852, -1, 444, 324, -1, 444, 166, + -1, 104, 368, -1, 824, 324, -1, 824, 166, -1, + 148, 104, 368, -1, 148, 181, -1, 148, 428, -1, + 148, 273, 298, -1, -1, 368, 518, 873, 519, -1, + 368, 518, 519, -1, 854, -1, 518, 872, 522, 824, + 519, -1, 547, 523, 824, -1, 856, -1, 857, 522, + 856, -1, 857, -1, 857, 522, -1, 824, 523, 824, + -1, 859, -1, 860, 522, 859, -1, 860, -1, 860, + 522, -1, 861, -1, -1, 38, -1, 399, -1, 30, + -1, 8, -1, 865, -1, 509, -1, 510, -1, 511, + -1, 512, -1, 15, -1, 513, -1, 514, -1, 16, + -1, 505, -1, 506, -1, 507, -1, 19, -1, 20, + -1, 21, -1, 8, -1, 292, 518, 869, 519, -1, + 864, -1, 292, 518, 869, 519, -1, 864, -1, 292, + 518, 869, 519, -1, 237, -1, 502, 237, -1, 177, + -1, 502, 177, -1, 194, -1, 502, 194, -1, 864, + -1, 546, 520, 869, -1, 826, -1, 870, 522, 826, + -1, 870, -1, 870, 522, -1, 824, -1, 872, 522, + 824, -1, 872, -1, 872, 522, -1, 873, -1, -1, + 876, -1, 875, 522, 876, -1, 824, -1, 933, 13, + 824, -1, 933, 14, 824, -1, 788, -1, 877, 522, + 788, -1, 879, 172, 824, -1, -1, 3, -1, 810, -1, 811, -1, 812, -1, 813, -1, 814, -1, 815, -1, 816, -1, 817, -1, 818, -1, 819, -1, 820, - -1, 548, -1, 822, 878, 881, 882, -1, 822, 878, - 881, -1, 318, 822, -1, 823, 199, 823, -1, -1, - 822, 881, 882, -1, 822, 882, 881, -1, 822, 881, - -1, 822, 882, -1, 869, -1, -1, 172, 822, -1, - 167, 822, -1, 822, 172, 870, -1, 172, 870, -1, - 870, -1, 687, -1, 518, 870, 519, -1, 892, -1, - 827, -1, 65, 889, 886, 888, 143, -1, 887, -1, - 886, 887, -1, 476, 822, 427, 822, -1, 139, 822, - -1, -1, 822, -1, -1, 891, -1, 890, 522, 891, - -1, 546, -1, 546, -1, 546, 549, -1, 516, 822, - 517, -1, 516, 893, 528, 893, 517, -1, 516, 893, - 528, 893, 528, 893, 517, -1, 516, 893, 528, 510, - 528, 893, 517, -1, 822, -1, -1, -1, 894, 550, - -1, -1, 518, 519, -1, 518, 872, 519, -1, 520, - 551, 895, -1, 516, 822, 517, -1, 516, 893, 528, - 893, 517, -1, 516, 893, 528, 893, 528, 893, 517, - -1, 516, 893, 528, 510, 528, 893, 517, -1, -1, - 897, 896, -1, 45, -1, -1, 901, -1, -1, 902, - -1, 900, 522, 902, -1, 900, -1, 900, 522, -1, - 822, 40, 924, -1, 822, 3, -1, 822, -1, 148, - 518, 911, 519, -1, 148, 546, -1, 903, -1, -1, - 822, 40, 546, -1, 905, -1, 906, 522, 905, -1, - 906, -1, 906, 522, -1, 355, 518, 907, 519, -1, - 355, 905, -1, -1, 545, -1, 909, 522, 545, -1, - 913, -1, 910, 522, 913, -1, 910, -1, 910, 522, - -1, 911, -1, 518, 911, 519, -1, 547, -1, 918, - -1, 546, 549, -1, 916, -1, 4, -1, 548, 894, - -1, 6, -1, 7, -1, 914, 548, -1, 914, 518, - 872, 710, 709, 519, 548, -1, 790, 548, -1, 806, - 518, 822, 519, 821, -1, 806, 916, 821, -1, 806, - 548, 821, -1, 438, -1, 160, -1, 280, -1, 9, - -1, 3, -1, 996, -1, 1001, -1, 3, -1, 996, - -1, 998, -1, 3, -1, 996, -1, 999, -1, 546, - -1, 546, 921, -1, 520, 551, -1, 921, 520, 551, - -1, 518, 911, 519, -1, -1, 917, -1, 552, -1, - 5, -1, 326, 913, 926, 40, 927, -1, 518, 874, - 519, -1, -1, 686, -1, 555, -1, 667, -1, 668, - -1, 972, -1, 984, -1, 100, 373, 545, 929, -1, - 100, 373, 192, 275, 152, 545, 929, -1, 100, 295, - 355, 373, 545, 929, -1, 929, 930, -1, -1, 604, - -1, 931, -1, 580, -1, 991, -1, 100, 937, 203, - 934, 935, 290, 545, 933, 518, 574, 519, 936, 779, - -1, 100, 937, 203, 934, 192, 275, 152, 633, 290, - 545, 933, 518, 574, 519, 936, 779, -1, 546, -1, - 457, 932, -1, -1, 89, -1, -1, 633, -1, -1, - 480, 619, -1, -1, 448, -1, -1, 32, 419, 773, - 389, 373, 913, -1, 32, 419, 192, 152, 773, 389, - 373, 913, -1, 32, 384, 545, 389, 373, 913, -1, - 32, 384, 192, 152, 545, 389, 373, 913, -1, 32, - 470, 545, 389, 373, 913, -1, 32, 470, 192, 152, - 545, 389, 373, 913, -1, 168, 75, 940, -1, 75, - 940, -1, 546, -1, -1, 84, 290, 943, 545, 222, - 942, -1, 84, 290, 82, 822, 222, 942, -1, 548, - -1, 280, -1, 419, -1, 384, -1, 174, -1, 246, - -1, 246, 419, -1, 470, -1, 108, -1, 203, -1, - 373, -1, 442, -1, 154, 108, 548, 676, -1, 154, - 108, 546, 431, 548, 676, -1, 198, 108, 548, -1, - 153, 949, -1, 153, 953, 947, 949, -1, 153, 468, - 949, -1, 153, 518, 952, 519, 949, -1, 468, -1, - -1, 954, -1, 594, -1, -1, 938, -1, 591, -1, - 533, -1, 990, -1, 939, -1, 668, -1, 993, -1, - 658, -1, 928, -1, 580, -1, 604, -1, 576, -1, - 544, -1, 972, -1, 652, -1, 587, -1, 931, -1, - 555, -1, 963, -1, 579, -1, 925, -1, 553, -1, - 686, -1, 600, -1, 667, -1, 586, -1, 967, -1, - 981, -1, 957, -1, 984, -1, 991, -1, 3, -1, - 996, -1, 1000, -1, 950, -1, 548, -1, 955, -1, - 952, 522, 955, -1, 35, -1, 34, -1, 438, -1, - 160, -1, 290, -1, 951, -1, 956, 948, -1, 950, - -1, 953, -1, 389, 958, -1, 389, 241, 958, -1, - 389, 388, 958, -1, 389, 178, 958, -1, 389, 465, - 958, -1, 959, -1, 988, 172, 104, -1, 429, 501, - 961, -1, 373, 548, -1, 988, 431, 962, -1, 988, - 507, 962, -1, 822, -1, 548, -1, 3, -1, 806, - 548, 821, -1, 806, 518, 916, 519, 548, -1, 594, - -1, 117, -1, 241, -1, 960, -1, 962, 522, 960, - -1, 240, 965, -1, 964, 214, 965, 966, -1, 964, - 214, 965, 172, 546, 966, -1, 964, 214, 965, 172, - 548, 966, -1, -1, 168, -1, 548, -1, 546, -1, - -1, 469, 548, -1, 469, 546, -1, 458, 969, 971, - 947, -1, 458, 969, 971, 947, 545, 922, -1, 458, - 969, 971, 947, 976, -1, 458, 518, 970, 519, -1, - 458, 518, 970, 519, 545, 922, -1, 953, -1, 468, - -1, 171, -1, 173, -1, 3, -1, 173, -1, -1, - 968, -1, 970, 522, 968, -1, 171, -1, -1, 560, - 122, 172, 973, 975, 974, 566, -1, 439, 704, 973, - -1, 773, -1, 773, 546, -1, 773, 40, 546, -1, - 477, 822, -1, -1, 457, 755, -1, -1, 953, 947, - -1, 953, 947, 545, 922, -1, 47, 979, 548, 980, - 676, -1, 47, 192, 275, 152, 979, 548, 980, 676, - -1, 128, 552, -1, 128, 108, 552, -1, 128, 108, - 192, 152, 552, -1, 108, -1, -1, 40, 546, -1, - -1, 357, 983, -1, 357, 241, 983, -1, 357, 388, - 983, -1, 357, 178, 983, -1, 357, 465, 983, -1, - 988, -1, 30, -1, 982, -1, 429, 501, -1, 433, - 224, 236, -1, 986, 686, -1, 415, 686, -1, 415, - 989, -1, 986, 989, -1, 986, 429, 501, -1, 986, - 433, 224, 236, -1, 986, 30, 987, -1, 986, -1, - 127, -1, 126, -1, 393, -1, 985, -1, 420, -1, - -1, 546, -1, 988, 520, 546, -1, 546, -1, 989, - 520, 546, -1, 61, 831, -1, 100, 650, 470, 545, - 639, 936, 40, 686, 992, -1, 100, 650, 470, 192, - 275, 152, 545, 639, 936, 40, 686, 992, -1, 100, - 295, 355, 650, 470, 545, 639, 936, 40, 686, 992, - -1, 100, 650, 345, 470, 545, 518, 643, 519, 936, - 40, 686, 992, -1, 100, 295, 355, 650, 345, 470, - 545, 518, 643, 519, 936, 40, 686, 992, -1, 480, - 74, 293, -1, 480, 64, 74, 293, -1, 480, 241, - 74, 293, -1, -1, 100, 650, 419, 995, 40, 686, - 994, -1, 100, 650, 419, 192, 275, 152, 995, 40, - 686, 994, -1, 100, 295, 355, 650, 419, 995, 40, - 686, 994, -1, 480, 107, -1, 480, 273, 107, -1, - -1, 545, 639, 626, 618, -1, 22, -1, 23, -1, - 24, -1, 25, -1, 26, -1, 27, -1, 28, -1, - 29, -1, 31, -1, 32, -1, 33, -1, 43, -1, - 44, -1, 46, -1, 47, -1, 48, -1, 50, -1, - 51, -1, 52, -1, 59, -1, 60, -1, 61, -1, - 62, -1, 63, -1, 64, -1, 67, -1, 68, -1, - 69, -1, 70, -1, 73, -1, 75, -1, 76, -1, - 77, -1, 78, -1, 84, -1, 85, -1, 86, -1, - 87, -1, 88, -1, 90, -1, 91, -1, 92, -1, - 94, -1, 95, -1, 96, -1, 97, -1, 98, -1, - 99, -1, 102, -1, 103, -1, 104, -1, 105, -1, - 106, -1, 107, -1, 108, -1, 109, -1, 110, -1, - 111, -1, 113, -1, 114, -1, 116, -1, 118, -1, - 120, -1, 121, -1, 122, -1, 123, -1, 124, -1, - 125, -1, 128, -1, 129, -1, 130, -1, 131, -1, - 134, -1, 135, -1, 136, -1, 137, -1, 138, -1, - 140, -1, 141, -1, 142, -1, 144, -1, 145, -1, - 146, -1, 148, -1, 149, -1, 150, -1, 151, -1, - 153, -1, 154, -1, 155, -1, 156, -1, 157, -1, - 158, -1, 161, -1, 163, -1, 164, -1, 166, -1, - 168, -1, 170, -1, 174, -1, 175, -1, 178, -1, - 180, -1, 184, -1, 185, -1, 187, -1, 188, -1, - 189, -1, 190, -1, 191, -1, 192, -1, 193, -1, - 195, -1, 196, -1, 197, -1, 198, -1, 200, -1, - 201, -1, 202, -1, 203, -1, 204, -1, 205, -1, - 206, -1, 208, -1, 211, -1, 212, -1, 213, -1, - 214, -1, 215, -1, 221, -1, 224, -1, 226, -1, - 227, -1, 228, -1, 229, -1, 230, -1, 231, -1, - 234, -1, 236, -1, 239, -1, 240, -1, 241, -1, - 242, -1, 243, -1, 244, -1, 245, -1, 246, -1, - 248, -1, 249, -1, 250, -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, - 271, -1, 272, -1, 273, -1, 276, -1, 277, -1, - 279, -1, 282, -1, 284, -1, 285, -1, 286, -1, - 288, -1, 289, -1, 292, -1, 293, -1, 294, -1, - 297, -1, 298, -1, 301, -1, 304, -1, 305, -1, - 306, -1, 307, -1, 308, -1, 309, -1, 310, -1, - 311, -1, 312, -1, 313, -1, 314, -1, 319, -1, - 320, -1, 323, -1, 324, -1, 326, -1, 327, -1, - 328, -1, 330, -1, 331, -1, 332, -1, 333, -1, - 334, -1, 335, -1, 337, -1, 338, -1, 339, -1, - 340, -1, 341, -1, 343, -1, 344, -1, 345, -1, - 346, -1, 348, -1, 349, -1, 350, -1, 351, -1, - 352, -1, 353, -1, 354, -1, 355, -1, 356, -1, - 357, -1, 358, -1, 359, -1, 360, -1, 362, -1, - 363, -1, 365, -1, 366, -1, 367, -1, 369, -1, - 370, -1, 371, -1, 372, -1, 373, -1, 374, -1, - 375, -1, 376, -1, 377, -1, 378, -1, 379, -1, - 380, -1, 381, -1, 384, -1, 385, -1, 386, -1, - 387, -1, 388, -1, 389, -1, 391, -1, 392, -1, - 395, -1, 396, -1, 398, -1, 400, -1, 401, -1, - 402, -1, 403, -1, 404, -1, 405, -1, 406, -1, - 407, -1, 408, -1, 409, -1, 410, -1, 411, -1, - 413, -1, 417, -1, 418, -1, 420, -1, 422, -1, - 423, -1, 424, -1, 425, -1, 426, -1, 428, -1, - 433, -1, 434, -1, 436, -1, 439, -1, 440, -1, - 442, -1, 443, -1, 444, -1, 445, -1, 446, -1, - 449, -1, 450, -1, 451, -1, 453, -1, 454, -1, - 455, -1, 456, -1, 458, -1, 459, -1, 460, -1, - 461, -1, 462, -1, 465, -1, 467, -1, 469, -1, - 470, -1, 471, -1, 472, -1, 473, -1, 474, -1, - 475, -1, 478, -1, 481, -1, 482, -1, 483, -1, - 484, -1, 485, -1, 486, -1, 498, -1, 499, -1, - 500, -1, 501, -1, 53, -1, 54, -1, 56, -1, - 57, -1, 71, -1, 72, -1, 79, -1, 83, -1, - 112, -1, 115, -1, 152, -1, 159, -1, 165, -1, - 176, -1, 182, -1, 183, -1, 210, -1, 216, -1, - 217, -1, 219, -1, 247, -1, 268, -1, 270, -1, - 274, -1, 281, -1, 283, -1, 299, -1, 303, -1, - 321, -1, 325, -1, 342, -1, 368, -1, 390, -1, - 397, -1, 412, -1, 414, -1, 429, -1, 430, -1, - 435, -1, 437, -1, 441, -1, 463, -1, 464, -1, - 487, -1, 488, -1, 489, -1, 490, -1, 491, -1, - 492, -1, 493, -1, 494, -1, 495, -1, 496, -1, - 497, -1, 42, -1, 49, -1, 55, -1, 81, -1, - 89, -1, 101, -1, 171, -1, 173, -1, 176, -1, - 177, -1, 194, -1, 209, -1, 222, -1, 223, -1, - 225, -1, 235, -1, 237, -1, 247, -1, 269, -1, - 278, -1, 300, -1, 302, -1, 322, -1, 364, -1, - 394, -1, 412, -1, 421, -1, 468, -1, 37, -1, - 42, -1, 49, -1, 55, -1, 81, -1, 83, -1, - 89, -1, 101, -1, 171, -1, 173, -1, 177, -1, - 194, -1, 209, -1, 222, -1, 223, -1, 225, -1, - 235, -1, 237, -1, 269, -1, 278, -1, 300, -1, - 302, -1, 322, -1, 364, -1, 383, -1, 394, -1, - 421, -1, 441, -1, 468, -1, 37, -1, 42, -1, - 49, -1, 53, -1, 54, -1, 55, -1, 56, -1, - 57, -1, 72, -1, 71, -1, 79, -1, 81, -1, - 83, -1, 89, -1, 101, -1, 112, -1, 115, -1, - 152, -1, 159, -1, 165, -1, 171, -1, 173, -1, - 176, -1, 177, -1, 182, -1, 183, -1, 194, -1, - 209, -1, 210, -1, 217, -1, 219, -1, 216, -1, - 222, -1, 223, -1, 225, -1, 235, -1, 237, -1, - 247, -1, 268, -1, 269, -1, 270, -1, 274, -1, - 278, -1, 281, -1, 283, -1, 300, -1, 299, -1, - 302, -1, 303, -1, 321, -1, 322, -1, 325, -1, - 342, -1, 364, -1, 368, -1, 383, -1, 390, -1, - 394, -1, 397, -1, 412, -1, 414, -1, 421, -1, - 429, -1, 430, -1, 435, -1, 437, -1, 441, -1, - 463, -1, 464, -1, 468, -1, 487, -1, 488, -1, - 489, -1, 490, -1, 491, -1, 492, -1, 493, -1, - 494, -1, 495, -1, 496, -1, 497, -1, 37, -1, - 42, -1, 49, -1, 55, -1, 81, -1, 83, -1, - 89, -1, 101, -1, 171, -1, 173, -1, 176, -1, - 177, -1, 194, -1, 209, -1, 222, -1, 223, -1, - 225, -1, 235, -1, 237, -1, 247, -1, 269, -1, - 278, -1, 300, -1, 302, -1, 322, -1, 364, -1, - 383, -1, 394, -1, 412, -1, 421, -1, 441, -1, - 468, -1, 30, -1, 34, -1, 35, -1, 36, -1, - 38, -1, 39, -1, 40, -1, 41, -1, 45, -1, - 58, -1, 65, -1, 66, -1, 74, -1, 80, -1, - 82, -1, 93, -1, 100, -1, 117, -1, 119, -1, - 126, -1, 127, -1, 132, -1, 133, -1, 139, -1, - 143, -1, 147, -1, 160, -1, 162, -1, 167, -1, - 169, -1, 172, -1, 179, -1, 181, -1, 186, -1, - 199, -1, 207, -1, 218, -1, 220, -1, 232, -1, - 233, -1, 238, -1, 275, -1, 280, -1, 287, -1, - 290, -1, 291, -1, 295, -1, 296, -1, 315, -1, - 316, -1, 317, -1, 318, -1, 329, -1, 336, -1, - 347, -1, 361, -1, 382, -1, 393, -1, 399, -1, - 415, -1, 416, -1, 419, -1, 427, -1, 431, -1, - 432, -1, 438, -1, 447, -1, 448, -1, 452, -1, - 457, -1, 466, -1, 476, -1, 477, -1, 479, -1, - 480, -1 + -1, 821, -1, 822, -1, 548, -1, 824, 881, 884, + 885, -1, 824, 881, 884, -1, 318, 824, -1, 825, + 199, 825, -1, -1, 824, 884, 885, -1, 824, 885, + 884, -1, 824, 884, -1, 824, 885, -1, 872, -1, + -1, 172, 824, -1, 167, 824, -1, 824, 172, 873, + -1, 172, 873, -1, 873, -1, 687, -1, 518, 873, + 519, -1, 895, -1, 830, -1, 65, 892, 889, 891, + 143, -1, 890, -1, 889, 890, -1, 476, 824, 427, + 824, -1, 139, 824, -1, -1, 824, -1, -1, 894, + -1, 893, 522, 894, -1, 546, -1, 546, -1, 546, + 549, -1, 516, 824, 517, -1, 516, 896, 523, 896, + 517, -1, 516, 896, 523, 896, 523, 896, 517, -1, + 516, 896, 523, 510, 523, 896, 517, -1, 824, -1, + -1, -1, 897, 550, -1, -1, 518, 519, -1, 518, + 875, 519, -1, 520, 551, 898, -1, 516, 824, 517, + -1, 516, 896, 523, 896, 517, -1, 516, 896, 523, + 896, 523, 896, 517, -1, 516, 896, 523, 510, 523, + 896, 517, -1, -1, 900, 899, -1, 45, -1, -1, + 904, -1, -1, 905, -1, 903, 522, 905, -1, 903, + -1, 903, 522, -1, 824, 40, 934, -1, 824, 3, + -1, 824, -1, 546, 523, 824, -1, 148, 518, 909, + 519, -1, 148, 907, -1, 547, -1, 907, 520, 547, + -1, 907, -1, 908, 522, 907, -1, 908, -1, 908, + 522, -1, 906, -1, -1, 824, 40, 546, -1, 911, + -1, 912, 522, 911, -1, 912, -1, 912, 522, -1, + 355, 518, 913, 519, -1, 355, 911, -1, -1, 907, + 40, 546, -1, 915, -1, 916, 522, 915, -1, 916, + -1, 916, 522, -1, 353, 518, 917, 519, -1, 353, + 915, -1, -1, 545, -1, 919, 522, 545, -1, 923, + -1, 920, 522, 923, -1, 920, -1, 920, 522, -1, + 921, -1, 518, 921, 519, -1, 547, -1, 928, -1, + 546, 549, -1, 926, -1, 4, -1, 548, 897, -1, + 6, -1, 7, -1, 924, 548, -1, 924, 518, 875, + 710, 709, 519, 548, -1, 792, 548, -1, 808, 518, + 824, 519, 823, -1, 808, 926, 823, -1, 808, 548, + 823, -1, 438, -1, 160, -1, 280, -1, 9, -1, + 3, -1, 1005, -1, 1010, -1, 3, -1, 1005, -1, + 1007, -1, 3, -1, 1005, -1, 1008, -1, 546, -1, + 546, 931, -1, 520, 551, -1, 931, 520, 551, -1, + 518, 921, 519, -1, -1, 927, -1, 552, -1, 5, + -1, 326, 923, 936, 40, 937, -1, 518, 877, 519, + -1, -1, 686, -1, 555, -1, 667, -1, 668, -1, + 982, -1, 994, -1, 100, 373, 545, 939, -1, 100, + 373, 192, 275, 152, 545, 939, -1, 100, 295, 355, + 373, 545, 939, -1, 939, 940, -1, -1, 604, -1, + 941, -1, 580, -1, 1000, -1, 100, 947, 203, 944, + 945, 290, 545, 943, 518, 574, 519, 946, 781, -1, + 100, 947, 203, 944, 192, 275, 152, 633, 290, 545, + 943, 518, 574, 519, 946, 781, -1, 546, -1, 457, + 942, -1, -1, 89, -1, -1, 633, -1, -1, 480, + 619, -1, -1, 448, -1, -1, 32, 419, 775, 389, + 373, 923, -1, 32, 419, 192, 152, 775, 389, 373, + 923, -1, 32, 384, 545, 389, 373, 923, -1, 32, + 384, 192, 152, 545, 389, 373, 923, -1, 32, 470, + 545, 389, 373, 923, -1, 32, 470, 192, 152, 545, + 389, 373, 923, -1, 168, 75, 950, -1, 75, 950, + -1, 546, -1, -1, 84, 290, 953, 545, 222, 952, + -1, 84, 290, 82, 824, 222, 952, -1, 548, -1, + 280, -1, 419, -1, 384, -1, 174, -1, 246, -1, + 246, 419, -1, 470, -1, 108, -1, 203, -1, 373, + -1, 442, -1, 154, 108, 548, 676, -1, 154, 108, + 546, 431, 548, 676, -1, 198, 108, 548, -1, 153, + 959, -1, 153, 963, 957, 959, -1, 153, 468, 959, + -1, 153, 518, 962, 519, 959, -1, 468, -1, -1, + 964, -1, 594, -1, -1, 948, -1, 591, -1, 533, + -1, 999, -1, 949, -1, 668, -1, 1002, -1, 658, + -1, 938, -1, 580, -1, 604, -1, 576, -1, 544, + -1, 982, -1, 652, -1, 587, -1, 941, -1, 555, + -1, 973, -1, 579, -1, 935, -1, 553, -1, 686, + -1, 600, -1, 667, -1, 586, -1, 977, -1, 991, + -1, 967, -1, 994, -1, 1000, -1, 3, -1, 1005, + -1, 1009, -1, 960, -1, 548, -1, 965, -1, 962, + 522, 965, -1, 35, -1, 34, -1, 438, -1, 160, + -1, 290, -1, 961, -1, 966, 958, -1, 960, -1, + 963, -1, 389, 968, -1, 389, 241, 968, -1, 389, + 388, 968, -1, 389, 178, 968, -1, 389, 465, 968, + -1, 969, -1, 998, 172, 104, -1, 429, 501, 971, + -1, 373, 548, -1, 998, 431, 972, -1, 998, 507, + 972, -1, 824, -1, 548, -1, 3, -1, 808, 548, + 823, -1, 808, 518, 926, 519, 548, -1, 594, -1, + 117, -1, 241, -1, 970, -1, 972, 522, 970, -1, + 240, 975, -1, 974, 214, 975, 976, -1, 974, 214, + 975, 172, 546, 976, -1, 974, 214, 975, 172, 548, + 976, -1, -1, 168, -1, 548, -1, 546, -1, -1, + 469, 548, -1, 469, 546, -1, 458, 979, 981, 957, + -1, 458, 979, 981, 957, 545, 932, -1, 458, 979, + 981, 957, 986, -1, 458, 518, 980, 519, -1, 458, + 518, 980, 519, 545, 932, -1, 963, -1, 468, -1, + 171, -1, 173, -1, 3, -1, 173, -1, -1, 978, + -1, 980, 522, 978, -1, 171, -1, -1, 560, 122, + 172, 983, 985, 984, 566, -1, 439, 704, 983, -1, + 775, -1, 775, 546, -1, 775, 40, 546, -1, 477, + 824, -1, -1, 457, 756, -1, -1, 963, 957, -1, + 963, 957, 545, 932, -1, 47, 989, 548, 990, 676, + -1, 47, 192, 275, 152, 989, 548, 990, 676, -1, + 128, 552, -1, 128, 108, 552, -1, 128, 108, 192, + 152, 552, -1, 108, -1, -1, 40, 546, -1, -1, + 357, 993, -1, 357, 241, 993, -1, 357, 388, 993, + -1, 357, 178, 993, -1, 357, 465, 993, -1, 998, + -1, 30, -1, 992, -1, 429, 501, -1, 433, 224, + 236, -1, 996, 686, -1, 415, 686, -1, 415, 545, + -1, 996, 545, -1, 996, 429, 501, -1, 996, 433, + 224, 236, -1, 996, 30, 997, -1, 996, -1, 127, + -1, 126, -1, 393, -1, 995, -1, 420, -1, -1, + 546, -1, 998, 520, 546, -1, 61, 834, -1, 100, + 650, 470, 545, 639, 946, 40, 686, 1001, -1, 100, + 650, 470, 192, 275, 152, 545, 639, 946, 40, 686, + 1001, -1, 100, 295, 355, 650, 470, 545, 639, 946, + 40, 686, 1001, -1, 100, 650, 345, 470, 545, 518, + 643, 519, 946, 40, 686, 1001, -1, 100, 295, 355, + 650, 345, 470, 545, 518, 643, 519, 946, 40, 686, + 1001, -1, 480, 74, 293, -1, 480, 64, 74, 293, + -1, 480, 241, 74, 293, -1, -1, 100, 650, 419, + 1004, 40, 686, 1003, -1, 100, 650, 419, 192, 275, + 152, 1004, 40, 686, 1003, -1, 100, 295, 355, 650, + 419, 1004, 40, 686, 1003, -1, 480, 107, -1, 480, + 273, 107, -1, -1, 545, 639, 626, 618, -1, 22, + -1, 23, -1, 24, -1, 25, -1, 26, -1, 27, + -1, 28, -1, 29, -1, 31, -1, 32, -1, 33, + -1, 43, -1, 44, -1, 46, -1, 47, -1, 48, + -1, 50, -1, 51, -1, 52, -1, 59, -1, 60, + -1, 61, -1, 62, -1, 63, -1, 64, -1, 67, + -1, 68, -1, 69, -1, 70, -1, 73, -1, 75, + -1, 76, -1, 77, -1, 78, -1, 84, -1, 85, + -1, 86, -1, 87, -1, 88, -1, 90, -1, 91, + -1, 92, -1, 94, -1, 95, -1, 96, -1, 97, + -1, 98, -1, 99, -1, 102, -1, 103, -1, 104, + -1, 105, -1, 106, -1, 107, -1, 108, -1, 109, + -1, 110, -1, 111, -1, 113, -1, 114, -1, 116, + -1, 118, -1, 120, -1, 121, -1, 122, -1, 123, + -1, 124, -1, 125, -1, 128, -1, 129, -1, 130, + -1, 131, -1, 134, -1, 135, -1, 136, -1, 137, + -1, 138, -1, 140, -1, 141, -1, 142, -1, 144, + -1, 145, -1, 146, -1, 148, -1, 149, -1, 150, + -1, 151, -1, 153, -1, 154, -1, 155, -1, 156, + -1, 157, -1, 158, -1, 161, -1, 163, -1, 164, + -1, 166, -1, 168, -1, 170, -1, 174, -1, 175, + -1, 178, -1, 180, -1, 184, -1, 185, -1, 187, + -1, 188, -1, 189, -1, 190, -1, 191, -1, 192, + -1, 193, -1, 195, -1, 196, -1, 197, -1, 198, + -1, 200, -1, 201, -1, 202, -1, 203, -1, 204, + -1, 205, -1, 206, -1, 208, -1, 211, -1, 212, + -1, 213, -1, 214, -1, 215, -1, 221, -1, 224, + -1, 226, -1, 227, -1, 228, -1, 229, -1, 230, + -1, 231, -1, 234, -1, 236, -1, 239, -1, 240, + -1, 241, -1, 242, -1, 243, -1, 244, -1, 245, + -1, 246, -1, 248, -1, 249, -1, 250, -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, 271, -1, 272, -1, 273, -1, 276, + -1, 277, -1, 279, -1, 282, -1, 284, -1, 285, + -1, 286, -1, 288, -1, 289, -1, 292, -1, 293, + -1, 294, -1, 297, -1, 298, -1, 301, -1, 304, + -1, 305, -1, 306, -1, 307, -1, 308, -1, 309, + -1, 310, -1, 311, -1, 312, -1, 313, -1, 314, + -1, 319, -1, 320, -1, 323, -1, 324, -1, 326, + -1, 327, -1, 328, -1, 330, -1, 331, -1, 332, + -1, 333, -1, 334, -1, 335, -1, 337, -1, 338, + -1, 339, -1, 340, -1, 341, -1, 343, -1, 344, + -1, 345, -1, 346, -1, 348, -1, 349, -1, 350, + -1, 351, -1, 352, -1, 353, -1, 354, -1, 355, + -1, 356, -1, 357, -1, 358, -1, 359, -1, 360, + -1, 362, -1, 363, -1, 365, -1, 366, -1, 367, + -1, 369, -1, 370, -1, 371, -1, 372, -1, 373, + -1, 374, -1, 375, -1, 376, -1, 377, -1, 378, + -1, 379, -1, 380, -1, 381, -1, 384, -1, 385, + -1, 386, -1, 387, -1, 388, -1, 389, -1, 391, + -1, 392, -1, 395, -1, 396, -1, 398, -1, 400, + -1, 401, -1, 402, -1, 403, -1, 404, -1, 405, + -1, 406, -1, 407, -1, 408, -1, 409, -1, 410, + -1, 411, -1, 413, -1, 417, -1, 418, -1, 420, + -1, 422, -1, 423, -1, 424, -1, 425, -1, 426, + -1, 428, -1, 433, -1, 434, -1, 436, -1, 439, + -1, 440, -1, 442, -1, 443, -1, 444, -1, 445, + -1, 446, -1, 449, -1, 450, -1, 451, -1, 453, + -1, 454, -1, 455, -1, 456, -1, 458, -1, 459, + -1, 460, -1, 461, -1, 462, -1, 465, -1, 467, + -1, 469, -1, 470, -1, 471, -1, 472, -1, 473, + -1, 474, -1, 475, -1, 478, -1, 481, -1, 482, + -1, 483, -1, 484, -1, 485, -1, 486, -1, 498, + -1, 499, -1, 500, -1, 501, -1, 53, -1, 54, + -1, 56, -1, 57, -1, 71, -1, 72, -1, 79, + -1, 83, -1, 112, -1, 115, -1, 152, -1, 159, + -1, 165, -1, 176, -1, 182, -1, 183, -1, 210, + -1, 216, -1, 217, -1, 219, -1, 247, -1, 268, + -1, 270, -1, 274, -1, 281, -1, 283, -1, 299, + -1, 303, -1, 321, -1, 325, -1, 342, -1, 368, + -1, 390, -1, 397, -1, 412, -1, 414, -1, 429, + -1, 430, -1, 435, -1, 437, -1, 441, -1, 463, + -1, 464, -1, 487, -1, 488, -1, 489, -1, 490, + -1, 491, -1, 492, -1, 493, -1, 494, -1, 495, + -1, 496, -1, 497, -1, 42, -1, 49, -1, 55, + -1, 81, -1, 89, -1, 101, -1, 171, -1, 173, + -1, 176, -1, 177, -1, 194, -1, 209, -1, 222, + -1, 223, -1, 225, -1, 235, -1, 237, -1, 247, + -1, 269, -1, 278, -1, 300, -1, 302, -1, 322, + -1, 364, -1, 394, -1, 412, -1, 421, -1, 468, + -1, 37, -1, 42, -1, 49, -1, 55, -1, 81, + -1, 83, -1, 89, -1, 101, -1, 171, -1, 173, + -1, 177, -1, 194, -1, 209, -1, 222, -1, 223, + -1, 225, -1, 235, -1, 237, -1, 269, -1, 278, + -1, 300, -1, 302, -1, 322, -1, 364, -1, 383, + -1, 394, -1, 421, -1, 441, -1, 468, -1, 37, + -1, 42, -1, 49, -1, 53, -1, 54, -1, 55, + -1, 56, -1, 57, -1, 72, -1, 71, -1, 79, + -1, 81, -1, 83, -1, 89, -1, 101, -1, 112, + -1, 115, -1, 152, -1, 159, -1, 165, -1, 171, + -1, 173, -1, 176, -1, 177, -1, 182, -1, 183, + -1, 194, -1, 209, -1, 210, -1, 217, -1, 219, + -1, 216, -1, 222, -1, 223, -1, 225, -1, 235, + -1, 237, -1, 247, -1, 268, -1, 269, -1, 270, + -1, 274, -1, 278, -1, 281, -1, 283, -1, 300, + -1, 299, -1, 302, -1, 303, -1, 321, -1, 322, + -1, 325, -1, 342, -1, 364, -1, 368, -1, 383, + -1, 390, -1, 394, -1, 397, -1, 412, -1, 414, + -1, 421, -1, 429, -1, 430, -1, 435, -1, 437, + -1, 441, -1, 463, -1, 464, -1, 468, -1, 487, + -1, 488, -1, 489, -1, 490, -1, 491, -1, 492, + -1, 493, -1, 494, -1, 495, -1, 496, -1, 497, + -1, 37, -1, 42, -1, 49, -1, 55, -1, 81, + -1, 83, -1, 89, -1, 101, -1, 171, -1, 173, + -1, 176, -1, 177, -1, 194, -1, 209, -1, 222, + -1, 223, -1, 225, -1, 235, -1, 237, -1, 247, + -1, 269, -1, 278, -1, 300, -1, 302, -1, 322, + -1, 364, -1, 383, -1, 394, -1, 412, -1, 421, + -1, 441, -1, 468, -1, 30, -1, 34, -1, 35, + -1, 36, -1, 38, -1, 39, -1, 40, -1, 41, + -1, 45, -1, 58, -1, 65, -1, 66, -1, 74, + -1, 80, -1, 82, -1, 93, -1, 100, -1, 117, + -1, 119, -1, 126, -1, 127, -1, 132, -1, 133, + -1, 139, -1, 143, -1, 147, -1, 160, -1, 162, + -1, 167, -1, 169, -1, 172, -1, 179, -1, 181, + -1, 186, -1, 199, -1, 207, -1, 218, -1, 220, + -1, 232, -1, 233, -1, 238, -1, 275, -1, 280, + -1, 287, -1, 290, -1, 291, -1, 295, -1, 296, + -1, 315, -1, 316, -1, 317, -1, 318, -1, 329, + -1, 336, -1, 347, -1, 361, -1, 382, -1, 393, + -1, 399, -1, 415, -1, 416, -1, 419, -1, 427, + -1, 431, -1, 432, -1, 438, -1, 447, -1, 448, + -1, 452, -1, 457, -1, 466, -1, 476, -1, 477, + -1, 479, -1, 480, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 508, 508, 524, 536, 545, 546, 547, 548, 549, - 550, 551, 552, 553, 554, 555, 556, 557, 558, 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, 587, 9, 18, 27, + 0, 509, 509, 525, 537, 546, 547, 548, 549, 550, + 551, 552, 553, 554, 555, 556, 557, 558, 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, 588, 9, 18, 27, 36, 45, 54, 63, 72, 85, 87, 93, 94, 99, 103, 107, 118, 126, 130, 139, 148, 157, 166, 175, 184, 192, 200, 209, 218, 227, 236, 253, 262, 271, @@ -2667,95 +2675,97 @@ static const yytype_uint16 yyrline[] = 563, 570, 571, 575, 576, 580, 581, 582, 586, 587, 591, 592, 608, 609, 612, 621, 632, 633, 634, 637, 638, 639, 643, 644, 645, 646, 650, 651, 655, 657, - 673, 675, 680, 683, 691, 695, 699, 703, 707, 711, - 718, 723, 730, 731, 735, 740, 744, 748, 756, 763, - 764, 769, 770, 774, 775, 780, 782, 784, 789, 809, - 810, 812, 817, 818, 822, 823, 826, 827, 852, 853, - 858, 862, 863, 867, 868, 872, 873, 874, 875, 876, - 880, 893, 900, 907, 914, 915, 919, 920, 924, 925, - 929, 930, 934, 935, 939, 940, 944, 955, 956, 957, - 958, 962, 963, 968, 969, 970, 979, 985, 994, 995, - 1008, 1009, 1013, 1014, 1018, 1019, 1025, 1031, 1039, 1048, - 1056, 1065, 1074, 1078, 1083, 1094, 1108, 1109, 1112, 1113, - 1114, 1117, 1125, 1135, 1136, 1137, 1140, 1148, 1157, 1161, - 1168, 1169, 1173, 1182, 1186, 1211, 1215, 1228, 1242, 1257, - 1269, 1282, 1296, 1310, 1323, 1338, 1357, 1363, 1368, 1374, - 1381, 1382, 1390, 1394, 1398, 1404, 1411, 1416, 1417, 1418, - 1419, 1420, 1421, 1425, 1426, 1438, 1439, 1444, 1451, 1458, - 1465, 1497, 1508, 1521, 1526, 1527, 1530, 1531, 1534, 1535, - 1540, 1541, 1546, 1550, 1556, 1577, 1585, 1598, 1601, 1605, - 1605, 1608, 1609, 1611, 1616, 1623, 1628, 1634, 1639, 1645, - 1649, 1656, 1663, 1673, 1674, 1678, 1680, 1683, 1687, 1688, - 1689, 1690, 1691, 1692, 1697, 1717, 1718, 1719, 1720, 1731, - 1745, 1746, 1752, 1757, 1762, 1767, 1772, 1777, 1782, 1787, - 1793, 1799, 1805, 1812, 1834, 1843, 1847, 1855, 1859, 1867, - 1879, 1900, 1904, 1910, 1914, 1927, 1935, 1945, 1947, 1949, - 1951, 1953, 1955, 1960, 1961, 1968, 1977, 1985, 1994, 2005, - 2013, 2014, 2015, 2019, 2019, 2022, 2022, 2025, 2025, 2028, - 2028, 2031, 2031, 2034, 2034, 2037, 2037, 2040, 2040, 2043, - 2043, 2046, 2046, 2049, 2049, 2052, 2052, 2055, 2055, 2058, - 2060, 2062, 2064, 2066, 2068, 2070, 2072, 2074, 2076, 2078, - 2080, 2082, 2084, 2089, 2094, 2100, 2107, 2112, 2118, 2124, - 2155, 2157, 2159, 2167, 2182, 2184, 2186, 2188, 2190, 2192, - 2194, 2196, 2198, 2200, 2202, 2204, 2206, 2208, 2210, 2212, - 2215, 2217, 2219, 2222, 2224, 2226, 2228, 2230, 2235, 2240, - 2247, 2252, 2259, 2264, 2271, 2276, 2284, 2292, 2300, 2308, - 2326, 2334, 2342, 2350, 2358, 2366, 2374, 2378, 2394, 2402, - 2410, 2418, 2426, 2434, 2442, 2446, 2450, 2454, 2458, 2466, - 2474, 2482, 2490, 2510, 2532, 2543, 2550, 2564, 2573, 2581, - 2589, 2609, 2611, 2613, 2615, 2617, 2619, 2621, 2623, 2625, - 2627, 2629, 2631, 2633, 2635, 2637, 2639, 2641, 2643, 2645, - 2647, 2649, 2651, 2655, 2659, 2663, 2677, 2678, 2692, 2693, - 2694, 2705, 2729, 2740, 2750, 2754, 2758, 2765, 2769, 2776, - 2780, 2784, 2788, 2790, 2793, 2796, 2807, 2812, 2819, 2825, - 2831, 2838, 2858, 2862, 2869, 2877, 2885, 2896, 2916, 2952, - 2963, 2964, 2971, 2977, 2979, 2981, 2985, 2994, 2999, 3006, - 3021, 3028, 3032, 3036, 3040, 3044, 3054, 3062, 3071, 3093, - 3094, 3098, 3099, 3100, 3104, 3105, 3112, 3113, 3117, 3118, - 3123, 3131, 3133, 3147, 3150, 3177, 3178, 3181, 3182, 3190, - 3198, 3206, 3215, 3225, 3243, 3289, 3298, 3307, 3316, 3325, - 3337, 3338, 3339, 3340, 3341, 3355, 3356, 3359, 3360, 3364, - 3374, 3375, 3379, 3380, 3384, 3391, 3392, 3397, 3398, 3403, - 3404, 3407, 3408, 3409, 3412, 3413, 3416, 3417, 3418, 3419, - 3420, 3421, 3422, 3423, 3424, 3425, 3426, 3427, 3428, 3429, - 3432, 3434, 3439, 3441, 3446, 3448, 3450, 3452, 3454, 3456, - 3458, 3460, 3474, 3476, 3481, 3485, 3492, 3497, 3503, 3507, - 3514, 3519, 3526, 3531, 3539, 3543, 3549, 3553, 3562, 3573, - 3574, 3578, 3582, 3589, 3590, 3591, 3592, 3593, 3594, 3595, - 3596, 3597, 3598, 3599, 3600, 3601, 3602, 3603, 3613, 3617, - 3624, 3631, 3632, 3648, 3652, 3657, 3661, 3676, 3681, 3685, - 3688, 3691, 3692, 3693, 3696, 3703, 3704, 3705, 3715, 3729, - 3730, 3734, 3745, 3746, 3749, 3750, 3754, 3755, 3758, 3764, - 3768, 3775, 3783, 3791, 3799, 3809, 3810, 3815, 3816, 3820, - 3821, 3822, 3826, 3835, 3843, 3851, 3860, 3875, 3876, 3881, - 3882, 3892, 3893, 3897, 3898, 3902, 3903, 3906, 3922, 3930, - 3940, 3941, 3944, 3945, 3948, 3952, 3953, 3957, 3958, 3961, - 3962, 3963, 3973, 3974, 3978, 3980, 3986, 3987, 3991, 3992, - 3995, 4006, 4009, 4020, 4024, 4028, 4040, 4044, 4053, 4060, - 4098, 4102, 4106, 4110, 4114, 4118, 4122, 4128, 4145, 4146, - 4147, 4150, 4151, 4152, 4155, 4156, 4157, 4160, 4161, 4164, - 4166, 4171, 4172, 4175, 4179, 4180, 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, 52, 5, 12, 22, 23, 7, 15, 26, - 27, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 7, 19, 33, 9, 16, 26, 33, 44, 45, - 50, 51, 52, 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, 91, 92, 93, 98, 99, 104, - 108, 116, 117, 122, 123, 124, 130, 135, 143, 144, - 10, 16, 22, 28, 34, 44, 45, 53, 64, 76, - 84, 95, 101, 105, 109, 124, 131, 132, 133, 137, - 138, 7, 17, 26, 35, 46, 47, 49, 50, 53, - 54, 55, 8, 22, 36, 48, 56, 70, 71, 72, - 73, 74, 87, 88, 93, 94, 98, 99, 7, 18, - 31, 35, 42, 53, 54, 60, 61, 9, 19, 7, - 16, 28, 35, 42, 51, 52, 56, 57, 2, 7, - 12, 17, 22, 31, 38, 48, 49, 56, 3, 10, - 17, 24, 31, 38, 45, 52, 61, 61, 63, 63, - 65, 65, 67, 68, 72, 73, 6, 8, 21, 34, + 673, 675, 680, 683, 688, 692, 696, 703, 707, 711, + 715, 722, 727, 734, 735, 739, 744, 748, 752, 760, + 767, 768, 773, 774, 778, 779, 784, 786, 788, 793, + 813, 814, 816, 821, 822, 826, 827, 830, 831, 856, + 857, 862, 866, 867, 871, 872, 876, 877, 878, 879, + 880, 884, 897, 904, 911, 918, 919, 923, 924, 928, + 929, 933, 934, 938, 939, 943, 944, 948, 959, 960, + 961, 962, 966, 967, 972, 973, 974, 983, 989, 998, + 999, 1012, 1013, 1017, 1018, 1022, 1023, 1027, 1038, 1044, + 1050, 1058, 1066, 1076, 1084, 1093, 1102, 1111, 1115, 1120, + 1125, 1136, 1150, 1151, 1154, 1155, 1156, 1159, 1167, 1177, + 1178, 1179, 1182, 1190, 1199, 1203, 1210, 1211, 1215, 1224, + 1228, 1253, 1257, 1270, 1284, 1299, 1311, 1324, 1338, 1352, + 1365, 1380, 1399, 1405, 1410, 1416, 1423, 1424, 1432, 1436, + 1440, 1446, 1453, 1458, 1459, 1460, 1461, 1462, 1463, 1467, + 1468, 1480, 1481, 1486, 1493, 1500, 1507, 1539, 1550, 1563, + 1568, 1569, 1572, 1573, 1576, 1577, 1582, 1583, 1588, 1592, + 1598, 1619, 1627, 1641, 1644, 1648, 1648, 1651, 1652, 1654, + 1659, 1666, 1671, 1677, 1682, 1688, 1692, 1699, 1706, 1716, + 1717, 1721, 1723, 1726, 1730, 1731, 1732, 1733, 1734, 1735, + 1740, 1760, 1761, 1762, 1763, 1774, 1788, 1789, 1795, 1800, + 1805, 1810, 1815, 1820, 1825, 1830, 1836, 1842, 1848, 1855, + 1877, 1886, 1890, 1898, 1902, 1910, 1922, 1943, 1947, 1953, + 1957, 1970, 1978, 1988, 1990, 1992, 1994, 1996, 1998, 2003, + 2004, 2011, 2020, 2028, 2037, 2048, 2056, 2057, 2058, 2062, + 2062, 2065, 2065, 2068, 2068, 2071, 2071, 2074, 2074, 2077, + 2077, 2080, 2080, 2083, 2083, 2086, 2086, 2089, 2089, 2092, + 2092, 2095, 2095, 2098, 2098, 2101, 2103, 2105, 2107, 2109, + 2111, 2113, 2115, 2117, 2119, 2121, 2123, 2125, 2127, 2132, + 2137, 2143, 2150, 2155, 2161, 2167, 2198, 2200, 2202, 2210, + 2225, 2227, 2229, 2231, 2233, 2235, 2237, 2239, 2241, 2243, + 2245, 2247, 2249, 2251, 2253, 2255, 2258, 2260, 2262, 2265, + 2267, 2269, 2271, 2273, 2278, 2283, 2290, 2295, 2302, 2307, + 2314, 2319, 2327, 2335, 2343, 2351, 2369, 2377, 2385, 2393, + 2401, 2409, 2417, 2421, 2437, 2445, 2453, 2461, 2469, 2477, + 2485, 2489, 2493, 2497, 2501, 2509, 2517, 2525, 2533, 2553, + 2575, 2586, 2593, 2607, 2616, 2624, 2633, 2654, 2656, 2658, + 2660, 2662, 2664, 2666, 2668, 2670, 2672, 2674, 2676, 2678, + 2680, 2682, 2684, 2686, 2688, 2690, 2692, 2694, 2696, 2700, + 2704, 2708, 2722, 2723, 2737, 2738, 2739, 2750, 2774, 2785, + 2795, 2799, 2803, 2810, 2814, 2821, 2828, 2829, 2830, 2831, + 2832, 2833, 2834, 2835, 2846, 2851, 2860, 2866, 2873, 2893, + 2897, 2904, 2912, 2920, 2931, 2951, 2987, 2998, 2999, 3006, + 3012, 3014, 3016, 3020, 3029, 3034, 3041, 3056, 3063, 3067, + 3071, 3075, 3079, 3089, 3097, 3106, 3128, 3129, 3133, 3134, + 3135, 3139, 3140, 3147, 3148, 3152, 3153, 3158, 3166, 3168, + 3182, 3185, 3212, 3213, 3216, 3217, 3225, 3233, 3241, 3250, + 3260, 3278, 3324, 3333, 3342, 3351, 3360, 3372, 3373, 3374, + 3375, 3376, 3390, 3391, 3394, 3395, 3399, 3409, 3410, 3414, + 3415, 3419, 3426, 3427, 3432, 3433, 3438, 3439, 3442, 3443, + 3444, 3447, 3448, 3451, 3452, 3453, 3454, 3455, 3456, 3457, + 3458, 3459, 3460, 3461, 3462, 3463, 3464, 3467, 3469, 3474, + 3476, 3481, 3483, 3485, 3487, 3489, 3491, 3493, 3495, 3509, + 3511, 3516, 3520, 3527, 3532, 3538, 3542, 3549, 3554, 3561, + 3566, 3574, 3578, 3584, 3588, 3597, 3608, 3609, 3613, 3617, + 3624, 3625, 3626, 3627, 3628, 3629, 3630, 3631, 3632, 3633, + 3634, 3635, 3636, 3637, 3638, 3648, 3652, 3659, 3666, 3667, + 3683, 3687, 3692, 3696, 3711, 3716, 3720, 3723, 3726, 3727, + 3728, 3731, 3738, 3739, 3740, 3750, 3764, 3765, 3769, 3780, + 3781, 3784, 3785, 3789, 3790, 3793, 3799, 3803, 3810, 3818, + 3826, 3834, 3844, 3845, 3850, 3851, 3855, 3856, 3857, 3861, + 3870, 3878, 3886, 3895, 3910, 3911, 3916, 3917, 3927, 3928, + 3932, 3933, 3937, 3938, 3941, 3957, 3965, 3973, 3983, 3984, + 3988, 3992, 3998, 4000, 4005, 4006, 4010, 4011, 4014, 4018, + 4019, 4023, 4024, 4027, 4028, 4029, 4032, 4036, 4037, 4041, + 4042, 4044, 4045, 4046, 4056, 4057, 4061, 4063, 4069, 4070, + 4074, 4075, 4078, 4089, 4092, 4103, 4107, 4111, 4123, 4127, + 4136, 4143, 4181, 4185, 4189, 4193, 4197, 4201, 4205, 4211, + 4228, 4229, 4230, 4233, 4234, 4235, 4238, 4239, 4240, 4243, + 4244, 4247, 4249, 4254, 4255, 4258, 4262, 4263, 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, 52, 5, 12, 22, 23, 7, + 15, 26, 27, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 7, 19, 33, 9, 16, 26, 33, + 44, 45, 50, 51, 52, 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, 91, 92, 93, 98, + 99, 104, 108, 116, 117, 122, 123, 124, 130, 135, + 143, 144, 10, 16, 22, 28, 34, 44, 45, 53, + 64, 76, 84, 95, 101, 105, 109, 124, 131, 132, + 133, 137, 138, 7, 17, 26, 35, 46, 47, 49, + 50, 53, 54, 55, 8, 22, 36, 48, 56, 70, + 71, 72, 73, 74, 87, 88, 93, 94, 98, 99, + 7, 18, 31, 35, 42, 53, 54, 60, 61, 9, + 19, 7, 16, 28, 35, 42, 51, 52, 56, 57, + 2, 7, 12, 17, 22, 31, 38, 48, 49, 56, + 3, 10, 17, 24, 31, 38, 45, 52, 61, 61, + 63, 63, 65, 65, 67, 68, 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, @@ -2910,8 +2920,8 @@ static const char *const yytname[] = "XMLROOT", "XMLSERIALIZE", "XMLTABLE", "YEAR_P", "YEARS_P", "YES_P", "ZONE", "NOT_LA", "NULLS_LA", "WITH_LA", "'<'", "'>'", "'='", "POSTFIXOP", "'+'", "'-'", "'*'", "'/'", "'%'", "'^'", "UMINUS", "'['", - "']'", "'('", "')'", "'.'", "';'", "','", "'?'", "'#'", "'$'", "'{'", - "'}'", "':'", "$accept", "stmtblock", "stmtmulti", "stmt", + "']'", "'('", "')'", "'.'", "';'", "','", "':'", "'?'", "'$'", "'#'", + "'{'", "'}'", "$accept", "stmtblock", "stmtmulti", "stmt", "AlterTableStmt", "alter_identity_column_option_list", "alter_column_default", "alter_identity_column_option", "alter_generic_option_list", "alter_table_cmd", "alter_using", @@ -2965,18 +2975,19 @@ static const char *const yytname[] = "by_name", "distinct_clause", "opt_all_clause", "opt_ignore_nulls", "opt_sort_clause", "sort_clause", "sortby_list", "sortby", "opt_asc_desc", "opt_nulls_order", "select_limit", "opt_select_limit", - "limit_clause", "offset_clause", "sample_count", "sample_clause", - "opt_sample_func", "tablesample_entry", "tablesample_clause", - "opt_tablesample_clause", "opt_repeatable_clause", "select_limit_value", - "select_offset_value", "select_fetch_first_value", "I_or_F_const", - "row_or_rows", "first_or_next", "group_clause", "group_by_list", - "group_by_list_opt_comma", "group_by_item", "empty_grouping_set", - "rollup_clause", "cube_clause", "grouping_sets_clause", - "grouping_or_grouping_id", "having_clause", "qualify_clause", - "for_locking_clause", "opt_for_locking_clause", "for_locking_items", - "for_locking_item", "for_locking_strength", "locked_rels_list", - "opt_nowait_or_skip", "values_clause", "values_clause_opt_comma", - "from_clause", "from_list", "from_list_opt_comma", "table_ref", + "limit_clause", "offset_clause", "sample_value", "sample_count", + "sample_clause", "opt_sample_func", "tablesample_entry", + "tablesample_clause", "opt_tablesample_clause", "opt_repeatable_clause", + "select_limit_value", "select_offset_value", "select_fetch_first_value", + "I_or_F_const", "row_or_rows", "first_or_next", "group_clause", + "group_by_list", "group_by_list_opt_comma", "group_by_item", + "empty_grouping_set", "rollup_clause", "cube_clause", + "grouping_sets_clause", "grouping_or_grouping_id", "having_clause", + "qualify_clause", "for_locking_clause", "opt_for_locking_clause", + "for_locking_items", "for_locking_item", "for_locking_strength", + "locked_rels_list", "opt_nowait_or_skip", "values_clause", + "values_clause_opt_comma", "from_clause", "from_list", + "from_list_opt_comma", "alias_prefix_colon_clause", "table_ref", "opt_pivot_group_by", "opt_include_nulls", "single_pivot_value", "pivot_header", "pivot_value", "pivot_value_list", "unpivot_header", "unpivot_value", "unpivot_value_list", "joined_table", "alias_clause", @@ -2995,8 +3006,8 @@ static const char *const yytname[] = "millisecond_keyword", "microsecond_keyword", "week_keyword", "quarter_keyword", "decade_keyword", "century_keyword", "millennium_keyword", "opt_interval", "a_expr", "b_expr", "c_expr", - "d_expr", "indirection_expr_or_a_expr", "indirection_expr", "list_expr", - "struct_expr", "map_expr", "func_application", "func_expr", + "d_expr", "indirection_expr_or_a_expr", "param_expr", "indirection_expr", + "list_expr", "struct_expr", "map_expr", "func_application", "func_expr", "func_expr_windowless", "func_expr_common_subexpr", "list_comprehension_lhs", "list_comprehension", "within_group_clause", "filter_clause", "export_clause", "window_clause", @@ -3018,13 +3029,16 @@ static const char *const yytname[] = "opt_func_arguments", "extended_indirection_el", "opt_extended_indirection", "opt_asymmetric", "opt_target_list_opt_comma", "target_list", "target_list_opt_comma", - "target_el", "except_list", "opt_except_list", "replace_list_el", + "target_el", "except_list", "except_name", "except_name_list", + "except_name_list_opt_comma", "opt_except_list", "replace_list_el", "replace_list", "replace_list_opt_comma", "opt_replace_list", - "qualified_name_list", "name_list", "name_list_opt_comma", - "name_list_opt_comma_opt_bracket", "name", "func_name", "AexprConst", - "Iconst", "type_function_name", "function_name_token", "type_name_token", - "any_name", "attrs", "opt_name_list", "param_name", "ColLabelOrString", - "PrepareStmt", "prep_type_clause", "PreparableStmt", "CreateSchemaStmt", + "rename_list_el", "rename_list", "rename_list_opt_comma", + "opt_rename_list", "qualified_name_list", "name_list", + "name_list_opt_comma", "name_list_opt_comma_opt_bracket", "name", + "func_name", "AexprConst", "Iconst", "type_function_name", + "function_name_token", "type_name_token", "any_name", "attrs", + "opt_name_list", "param_name", "ColLabelOrString", "PrepareStmt", + "prep_type_clause", "PreparableStmt", "CreateSchemaStmt", "OptSchemaEltList", "schema_stmt", "IndexStmt", "access_method", "access_method_clause", "opt_concurrently", "opt_index_name", "opt_reloptions", "opt_unique", "AlterObjectSchemaStmt", @@ -3041,11 +3055,10 @@ static const char *const yytname[] = "AnalyzeStmt", "AttachStmt", "DetachStmt", "opt_database", "opt_database_alias", "VariableResetStmt", "generic_reset", "reset_rest", "VariableShowStmt", "describe_or_desc", "show_or_describe", "opt_tables", - "var_name", "table_id", "CallStmt", "ViewStmt", "opt_check_option", - "CreateAsStmt", "opt_with_data", "create_as_target", - "unreserved_keyword", "col_name_keyword", "func_name_keyword", - "type_name_keyword", "other_keyword", "type_func_name_keyword", - "reserved_keyword", 0 + "var_name", "CallStmt", "ViewStmt", "opt_check_option", "CreateAsStmt", + "opt_with_data", "create_as_target", "unreserved_keyword", + "col_name_keyword", "func_name_keyword", "type_name_keyword", + "other_keyword", "type_func_name_keyword", "reserved_keyword", 0 }; #endif @@ -3106,7 +3119,7 @@ static const yytype_uint16 yytoknum[] = 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 60, 62, 61, 760, 43, 45, 42, 47, 37, 94, 761, 91, 93, 40, 41, - 46, 59, 44, 63, 35, 36, 123, 125, 58 + 46, 59, 44, 58, 63, 36, 35, 123, 125 }; # endif @@ -3176,159 +3189,161 @@ static const yytype_uint16 yyr1[] = 706, 707, 707, 708, 708, 709, 709, 709, 710, 710, 711, 711, 712, 712, 713, 713, 714, 714, 714, 715, 715, 715, 716, 716, 716, 716, 717, 717, 718, 718, - 718, 718, 719, 719, 720, 720, 720, 720, 720, 720, - 721, 721, 722, 722, 723, 723, 723, 723, 724, 725, - 725, 726, 726, 727, 727, 727, 727, 727, 728, 729, - 729, 729, 730, 730, 731, 731, 732, 732, 733, 733, - 733, 734, 734, 735, 735, 736, 736, 736, 736, 736, - 737, 738, 739, 740, 741, 741, 742, 742, 743, 743, - 744, 744, 745, 745, 746, 746, 747, 748, 748, 748, - 748, 749, 749, 750, 750, 750, 751, 751, 752, 752, - 753, 753, 754, 754, 755, 755, 756, 756, 756, 756, - 756, 756, 756, 756, 756, 756, 757, 757, 758, 758, - 758, 759, 759, 760, 760, 760, 761, 761, 762, 762, - 763, 763, 764, 765, 765, 766, 766, 766, 766, 766, - 766, 766, 766, 766, 766, 766, 767, 767, 767, 767, - 768, 768, 769, 769, 769, 769, 769, 770, 770, 770, - 770, 770, 770, 771, 771, 772, 772, 773, 773, 773, - 773, 774, 774, 775, 776, 776, 777, 777, 778, 778, - 779, 779, 780, 780, 781, 782, 782, 783, 783, 784, - 784, 785, 785, 786, 786, 786, 786, 786, 786, 786, - 786, 786, 786, 787, 787, 788, 788, 788, 789, 789, - 789, 789, 789, 789, 789, 790, 790, 790, 790, 791, - 792, 792, 793, 793, 793, 793, 793, 793, 793, 793, - 793, 793, 793, 794, 794, 795, 795, 796, 796, 797, - 798, 799, 799, 800, 800, 801, 802, 803, 803, 803, - 803, 803, 803, 804, 804, 805, 805, 805, 805, 806, - 807, 807, 807, 808, 808, 809, 809, 810, 810, 811, - 811, 812, 812, 813, 813, 814, 814, 815, 815, 816, - 816, 817, 817, 818, 818, 819, 819, 820, 820, 821, - 821, 821, 821, 821, 821, 821, 821, 821, 821, 821, - 821, 821, 821, 821, 821, 821, 821, 821, 821, 821, - 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, - 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, - 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, - 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, - 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, - 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, - 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, - 822, 823, 823, 823, 823, 823, 823, 823, 823, 823, + 718, 718, 719, 719, 720, 720, 720, 721, 721, 721, + 721, 722, 722, 723, 723, 724, 724, 724, 724, 725, + 726, 726, 727, 727, 728, 728, 728, 728, 728, 729, + 730, 730, 730, 731, 731, 732, 732, 733, 733, 734, + 734, 734, 735, 735, 736, 736, 737, 737, 737, 737, + 737, 738, 739, 740, 741, 742, 742, 743, 743, 744, + 744, 745, 745, 746, 746, 747, 747, 748, 749, 749, + 749, 749, 750, 750, 751, 751, 751, 752, 752, 753, + 753, 754, 754, 755, 755, 756, 756, 757, 758, 758, + 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, + 758, 758, 759, 759, 760, 760, 760, 761, 761, 762, + 762, 762, 763, 763, 764, 764, 765, 765, 766, 767, + 767, 768, 768, 768, 768, 768, 768, 768, 768, 768, + 768, 768, 769, 769, 769, 769, 770, 770, 771, 771, + 771, 771, 771, 772, 772, 772, 772, 772, 772, 773, + 773, 774, 774, 775, 775, 775, 775, 776, 776, 777, + 778, 778, 779, 779, 780, 780, 781, 781, 782, 782, + 783, 784, 784, 785, 785, 786, 786, 787, 787, 788, + 788, 788, 788, 788, 788, 788, 788, 788, 788, 789, + 789, 790, 790, 790, 791, 791, 791, 791, 791, 791, + 791, 792, 792, 792, 792, 793, 794, 794, 795, 795, + 795, 795, 795, 795, 795, 795, 795, 795, 795, 796, + 796, 797, 797, 798, 798, 799, 800, 801, 801, 802, + 802, 803, 804, 805, 805, 805, 805, 805, 805, 806, + 806, 807, 807, 807, 807, 808, 809, 809, 809, 810, + 810, 811, 811, 812, 812, 813, 813, 814, 814, 815, + 815, 816, 816, 817, 817, 818, 818, 819, 819, 820, + 820, 821, 821, 822, 822, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, - 823, 823, 823, 823, 823, 823, 824, 824, 825, 825, - 825, 825, 825, 825, 826, 826, 826, 827, 827, 827, - 827, 827, 827, 827, 827, 827, 827, 827, 827, 828, - 829, 830, 831, 831, 831, 831, 831, 831, 832, 832, - 833, 833, 834, 834, 834, 834, 834, 834, 834, 834, - 834, 834, 834, 834, 834, 834, 835, 836, 836, 837, - 837, 838, 838, 838, 839, 839, 840, 840, 841, 841, - 842, 843, 843, 843, 844, 845, 845, 846, 846, 847, - 847, 847, 847, 848, 848, 849, 849, 849, 849, 849, - 850, 850, 850, 850, 850, 851, 851, 852, 852, 853, - 854, 854, 855, 855, 856, 857, 857, 858, 858, 859, - 859, 860, 860, 860, 861, 861, 862, 862, 862, 862, - 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, - 863, 863, 864, 864, 865, 865, 865, 865, 865, 865, - 865, 865, 866, 866, 867, 867, 868, 868, 869, 869, - 870, 870, 871, 871, 872, 872, 873, 873, 873, 874, - 874, 875, 875, 876, 876, 876, 876, 876, 876, 876, - 876, 876, 876, 876, 876, 876, 876, 876, 877, 877, - 878, 879, 879, 880, 880, 880, 880, 880, 880, 881, - 882, 883, 883, 883, 884, 884, 884, 884, 885, 886, - 886, 887, 888, 888, 889, 889, 890, 890, 891, 892, - 892, 550, 550, 550, 550, 893, 893, 894, 894, 895, - 895, 895, 896, 896, 896, 896, 896, 897, 897, 898, - 898, 899, 899, 900, 900, 901, 901, 902, 902, 902, - 903, 903, 904, 904, 905, 906, 906, 907, 907, 908, - 908, 908, 909, 909, 910, 910, 911, 911, 912, 912, - 913, 914, 914, 915, 915, 915, 915, 915, 915, 915, - 915, 915, 915, 915, 915, 915, 915, 916, 917, 917, - 917, 918, 918, 918, 919, 919, 919, 920, 920, 921, - 921, 922, 922, 923, 924, 924, 925, 926, 926, 927, - 927, 927, 927, 927, 927, 928, 928, 928, 929, 929, - 930, 930, 930, 930, 931, 931, 932, 933, 933, 934, - 934, 935, 935, 936, 936, 937, 937, 938, 938, 938, - 938, 938, 938, 939, 939, 940, 940, 941, 941, 942, - 942, 943, 943, 943, 943, 943, 943, 943, 943, 943, - 943, 944, 944, 945, 946, 946, 946, 946, 947, 947, - 948, 948, 948, 949, 949, 949, 949, 949, 949, 949, - 949, 949, 949, 949, 949, 949, 949, 949, 949, 949, - 949, 949, 949, 949, 949, 949, 949, 949, 949, 949, - 949, 949, 949, 949, 950, 950, 950, 951, 951, 952, - 952, 953, 953, 954, 954, 954, 954, 955, 956, 956, - 957, 957, 957, 957, 957, 958, 958, 958, 958, 959, - 959, 960, 961, 961, 961, 961, 961, 961, 961, 962, - 962, 963, 963, 963, 963, 964, 964, 965, 965, 966, + 823, 823, 823, 823, 823, 823, 824, 824, 824, 824, + 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, + 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, + 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, + 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, + 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, + 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, + 824, 824, 824, 824, 824, 824, 824, 825, 825, 825, + 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, + 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, + 825, 825, 826, 826, 827, 827, 827, 827, 827, 827, + 828, 828, 828, 829, 829, 829, 830, 830, 830, 830, + 830, 830, 830, 830, 830, 830, 831, 832, 833, 834, + 834, 834, 834, 834, 834, 835, 835, 836, 836, 837, + 837, 837, 837, 837, 837, 837, 837, 837, 837, 837, + 837, 837, 837, 838, 839, 839, 840, 840, 841, 841, + 841, 842, 842, 843, 843, 844, 844, 845, 846, 846, + 846, 847, 848, 848, 849, 849, 850, 850, 850, 850, + 851, 851, 852, 852, 852, 852, 852, 853, 853, 853, + 853, 853, 854, 854, 855, 855, 856, 857, 857, 858, + 858, 859, 860, 860, 861, 861, 862, 862, 863, 863, + 863, 864, 864, 865, 865, 865, 865, 865, 865, 865, + 865, 865, 865, 865, 865, 865, 865, 866, 866, 867, + 867, 868, 868, 868, 868, 868, 868, 868, 868, 869, + 869, 870, 870, 871, 871, 872, 872, 873, 873, 874, + 874, 875, 875, 876, 876, 876, 877, 877, 878, 878, + 879, 879, 879, 879, 879, 879, 879, 879, 879, 879, + 879, 879, 879, 879, 879, 880, 880, 881, 882, 882, + 883, 883, 883, 883, 883, 883, 884, 885, 886, 886, + 886, 887, 887, 887, 887, 888, 889, 889, 890, 891, + 891, 892, 892, 893, 893, 894, 895, 895, 550, 550, + 550, 550, 896, 896, 897, 897, 898, 898, 898, 899, + 899, 899, 899, 899, 900, 900, 901, 901, 902, 902, + 903, 903, 904, 904, 905, 905, 905, 905, 906, 906, + 907, 907, 908, 908, 909, 909, 910, 910, 911, 912, + 912, 913, 913, 914, 914, 914, 915, 916, 916, 917, + 917, 918, 918, 918, 919, 919, 920, 920, 921, 921, + 922, 922, 923, 924, 924, 925, 925, 925, 925, 925, + 925, 925, 925, 925, 925, 925, 925, 925, 925, 926, + 927, 927, 927, 928, 928, 928, 929, 929, 929, 930, + 930, 931, 931, 932, 932, 933, 934, 934, 935, 936, + 936, 937, 937, 937, 937, 937, 937, 938, 938, 938, + 939, 939, 940, 940, 940, 940, 941, 941, 942, 943, + 943, 944, 944, 945, 945, 946, 946, 947, 947, 948, + 948, 948, 948, 948, 948, 949, 949, 950, 950, 951, + 951, 952, 952, 953, 953, 953, 953, 953, 953, 953, + 953, 953, 953, 954, 954, 955, 956, 956, 956, 956, + 957, 957, 958, 958, 958, 959, 959, 959, 959, 959, + 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, + 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, + 959, 959, 959, 959, 959, 959, 960, 960, 960, 961, + 961, 962, 962, 963, 963, 964, 964, 964, 964, 965, 966, 966, 967, 967, 967, 967, 967, 968, 968, 968, - 968, 968, 969, 969, 970, 970, 971, 971, 972, 972, - 973, 973, 973, 974, 974, 975, 975, 976, 976, 977, - 977, 978, 978, 978, 979, 979, 980, 980, 981, 981, - 981, 981, 981, 982, 982, 983, 983, 983, 984, 984, - 984, 984, 984, 984, 984, 984, 985, 985, 986, 986, - 987, 987, 988, 988, 989, 989, 990, 991, 991, 991, - 991, 991, 992, 992, 992, 992, 993, 993, 993, 994, - 994, 994, 995, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, - 996, 996, 996, 996, 996, 996, 996, 997, 997, 997, - 997, 997, 997, 997, 997, 997, 997, 997, 997, 997, - 997, 997, 997, 997, 997, 997, 997, 997, 997, 997, - 997, 997, 997, 997, 997, 997, 997, 997, 997, 997, - 997, 997, 997, 997, 997, 997, 997, 997, 997, 997, - 997, 997, 997, 997, 997, 997, 997, 997, 997, 997, - 997, 998, 998, 998, 998, 998, 998, 998, 998, 998, - 998, 998, 998, 998, 998, 998, 998, 998, 998, 998, - 998, 998, 998, 998, 998, 998, 998, 998, 998, 999, - 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, - 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, - 999, 999, 999, 999, 999, 999, 999, 999, 1000, 1000, - 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, - 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, - 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, - 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, - 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, - 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, - 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, - 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1001, - 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, - 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, - 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, - 1001, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, - 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, - 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, - 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, - 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, - 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, - 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, - 1002, 1002, 1002, 1002, 1002, 1002 + 968, 969, 969, 970, 971, 971, 971, 971, 971, 971, + 971, 972, 972, 973, 973, 973, 973, 974, 974, 975, + 975, 976, 976, 976, 977, 977, 977, 977, 977, 978, + 978, 978, 978, 978, 979, 979, 980, 980, 981, 981, + 982, 982, 983, 983, 983, 984, 984, 985, 985, 986, + 986, 987, 987, 988, 988, 988, 989, 989, 990, 990, + 991, 991, 991, 991, 991, 992, 992, 993, 993, 993, + 994, 994, 994, 994, 994, 994, 994, 994, 995, 995, + 996, 996, 997, 997, 998, 998, 999, 1000, 1000, 1000, + 1000, 1000, 1001, 1001, 1001, 1001, 1002, 1002, 1002, 1003, + 1003, 1003, 1004, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1006, 1006, 1006, + 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, + 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, + 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, + 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, + 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, + 1006, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, + 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, + 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1008, + 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, + 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, + 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1009, 1009, + 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, + 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, + 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, + 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, + 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, + 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, + 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, + 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1010, + 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, + 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, + 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, + 1010, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, + 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, + 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, + 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, + 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, + 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, + 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, + 1011, 1011, 1011, 1011, 1011, 1011 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ @@ -3397,95 +3412,97 @@ static const yytype_uint8 yyr2[] = 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, 2, 2, 2, 2, 1, 2, - 3, 0, 1, 0, 5, 1, 4, 6, 2, 1, - 0, 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, 3, 3, 3, 3, - 3, 3, 1, 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, 3, 1, - 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, 2, 2, - 2, 2, 1, 3, 0, 1, 1, 1, 1, 5, - 2, 1, 1, 1, 1, 4, 1, 2, 2, 1, - 3, 3, 2, 1, 0, 5, 2, 5, 2, 1, - 3, 3, 0, 1, 1, 1, 1, 1, 1, 1, + 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, 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, 3, 3, + 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, 3, 1, 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, 2, 2, 2, 2, 1, 3, + 0, 1, 1, 1, 1, 5, 2, 1, 1, 1, + 1, 4, 1, 2, 2, 1, 3, 3, 2, 1, + 0, 5, 2, 5, 2, 1, 3, 3, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 3, + 3, 3, 3, 3, 3, 0, 1, 3, 3, 5, + 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, + 3, 2, 2, 3, 3, 5, 4, 6, 3, 5, + 4, 6, 4, 6, 5, 7, 3, 2, 4, 3, + 2, 3, 3, 3, 3, 4, 3, 4, 3, 4, + 5, 6, 6, 7, 6, 7, 6, 7, 3, 4, + 4, 6, 1, 5, 4, 4, 6, 1, 3, 2, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 2, 2, 5, 6, + 6, 7, 1, 2, 1, 1, 1, 2, 2, 4, + 3, 1, 1, 1, 1, 2, 1, 1, 1, 1, + 1, 1, 1, 2, 4, 2, 3, 3, 4, 3, + 6, 7, 9, 7, 7, 5, 1, 1, 1, 5, + 6, 6, 4, 4, 4, 4, 6, 5, 5, 5, + 4, 6, 4, 1, 7, 9, 5, 0, 5, 4, + 0, 1, 0, 2, 0, 1, 3, 3, 2, 2, + 0, 6, 1, 0, 3, 0, 3, 3, 3, 0, + 1, 4, 2, 2, 2, 2, 2, 3, 2, 2, + 3, 0, 4, 3, 1, 5, 3, 1, 3, 1, + 2, 3, 1, 3, 1, 2, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 3, 3, 3, 3, 3, 3, 3, 0, - 1, 3, 3, 5, 2, 2, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 2, 2, 3, 3, 2, 2, 3, 3, 5, - 4, 6, 3, 5, 4, 6, 4, 6, 5, 7, - 3, 2, 4, 3, 2, 3, 3, 3, 3, 4, - 3, 4, 3, 4, 5, 6, 6, 7, 6, 7, - 6, 7, 3, 4, 4, 6, 1, 5, 4, 3, - 5, 1, 3, 2, 2, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 2, 2, 5, 6, 6, 7, 1, 2, 1, 1, - 1, 2, 2, 4, 3, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 2, 4, 2, 2, 3, - 3, 4, 3, 6, 7, 9, 7, 7, 5, 1, - 1, 1, 5, 6, 6, 4, 4, 4, 4, 6, - 5, 5, 5, 4, 6, 4, 1, 7, 9, 5, - 0, 5, 4, 0, 1, 0, 2, 0, 1, 3, - 3, 2, 2, 0, 6, 1, 0, 3, 0, 3, - 3, 3, 0, 1, 4, 2, 2, 2, 2, 2, - 3, 2, 2, 3, 0, 4, 3, 1, 5, 3, - 1, 3, 1, 2, 3, 1, 3, 1, 2, 1, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, + 4, 1, 4, 1, 2, 1, 2, 1, 2, 1, + 3, 1, 3, 1, 2, 1, 3, 1, 2, 1, + 0, 1, 3, 1, 3, 3, 1, 3, 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 4, 1, 4, 1, 4, 1, 2, 1, 2, - 1, 2, 1, 3, 1, 3, 1, 2, 1, 3, - 1, 2, 1, 0, 1, 3, 1, 3, 3, 1, - 3, 3, 0, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 4, 3, - 2, 3, 0, 3, 3, 2, 2, 1, 0, 2, - 2, 3, 2, 1, 1, 3, 1, 1, 5, 1, - 2, 4, 2, 0, 1, 0, 1, 3, 1, 1, - 2, 3, 5, 7, 7, 1, 0, 0, 2, 0, - 2, 3, 3, 3, 5, 7, 7, 0, 2, 1, - 0, 1, 0, 1, 3, 1, 2, 3, 2, 1, - 4, 2, 1, 0, 3, 1, 3, 1, 2, 4, - 2, 0, 1, 3, 1, 3, 1, 2, 1, 3, - 1, 1, 2, 1, 1, 2, 1, 1, 2, 7, - 2, 5, 3, 3, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, - 3, 3, 0, 1, 1, 1, 5, 3, 0, 1, - 1, 1, 1, 1, 1, 4, 7, 6, 2, 0, - 1, 1, 1, 1, 13, 16, 1, 2, 0, 1, - 0, 1, 0, 2, 0, 1, 0, 6, 8, 6, - 8, 6, 8, 3, 2, 1, 0, 6, 6, 1, - 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, - 1, 4, 6, 3, 2, 4, 3, 5, 1, 0, - 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4, 3, 2, 3, 0, + 3, 3, 2, 2, 1, 0, 2, 2, 3, 2, + 1, 1, 3, 1, 1, 5, 1, 2, 4, 2, + 0, 1, 0, 1, 3, 1, 1, 2, 3, 5, + 7, 7, 1, 0, 0, 2, 0, 2, 3, 3, + 3, 5, 7, 7, 0, 2, 1, 0, 1, 0, + 1, 3, 1, 2, 3, 2, 1, 3, 4, 2, + 1, 3, 1, 3, 1, 2, 1, 0, 3, 1, + 3, 1, 2, 4, 2, 0, 3, 1, 3, 1, + 2, 4, 2, 0, 1, 3, 1, 3, 1, 2, + 1, 3, 1, 1, 2, 1, 1, 2, 1, 1, + 2, 7, 2, 5, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 3, 3, 0, 1, 1, 1, 5, 3, + 0, 1, 1, 1, 1, 1, 1, 4, 7, 6, + 2, 0, 1, 1, 1, 1, 13, 16, 1, 2, + 0, 1, 0, 1, 0, 2, 0, 1, 0, 6, + 8, 6, 8, 6, 8, 3, 2, 1, 0, 6, + 6, 1, 1, 1, 1, 1, 1, 2, 1, 1, + 1, 1, 1, 4, 6, 3, 2, 4, 3, 5, + 1, 0, 1, 1, 0, 1, 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, 1, 1, 1, 2, 1, 1, - 2, 3, 3, 3, 3, 1, 3, 3, 2, 3, - 3, 1, 1, 1, 3, 5, 1, 1, 1, 1, - 3, 2, 4, 6, 6, 0, 1, 1, 1, 0, - 2, 2, 4, 6, 5, 4, 6, 1, 1, 1, - 1, 1, 1, 0, 1, 3, 1, 0, 7, 3, - 1, 2, 3, 2, 0, 2, 0, 2, 4, 5, - 8, 2, 3, 5, 1, 0, 2, 0, 2, 3, - 3, 3, 3, 1, 1, 1, 2, 3, 2, 2, - 2, 2, 3, 4, 3, 1, 1, 1, 1, 1, - 1, 0, 1, 3, 1, 3, 2, 9, 12, 11, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3, 1, 1, 1, 1, 1, 1, 2, + 1, 1, 2, 3, 3, 3, 3, 1, 3, 3, + 2, 3, 3, 1, 1, 1, 3, 5, 1, 1, + 1, 1, 3, 2, 4, 6, 6, 0, 1, 1, + 1, 0, 2, 2, 4, 6, 5, 4, 6, 1, + 1, 1, 1, 1, 1, 0, 1, 3, 1, 0, + 7, 3, 1, 2, 3, 2, 0, 2, 0, 2, + 4, 5, 8, 2, 3, 5, 1, 0, 2, 0, + 2, 3, 3, 3, 3, 1, 1, 1, 2, 3, + 2, 2, 2, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -3557,3849 +3574,4519 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint16 yydefact[] = { - 156, 265, 0, 1412, 1411, 1485, 265, 0, 1346, 0, - 265, 501, 406, 0, 1507, 1506, 0, 208, 265, 0, - 156, 0, 1446, 0, 0, 0, 564, 567, 565, 0, - 0, 0, 265, 604, 0, 1508, 265, 0, 0, 596, - 566, 0, 1463, 0, 0, 0, 0, 0, 2, 4, + 156, 265, 0, 1434, 1433, 1507, 265, 0, 1368, 0, + 265, 501, 406, 0, 1529, 1528, 0, 208, 265, 0, + 156, 0, 1468, 0, 0, 0, 564, 567, 565, 0, + 0, 0, 265, 604, 0, 1530, 265, 0, 0, 596, + 566, 0, 1485, 0, 0, 0, 0, 0, 2, 4, 7, 21, 35, 31, 0, 20, 33, 18, 17, 38, 26, 6, 24, 37, 40, 19, 25, 15, 39, 13, - 36, 540, 526, 609, 539, 0, 0, 155, 708, 547, - 34, 16, 30, 5, 11, 12, 28, 29, 27, 1369, + 36, 540, 526, 609, 539, 0, 0, 155, 709, 547, + 34, 16, 30, 5, 11, 12, 28, 29, 27, 1391, 43, 32, 0, 41, 22, 8, 9, 23, 42, 44, - 1509, 1505, 10, 45, 14, 264, 263, 257, 0, 0, - 0, 0, 0, 1484, 0, 0, 268, 112, 1533, 1534, - 1535, 1536, 1537, 1538, 1539, 1540, 1541, 1542, 1543, 1911, - 1544, 1545, 1546, 1547, 1548, 1912, 1549, 1550, 1551, 1857, - 1858, 1913, 1859, 1860, 1552, 1553, 1554, 1555, 1556, 1557, - 1558, 1559, 1560, 1561, 1861, 1862, 1562, 1563, 1564, 1565, - 1566, 1863, 1914, 1864, 1567, 1568, 1569, 1570, 1571, 1915, - 1572, 1573, 1574, 1575, 1576, 1577, 1578, 1579, 1580, 1916, - 1581, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, - 1865, 1591, 1592, 1866, 1593, 1594, 1595, 1596, 1597, 1598, - 1599, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, - 1609, 1610, 1611, 1612, 1613, 1614, 1615, 1616, 1617, 1618, - 1619, 1867, 1620, 1621, 1622, 1623, 1624, 1625, 1868, 1626, - 1627, 1628, 1869, 1629, 1630, 1631, 1917, 1918, 1632, 1633, - 1870, 1920, 1634, 1635, 1871, 1872, 1636, 1637, 1638, 1639, - 1640, 1641, 1642, 1643, 1644, 1921, 1645, 1646, 1647, 1648, - 1649, 1650, 1651, 1652, 1653, 1654, 1655, 1656, 1922, 1873, - 1657, 1658, 1659, 1660, 1661, 1874, 1875, 1876, 1662, 1923, - 1924, 1663, 1925, 1664, 1665, 1666, 1667, 1668, 1669, 1670, - 1926, 1671, 1927, 1672, 1673, 1674, 1675, 1676, 1677, 1678, - 1679, 1877, 1680, 1681, 1682, 1683, 1684, 1685, 1686, 1687, - 1688, 1689, 1690, 1691, 1692, 1693, 1694, 1695, 1696, 1697, - 1698, 1699, 1878, 1929, 1879, 1700, 1701, 1702, 1880, 1703, - 1704, 1930, 1705, 1881, 1706, 1882, 1707, 1708, 1709, 1710, - 1711, 1712, 1713, 1714, 1715, 1716, 1883, 1931, 1717, 1932, - 1884, 1718, 1719, 1720, 1721, 1722, 1723, 1724, 1725, 1726, - 1727, 1728, 1729, 1730, 1885, 1933, 1731, 1732, 1886, 1733, - 1734, 1735, 1736, 1737, 1738, 1739, 1740, 1741, 1742, 1743, - 1744, 1745, 1746, 1887, 1747, 1748, 1749, 1750, 1751, 1752, - 1753, 1754, 1755, 1756, 1757, 1758, 1759, 1760, 1761, 1762, - 1763, 1764, 1765, 1934, 1766, 1767, 1768, 1888, 1769, 1770, - 1771, 1772, 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1780, - 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1889, 1788, 1789, - 1935, 1790, 1791, 1890, 1792, 1793, 1794, 1795, 1796, 1797, - 1798, 1799, 1800, 1801, 1802, 1803, 1804, 1891, 1805, 1892, - 1806, 1807, 1808, 1937, 1809, 1810, 1811, 1812, 1813, 1814, - 1893, 1894, 1815, 1816, 1895, 1817, 1896, 1818, 1819, 1897, - 1820, 1821, 1822, 1823, 1824, 1825, 1826, 1827, 1828, 1829, - 1830, 1831, 1832, 1833, 1834, 1835, 1836, 1898, 1899, 1837, - 1838, 1938, 1839, 1840, 1841, 1842, 1843, 1844, 1845, 1846, - 1847, 1848, 1849, 1850, 1851, 1852, 1900, 1901, 1902, 1903, - 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1853, 1854, 1855, - 1856, 0, 1516, 0, 1271, 113, 114, 1293, 112, 1870, - 1877, 1891, 1345, 1344, 113, 0, 260, 500, 0, 0, - 0, 0, 0, 0, 210, 0, 400, 399, 0, 1335, - 405, 0, 0, 0, 116, 108, 1733, 115, 1270, 106, - 122, 2081, 2082, 2083, 2084, 1968, 2085, 2086, 2087, 2088, - 1969, 2089, 1970, 1971, 1972, 1973, 1974, 1975, 2090, 2091, - 2092, 1977, 1976, 2093, 1978, 2094, 1979, 2095, 1980, 1981, - 2096, 2097, 1982, 1587, 1983, 1984, 2098, 2099, 2100, 2101, - 2102, 2103, 2104, 2105, 2106, 1985, 1986, 2107, 2108, 1987, - 2109, 2110, 1988, 2111, 1989, 1990, 1991, 2112, 2113, 1992, - 1993, 2114, 1994, 2115, 2116, 1995, 1996, 1999, 1997, 2117, - 1998, 2118, 2000, 2001, 2002, 2119, 2120, 2003, 2004, 2121, - 2005, 2006, 2007, 2008, 2009, 2122, 2010, 2123, 2011, 2012, - 2124, 2125, 2126, 2127, 2128, 2014, 2013, 2015, 2016, 2129, - 2130, 2131, 2132, 2017, 2018, 2019, 2133, 2134, 2020, 2135, - 2136, 2021, 2022, 2137, 2023, 2024, 2138, 2025, 2026, 2139, - 2027, 2028, 2140, 2141, 2142, 2029, 2143, 2030, 2031, 2144, - 2145, 2032, 2033, 2146, 2034, 2147, 2148, 2149, 2150, 2035, - 2036, 2151, 2037, 2152, 2153, 2154, 2155, 2038, 2039, 2040, - 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 1481, 124, + 1531, 1527, 10, 45, 14, 264, 263, 257, 0, 0, + 0, 0, 0, 1506, 0, 0, 268, 112, 1553, 1554, + 1555, 1556, 1557, 1558, 1559, 1560, 1561, 1562, 1563, 1931, + 1564, 1565, 1566, 1567, 1568, 1932, 1569, 1570, 1571, 1877, + 1878, 1933, 1879, 1880, 1572, 1573, 1574, 1575, 1576, 1577, + 1578, 1579, 1580, 1581, 1881, 1882, 1582, 1583, 1584, 1585, + 1586, 1883, 1934, 1884, 1587, 1588, 1589, 1590, 1591, 1935, + 1592, 1593, 1594, 1595, 1596, 1597, 1598, 1599, 1600, 1936, + 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, 1610, + 1885, 1611, 1612, 1886, 1613, 1614, 1615, 1616, 1617, 1618, + 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1626, 1627, 1628, + 1629, 1630, 1631, 1632, 1633, 1634, 1635, 1636, 1637, 1638, + 1639, 1887, 1640, 1641, 1642, 1643, 1644, 1645, 1888, 1646, + 1647, 1648, 1889, 1649, 1650, 1651, 1937, 1938, 1652, 1653, + 1890, 1940, 1654, 1655, 1891, 1892, 1656, 1657, 1658, 1659, + 1660, 1661, 1662, 1663, 1664, 1941, 1665, 1666, 1667, 1668, + 1669, 1670, 1671, 1672, 1673, 1674, 1675, 1676, 1942, 1893, + 1677, 1678, 1679, 1680, 1681, 1894, 1895, 1896, 1682, 1943, + 1944, 1683, 1945, 1684, 1685, 1686, 1687, 1688, 1689, 1690, + 1946, 1691, 1947, 1692, 1693, 1694, 1695, 1696, 1697, 1698, + 1699, 1897, 1700, 1701, 1702, 1703, 1704, 1705, 1706, 1707, + 1708, 1709, 1710, 1711, 1712, 1713, 1714, 1715, 1716, 1717, + 1718, 1719, 1898, 1949, 1899, 1720, 1721, 1722, 1900, 1723, + 1724, 1950, 1725, 1901, 1726, 1902, 1727, 1728, 1729, 1730, + 1731, 1732, 1733, 1734, 1735, 1736, 1903, 1951, 1737, 1952, + 1904, 1738, 1739, 1740, 1741, 1742, 1743, 1744, 1745, 1746, + 1747, 1748, 1749, 1750, 1905, 1953, 1751, 1752, 1906, 1753, + 1754, 1755, 1756, 1757, 1758, 1759, 1760, 1761, 1762, 1763, + 1764, 1765, 1766, 1907, 1767, 1768, 1769, 1770, 1771, 1772, + 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1782, + 1783, 1784, 1785, 1954, 1786, 1787, 1788, 1908, 1789, 1790, + 1791, 1792, 1793, 1794, 1795, 1796, 1797, 1798, 1799, 1800, + 1801, 1802, 1803, 1804, 1805, 1806, 1807, 1909, 1808, 1809, + 1955, 1810, 1811, 1910, 1812, 1813, 1814, 1815, 1816, 1817, + 1818, 1819, 1820, 1821, 1822, 1823, 1824, 1911, 1825, 1912, + 1826, 1827, 1828, 1957, 1829, 1830, 1831, 1832, 1833, 1834, + 1913, 1914, 1835, 1836, 1915, 1837, 1916, 1838, 1839, 1917, + 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, + 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1918, 1919, 1857, + 1858, 1958, 1859, 1860, 1861, 1862, 1863, 1864, 1865, 1866, + 1867, 1868, 1869, 1870, 1871, 1872, 1920, 1921, 1922, 1923, + 1924, 1925, 1926, 1927, 1928, 1929, 1930, 1873, 1874, 1875, + 1876, 0, 1536, 0, 1293, 113, 114, 1315, 112, 1890, + 1897, 1911, 1367, 1366, 113, 0, 260, 500, 0, 0, + 0, 0, 0, 0, 210, 0, 400, 399, 0, 1357, + 405, 0, 0, 0, 116, 108, 1753, 115, 1292, 106, + 122, 2101, 2102, 2103, 2104, 1988, 2105, 2106, 2107, 2108, + 1989, 2109, 1990, 1991, 1992, 1993, 1994, 1995, 2110, 2111, + 2112, 1997, 1996, 2113, 1998, 2114, 1999, 2115, 2000, 2001, + 2116, 2117, 2002, 1607, 2003, 2004, 2118, 2119, 2120, 2121, + 2122, 2123, 2124, 2125, 2126, 2005, 2006, 2127, 2128, 2007, + 2129, 2130, 2008, 2131, 2009, 2010, 2011, 2132, 2133, 2012, + 2013, 2134, 2014, 2135, 2136, 2015, 2016, 2019, 2017, 2137, + 2018, 2138, 2020, 2021, 2022, 2139, 2140, 2023, 2024, 2141, + 2025, 2026, 2027, 2028, 2029, 2142, 2030, 2143, 2031, 2032, + 2144, 2145, 2146, 2147, 2148, 2034, 2033, 2035, 2036, 2149, + 2150, 2151, 2152, 2037, 2038, 2039, 2153, 2154, 2040, 2155, + 2156, 2041, 2042, 2157, 2043, 2044, 2158, 2045, 2046, 2159, + 2047, 2048, 2160, 2161, 2162, 2049, 2163, 2050, 2051, 2164, + 2165, 2052, 2053, 2166, 2054, 2167, 2168, 2169, 2170, 2055, + 2056, 2171, 2057, 2172, 2173, 2174, 2175, 2058, 2059, 2060, + 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2068, 1503, 124, 123, 125, 0, 424, 425, 0, 435, 0, 417, 422, 418, 0, 444, 437, 445, 426, 416, 438, 427, 415, 209, 0, 446, 432, 420, 0, 0, 0, 0, 261, - 222, 406, 0, 156, 0, 1375, 1385, 1394, 1390, 1384, - 1392, 1382, 1398, 1388, 1374, 1396, 1383, 1387, 1380, 1397, - 1378, 1395, 1393, 1381, 1389, 1373, 1377, 1364, 1369, 1401, - 1391, 1399, 1386, 1400, 1402, 1376, 1403, 1379, 0, 1346, - 0, 1863, 1914, 1868, 0, 1881, 0, 1884, 1885, 1769, - 1892, 1895, 1896, 1897, 1898, 0, 777, 115, 110, 761, - 0, 542, 712, 722, 761, 766, 1050, 789, 1051, 0, - 117, 1448, 1447, 1441, 195, 1308, 1494, 1634, 1674, 1786, - 1893, 1815, 1837, 1512, 1495, 1488, 1493, 262, 603, 601, - 0, 1242, 1634, 1674, 1773, 1786, 1893, 1837, 1420, 1425, - 0, 268, 1514, 1499, 0, 1500, 115, 548, 595, 0, - 269, 1462, 0, 1467, 0, 1749, 575, 578, 1302, 576, - 540, 0, 0, 1, 156, 0, 162, 0, 599, 599, - 0, 599, 0, 532, 0, 0, 540, 535, 539, 709, - 1368, 1477, 0, 1511, 1893, 1815, 1498, 1501, 1643, 0, - 0, 1643, 0, 1643, 0, 1643, 0, 0, 1487, 0, - 258, 1226, 0, 1272, 118, 0, 0, 1357, 1353, 1358, - 1354, 1359, 1352, 1351, 1360, 1356, 0, 0, 0, 371, - 404, 403, 402, 401, 406, 1643, 1319, 0, 206, 462, - 463, 0, 0, 0, 0, 0, 1330, 109, 107, 1643, - 1482, 433, 434, 0, 423, 419, 421, 0, 0, 1643, - 1297, 443, 439, 1643, 443, 1264, 1643, 0, 0, 214, - 0, 399, 1366, 1404, 2035, 1418, 0, 1419, 1409, 1372, - 1405, 1406, 156, 0, 499, 1343, 0, 0, 0, 1172, - 761, 766, 0, 0, 779, 0, 1192, 0, 1198, 0, - 0, 0, 761, 547, 0, 722, 778, 111, 0, 759, - 760, 650, 650, 604, 0, 585, 771, 0, 0, 774, - 772, 0, 774, 0, 0, 0, 774, 770, 730, 0, - 650, 0, 759, 762, 650, 0, 781, 1363, 0, 0, - 0, 0, 1491, 1489, 1490, 1496, 0, 1492, 0, 0, - 1274, 1276, 1277, 1140, 1287, 1028, 0, 1858, 1859, 1860, - 1215, 1861, 1862, 1864, 1865, 1866, 986, 1607, 1867, 1285, - 1869, 1871, 1872, 1874, 1875, 1876, 1877, 1878, 1879, 0, - 1286, 1882, 1712, 1887, 1888, 1890, 1893, 1894, 1284, 1899, - 0, 0, 0, 1253, 1163, 0, 1027, 0, 0, 0, - 1219, 1227, 1020, 0, 0, 825, 826, 847, 848, 827, - 853, 854, 856, 828, 0, 1249, 920, 1016, 1237, 1025, - 1033, 1029, 1030, 1070, 1031, 1049, 1034, 1107, 1026, 0, - 1032, 1018, 1245, 585, 1243, 0, 1019, 1273, 585, 1241, - 1423, 1421, 1428, 1422, 0, 1424, 0, 0, 0, 259, - 0, 111, 1470, 1469, 1461, 1459, 1460, 1458, 1457, 1464, - 0, 1466, 1369, 1158, 1160, 0, 577, 0, 0, 0, - 529, 528, 530, 3, 0, 0, 0, 1624, 0, 597, - 598, 0, 0, 0, 0, 0, 0, 0, 0, 693, - 624, 625, 627, 690, 694, 702, 0, 0, 0, 0, - 0, 536, 0, 1302, 1449, 1510, 1504, 1502, 0, 0, - 0, 140, 140, 0, 0, 0, 0, 0, 100, 49, - 93, 0, 0, 0, 0, 236, 249, 0, 0, 0, - 0, 0, 246, 0, 0, 229, 51, 223, 225, 0, - 140, 0, 47, 0, 0, 0, 53, 1485, 0, 499, - 266, 267, 1225, 0, 120, 121, 119, 112, 0, 2049, - 1911, 1912, 1913, 1914, 1864, 1915, 1916, 0, 1917, 1918, - 1870, 1920, 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1877, - 1929, 1930, 1931, 1932, 1933, 1934, 2075, 1935, 1891, 1937, - 1897, 0, 1938, 1042, 1166, 609, 1164, 1303, 0, 113, - 1290, 0, 1355, 0, 0, 0, 0, 497, 0, 0, - 0, 0, 1315, 0, 1643, 207, 211, 0, 1643, 202, - 1643, 371, 0, 1643, 371, 1643, 0, 1329, 1332, 0, - 436, 431, 429, 428, 430, 1643, 255, 0, 0, 1298, - 441, 442, 0, 410, 0, 0, 412, 0, 0, 219, - 0, 217, 0, 406, 156, 0, 230, 1414, 1415, 1413, - 0, 0, 1408, 1371, 233, 250, 1417, 1407, 1416, 1370, - 1365, 0, 0, 1361, 485, 0, 0, 0, 1173, 896, - 895, 877, 878, 893, 894, 879, 880, 887, 888, 898, - 897, 885, 886, 881, 882, 875, 876, 891, 892, 883, - 884, 889, 890, 873, 874, 1187, 1174, 1175, 1176, 1177, - 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 0, - 0, 721, 719, 0, 0, 0, 0, 0, 0, 1219, - 0, 991, 1026, 0, 0, 0, 1158, 1197, 0, 0, - 0, 0, 0, 0, 1158, 1203, 0, 0, 745, 757, - 0, 643, 649, 720, 718, 0, 1242, 713, 0, 791, - 0, 771, 0, 770, 0, 0, 773, 767, 0, 768, - 0, 0, 0, 0, 769, 0, 0, 0, 0, 0, - 716, 0, 757, 0, 717, 788, 1431, 1439, 196, 0, - 1294, 1939, 1940, 1941, 835, 1942, 864, 842, 864, 864, - 1943, 1944, 1945, 1946, 831, 831, 844, 1947, 1948, 1949, - 1950, 1951, 832, 833, 869, 1952, 1953, 1954, 1955, 1956, - 0, 0, 1957, 864, 1958, 831, 1959, 1960, 1961, 836, - 1962, 799, 1963, 0, 1964, 834, 800, 1965, 872, 872, - 1966, 0, 859, 1967, 0, 1169, 809, 817, 818, 819, - 820, 845, 846, 821, 851, 852, 822, 919, 0, 831, - 1295, 1296, 156, 1497, 1513, 0, 1163, 1035, 863, 850, - 1214, 0, 858, 857, 0, 1163, 840, 839, 838, 1022, - 0, 837, 1120, 864, 864, 862, 945, 841, 0, 0, - 0, 0, 0, 868, 0, 866, 946, 924, 925, 0, - 0, 1252, 1261, 1158, 1162, 0, 1020, 1158, 0, 1037, - 1038, 0, 1110, 1112, 0, 0, 1220, 1275, 1021, 0, - 1280, 0, 0, 919, 919, 1248, 1140, 0, 1130, 1133, - 0, 0, 1137, 1138, 1139, 0, 0, 0, 1240, 0, - 1148, 1150, 0, 0, 961, 1146, 0, 964, 0, 0, - 0, 0, 1134, 1135, 1136, 1126, 1127, 1128, 1129, 1131, - 1132, 1144, 1125, 942, 0, 1017, 0, 1073, 0, 941, - 1246, 711, 0, 1278, 711, 1433, 1437, 1438, 1432, 1436, - 0, 1427, 1426, 1429, 1430, 1515, 0, 1471, 1455, 0, - 1452, 1161, 706, 579, 1266, 0, 583, 1476, 161, 160, - 0, 213, 0, 552, 551, 618, 610, 612, 618, 0, - 550, 0, 666, 667, 0, 0, 0, 0, 699, 697, - 1274, 1287, 654, 628, 653, 0, 0, 632, 0, 658, - 920, 692, 534, 622, 623, 626, 533, 0, 695, 0, - 705, 0, 571, 573, 556, 570, 568, 553, 561, 693, - 627, 0, 1478, 0, 0, 1442, 1503, 0, 0, 0, - 0, 0, 1643, 0, 0, 802, 84, 65, 323, 139, - 0, 0, 0, 0, 0, 0, 0, 92, 89, 90, - 91, 0, 0, 0, 0, 1294, 234, 235, 248, 0, - 239, 240, 237, 241, 242, 0, 0, 227, 228, 0, - 0, 0, 0, 226, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1486, 1479, 1221, 1226, 609, 609, 609, - 0, 607, 608, 0, 0, 0, 0, 0, 484, 369, - 379, 0, 0, 0, 1319, 206, 0, 0, 0, 0, - 0, 0, 406, 1322, 1320, 1318, 1321, 1323, 1613, 190, - 0, 0, 0, 0, 0, 198, 201, 0, 368, 342, - 0, 0, 1334, 0, 0, 457, 455, 458, 447, 460, - 450, 0, 1643, 358, 1331, 0, 1483, 0, 0, 253, - 443, 1299, 0, 440, 443, 1265, 0, 443, 221, 0, - 0, 1367, 1410, 231, 251, 232, 252, 499, 494, 524, - 0, 502, 507, 482, 0, 482, 0, 504, 508, 482, - 503, 0, 482, 498, 0, 1065, 0, 1055, 0, 0, - 780, 0, 0, 1056, 993, 994, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1011, 1010, 1057, 784, 0, 787, - 0, 0, 1195, 1196, 0, 1058, 0, 0, 1202, 0, - 0, 0, 1063, 0, 723, 0, 0, 0, 638, 642, - 645, 0, 648, 585, 541, 1634, 1674, 0, 596, 596, - 596, 594, 584, 0, 670, 0, 0, 0, 746, 0, - 0, 748, 750, 0, 0, 753, 0, 729, 728, 0, - 0, 0, 0, 792, 0, 1270, 0, 0, 197, 0, - 0, 0, 817, 0, 0, 0, 807, 803, 0, 899, - 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, - 910, 911, 823, 1307, 0, 829, 1310, 0, 1311, 1312, - 1309, 1306, 1313, 1314, 0, 0, 0, 0, 1213, 1209, - 0, 0, 0, 0, 1115, 1117, 1119, 0, 861, 860, - 1124, 1130, 1133, 1137, 1138, 1139, 1134, 1135, 1136, 1126, - 1127, 1128, 1129, 1131, 1132, 0, 1152, 0, 1106, 0, - 0, 0, 0, 0, 0, 0, 1251, 0, 989, 0, - 1039, 1024, 0, 0, 1113, 1040, 1253, 1228, 0, 0, - 0, 1283, 1282, 921, 930, 933, 965, 966, 937, 938, - 939, 943, 1305, 1304, 1247, 0, 1239, 0, 0, 922, - 947, 952, 0, 1204, 1207, 982, 1206, 0, 970, 0, - 960, 0, 968, 972, 948, 963, 0, 944, 0, 1240, - 1149, 1151, 0, 1147, 0, 934, 935, 936, 926, 927, - 928, 929, 931, 932, 940, 1123, 1121, 1122, 0, 1226, - 0, 1238, 0, 0, 1075, 0, 0, 967, 1244, 0, - 791, 609, 791, 0, 919, 1472, 1302, 1465, 1302, 1454, - 1159, 1267, 1301, 581, 0, 0, 0, 1474, 147, 151, - 0, 1227, 181, 183, 711, 0, 616, 617, 621, 0, - 0, 621, 600, 549, 1888, 1769, 0, 0, 0, 0, - 659, 700, 0, 691, 656, 657, 0, 655, 1274, 660, - 1273, 661, 664, 665, 633, 1262, 701, 703, 0, 696, - 0, 1268, 555, 574, 0, 0, 0, 0, 0, 538, - 537, 707, 1449, 1449, 1451, 1450, 0, 50, 0, 1643, - 67, 0, 0, 0, 0, 0, 0, 273, 0, 373, - 273, 105, 1643, 443, 1643, 443, 1537, 1608, 1787, 0, - 63, 347, 96, 0, 133, 376, 0, 332, 86, 101, - 126, 0, 0, 52, 224, 238, 243, 129, 247, 244, - 1339, 245, 140, 0, 48, 0, 127, 0, 1337, 0, - 0, 54, 131, 1341, 1487, 0, 1225, 0, 607, 607, - 607, 0, 1165, 0, 0, 0, 1167, 1168, 960, 1349, - 1348, 1350, 1347, 470, 483, 0, 370, 0, 496, 473, - 474, 484, 1317, 211, 0, 202, 371, 0, 371, 0, - 1319, 0, 0, 192, 188, 206, 212, 0, 0, 0, - 0, 0, 369, 361, 359, 392, 0, 366, 360, 0, - 0, 318, 0, 1531, 0, 0, 0, 0, 464, 0, - 0, 0, 0, 0, 0, 255, 256, 409, 1300, 411, - 0, 413, 220, 218, 1362, 2005, 490, 1163, 0, 488, - 495, 489, 492, 493, 487, 486, 0, 481, 0, 517, - 0, 0, 0, 0, 0, 0, 0, 0, 1052, 1171, - 0, 1190, 1189, 992, 999, 1002, 1006, 1007, 1008, 1191, - 0, 0, 0, 1003, 1004, 1005, 995, 996, 997, 998, - 1000, 1001, 1009, 789, 0, 0, 783, 1200, 1199, 1193, - 1194, 0, 1060, 1061, 1062, 1201, 0, 0, 758, 636, - 634, 637, 639, 635, 0, 0, 791, 596, 596, 596, - 596, 593, 0, 0, 0, 790, 0, 687, 754, 752, - 0, 776, 0, 749, 0, 755, 0, 740, 0, 747, - 796, 763, 0, 0, 765, 1440, 813, 0, 808, 804, - 0, 0, 0, 814, 0, 0, 0, 0, 0, 0, - 0, 1170, 0, 602, 1036, 0, 0, 0, 1210, 0, - 988, 830, 843, 0, 1118, 1041, 0, 1141, 1105, 871, - 870, 872, 872, 0, 0, 0, 0, 1260, 1218, 0, - 1066, 1216, 1159, 1109, 1111, 1261, 1023, 855, 919, 0, - 0, 0, 0, 0, 0, 0, 971, 962, 0, 969, - 973, 0, 0, 0, 956, 0, 0, 954, 983, 950, - 0, 0, 984, 1225, 0, 1229, 0, 0, 1074, 1083, - 714, 710, 670, 607, 670, 0, 1434, 1456, 1453, 582, - 156, 1475, 0, 170, 0, 0, 0, 0, 173, 187, - 184, 1474, 0, 0, 611, 613, 0, 1142, 621, 615, - 663, 662, 0, 631, 698, 629, 0, 704, 0, 572, - 0, 558, 0, 732, 0, 0, 1443, 1444, 0, 0, - 0, 322, 0, 0, 0, 273, 0, 381, 0, 388, - 0, 0, 373, 354, 85, 0, 0, 0, 59, 104, - 77, 69, 55, 83, 0, 0, 88, 0, 81, 98, - 99, 97, 102, 0, 283, 308, 0, 0, 319, 0, + 222, 406, 0, 156, 0, 1397, 1407, 1416, 1412, 1406, + 1414, 1404, 1420, 1410, 1396, 1418, 1405, 1409, 1402, 1419, + 1400, 1417, 1415, 1403, 1411, 1395, 1399, 1386, 1391, 1423, + 1413, 1421, 1408, 1422, 1424, 1398, 1425, 1401, 0, 1368, + 0, 1883, 1934, 1888, 0, 1901, 0, 1904, 1905, 1789, + 1912, 1915, 1916, 1917, 1918, 0, 783, 115, 110, 767, + 0, 542, 0, 713, 727, 767, 772, 1057, 795, 1058, + 0, 117, 1470, 1469, 1463, 195, 1330, 1516, 1654, 1694, + 1806, 1913, 1835, 1857, 1534, 1517, 1510, 1515, 262, 603, + 601, 0, 1249, 1654, 1694, 1793, 1806, 1913, 1857, 1442, + 1447, 0, 268, 1522, 115, 110, 1521, 0, 548, 595, + 0, 269, 1484, 0, 1489, 0, 1769, 575, 578, 1324, + 576, 540, 0, 0, 1, 156, 0, 162, 0, 599, + 599, 0, 599, 0, 532, 0, 0, 540, 535, 539, + 710, 1390, 1499, 0, 1533, 1913, 1835, 1523, 1520, 1663, + 0, 0, 1663, 0, 1663, 0, 1663, 0, 0, 1509, + 0, 258, 1233, 0, 1294, 118, 0, 0, 1379, 1375, + 1380, 1376, 1381, 1374, 1373, 1382, 1378, 0, 0, 0, + 371, 404, 403, 402, 401, 406, 1663, 1341, 0, 206, + 462, 463, 0, 0, 0, 0, 0, 1352, 109, 107, + 1663, 1504, 433, 434, 0, 423, 419, 421, 0, 0, + 1663, 1319, 443, 439, 1663, 443, 1286, 1663, 0, 0, + 214, 0, 399, 1388, 1426, 2055, 1440, 0, 1441, 1431, + 1394, 1427, 1428, 156, 0, 499, 1365, 0, 0, 0, + 1179, 767, 772, 0, 0, 785, 0, 1199, 0, 1205, + 0, 0, 0, 767, 547, 0, 727, 784, 111, 717, + 0, 765, 766, 651, 651, 604, 0, 585, 0, 651, + 651, 651, 777, 0, 0, 780, 778, 0, 780, 0, + 0, 0, 780, 776, 736, 0, 651, 0, 765, 768, + 651, 0, 787, 1385, 0, 0, 0, 0, 1513, 1511, + 1512, 1518, 0, 1514, 0, 0, 1296, 1298, 1299, 1147, + 1309, 1034, 0, 1878, 1879, 1880, 1222, 1881, 1882, 1884, + 1885, 1886, 992, 1627, 1887, 1307, 1889, 1891, 1892, 1894, + 1895, 1896, 1897, 1898, 1899, 0, 1308, 1902, 1732, 1907, + 1908, 1910, 1913, 1914, 1306, 1919, 0, 0, 0, 1267, + 1170, 0, 1033, 0, 0, 0, 1226, 1234, 1026, 0, + 0, 831, 832, 853, 854, 833, 859, 860, 862, 834, + 0, 1256, 926, 1022, 1244, 1036, 1031, 1041, 1037, 1038, + 1077, 1039, 1056, 1042, 1114, 1032, 0, 1040, 1024, 1252, + 585, 1250, 0, 1025, 1295, 585, 1248, 1445, 1443, 1450, + 1444, 0, 1446, 0, 0, 0, 259, 111, 1492, 1491, + 1483, 1481, 1482, 1480, 1479, 1486, 0, 1488, 1391, 1226, + 1165, 1167, 0, 577, 0, 0, 0, 529, 528, 530, + 3, 0, 0, 0, 1644, 0, 597, 598, 0, 0, + 0, 0, 0, 0, 0, 0, 694, 624, 625, 627, + 691, 695, 703, 0, 0, 0, 0, 0, 536, 0, + 1324, 1471, 1532, 1526, 1524, 0, 0, 0, 140, 140, + 0, 0, 0, 0, 0, 100, 49, 93, 0, 0, + 0, 0, 236, 249, 0, 0, 0, 0, 0, 246, + 0, 0, 229, 51, 223, 225, 0, 140, 0, 47, + 0, 0, 0, 53, 1507, 0, 499, 266, 267, 1232, + 0, 120, 121, 119, 112, 0, 2069, 1931, 1932, 1933, + 1934, 1884, 1935, 1936, 0, 1937, 1938, 1890, 1940, 1941, + 1942, 1943, 1944, 1945, 1946, 1947, 1897, 1949, 1950, 1951, + 1952, 1953, 1954, 2095, 1955, 1911, 1957, 1917, 0, 1958, + 1049, 1173, 609, 1171, 1325, 0, 113, 1312, 0, 1377, + 0, 0, 0, 0, 497, 0, 0, 0, 0, 1337, + 0, 1663, 207, 211, 0, 1663, 202, 1663, 371, 0, + 1663, 371, 1663, 0, 1351, 1354, 0, 436, 431, 429, + 428, 430, 1663, 255, 0, 0, 1320, 441, 442, 0, + 410, 0, 0, 412, 0, 0, 219, 0, 217, 0, + 406, 156, 0, 230, 1436, 1437, 1435, 0, 0, 1430, + 1393, 233, 250, 1439, 1429, 1438, 1392, 1387, 0, 0, + 1383, 485, 0, 0, 0, 1180, 902, 901, 883, 884, + 899, 900, 885, 886, 893, 894, 904, 903, 891, 892, + 887, 888, 881, 882, 897, 898, 889, 890, 895, 896, + 879, 880, 1194, 1181, 1182, 1183, 1184, 1185, 1186, 1187, + 1188, 1189, 1190, 1191, 1192, 1193, 0, 0, 726, 723, + 0, 0, 0, 0, 0, 0, 1226, 0, 997, 1032, + 0, 0, 0, 1165, 1204, 0, 0, 0, 0, 0, + 0, 1165, 1210, 0, 0, 751, 763, 0, 644, 650, + 724, 722, 0, 1249, 714, 0, 797, 727, 725, 719, + 721, 0, 777, 0, 776, 0, 0, 779, 773, 0, + 774, 0, 0, 0, 0, 775, 0, 0, 0, 0, + 0, 718, 0, 763, 0, 720, 794, 1453, 1461, 196, + 0, 1316, 1959, 1960, 1961, 841, 1962, 870, 848, 870, + 870, 1963, 1964, 1965, 1966, 837, 837, 850, 1967, 1968, + 1969, 1970, 1971, 838, 839, 875, 1972, 1973, 1974, 1975, + 1976, 0, 0, 1977, 870, 1978, 837, 1979, 1980, 1981, + 842, 1982, 805, 1983, 0, 1984, 840, 806, 1985, 878, + 878, 1986, 0, 865, 1987, 0, 1176, 815, 823, 824, + 825, 826, 851, 852, 827, 857, 858, 828, 925, 0, + 837, 1317, 1318, 156, 1519, 1535, 0, 1170, 1043, 869, + 856, 1221, 0, 864, 863, 0, 1170, 846, 845, 844, + 1028, 0, 843, 1127, 870, 870, 868, 951, 847, 0, + 0, 0, 0, 0, 874, 0, 872, 952, 930, 931, + 0, 0, 1266, 1275, 1165, 1169, 0, 1026, 1165, 0, + 1035, 1045, 0, 1117, 1119, 0, 0, 0, 1227, 1297, + 1027, 0, 1302, 0, 0, 925, 925, 1255, 1147, 0, + 1137, 1140, 0, 0, 1144, 1145, 1146, 0, 0, 0, + 1247, 0, 1155, 1157, 0, 0, 967, 1153, 0, 970, + 0, 0, 0, 0, 1141, 1142, 1143, 1133, 1134, 1135, + 1136, 1138, 1139, 1151, 1132, 948, 0, 1023, 0, 1080, + 0, 947, 1253, 712, 0, 1300, 712, 1455, 1459, 1460, + 1454, 1458, 0, 1449, 1448, 1451, 1452, 0, 1493, 1477, + 0, 1474, 1168, 707, 579, 1288, 0, 583, 1498, 161, + 160, 0, 213, 0, 552, 551, 618, 610, 612, 618, + 0, 550, 0, 667, 668, 0, 0, 0, 0, 700, + 698, 1296, 1309, 655, 628, 654, 0, 0, 632, 0, + 659, 926, 693, 534, 622, 623, 626, 533, 0, 696, + 0, 706, 0, 571, 573, 556, 570, 568, 553, 561, + 694, 627, 0, 1500, 0, 0, 1464, 1525, 0, 0, + 0, 0, 0, 1663, 0, 0, 808, 84, 65, 323, + 139, 0, 0, 0, 0, 0, 0, 0, 92, 89, + 90, 91, 0, 0, 0, 0, 1316, 234, 235, 248, + 0, 239, 240, 237, 241, 242, 0, 0, 227, 228, + 0, 0, 0, 0, 226, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1508, 1501, 1228, 1233, 609, 609, + 609, 0, 607, 608, 0, 0, 0, 0, 0, 484, + 369, 379, 0, 0, 0, 1341, 206, 0, 0, 0, + 0, 0, 0, 406, 1344, 1342, 1340, 1343, 1345, 1633, + 190, 0, 0, 0, 0, 0, 198, 201, 0, 368, + 342, 0, 0, 1356, 0, 0, 457, 455, 458, 447, + 460, 450, 0, 1663, 358, 1353, 0, 1505, 0, 0, + 253, 443, 1321, 0, 440, 443, 1287, 0, 443, 221, + 0, 0, 1389, 1432, 231, 251, 232, 252, 499, 494, + 524, 0, 502, 507, 482, 0, 482, 0, 504, 508, + 482, 503, 0, 482, 498, 0, 1072, 0, 1062, 0, + 0, 786, 0, 0, 1063, 999, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 499, 1226, 1222, 1226, 0, 0, 0, 609, 605, 606, - 1043, 0, 469, 523, 520, 521, 519, 229, 380, 0, - 0, 0, 200, 368, 0, 1334, 449, 452, 1316, 406, - 0, 193, 0, 191, 211, 0, 0, 202, 371, 0, - 346, 342, 367, 340, 339, 341, 0, 1532, 222, 0, - 1526, 371, 1333, 0, 0, 465, 456, 0, 461, 0, - 0, 459, 0, 1328, 254, 443, 0, 477, 518, 525, - 505, 510, 0, 516, 512, 511, 506, 514, 513, 509, - 1053, 1064, 1188, 0, 0, 0, 0, 782, 785, 0, - 1059, 1054, 756, 0, 0, 670, 0, 0, 0, 0, - 587, 586, 592, 0, 0, 1077, 751, 0, 0, 0, - 738, 727, 733, 734, 0, 0, 0, 794, 793, 764, - 817, 0, 797, 817, 0, 817, 0, 815, 0, 824, - 912, 913, 914, 915, 916, 917, 918, 849, 0, 1212, - 1208, 1114, 1116, 1153, 867, 865, 987, 1250, 1158, 1255, - 1257, 0, 0, 0, 0, 1108, 990, 1281, 923, 0, - 0, 953, 1205, 974, 0, 0, 0, 949, 1141, 0, - 0, 0, 0, 0, 958, 0, 1233, 1226, 0, 1232, - 0, 0, 0, 0, 1048, 715, 687, 0, 687, 0, - 0, 1473, 0, 1468, 148, 149, 150, 0, 0, 0, - 165, 142, 0, 0, 182, 170, 158, 619, 620, 0, - 614, 630, 1263, 1269, 557, 0, 1020, 0, 0, 554, - 0, 134, 273, 0, 0, 66, 0, 390, 334, 382, - 365, 349, 0, 0, 0, 274, 0, 407, 0, 0, - 355, 0, 0, 0, 0, 335, 0, 0, 294, 0, - 0, 365, 0, 372, 290, 291, 0, 58, 78, 0, - 74, 0, 103, 0, 0, 0, 0, 0, 61, 73, - 0, 56, 0, 443, 443, 64, 1294, 1939, 1940, 1941, - 1942, 1943, 1944, 1945, 1946, 1947, 1948, 2059, 1949, 1950, - 1951, 1952, 1953, 1954, 1955, 1956, 2068, 1957, 280, 1958, - 1712, 1959, 1960, 1961, 1962, 1963, 0, 1964, 800, 1965, - 1966, 2147, 1967, 1126, 1127, 279, 278, 375, 275, 383, - 277, 0, 1295, 276, 378, 333, 130, 1340, 0, 128, - 0, 1338, 137, 135, 132, 1342, 1480, 0, 0, 1046, - 1047, 1044, 607, 0, 0, 0, 499, 476, 0, 0, - 0, 1531, 0, 0, 1643, 0, 189, 0, 0, 203, - 1334, 199, 368, 0, 398, 318, 393, 0, 1531, 1529, - 0, 1334, 1525, 448, 451, 0, 0, 540, 453, 0, - 0, 0, 414, 491, 0, 515, 1012, 0, 0, 0, - 0, 646, 0, 652, 687, 591, 590, 589, 588, 669, - 1582, 1871, 1768, 0, 673, 668, 671, 676, 678, 677, - 679, 675, 686, 0, 689, 775, 1154, 1156, 0, 0, - 0, 0, 739, 741, 0, 743, 0, 795, 811, 0, - 812, 0, 810, 805, 816, 1211, 1258, 1259, 1254, 0, - 920, 1217, 980, 978, 975, 0, 976, 957, 0, 0, - 955, 951, 0, 985, 0, 0, 1230, 0, 1069, 0, - 1072, 1086, 1082, 1081, 1077, 1043, 1077, 1435, 580, 169, - 146, 172, 171, 0, 1227, 179, 0, 0, 170, 0, - 174, 466, 0, 0, 569, 731, 562, 563, 0, 386, + 0, 0, 0, 0, 0, 1017, 1016, 1064, 790, 0, + 793, 0, 0, 1202, 1203, 0, 1065, 0, 0, 1209, + 0, 0, 0, 1070, 0, 728, 0, 0, 634, 635, + 643, 639, 646, 0, 649, 636, 585, 541, 1654, 1694, + 0, 596, 596, 596, 594, 584, 0, 671, 729, 0, + 0, 0, 752, 0, 0, 754, 756, 0, 0, 759, + 0, 735, 734, 0, 0, 0, 0, 798, 0, 1292, + 0, 0, 197, 0, 0, 0, 823, 0, 0, 0, + 813, 809, 0, 905, 906, 907, 908, 909, 910, 911, + 912, 913, 914, 915, 916, 917, 829, 1329, 0, 835, + 1332, 0, 1333, 1334, 1331, 1328, 1335, 1336, 0, 0, + 0, 0, 1220, 1216, 0, 0, 0, 0, 1122, 1124, + 1126, 0, 867, 866, 1131, 1137, 1140, 1144, 1145, 1146, + 1141, 1142, 1143, 1133, 1134, 1135, 1136, 1138, 1139, 0, + 1159, 0, 1113, 0, 0, 0, 0, 0, 0, 0, + 1260, 1259, 0, 1283, 0, 1046, 1030, 0, 0, 1120, + 1047, 1267, 1257, 1235, 0, 0, 0, 1305, 1304, 927, + 936, 939, 971, 972, 943, 944, 945, 949, 1327, 1326, + 1254, 0, 1246, 0, 0, 928, 953, 958, 0, 1211, + 1214, 988, 1213, 0, 976, 0, 966, 0, 974, 978, + 954, 969, 0, 950, 0, 1247, 1156, 1158, 0, 1154, + 0, 940, 941, 942, 932, 933, 934, 935, 937, 938, + 946, 1130, 1128, 1129, 0, 1233, 0, 1245, 0, 0, + 1082, 0, 0, 973, 1251, 0, 797, 609, 797, 0, + 925, 1494, 1324, 1487, 1324, 1476, 1166, 1289, 1323, 581, + 0, 0, 0, 1496, 147, 151, 0, 1234, 181, 183, + 712, 0, 616, 617, 621, 0, 0, 621, 600, 549, + 1908, 1789, 0, 0, 0, 0, 660, 701, 0, 692, + 657, 658, 0, 656, 1296, 661, 1295, 662, 665, 666, + 633, 1284, 702, 704, 0, 697, 0, 1290, 555, 574, + 0, 0, 0, 0, 0, 538, 537, 708, 1471, 1471, + 1473, 1472, 0, 50, 0, 1663, 67, 0, 0, 0, + 0, 0, 0, 273, 0, 373, 273, 105, 1663, 443, + 1663, 443, 1557, 1628, 1807, 0, 63, 347, 96, 0, + 133, 376, 0, 332, 86, 101, 126, 0, 0, 52, + 224, 238, 243, 129, 247, 244, 1361, 245, 140, 0, + 48, 0, 127, 0, 1359, 0, 0, 54, 131, 1363, + 1509, 0, 1232, 0, 607, 607, 607, 0, 1172, 0, + 0, 0, 1174, 1175, 966, 1371, 1370, 1372, 1369, 470, + 483, 0, 370, 0, 496, 473, 474, 484, 1339, 211, + 0, 202, 371, 0, 371, 0, 1341, 0, 0, 192, + 188, 206, 212, 0, 0, 0, 0, 0, 369, 361, + 359, 392, 0, 366, 360, 0, 0, 318, 0, 1551, + 0, 0, 0, 0, 464, 0, 0, 0, 0, 0, + 0, 255, 256, 409, 1322, 411, 0, 413, 220, 218, + 1384, 2025, 490, 1170, 0, 488, 495, 489, 492, 493, + 487, 486, 0, 481, 0, 517, 0, 0, 0, 0, + 0, 0, 0, 0, 1059, 1178, 0, 1197, 1196, 998, + 1005, 1008, 1012, 1013, 1014, 1198, 0, 0, 0, 1009, + 1010, 1011, 1001, 1002, 1003, 1004, 1006, 1007, 1015, 795, + 0, 0, 789, 1207, 1206, 1200, 1201, 0, 1067, 1068, + 1069, 1208, 0, 0, 764, 638, 640, 637, 0, 0, + 797, 596, 596, 596, 596, 593, 0, 0, 0, 796, + 0, 688, 760, 758, 0, 782, 0, 755, 0, 761, + 0, 746, 0, 753, 802, 769, 0, 0, 771, 1462, + 819, 0, 814, 810, 0, 0, 0, 820, 0, 0, + 0, 0, 0, 0, 0, 1177, 0, 602, 1044, 0, + 0, 0, 1217, 0, 994, 836, 849, 0, 1125, 1048, + 0, 1148, 1112, 877, 876, 878, 878, 0, 1262, 1264, + 0, 0, 0, 0, 1274, 0, 995, 1225, 0, 1073, + 1223, 1166, 1116, 1118, 1275, 1029, 861, 925, 0, 0, + 0, 0, 0, 0, 0, 977, 968, 0, 975, 979, + 0, 0, 0, 962, 0, 0, 960, 989, 956, 0, + 0, 990, 1232, 0, 1236, 0, 0, 1081, 1090, 715, + 711, 671, 607, 671, 0, 1456, 1478, 1475, 582, 156, + 1497, 0, 170, 0, 0, 0, 0, 173, 187, 184, + 1496, 0, 0, 611, 613, 0, 1149, 621, 615, 664, + 663, 0, 631, 699, 629, 0, 705, 0, 572, 0, + 558, 0, 738, 0, 0, 1465, 1466, 0, 0, 0, + 322, 0, 0, 0, 273, 0, 381, 0, 388, 0, + 0, 373, 354, 85, 0, 0, 0, 59, 104, 77, + 69, 55, 83, 0, 0, 88, 0, 81, 98, 99, + 97, 102, 0, 283, 308, 0, 0, 319, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 499, + 1233, 1229, 1233, 0, 0, 0, 609, 605, 606, 1050, + 0, 469, 523, 520, 521, 519, 229, 380, 0, 0, + 0, 200, 368, 0, 1356, 449, 452, 1338, 406, 0, + 193, 0, 191, 211, 0, 0, 202, 371, 0, 346, + 342, 367, 340, 339, 341, 0, 1552, 222, 0, 1546, + 371, 1355, 0, 0, 465, 456, 0, 461, 0, 0, + 459, 0, 1350, 254, 443, 0, 477, 518, 525, 505, + 510, 0, 516, 512, 511, 506, 514, 513, 509, 1060, + 1071, 1195, 0, 0, 0, 0, 788, 791, 0, 1066, + 1061, 762, 0, 0, 671, 0, 0, 0, 0, 587, + 586, 592, 0, 0, 1084, 757, 0, 0, 0, 744, + 733, 739, 740, 0, 0, 0, 800, 799, 770, 823, + 0, 803, 823, 0, 823, 0, 821, 0, 830, 918, + 919, 920, 921, 922, 923, 924, 855, 0, 1219, 1215, + 1121, 1123, 1160, 873, 871, 993, 1265, 1258, 1261, 1165, + 1269, 1271, 0, 0, 0, 0, 1282, 0, 0, 1115, + 1283, 1303, 929, 0, 0, 959, 1212, 980, 0, 0, + 0, 955, 1148, 0, 0, 0, 0, 0, 964, 0, + 1240, 1233, 0, 1239, 0, 0, 0, 0, 1055, 716, + 688, 0, 688, 0, 0, 1495, 0, 1490, 148, 149, + 150, 0, 0, 0, 165, 142, 0, 0, 182, 170, + 158, 619, 620, 0, 614, 630, 1285, 1291, 557, 0, + 1026, 0, 0, 554, 0, 134, 273, 0, 0, 66, + 0, 390, 334, 382, 365, 349, 0, 0, 0, 274, + 0, 407, 0, 0, 355, 0, 0, 0, 0, 335, + 0, 0, 294, 0, 0, 365, 0, 372, 290, 291, + 0, 58, 78, 0, 74, 0, 103, 0, 0, 0, + 0, 0, 61, 73, 0, 56, 808, 443, 443, 64, + 1316, 1959, 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, + 1968, 2079, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, + 2088, 1977, 280, 1978, 1732, 1979, 1980, 1981, 1982, 1983, + 0, 1984, 806, 1985, 1986, 2167, 1987, 1133, 1134, 279, + 278, 375, 275, 383, 277, 0, 1317, 276, 378, 333, + 130, 1362, 0, 128, 0, 1360, 137, 135, 132, 1364, + 1502, 0, 0, 1053, 1054, 1051, 607, 0, 0, 0, + 499, 476, 0, 0, 0, 1551, 0, 0, 1663, 0, + 189, 0, 0, 203, 1356, 199, 368, 0, 398, 318, + 393, 0, 1551, 1549, 0, 1356, 1545, 448, 451, 0, + 0, 540, 453, 0, 0, 0, 414, 491, 0, 515, + 1018, 0, 0, 0, 0, 647, 0, 653, 688, 591, + 590, 589, 588, 670, 1602, 1891, 1788, 0, 674, 669, + 672, 677, 679, 678, 680, 676, 687, 0, 690, 781, + 1161, 1163, 0, 0, 0, 0, 745, 747, 0, 749, + 0, 801, 817, 0, 818, 0, 816, 811, 822, 1218, + 1263, 1272, 1273, 1268, 1277, 1279, 0, 0, 0, 926, + 1224, 996, 986, 984, 981, 0, 982, 963, 0, 0, + 961, 957, 0, 991, 0, 0, 1237, 0, 1076, 0, + 1079, 1093, 1089, 1088, 1084, 1050, 1084, 1457, 580, 169, + 146, 172, 171, 0, 1234, 179, 0, 0, 170, 0, + 174, 466, 0, 0, 569, 737, 562, 563, 0, 386, 68, 0, 365, 0, 273, 351, 350, 353, 348, 352, 0, 408, 0, 0, 292, 0, 299, 337, 338, 336, 293, 365, 371, 295, 0, 0, 0, 70, 60, 57, - 62, 71, 0, 0, 72, 75, 796, 87, 80, 1294, - 2068, 2077, 0, 0, 0, 0, 0, 1224, 1223, 0, - 472, 471, 522, 468, 479, 229, 0, 0, 0, 342, - 1528, 0, 0, 0, 368, 194, 0, 0, 0, 0, - 1531, 0, 0, 270, 0, 315, 0, 215, 1530, 0, - 0, 1517, 0, 0, 1326, 1327, 0, 478, 1013, 0, - 1014, 786, 0, 0, 644, 1077, 0, 0, 0, 680, - 674, 0, 1076, 1078, 0, 641, 1157, 735, 0, 737, - 0, 761, 0, 761, 744, 806, 798, 1256, 1067, 0, - 977, 981, 979, 959, 1226, 1234, 1226, 1231, 1071, 1085, - 1088, 689, 1279, 689, 0, 0, 157, 0, 0, 154, - 141, 159, 1143, 559, 560, 0, 273, 0, 364, 387, - 304, 282, 0, 0, 0, 289, 296, 397, 298, 0, - 79, 95, 0, 0, 377, 138, 136, 1045, 499, 0, - 205, 1334, 318, 1525, 0, 0, 0, 0, 342, 222, - 1527, 331, 324, 325, 326, 327, 328, 329, 330, 345, - 344, 316, 317, 0, 0, 0, 0, 454, 1328, 0, - 176, 185, 0, 176, 1015, 647, 0, 689, 0, 0, - 0, 672, 0, 0, 688, 0, 545, 1155, 0, 726, - 724, 0, 725, 0, 0, 0, 0, 609, 641, 641, - 143, 0, 144, 180, 0, 0, 0, 371, 389, 363, - 0, 356, 302, 301, 303, 307, 0, 305, 0, 321, - 0, 314, 282, 0, 82, 0, 384, 467, 475, 0, - 272, 1519, 368, 0, 204, 1525, 318, 1531, 1525, 0, - 1522, 0, 0, 0, 0, 178, 1334, 0, 178, 0, - 641, 682, 0, 681, 1080, 1079, 643, 736, 0, 1068, - 1236, 1235, 0, 1092, 544, 543, 0, 0, 0, 0, - 397, 0, 343, 0, 0, 304, 0, 297, 394, 395, - 396, 0, 310, 300, 311, 76, 94, 385, 0, 368, - 1520, 271, 216, 1518, 1523, 1524, 0, 176, 175, 618, - 177, 791, 186, 618, 651, 546, 683, 640, 742, 1087, - 0, 0, 0, 0, 0, 153, 791, 164, 0, 314, - 362, 357, 281, 306, 320, 0, 0, 0, 312, 0, - 313, 1525, 0, 178, 621, 1324, 621, 1857, 1583, 1822, - 0, 1104, 1093, 1104, 1104, 1084, 145, 152, 0, 273, - 286, 0, 285, 0, 374, 309, 1521, 1334, 618, 166, - 167, 0, 1097, 1096, 1095, 1099, 1098, 0, 1091, 1089, - 1090, 791, 391, 284, 288, 287, 791, 621, 0, 0, - 1101, 0, 1102, 163, 1325, 168, 1094, 1100, 1103 + 62, 71, 0, 0, 72, 75, 802, 807, 87, 80, + 1316, 2088, 2097, 0, 0, 0, 0, 0, 1231, 1230, + 0, 472, 471, 522, 468, 479, 229, 0, 0, 0, + 342, 1548, 0, 0, 0, 368, 194, 0, 0, 0, + 0, 1551, 0, 0, 270, 0, 315, 0, 215, 1550, + 0, 0, 1537, 0, 0, 1348, 1349, 0, 478, 1019, + 0, 1020, 792, 0, 0, 645, 1084, 0, 0, 0, + 681, 675, 0, 1083, 1085, 0, 642, 1164, 741, 0, + 743, 0, 767, 0, 767, 750, 812, 804, 1270, 1280, + 1281, 1276, 1074, 0, 983, 987, 985, 965, 1233, 1241, + 1233, 1238, 1078, 1092, 1095, 690, 1301, 690, 0, 0, + 157, 0, 0, 154, 141, 159, 1150, 559, 560, 0, + 273, 0, 364, 387, 304, 282, 0, 0, 0, 289, + 296, 397, 298, 0, 79, 95, 0, 0, 377, 138, + 136, 1052, 499, 0, 205, 1356, 318, 1545, 0, 0, + 0, 0, 342, 222, 1547, 331, 324, 325, 326, 327, + 328, 329, 330, 345, 344, 316, 317, 0, 0, 0, + 0, 454, 1350, 0, 176, 185, 0, 176, 1021, 648, + 0, 690, 0, 0, 0, 673, 0, 0, 689, 0, + 545, 1162, 0, 732, 730, 0, 731, 1278, 0, 0, + 0, 0, 609, 642, 642, 143, 0, 144, 180, 0, + 0, 0, 371, 389, 363, 0, 356, 302, 301, 303, + 307, 0, 305, 0, 321, 0, 314, 282, 0, 82, + 0, 384, 467, 475, 0, 272, 1539, 368, 0, 204, + 1545, 318, 1551, 1545, 0, 1542, 0, 0, 0, 0, + 178, 1356, 0, 178, 0, 642, 683, 0, 682, 1087, + 1086, 644, 742, 0, 1075, 1243, 1242, 0, 1099, 544, + 543, 0, 0, 0, 0, 397, 0, 343, 0, 0, + 304, 0, 297, 394, 395, 396, 0, 310, 300, 311, + 76, 94, 385, 0, 368, 1540, 271, 216, 1538, 1543, + 1544, 0, 176, 175, 618, 177, 797, 186, 618, 652, + 546, 684, 641, 748, 1094, 0, 0, 0, 0, 0, + 153, 797, 164, 0, 314, 362, 357, 281, 306, 320, + 0, 0, 0, 312, 0, 313, 1545, 0, 178, 621, + 1346, 621, 1877, 1603, 1842, 0, 1111, 1100, 1111, 1111, + 1091, 145, 152, 0, 273, 286, 0, 285, 0, 374, + 309, 1541, 1356, 618, 166, 167, 0, 1104, 1103, 1102, + 1106, 1105, 0, 1098, 1096, 1097, 797, 391, 284, 288, + 287, 797, 621, 0, 0, 1108, 0, 1109, 163, 1347, + 168, 1101, 1107, 1110 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 47, 48, 49, 755, 2640, 2641, 2642, 2269, 1218, - 3414, 2270, 1219, 1220, 2644, 756, 806, 1100, 808, 1101, - 1618, 914, 1254, 1255, 757, 1771, 758, 2870, 2189, 2586, - 3396, 54, 3145, 2192, 1176, 3148, 3361, 2863, 3143, 2587, - 3435, 3489, 3146, 2193, 2194, 3362, 2195, 759, 2702, 2703, - 760, 761, 1855, 58, 1316, 551, 1852, 762, 763, 1349, - 1350, 969, 764, 1856, 1799, 2986, 1238, 1789, 1364, 62, - 1879, 765, 107, 910, 64, 766, 2629, 2987, 3407, 2655, - 3544, 2923, 2924, 3404, 3405, 2632, 2272, 3472, 3473, 2717, - 1780, 3467, 2353, 3349, 2276, 2257, 2925, 2361, 3308, 3034, - 2273, 2905, 2354, 3400, 1874, 2355, 3401, 3164, 2356, 1830, - 1859, 2633, 3474, 2277, 1831, 2628, 2988, 1768, 2357, 3411, - 2358, 552, 2909, 767, 746, 747, 961, 1343, 748, 768, - 1865, 1866, 1867, 1868, 1869, 1870, 945, 1871, 769, 770, - 2682, 2331, 3215, 2736, 3216, 2398, 2325, 1373, 2390, 1899, - 1833, 1374, 540, 1913, 2737, 2687, 1900, 771, 1102, 72, - 73, 1015, 74, 3158, 75, 76, 1742, 1743, 1744, 854, - 866, 867, 2185, 1459, 1982, 859, 1181, 1711, 840, 841, - 2315, 882, 1822, 1706, 1707, 2198, 2594, 1735, 1736, 1190, - 1191, 1970, 3376, 1971, 1972, 1452, 1453, 3254, 1723, 1727, - 1728, 2219, 2209, 1714, 2467, 3074, 3075, 3076, 3077, 3078, - 3079, 3080, 1103, 2775, 3265, 1731, 1732, 1193, 1194, 1195, - 1740, 2229, 78, 79, 2170, 2570, 2571, 812, 3091, 1478, - 1745, 2779, 2780, 2781, 3094, 3095, 3096, 813, 1010, 1011, - 1034, 1029, 1467, 1991, 814, 815, 1947, 1948, 2436, 1036, - 1984, 2002, 2003, 2787, 2491, 1544, 2258, 1545, 1546, 2017, - 1547, 1104, 1548, 1576, 1105, 1581, 1550, 1106, 1107, 1108, - 1553, 1109, 1110, 1111, 1112, 1569, 1113, 1114, 1593, 2019, - 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, - 2030, 2031, 2032, 1163, 1746, 1116, 1117, 1118, 1119, 1120, - 1121, 1122, 1123, 1124, 817, 1125, 2529, 1126, 1667, 2164, - 2569, 3084, 3262, 3263, 2854, 3133, 3290, 3387, 3503, 3531, - 3532, 3558, 1127, 1128, 1612, 1613, 1614, 2054, 2055, 2056, - 2057, 2158, 1661, 1662, 1129, 2990, 1664, 2077, 3087, 3088, - 1164, 1445, 1605, 1295, 1296, 1558, 1419, 1420, 1426, 1922, - 1434, 1438, 1952, 1953, 1446, 2125, 1130, 2048, 2049, 2509, - 1571, 2530, 2531, 1131, 1253, 1617, 2849, 2161, 1665, 2118, - 1138, 1132, 1139, 1134, 1601, 1602, 2527, 2820, 2821, 2088, - 2226, 1694, 2231, 2232, 965, 1135, 1136, 1137, 1297, 524, - 1559, 3490, 1339, 1169, 1298, 2114, 772, 1041, 2041, 773, - 1312, 1845, 774, 3245, 3051, 1328, 1875, 2366, 553, 775, - 776, 533, 85, 2320, 926, 86, 87, 88, 891, 1366, - 777, 1367, 1368, 976, 89, 2738, 978, 979, 779, 848, - 849, 1487, 1681, 1488, 780, 92, 823, 1755, 781, 1159, - 863, 1160, 1162, 782, 1178, 2583, 2187, 95, 96, 97, - 115, 1249, 783, 834, 835, 872, 100, 101, 1206, 836, - 855, 785, 786, 3241, 787, 2720, 1322, 534, 526, 527, - 1561, 720, 1300, 721 + -1, 47, 48, 49, 755, 2659, 2660, 2661, 2285, 1225, + 3449, 2286, 1226, 1227, 2663, 756, 806, 1169, 855, 1107, + 1628, 915, 1261, 1262, 757, 1782, 758, 2894, 2205, 2605, + 3431, 54, 3175, 2208, 1183, 3178, 3395, 2887, 3173, 2606, + 3470, 3524, 3176, 2209, 2210, 3396, 2211, 759, 2721, 2722, + 760, 761, 1866, 58, 1323, 551, 1863, 762, 763, 1356, + 1357, 970, 764, 1867, 1810, 3010, 1245, 1800, 1371, 62, + 1890, 765, 107, 911, 64, 766, 2648, 3011, 3442, 2674, + 3579, 2947, 2948, 3439, 3440, 2651, 2288, 3507, 3508, 2736, + 1791, 3502, 2369, 3383, 2292, 2273, 2949, 2377, 3342, 3058, + 2289, 2929, 2370, 3435, 1885, 2371, 3436, 3194, 2372, 1841, + 1870, 2652, 3509, 2293, 1842, 2647, 3012, 1779, 2373, 3446, + 2374, 552, 2933, 767, 746, 747, 962, 1350, 748, 768, + 1876, 1877, 1878, 1879, 1880, 1881, 946, 1882, 769, 770, + 2701, 2347, 3246, 2755, 3247, 2414, 2341, 1380, 2406, 1910, + 1844, 1381, 540, 1924, 2756, 2706, 1911, 771, 1108, 72, + 73, 1017, 74, 3188, 75, 76, 1753, 1754, 1755, 857, + 867, 868, 2201, 1466, 1995, 860, 1188, 1722, 841, 842, + 2331, 883, 1833, 1717, 1718, 2214, 2613, 1746, 1747, 1197, + 1198, 1981, 1982, 3410, 1983, 1984, 1459, 1460, 3285, 1734, + 1738, 1739, 2235, 2225, 1725, 2481, 3098, 3099, 3100, 3101, + 3102, 3103, 3104, 1109, 2794, 3296, 1742, 1743, 1200, 1201, + 1202, 1751, 2245, 78, 79, 2186, 2589, 2590, 812, 813, + 3115, 1489, 1756, 2798, 2799, 2800, 3118, 3119, 3120, 814, + 1012, 1013, 1040, 1035, 1478, 2005, 815, 816, 1958, 1959, + 2452, 1042, 1997, 2016, 2017, 2806, 2505, 1555, 2274, 1556, + 1557, 2031, 1558, 1110, 1559, 1587, 1111, 1592, 1561, 1112, + 1113, 1114, 1564, 1115, 1116, 1117, 1118, 1580, 1119, 1120, + 1604, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, + 2042, 2043, 2044, 2045, 2046, 1170, 1757, 1122, 1123, 1124, + 1125, 1126, 1127, 1128, 1129, 1130, 1131, 818, 1132, 2548, + 1133, 1679, 2180, 2588, 3108, 3293, 3294, 2878, 3163, 3324, + 3422, 3538, 3566, 3567, 3593, 1134, 1135, 1623, 1624, 1625, + 2068, 2069, 2070, 2071, 2174, 1673, 1674, 1136, 3014, 1676, + 2091, 3111, 3112, 1171, 1452, 1616, 1302, 1303, 1569, 1426, + 1427, 1433, 1933, 1441, 1445, 1963, 1964, 1453, 2141, 1137, + 2062, 2063, 2523, 1582, 2549, 2550, 1138, 1260, 1629, 2873, + 2177, 1677, 2134, 1145, 1139, 1146, 1141, 1612, 2845, 2539, + 2540, 1613, 2544, 2841, 2842, 2103, 2846, 3135, 3136, 2546, + 2242, 1705, 2247, 2248, 966, 1142, 1143, 1144, 1304, 524, + 1570, 3525, 1346, 1176, 1305, 2130, 772, 1047, 2055, 773, + 1319, 1856, 774, 3276, 3075, 1335, 1886, 2382, 553, 775, + 776, 533, 85, 2336, 927, 86, 87, 88, 892, 1373, + 777, 1374, 1375, 977, 89, 2757, 979, 980, 779, 849, + 850, 1498, 1693, 1499, 780, 92, 824, 1766, 781, 1165, + 864, 1166, 1168, 782, 1185, 2602, 2203, 95, 96, 97, + 115, 1256, 783, 835, 836, 873, 100, 101, 1213, 837, + 785, 786, 3272, 787, 2739, 1329, 534, 526, 527, 1572, + 720, 1307, 721 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -3017 +#define YYPACT_NINF -3072 static const int yypact[] = { - 6596, -26, 739, -3017, -3017, 275, -26, 49530, 64984, 350, - -26, 136, 2383, 51526, -3017, -3017, 46037, 3819, -26, 55019, - 72380, 321, 582, 31527, 552, 55518, -3017, -3017, -3017, 64984, - 55019, 56017, -26, 345, 65483, -3017, -26, 34022, 52025, 337, - -3017, 55019, 67, 313, 56516, 55019, 2833, 854, 346, -3017, - -3017, -3017, -3017, -3017, 168, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, 156, -3017, 200, 166, 31527, 31527, 53, 376, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, 396, - -3017, -3017, 709, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, 33523, -3017, -3017, -3017, -3017, -3017, -3017, 57015, 55019, - 57514, 52524, 58013, -3017, 672, 936, 612, 194, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - 204, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, 459, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, 206, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, 666, -3017, 516, -3017, 209, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, 870, -3017, -3017, 998, 2691, - 55019, 950, 986, 775, -3017, 58512, -3017, 756, 55019, -3017, - -3017, 819, 741, 999, -3017, -3017, 53023, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, 46536, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, 1004, -3017, -3017, 831, -3017, 148, -3017, -3017, - 875, 820, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, 923, -3017, -3017, -3017, 959, 65982, 59011, 59510, -3017, - 827, 1658, 7978, 72398, 30527, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, 396, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, 55518, 64984, - 833, 841, 1137, 850, 32026, 866, 34522, 873, 879, 1244, - 912, 919, 932, 957, 313, 31027, 935, 666, -3017, 60009, - 60009, -28, 3241, -3017, 60009, 60508, -3017, 992, -3017, 936, - -3017, -3017, -3017, -3017, 342, 970, -3017, 61007, 61007, 61007, - 1033, 1283, 61007, -3017, -3017, -3017, 1025, -3017, -3017, 1280, - 19682, 19682, 66481, 66481, 936, 66481, 1073, 66481, -3017, -3017, - 54, 612, -3017, -3017, 53, 1059, 666, -3017, -3017, 52025, - -3017, -3017, 316, 1423, 19682, 55019, 1076, -3017, 1086, 1076, - 1091, 1097, 1099, -3017, 6596, 1464, 1344, 53522, 724, 724, - 1582, 724, 1006, 1008, 5405, 2999, -3017, 196, -3017, 1125, - -3017, 55019, 55518, 1237, 1161, 1454, -3017, 1059, 1528, 147, - 1334, 1571, 6090, 1594, 184, 1601, 483, 1602, 1676, 40, - -3017, 19682, 47035, 666, -3017, 11841, 19682, -3017, -3017, -3017, - 1307, -3017, -3017, -3017, -3017, -3017, 55019, 64984, 1233, 1238, - -3017, -3017, -3017, -3017, 956, 1482, -3017, 1719, 66980, -3017, - -3017, 1290, 61506, 62005, 62504, 63003, 1674, -3017, -3017, 1609, - -3017, -3017, -3017, 1281, -3017, -3017, -3017, 195, 67479, 1612, - 1246, 119, -3017, 1616, 198, -3017, 1619, 1480, 15490, -3017, - 1417, -3017, -3017, -3017, 313, -3017, 284, -3017, -3017, 43138, - -3017, -3017, 72398, 1345, 1256, -3017, 19682, 19682, 1259, 8514, - 60009, 60508, 19682, 55019, -3017, 19682, 24398, 1260, 19682, 19682, - 12870, 19682, 29529, 60009, 3241, 1261, -3017, 791, 55019, 1264, - -3017, 1358, 1358, 345, 31527, 1561, -3017, 212, 1558, 1484, - -3017, 31527, 1484, 1030, 1268, 1562, 1484, -3017, 514, 1563, - 1358, 35021, 1273, -3017, 1358, 1493, -3017, -3017, 19682, 15490, - 69974, 1752, -3017, -3017, -3017, -3017, 1557, -3017, 64984, 1276, - -3017, -3017, -3017, -3017, -3017, -3017, 671, 1790, 175, 1791, - 19682, 175, 175, 1279, 210, 210, -3017, 1474, 1288, -3017, - 214, 1289, 1292, 1806, 1807, 176, 164, 1136, 175, 19682, - -3017, 210, 1296, 1810, 1302, 1816, 188, 222, -3017, 215, - 19682, 19682, 19682, 310, 19682, 10793, -3017, 1818, 47035, 55019, - 697, -3017, 666, 1310, 936, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, 1312, -3017, 179, 6769, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, 1351, -3017, -3017, -3017, -3017, 1523, 19682, - -3017, -3017, 1316, 1561, -3017, 218, -3017, -3017, 1561, -3017, - -3017, -3017, -3017, -3017, 249, -3017, 1731, 19682, 19682, -3017, - 64984, 666, 67978, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - 395, -3017, 396, 44856, 1319, 1318, 1076, 55019, 55019, 1803, - -3017, -3017, -3017, -3017, 52025, 118, 1626, 158, 1460, -3017, - -3017, 53, 53, 16014, 812, 216, 491, 16538, 20206, 1684, - 1565, 599, 614, 1686, -3017, 1573, 1800, 24398, 19682, 19682, - 1006, 1008, 19682, 1086, 135, -3017, -3017, -3017, 1627, 55019, - 50029, 787, 928, 1354, 1431, 1355, 262, 1775, -3017, 1352, - -3017, 1445, 55019, 71925, 273, -3017, 1819, 273, 273, 768, - 1821, 1453, 258, 1615, 30, 371, 1352, 3469, -3017, 52025, - 146, 141, 1352, 55019, 1456, 560, 1352, 1777, 64984, 1256, - -3017, -3017, 40704, 1360, -3017, -3017, -3017, 181, 15490, -3017, - 1105, 1272, 1313, 387, 189, 1443, 1466, 15490, 1502, 1539, - 187, 1564, 1572, 1574, 1576, 1579, 1583, 1586, 1589, 162, - 1593, 1600, 1618, 1641, 1647, 1653, -3017, 1657, 191, 1662, - 199, 15490, 1669, -3017, 44856, 24, -3017, -3017, 1672, 193, - -3017, 44956, -3017, 1667, 1459, 1461, 64984, 1413, 55019, 1514, - 843, 1744, 1797, 70458, 1623, -3017, 1701, 55019, 1629, 3469, - 1630, 1383, 1862, 1631, 1238, 1634, 1392, -3017, 68477, 47035, - -3017, -3017, -3017, -3017, -3017, 1766, 1755, 64984, 47035, 1420, - -3017, -3017, 64984, -3017, 55019, 55019, -3017, 55019, 64984, -3017, - 576, 44856, 1935, 937, 72398, 48532, -3017, -3017, -3017, -3017, - 1047, 1062, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, 936, 47035, -3017, 3598, 43759, 1438, 19682, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, 1439, - 1793, -3017, -3017, 5541, 1447, 44054, 1448, 24398, 24398, 666, - 3938, -3017, -3017, 24398, 1449, 49031, 43673, 1428, 1451, 44239, - 17062, 19682, 17062, 17062, 44305, -3017, 1452, 44394, 60009, 1444, - 55019, 54021, -3017, -3017, -3017, 19682, 19682, 3241, 54520, 1492, - 31527, -3017, 31527, -3017, 1747, 31527, -3017, -3017, 6913, -3017, - 31527, 1750, 19682, 31527, -3017, 31527, 1697, 1699, 1465, 31527, - -3017, 55019, 1467, 55019, -3017, -3017, 44856, -3017, 1469, 632, - 1468, -3017, -3017, -3017, -3017, -3017, 1520, -3017, 1520, 1520, - -3017, -3017, -3017, -3017, 1475, 1475, 1477, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - 1481, 1136, -3017, 1520, -3017, 1475, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, 71925, -3017, -3017, -3017, -3017, 418, 620, - -3017, 1487, -3017, -3017, 1488, -3017, 1472, 1968, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, 41013, 644, 1475, - -3017, -3017, 5290, -3017, -3017, 19682, 19682, -3017, -3017, 1490, - 44856, 1534, -3017, -3017, 19682, 19682, -3017, -3017, -3017, -3017, - 2002, -3017, 19682, 1520, 1520, -3017, 43691, -3017, 39514, 17586, - 1587, 1588, 2002, -3017, 2002, -3017, 43691, 2001, 2001, 1500, - 37516, -3017, 1665, 44603, -3017, 1504, 1677, 7335, 1503, -3017, - -3017, 1494, -3017, 1506, 1499, 41641, 182, 666, 666, 19682, - -3017, 2002, 19682, 44045, 44045, -3017, 235, 69974, 19682, 19682, - 19682, 19682, 19682, 19682, 19682, 19682, 45538, 1604, 177, 64984, - 19682, 19682, 29024, 1239, -3017, 19682, 1749, -3017, 1512, 19682, - 1603, 902, 19682, 19682, 19682, 19682, 19682, 19682, 19682, 19682, - 19682, -3017, -3017, 28009, 240, 702, 1855, 1874, -12, 302, - 19682, 1870, 11841, -3017, 1870, -3017, -3017, -3017, -3017, -3017, - 219, -3017, -3017, 1469, 1469, -3017, 64984, -3017, 55019, 316, - 51027, 19682, -3017, -3017, 1521, 1533, 169, 1598, -3017, -3017, - 55019, -3017, 38015, 1838, -3017, 356, 1536, -3017, 43634, 1794, - 1838, 53, -3017, -3017, 25446, 1670, 1832, 1770, -3017, -3017, - 1751, 1753, -3017, 1543, 45045, 20730, 20730, -3017, 1332, 44856, - 1337, -3017, -3017, -3017, -3017, -3017, -3017, 528, -3017, 55019, - 117, 35520, -3017, 1545, 106, -3017, 4724, 1887, 1850, 1684, - 614, 1552, -3017, 55518, 55518, -3017, -3017, 1116, 1554, 68976, - 55019, 1846, 1799, 1848, 328, 69974, -3017, -3017, -3017, -3017, - 55019, 64984, 63502, 69475, 47534, 55019, 47035, -3017, -3017, -3017, - -3017, 55019, 1315, 55019, 7055, -3017, -3017, -3017, -3017, 273, - -3017, -3017, -3017, -3017, -3017, 64984, 55019, -3017, -3017, 273, - 64984, 55019, 273, -3017, 1248, 55019, 55019, 55019, 55019, 1585, - 55019, 55019, 936, -3017, -3017, -3017, 21254, 103, 103, 1780, - 13394, 160, -3017, 19682, 19682, 304, 263, 64984, 1745, -3017, - -3017, 706, 1796, 114, -3017, 64984, 1608, 55019, 55019, 55019, - 55019, 55019, 1854, -3017, -3017, -3017, -3017, -3017, 1570, -3017, - 1938, 2090, 1578, 1580, 1942, -3017, 3469, 1945, 50528, 786, - 1812, 1947, 1621, 1950, 13918, -3017, -3017, 1591, -3017, -3017, - 1592, 2064, 1830, -3017, -3017, 1826, -3017, 64984, 2105, -3017, - 119, -3017, 47035, -3017, 198, -3017, 1827, 220, -3017, 15490, - 19682, -3017, -3017, -3017, -3017, -3017, -3017, 1256, 28519, -3017, - 723, -3017, -3017, 2078, 936, 2078, 593, -3017, -3017, 2078, - -3017, 2060, 2078, -3017, 69974, -3017, 7532, -3017, 19682, 19682, - -3017, 19682, 1948, -3017, 2111, 2111, 69974, 24398, 24398, 24398, - 24398, 24398, 24398, 524, 1296, 24398, 24398, 24398, 24398, 24398, - 24398, 24398, 24398, 24398, 25970, 513, -3017, -3017, 779, 2083, - 19682, 19682, 1958, 1948, 19682, -3017, 69974, 1607, -3017, 1611, - 1613, 19682, -3017, 69974, -3017, 55019, 1620, 17, 26, -3017, - 1622, 1628, -3017, 1561, -3017, 1018, 1022, 55019, 3231, 3817, - 4493, -3017, -3017, 19682, 1956, 6913, 6913, 31527, -3017, 19682, - 1632, -3017, -3017, 31527, 1974, -3017, 6913, -3017, -3017, 36019, - 6913, 69974, 796, -3017, 55019, 69974, 801, 19682, -3017, 15490, - 2141, 69974, 2106, 64984, 64984, 2144, 1635, 1638, 2002, 1725, - -3017, 1726, 1729, 1730, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, 69974, -3017, -3017, 174, -3017, -3017, - -3017, -3017, -3017, -3017, 1644, 1648, 19682, 19682, 112, -3017, - 7927, 1645, 1650, 4610, -3017, 1649, -3017, 1643, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, -3017, -3017, 1654, -3017, 1656, -3017, 1659, - 1679, 1681, 1664, 1671, 19682, 55019, -3017, 21778, -3017, 64984, - -3017, -3017, 19682, 19682, 55019, -3017, 2025, -3017, 1680, 1682, - 8232, -3017, -3017, -3017, 230, 404, 7582, 302, 5399, 5399, - 5399, 43691, -3017, -3017, -3017, 1683, -3017, 24398, 24398, -3017, - 1225, 1709, 10793, -3017, -3017, -3017, -3017, 2005, -3017, 774, - -3017, 1668, -3017, -3017, 1944, -3017, 39514, 44153, 19682, 190, - -3017, 19682, 29024, 19682, 1764, 5399, 5399, 5399, 277, 277, - 230, 230, 230, 404, 302, -3017, -3017, -3017, 1685, 19682, - 47035, -3017, 1687, 1688, 2043, 1302, 19682, -3017, -3017, 31527, - 1492, 24, 1492, 2002, 44045, -3017, 1086, -3017, 1086, -3017, - 44856, 55019, -3017, -3017, 1954, 1689, 31527, 1723, 2172, 2154, - 64984, -3017, -3017, 1692, 1870, 1708, -3017, -3017, 1721, 19682, - 1185, 1721, -3017, 1838, 15, 1934, 1158, 1158, 1332, 1936, - -3017, -3017, 1776, -3017, -3017, -3017, 19682, 14442, 1341, -3017, - 1343, -3017, -3017, -3017, -3017, -3017, 1710, -3017, 1991, -3017, - 55019, -3017, -3017, 24398, 2179, 19682, 36518, 2180, 1977, -3017, - -3017, -3017, 1779, 1779, -3017, -3017, 1820, 1352, 19682, 1972, - -3017, 157, 1732, 2097, 343, 2050, 64984, -3017, 332, 344, - -3017, 776, 2103, 220, 2104, 220, 47035, 47035, 47035, 806, - -3017, -3017, -3017, 936, -3017, -87, 815, -3017, -3017, -3017, - -3017, 1834, 692, 1352, 3469, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, 221, 720, 1352, 1836, -3017, 1840, -3017, 1841, - 764, 1352, -3017, -3017, 1676, 9217, 44856, 535, 160, 160, - 160, 15490, -3017, 1976, 1981, 1754, 44856, 44856, 165, -3017, - -3017, -3017, -3017, 1758, -3017, 231, -3017, 64984, -3017, -3017, - -3017, 1745, 1797, 1701, 55019, 3469, 1760, 2240, 1238, 1392, - -3017, 1927, 913, 1851, -3017, 64984, -3017, 47035, 64984, 55019, - 55019, 55019, 64001, -3017, -3017, -3017, 1767, 1763, -3017, 13, - 2000, 1999, 55019, 1813, 55019, 1355, 2250, 55019, -3017, 824, - 1392, 1392, 18110, 2145, 55019, 1755, -3017, -3017, -3017, -3017, - 64984, -3017, -3017, 44856, -3017, 1773, -3017, 19682, 48033, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, 47035, -3017, 936, -3017, - 936, 2020, 64984, 42140, 936, 42639, 936, 1782, -3017, 44856, - 8322, 44856, 1958, -3017, 232, 2111, 536, 536, 536, 5906, - 2134, 363, 1789, 536, 536, 536, 283, 283, 232, 232, - 232, 2111, 513, 992, 49031, 1801, -3017, 44856, 44856, -3017, - -3017, 1798, -3017, -3017, -3017, -3017, 1802, 1804, -3017, -3017, - -3017, -3017, -3017, -3017, 64984, 1168, 1492, 337, 337, 337, - 337, -3017, 55019, 55019, 55019, 44856, 2249, 2123, -3017, -3017, - 6913, 44856, 55019, -3017, 26999, -3017, 55019, -3017, 2148, -3017, - 2238, -3017, 55019, 830, -3017, -3017, -3017, 834, 1817, 1638, - 69974, 836, 842, -3017, 2002, 151, 1809, 1450, 924, 570, - 1350, -3017, 52025, -3017, -3017, 1822, 44660, 19682, -3017, 2183, - -3017, -3017, -3017, 19682, 19682, -3017, 39514, -3017, -3017, -3017, - -3017, -55, -55, 8455, 1823, 10793, 44747, -3017, -3017, 2130, - 1824, -3017, 8678, 44856, -3017, 1665, -3017, -3017, 44045, 19682, - 2547, 5060, 19682, 1828, 19682, 2150, -3017, -3017, 1814, -3017, - -3017, 69974, 19682, 1829, 3859, 24398, 24398, 4710, -3017, 5386, - 19682, 10793, -3017, 40791, 1811, 1825, 1780, 18634, -3017, 2048, - 1831, -3017, 1956, 160, 1956, 1835, -3017, -3017, -3017, -3017, - 5290, -3017, 19682, 1989, 64984, 542, 1872, 844, -3017, 666, - 38015, 1723, 19682, 608, -3017, -3017, 1833, -3017, 1721, -3017, - -3017, -3017, 2065, -3017, -3017, -3017, 55019, -3017, 1839, -3017, - 35520, 2176, 11317, -3017, 35520, 55019, -3017, -3017, 55019, 40021, - 2207, -3017, 64984, 64984, 64984, -3017, 64984, 1842, 1843, 248, - 1845, 389, -3017, 2194, 248, 2184, 247, 1355, 258, 2907, - 461, -3017, -3017, -3017, 1919, 55019, -3017, 64984, -3017, -3017, - -3017, -3017, -3017, 47534, -3017, -3017, 39014, 47035, -3017, 47035, - 55019, 55019, 55019, 55019, 55019, 55019, 55019, 55019, 55019, 55019, - 1256, 19682, -3017, 19682, 1847, 1849, 1852, 1780, -3017, -3017, - -3017, 282, -3017, 1859, -3017, -3017, -3017, 371, -3017, 231, - 1864, 1865, -3017, 50528, 2691, 1621, -3017, 1592, 1797, 680, - 64485, -3017, 1866, 1869, 1701, 855, 867, 3469, 1868, 2330, - -3017, 786, 50528, -3017, -3017, -3017, 2298, -3017, 827, 228, - -3017, 1238, -3017, 2691, 1392, -3017, -3017, 2347, -3017, 2348, - 2691, 44856, 64984, 1937, -3017, 220, 871, -3017, -3017, -3017, - -3017, -3017, 64984, 1871, -3017, 1871, -3017, -3017, 1871, -3017, - -3017, -3017, -3017, 24398, 2220, 1877, 69974, -3017, -3017, 55019, - -3017, -3017, -3017, 876, 1878, 1956, 55019, 55019, 55019, 55019, - -3017, -3017, -3017, 19158, 19682, 1917, -3017, 1881, 12365, 2203, - -3017, 26494, -3017, -3017, 1884, 36019, 64984, -3017, -3017, -3017, - -3017, 2002, -3017, -3017, 64984, -3017, 1888, -3017, 1894, -3017, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, 19682, 44856, - -3017, 44856, -3017, -3017, -3017, -3017, -3017, -3017, 7206, -3017, - 1882, 1893, 64984, 19682, 64984, -3017, -3017, -3017, 391, 19682, - 19682, 1225, -3017, 6514, 19682, 69974, 886, 1225, 267, 19682, - 5646, 6346, 19682, 19682, 5456, 40060, -3017, 22302, 14966, -3017, - 1897, 19682, 40099, 38514, -3017, 31527, 2123, 1898, 2123, 936, - 1899, 44856, 19682, -3017, -3017, -3017, -3017, 1957, -5, 33024, - 2129, -3017, 1906, 64984, -3017, 1989, 44856, -3017, -3017, 39514, - -3017, -3017, -3017, -3017, -3017, 2363, 1012, 1904, 1907, -3017, - 1269, -3017, -3017, 64984, 1909, -3017, 1912, 248, -3017, 64984, - 1952, -3017, 271, 2228, 111, -3017, 19682, -3017, 2308, 2394, - 2194, 1918, 64984, 55019, 24398, -3017, 285, 183, -3017, 2208, - 55019, 1952, 2349, -3017, -3017, -3017, 389, -3017, 2246, 2159, - -3017, 273, -3017, 19682, 389, 2160, 154, 64984, -3017, -3017, - 2370, -3017, 69974, 220, 220, -3017, 1468, 1921, 1922, 1923, - 1924, 1925, 1928, 1929, 1931, 1932, 1939, -3017, 1940, 1941, - 1943, 1946, 1953, 1955, 1961, 1966, 1481, 1967, -3017, 1970, - 1833, 1973, 1975, 1978, 1982, 1983, 70942, 1984, 1985, 1992, - 1993, 1487, 1994, 1047, 1062, -3017, -3017, -3017, -3017, -3017, - -3017, 1246, 1995, -3017, 1990, -3017, -3017, -3017, 2016, -3017, - 2031, -3017, -3017, -3017, -3017, -3017, -3017, 1951, 1960, -3017, - -3017, -3017, 160, 1997, 2003, 64984, 1256, 121, 47035, 64984, - 2006, 1813, 2425, 1211, 2217, 2008, -3017, 936, 2009, -3017, - 1621, -3017, 50528, 2482, 268, 1999, -3017, 323, 1813, -3017, - 2389, 1621, 2021, -3017, 1592, 2100, 19682, 150, -3017, 2219, - 64984, 2010, -3017, -3017, 48033, 1871, 6153, 24398, 69974, 896, - 920, -3017, 2511, 2167, 2123, -3017, -3017, -3017, -3017, -3017, - 2011, 20, 2013, 10269, 2012, -3017, -3017, -3017, -3017, -3017, - -3017, 44856, 44856, 64984, 2188, -3017, -3017, 2014, 2019, 37017, - 2474, 2024, -3017, -3017, 2340, -3017, 30028, -3017, 1638, 2023, - 1638, 69974, 1638, -3017, -3017, 44856, 19682, -3017, -3017, 41088, - 2358, -3017, 1225, 1225, 6514, 942, -3017, 1225, 19682, 19682, - 1225, 1225, 19682, -3017, 9743, 540, -3017, 948, -3017, 40147, - -3017, 71426, -3017, -3017, 1917, 936, 1917, -3017, -3017, 2029, - -3017, -3017, -3017, 2094, -3017, -3017, 952, 2461, 1989, 19682, - -3017, -3017, 2038, 35520, -3017, -3017, -3017, -3017, 35520, 248, - -3017, 2212, 1952, 2046, -3017, -3017, -3017, -3017, -3017, -3017, - 40186, -3017, 113, 19682, -3017, 944, 5906, -3017, -3017, -3017, - -3017, 1952, 1238, -3017, 55019, 2525, 2417, -3017, -3017, 44856, - -3017, -3017, 2002, 2002, -3017, -3017, 2238, -3017, -3017, 2051, - -3017, -3017, 1246, 587, 39014, 55019, 55019, -3017, -3017, 2054, - -3017, -3017, -3017, -3017, -3017, 371, 2446, 971, 978, 786, - -3017, 2691, 55019, 2422, 50528, -3017, 47035, 2536, 2058, 55019, - 1813, 358, 358, -3017, 2209, -3017, 2210, -3017, -3017, 2540, - 291, -3017, 1288, 55019, -3017, -3017, 32525, -3017, 6153, 979, - -3017, -3017, 2063, 2066, -3017, 1917, 19682, 2074, 19682, -3017, - 22826, 2553, 2073, -3017, 19682, 2139, 27504, -3017, 19682, -3017, - 55019, 60009, 2085, 60009, -3017, -3017, -3017, -3017, -3017, 19682, - -3017, 1225, 1225, 1225, 19682, -3017, 19682, -3017, -3017, -3017, - 2297, 2188, -3017, 2188, 19682, 2691, 666, 3519, 64984, 35, - -3017, 44856, -3017, -3017, -3017, 55019, -3017, 47035, -3017, 248, - -11, 2095, 19682, 40539, 2328, -3017, -3017, 2365, -3017, 2426, - -3017, 2163, 597, 2174, -3017, -3017, -3017, -3017, 1256, 936, - -3017, 1621, 1999, 2021, 2109, 55019, 984, 2691, 786, 827, - -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, - -3017, -3017, -3017, 2691, 2549, 2335, 2555, -3017, 1937, 19682, - 94, -3017, 990, 2550, -3017, -3017, 2623, 2188, 2116, 22826, - 2117, -3017, 2119, 64984, 44856, 2267, -3017, -3017, 2120, -3017, - -3017, 19682, -3017, 41145, 2127, 2128, 2588, 1780, 2139, 2139, - -3017, -5, -3017, -3017, 2560, 32525, 2507, 1238, 248, 2151, - 1021, -3017, -3017, -3017, -3017, -3017, 3469, -3017, 40626, 2375, - 217, 2371, 2095, 19682, -3017, 2213, -3017, -3017, -3017, 2620, - -3017, -3017, 50528, 2147, -3017, 2021, 1999, 1813, 2021, 2369, - -3017, 2374, 2152, 40665, 64984, 64984, 1621, 32525, 64984, 2149, - 2139, -3017, 2153, -3017, -3017, -3017, 54021, -3017, 2157, -3017, - -3017, -3017, 19682, 735, -3017, -3017, 2201, 55019, 1028, 65, - 2365, 39014, -3017, 47035, 1442, -11, 2464, -3017, -3017, -3017, - -3017, 115, 2381, -3017, 2390, -3017, 44856, -3017, 2691, 50528, - -3017, -3017, -3017, -3017, -3017, -3017, 32525, 2550, -3017, 356, - -3017, 1492, -3017, 356, -3017, -3017, -3017, -3017, -3017, 1428, - 23350, 23350, 23350, 2164, 2691, -3017, 1492, -3017, 2284, 2371, - -3017, -3017, -3017, -3017, -3017, 269, 269, 2557, -3017, 2232, - -3017, 2021, 1035, 64984, 1721, -3017, 1721, 24922, 2320, 293, - 43712, 2548, -3017, 2548, 2548, -3017, -3017, -3017, 38015, -3017, - -3017, 2670, -3017, 260, -3017, -3017, -3017, 1621, 356, -3017, - -3017, 2662, -3017, -3017, -3017, -3017, -3017, 159, -3017, -3017, - -3017, 1492, 248, -3017, -3017, -3017, 1492, 1721, 23874, 2333, - -3017, 2408, -3017, -3017, -3017, -3017, -3017, -3017, -3017 + 7355, -34, 651, -3072, -3072, 286, -34, 51694, 66649, 129, + -34, 186, 2535, 53690, -3072, -3072, 48201, 2849, -34, 56684, + 74045, 397, 475, 33132, 457, 57183, -3072, -3072, -3072, 66649, + 56684, 57682, -34, 327, 67148, -3072, -34, 36128, 54189, 387, + -3072, 56684, 58, 136, 58181, 56684, 5695, 752, 331, -3072, + -3072, -3072, -3072, -3072, 118, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, 150, -3072, 263, 167, 33132, 33132, 1044, 373, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, 450, + -3072, -3072, 740, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, 35628, -3072, -3072, -3072, -3072, -3072, -3072, 58680, 56684, + 59179, 54688, 59678, -3072, 704, 1014, 690, 147, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + 184, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, 532, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, 189, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, 533, -3072, 581, -3072, 194, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, 966, -3072, -3072, 1020, 2993, + 56684, 458, 542, 794, -3072, 60177, -3072, 780, 56684, -3072, + -3072, 785, 911, 970, -3072, -3072, 55187, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, 48700, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, 973, -3072, -3072, 741, -3072, 158, -3072, -3072, + 765, 733, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, 859, -3072, -3072, -3072, 831, 67647, 60676, 61175, -3072, + 734, 2559, 8055, 74063, 32132, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, 450, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, 57183, 66649, + 742, 756, 1097, 802, 34130, 809, 36628, 813, 851, 1139, + 866, 914, 935, 962, 136, 32632, 758, 533, 841, 61674, + 61674, -36, 33631, 192, -3072, 61674, 62173, -3072, 981, -3072, + 1014, -3072, -3072, -3072, -3072, -98, 975, -3072, 62672, 62672, + 62672, 1002, 1264, 62672, -3072, -3072, -3072, 995, -3072, -3072, + 1257, 20701, 20701, 68146, 68146, 1014, 68146, 1054, 68146, -3072, + -3072, 72, 690, -3072, 533, -3072, -3072, 1044, -3072, -3072, + 54189, -3072, -3072, 285, 1394, 20701, 56684, 1060, -3072, 1074, + 1060, 1076, 1099, 1107, -3072, 7355, 1444, 1326, 55686, 337, + 337, 1589, 337, 906, 953, 2653, 4581, -3072, 1578, -3072, + 1126, -3072, 56684, 57183, 1231, 1152, 1431, -3072, -3072, 1517, + 1385, 1318, 1524, 7326, 1526, 1617, 1532, 1736, 1565, 1684, + 24, -3072, 20701, 49199, 533, -3072, 11776, 20701, -3072, -3072, + -3072, 1300, -3072, -3072, -3072, -3072, -3072, 56684, 66649, 1209, + 1215, -3072, -3072, -3072, -3072, 2080, 1462, -3072, 1699, 68645, + -3072, -3072, 1271, 63171, 63670, 64169, 64668, 1664, -3072, -3072, + 1603, -3072, -3072, -3072, 1273, -3072, -3072, -3072, 185, 69144, + 1608, 1250, 117, -3072, 1620, 140, -3072, 1625, 1489, 15451, + -3072, 1434, -3072, -3072, -3072, 136, -3072, 511, -3072, -3072, + 45302, -3072, -3072, 74063, 1359, 1276, -3072, 20701, 20701, 1280, + 8290, 61674, 62173, 20701, 56684, -3072, 20701, 25426, 1281, 20701, + 20701, 12826, 20701, 31134, 61674, 192, 1272, -3072, 728, -3072, + 56684, 1282, -3072, 1371, 1371, 327, 33132, 1577, 32632, 1371, + 1371, 1371, -3072, 1213, 1576, 1504, -3072, 33132, 1504, 1388, + 1288, 1582, 1504, -3072, 265, 1586, 1371, 37127, 1291, -3072, + 1371, 1518, -3072, -3072, 20701, 15451, 71639, 1774, -3072, -3072, + -3072, -3072, 1581, -3072, 66649, 1303, -3072, -3072, -3072, -3072, + -3072, -3072, 678, 1813, 169, 1814, 20701, 169, 169, 1304, + 203, 203, -3072, 1507, 1307, -3072, 204, 1311, 1315, 1829, + 1830, 182, 152, 709, 169, 20701, -3072, 203, 1319, 1831, + 1338, 1839, 209, 212, -3072, 206, 20701, 20701, 20701, 689, + 20701, 10726, -3072, 49199, 1849, 56684, 403, -3072, 533, 1345, + 1014, -3072, -3072, -3072, -3072, -3072, -3072, -3072, 1351, -3072, + 187, 6462, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + 1389, -3072, -3072, -3072, -3072, 1569, 20701, -3072, -3072, 1350, + 1577, -3072, 213, -3072, -3072, 1577, -3072, -3072, -3072, -3072, + -3072, 234, -3072, 1775, 20701, 20701, -3072, 533, 69643, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, 667, -3072, 450, 592, + 47020, 1356, 1362, 1060, 56684, 56684, 1840, -3072, -3072, -3072, + -3072, 54189, 170, 1663, 171, 1496, -3072, -3072, 1044, 1044, + 15976, 1104, 225, 103, 16501, 21226, 1721, 1602, 229, 660, + 1724, -3072, 1610, 1837, 25426, 20701, 20701, 906, 953, 20701, + 1074, 94, -3072, -3072, -3072, 1669, 56684, 52193, 325, 738, + 1390, 1475, 1391, 207, 1819, -3072, 1392, -3072, 1476, 56684, + 73590, 226, -3072, 1856, 226, 226, 238, 1860, 1490, 259, + 1654, 62, -72, 1392, 1857, -3072, 54189, 143, 97, 1392, + 56684, 1493, 654, 1392, 1818, 66649, 1276, -3072, -3072, 43144, + 1404, -3072, -3072, -3072, 165, 15451, -3072, 1274, 1279, 1340, + 368, 145, 1361, 1380, 15451, 1400, 1522, 188, 1585, 1588, + 1601, 1615, 1653, 1660, 1674, 1679, 149, 1685, 1690, 1692, + 1695, 1700, 1702, -3072, 1709, 193, 1713, 202, 15451, 1718, + -3072, 47020, 25, -3072, -3072, 1722, 199, -3072, 47120, -3072, + 1706, 1498, 1506, 66649, 1458, 56684, 1570, 987, 1797, 1851, + 72123, 1677, -3072, 1754, 56684, 1682, 1857, 1686, 1441, 1922, + 1689, 1215, 1693, 1451, -3072, 70142, 49199, -3072, -3072, -3072, + -3072, -3072, 1820, 1799, 66649, 49199, 1455, -3072, -3072, 66649, + -3072, 56684, 56684, -3072, 56684, 66649, -3072, 712, 47020, 1965, + 1102, 74063, 50696, -3072, -3072, -3072, -3072, 916, 1067, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, 1014, 49199, + -3072, 3606, 45923, 1460, 20701, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, 1461, 1809, -3072, -3072, + 5765, 1463, 46218, 1464, 25426, 25426, 533, 2790, -3072, -3072, + 25426, 1465, 51195, 45837, 1466, 1467, 46403, 17026, 20701, 17026, + 17026, 46469, -3072, 1471, 46558, 61674, 1473, 56684, 30630, -3072, + -3072, -3072, 20701, 20701, 192, 56185, 1508, 1474, -3072, -3072, + -3072, 33132, -3072, 33132, -3072, 1767, 33132, -3072, -3072, 2036, + -3072, 33132, 1770, 20701, 33132, -3072, 33132, 1716, 1719, 1484, + 33132, -3072, 56684, 1487, 56684, -3072, -3072, 47020, -3072, 1485, + 746, 1491, -3072, -3072, -3072, -3072, -3072, 1542, -3072, 1542, + 1542, -3072, -3072, -3072, -3072, 1492, 1492, 1495, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, 1503, 709, -3072, 1542, -3072, 1492, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, 73590, -3072, -3072, -3072, -3072, 565, + 677, -3072, 1509, -3072, -3072, 1510, -3072, 1502, 1985, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, 6072, 751, + 1492, -3072, -3072, 6514, -3072, -3072, 20701, 20701, -3072, -3072, + 1513, 47020, 1550, -3072, -3072, 20701, 20701, -3072, -3072, -3072, + -3072, 2023, -3072, 20701, 1542, 1542, -3072, 43180, -3072, 42119, + 17551, 1609, 1611, 2023, -3072, 2023, -3072, 43180, 2026, 2026, + 1521, 37626, -3072, 1687, 46767, -3072, 1529, 1918, 6712, 1528, + -3072, -3072, 1520, -3072, 1530, 1533, 43805, 20701, 183, 533, + 533, 20701, -3072, 2023, 20701, 8317, 8317, -3072, 241, 71639, + 20701, 20701, 20701, 20701, 20701, 20701, 20701, 20701, 47702, 1619, + 179, 66649, 20701, 20701, 30120, 1082, -3072, 20701, 1778, -3072, + 1538, 20701, 1629, 302, 20701, 20701, 20701, 20701, 20701, 20701, + 20701, 20701, 20701, -3072, -3072, 29101, 251, 646, 1882, 1903, + -2, 358, 20701, 1895, 11776, -3072, 1895, -3072, -3072, -3072, + -3072, -3072, 214, -3072, -3072, 1485, 1485, 66649, -3072, 56684, + 285, 53191, 20701, -3072, -3072, 1546, 1552, 155, 1622, -3072, + -3072, 56684, -3072, 40620, 1854, -3072, 345, 1554, -3072, 45798, + 1808, 1854, 1044, -3072, -3072, 26476, 1694, 1855, 1793, -3072, + -3072, 1777, 1779, -3072, 1572, 47209, 21751, 21751, -3072, 1262, + 47020, 1375, -3072, -3072, -3072, -3072, -3072, -3072, 574, -3072, + 56684, 459, 38125, -3072, 1574, 164, -3072, 2878, 1906, 1879, + 1721, 660, 1587, -3072, 57183, 57183, -3072, -3072, 1776, 1591, + 70641, 56684, 1876, 1832, 1877, 300, 71639, -3072, -3072, -3072, + -3072, 56684, 66649, 65167, 71140, 49698, 56684, 49199, -3072, -3072, + -3072, -3072, 56684, 456, 56684, 7343, -3072, -3072, -3072, -3072, + 226, -3072, -3072, -3072, -3072, -3072, 66649, 56684, -3072, -3072, + 226, 66649, 56684, 226, -3072, 1850, 56684, 56684, 56684, 56684, + 1878, 56684, 56684, 1014, -3072, -3072, -3072, 22276, 32, 32, + 1816, 13351, 163, -3072, 20701, 20701, 792, 271, 66649, 1771, + -3072, -3072, 760, 1822, 127, -3072, 66649, 1643, 56684, 56684, + 56684, 56684, 56684, 1439, -3072, -3072, -3072, -3072, -3072, 1596, + -3072, 1963, 2113, 1599, 1614, 1967, -3072, 1857, 1968, 52692, + 735, 2657, 1969, 1648, 1983, 13876, -3072, -3072, 1618, -3072, + -3072, 1621, 2099, 1866, -3072, -3072, 1852, -3072, 66649, 2142, + -3072, 117, -3072, 49199, -3072, 140, -3072, 1858, 243, -3072, + 15451, 20701, -3072, -3072, -3072, -3072, -3072, -3072, 1276, 29611, + -3072, 762, -3072, -3072, 2106, 1014, 2106, 761, -3072, -3072, + 2106, -3072, 2094, 2106, -3072, 71639, -3072, 7266, -3072, 20701, + 20701, -3072, 20701, 1982, -3072, 2144, 2144, 71639, 25426, 25426, + 25426, 25426, 25426, 25426, 252, 1319, 25426, 25426, 25426, 25426, + 25426, 25426, 25426, 25426, 25426, 27001, 432, -3072, -3072, 764, + 2118, 20701, 20701, 1992, 1982, 20701, -3072, 71639, 1641, -3072, + 1642, 1644, 20701, -3072, 71639, -3072, 56684, 1645, -3072, -3072, + -3072, 115, 1649, 1652, -3072, -3072, 1577, -3072, 875, 984, + 56684, 2254, 3554, 4652, -3072, -3072, 20701, 1990, -3072, 2036, + 2036, 33132, -3072, 20701, 1655, -3072, -3072, 33132, 1999, -3072, + 2036, -3072, -3072, 38624, 2036, 71639, 775, -3072, 56684, 71639, + 793, 20701, -3072, 15451, 2173, 71639, 2138, 66649, 66649, 2176, + 1666, 1667, 2023, 1749, -3072, 1753, 1755, 1756, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, 71639, -3072, + -3072, 124, -3072, -3072, -3072, -3072, -3072, -3072, 1670, 1668, + 20701, 20701, 93, -3072, 7606, 1671, 1672, 5691, -3072, 1675, + -3072, 1665, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, -3072, 1678, + -3072, 1673, -3072, 1680, 1701, 1703, 1681, 1691, 20701, 56684, + -3072, 1704, 22801, 1835, 66649, -3072, -3072, 20701, 20701, 56684, + -3072, 2046, 47020, -3072, 1696, 1708, 7829, -3072, -3072, -3072, + 231, 903, 8732, 358, 4270, 4270, 4270, 43180, -3072, -3072, + -3072, 1705, -3072, 25426, 25426, -3072, 3699, 3070, 10726, -3072, + -3072, -3072, -3072, 2047, -3072, 1125, -3072, 1710, -3072, -3072, + 3493, -3072, 42119, 9450, 20701, 200, -3072, 20701, 30120, 20701, + 1789, 4270, 4270, 4270, 280, 280, 231, 231, 231, 903, + 358, -3072, -3072, -3072, 1711, 20701, 49199, -3072, 1714, 1720, + 2066, 1338, 20701, -3072, -3072, 33132, 1508, 25, 1508, 2023, + 8317, -3072, 1074, -3072, 1074, -3072, 47020, 56684, -3072, -3072, + 1972, 1725, 33132, 1757, 2200, 2187, 66649, -3072, -3072, 1726, + 1895, 1740, -3072, -3072, 1746, 20701, 1098, 1746, -3072, 1854, + 31, 1960, 1137, 1137, 1262, 1961, -3072, -3072, 1802, -3072, + -3072, -3072, 20701, 14401, 1379, -3072, 1381, -3072, -3072, -3072, + -3072, -3072, 1731, -3072, 2015, -3072, 56684, -3072, -3072, 25426, + 2203, 20701, 39123, 2204, 2000, -3072, -3072, -3072, 1800, 1800, + -3072, -3072, 1841, 1392, 20701, 1993, -3072, 154, 1760, 2121, + 357, 2071, 66649, -3072, 343, 350, -3072, 468, 2127, 243, + 2132, 243, 49199, 49199, 49199, 800, -3072, -3072, -3072, 1014, + -3072, 279, 806, -3072, -3072, -3072, -3072, 1862, 656, 1392, + 1857, -3072, -3072, -3072, -3072, -3072, -3072, -3072, 177, 692, + 1392, 1865, -3072, 1867, -3072, 1868, 781, 1392, -3072, -3072, + 1684, 18076, 47020, 333, 163, 163, 163, 15451, -3072, 2003, + 2004, 1768, 47020, 47020, 156, -3072, -3072, -3072, -3072, 1783, + -3072, 367, -3072, 66649, -3072, -3072, -3072, 1771, 1851, 1754, + 56684, 1857, 1785, 2249, 1215, 1451, -3072, 1942, 808, 1584, + -3072, 66649, -3072, 49199, 66649, 56684, 56684, 56684, 65666, -3072, + -3072, -3072, 1788, 1786, -3072, 22, 2024, 2021, 56684, 1833, + 56684, 1391, 2276, 56684, -3072, 814, 1451, 1451, 18601, 2166, + 56684, 1799, -3072, -3072, -3072, -3072, 66649, -3072, -3072, 47020, + -3072, 1796, -3072, 20701, 50197, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, 49199, -3072, 1014, -3072, 1014, 2044, 66649, 44304, + 1014, 44803, 1014, 1806, -3072, 47020, 8173, 47020, 1992, -3072, + 244, 2144, 796, 796, 796, 3353, 2155, 247, 1811, 796, + 796, 796, 377, 377, 244, 244, 244, 2144, 432, 981, + 51195, 1815, -3072, 47020, 47020, -3072, -3072, 1812, -3072, -3072, + -3072, -3072, 1817, 1824, -3072, -3072, -3072, -3072, 66649, 173, + 1508, 387, 387, 387, 387, -3072, 56684, 56684, 56684, 47020, + 2273, 2148, -3072, -3072, 2036, 47020, 56684, -3072, 28051, -3072, + 56684, -3072, 2170, -3072, 2266, -3072, 56684, 826, -3072, -3072, + -3072, 830, 1844, 1667, 71639, 844, 846, -3072, 2023, 211, + 1828, 817, 274, 797, 1397, -3072, 54189, -3072, -3072, 1838, + 46824, 20701, -3072, 2206, -3072, -3072, -3072, 20701, 20701, -3072, + 42119, -3072, -3072, -3072, -3072, 344, 344, 8692, 1704, 1842, + 1843, 56684, 10726, 46911, -3072, 39622, -3072, -3072, 2164, 1845, + -3072, 8884, 47020, -3072, 1687, -3072, -3072, 8317, 20701, 3648, + 3670, 20701, 1847, 20701, 2197, -3072, -3072, 1859, -3072, -3072, + 71639, 20701, 1853, 5327, 25426, 25426, 6012, -3072, 6179, 20701, + 10726, -3072, 43231, 1861, 1864, 1816, 19126, -3072, 2069, 1869, + -3072, 1990, 163, 1990, 1870, -3072, -3072, -3072, -3072, 6514, + -3072, 20701, 2012, 66649, 530, 1966, 869, -3072, 533, 40620, + 1757, 20701, 267, -3072, -3072, 1874, -3072, 1746, -3072, -3072, + -3072, 2085, -3072, -3072, -3072, 56684, -3072, 1880, -3072, 38125, + 2202, 11251, -3072, 38125, 56684, -3072, -3072, 56684, 9298, 2228, + -3072, 66649, 66649, 66649, -3072, 66649, 1871, 1883, 657, 1885, + 744, -3072, 2294, 657, 2210, 245, 1391, 259, 2665, 53, + -3072, -3072, -3072, 1946, 56684, -3072, 66649, -3072, -3072, -3072, + -3072, -3072, 49698, -3072, -3072, 41619, 49199, -3072, 49199, 56684, + 56684, 56684, 56684, 56684, 56684, 56684, 56684, 56684, 56684, 1276, + 20701, -3072, 20701, 1887, 1888, 1889, 1816, -3072, -3072, -3072, + 240, -3072, 1890, -3072, -3072, -3072, -72, -3072, 367, 1891, + 1896, -3072, 52692, 2993, 1648, -3072, 1621, 1851, 120, 66150, + -3072, 1898, 1900, 1754, 873, 880, 1857, 1905, 2358, -3072, + 735, 52692, -3072, -3072, -3072, 2338, -3072, 734, 233, -3072, + 1215, -3072, 2993, 1451, -3072, -3072, 2387, -3072, 2388, 2993, + 47020, 66649, 1973, -3072, 243, 881, -3072, -3072, -3072, -3072, + -3072, 66649, 1909, -3072, 1909, -3072, -3072, 1909, -3072, -3072, + -3072, -3072, 25426, 2260, 1915, 71639, -3072, -3072, 56684, -3072, + -3072, -3072, 882, 1917, 1990, 56684, 56684, 56684, 56684, -3072, + -3072, -3072, 19651, 20701, 1970, -3072, 1920, 12301, 2245, -3072, + 27526, -3072, -3072, 1926, 38624, 66649, -3072, -3072, -3072, -3072, + 2023, -3072, -3072, 66649, -3072, 1933, -3072, 1934, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, 20701, 47020, -3072, + 47020, -3072, -3072, -3072, -3072, -3072, 56684, -3072, -3072, 6584, + -3072, 1930, 1935, 66649, 56684, 121, -3072, 20701, 66649, -3072, + 1835, -3072, 405, 20701, 20701, 3699, -3072, 45855, 20701, 71639, + 896, 3699, 262, 20701, 3927, 4601, 20701, 20701, 6599, 9393, + -3072, 23326, 14926, -3072, 1936, 20701, 9432, 41119, -3072, 33132, + 2148, 1937, 2148, 1014, 1938, 47020, 20701, -3072, -3072, -3072, + -3072, 1995, -23, 35128, 2169, -3072, 1955, 66649, -3072, 2012, + 47020, -3072, -3072, 42119, -3072, -3072, -3072, -3072, -3072, 2410, + 2301, 1954, 1957, -3072, 1301, -3072, -3072, 66649, 1958, -3072, + 1964, 657, -3072, 66649, 2002, -3072, 255, 2274, 153, -3072, + 20701, -3072, 2363, 2445, 2294, 1971, 66649, 56684, 25426, -3072, + 277, 224, -3072, 2259, 56684, 2002, 2402, -3072, -3072, -3072, + 744, -3072, 2299, 2214, -3072, 226, -3072, 20701, 744, 2215, + 239, 66649, -3072, -3072, 2582, -3072, 71639, 243, 243, -3072, + 1491, 1976, 1980, 1984, 1987, 1989, 2005, 2007, 2008, 2009, + 2010, -3072, 2013, 2014, 2016, 2017, 2018, 2027, 2028, 2032, + 1503, 2033, -3072, 2038, 1874, 2039, 2040, 2041, 2042, 2045, + 72607, 2050, 2051, 2055, 2056, 1509, 2058, 916, 1067, -3072, + -3072, -3072, -3072, -3072, -3072, 1250, 2060, -3072, 2025, -3072, + -3072, -3072, 2079, -3072, 2084, -3072, -3072, -3072, -3072, -3072, + -3072, 2006, 2049, -3072, -3072, -3072, 163, 2062, 2063, 66649, + 1276, 125, 49199, 66649, 2064, 1833, 2484, 834, 2268, 2067, + -3072, 1014, 2074, -3072, 1648, -3072, 52692, 2875, 618, 2021, + -3072, 196, 1833, -3072, 2477, 1648, 2109, -3072, 1621, 2174, + 20701, 160, -3072, 2305, 66649, 2078, -3072, -3072, 50197, 1909, + 4715, 25426, 71639, 915, 930, -3072, 2589, 2246, 2148, -3072, + -3072, -3072, -3072, -3072, 2081, -38, 2083, 10201, 2086, -3072, + -3072, -3072, -3072, -3072, -3072, 47020, 47020, 66649, 2267, -3072, + -3072, 2090, 2087, 40121, 2546, 2088, -3072, -3072, 2419, -3072, + 31633, -3072, 1667, 2103, 1667, 71639, 1667, -3072, -3072, 47020, + 1704, 20701, -3072, -3072, -3072, 2105, 2102, 66649, 43270, 2436, + -3072, -3072, 3699, 3699, 45855, 932, -3072, 3699, 20701, 20701, + 3699, 3699, 20701, -3072, 20176, 446, -3072, 946, -3072, 42626, + -3072, 73091, -3072, -3072, 1970, 1014, 1970, -3072, -3072, 2108, + -3072, -3072, -3072, 2171, -3072, -3072, 951, 2543, 2012, 20701, + -3072, -3072, 2119, 38125, -3072, -3072, -3072, -3072, 38125, 657, + -3072, 2292, 2002, 2128, -3072, -3072, -3072, -3072, -3072, -3072, + 42665, -3072, 65, 20701, -3072, 925, 3353, -3072, -3072, -3072, + -3072, 2002, 1215, -3072, 56684, 2605, 2496, -3072, -3072, 47020, + -3072, -3072, 2023, 2023, -3072, -3072, 2266, -3072, -3072, -3072, + 2129, -3072, -3072, 1250, 310, 41619, 56684, 56684, -3072, -3072, + 2133, -3072, -3072, -3072, -3072, -3072, -72, 2529, 959, 976, + 735, -3072, 2993, 56684, 2502, 52692, -3072, 49199, 2615, 2137, + 56684, 1833, 1086, 1086, -3072, 2288, -3072, 2289, -3072, -3072, + 2619, 261, -3072, 1307, 56684, -3072, -3072, 34629, -3072, 4715, + 986, -3072, -3072, 2143, 2145, -3072, 1970, 20701, 2146, 20701, + -3072, 23851, 2621, 2152, -3072, 20701, 2209, 28576, -3072, 20701, + -3072, 56684, 61674, 2149, 61674, -3072, -3072, -3072, -3072, 56684, + -3072, -3072, -3072, 20701, -3072, 3699, 3699, 3699, 20701, -3072, + 20701, -3072, -3072, -3072, 2360, 2267, -3072, 2267, 20701, 2993, + 533, 3911, 66649, 26, -3072, 47020, -3072, -3072, -3072, 56684, + -3072, 49199, -3072, 657, -6, 2157, 20701, 42704, 2396, -3072, + -3072, 2428, -3072, 2487, -3072, 2222, 538, 2247, -3072, -3072, + -3072, -3072, 1276, 1014, -3072, 1648, 2021, 2109, 2175, 56684, + 991, 2993, 735, 734, -3072, -3072, -3072, -3072, -3072, -3072, + -3072, -3072, -3072, -3072, -3072, -3072, -3072, 2993, 2613, 2398, + 2618, -3072, 1973, 20701, 217, -3072, 1011, 2614, -3072, -3072, + 2687, 2267, 2179, 23851, 2180, -3072, 2182, 66649, 47020, 2331, + -3072, -3072, 2184, -3072, -3072, 20701, -3072, -3072, 43309, 2189, + 2191, 2645, 1816, 2209, 2209, -3072, -23, -3072, -3072, 2617, + 34629, 2579, 1215, 657, 2216, 1023, -3072, -3072, -3072, -3072, + -3072, 1857, -3072, 42752, 2453, 151, 2437, 2157, 20701, -3072, + 2286, -3072, -3072, -3072, 2689, -3072, -3072, 52692, 2212, -3072, + 2109, 2021, 1833, 2109, 2439, -3072, 2443, 2221, 42791, 66649, + 66649, 1648, 34629, 66649, 2224, 2209, -3072, 2225, -3072, -3072, + -3072, 30630, -3072, 2227, -3072, -3072, -3072, 20701, 439, -3072, + -3072, 2279, 56684, 1024, 56, 2428, 41619, -3072, 49199, 1500, + -6, 2545, -3072, -3072, -3072, -3072, 168, 2462, -3072, 2463, + -3072, 47020, -3072, 2993, 52692, -3072, -3072, -3072, -3072, -3072, + -3072, 34629, 2614, -3072, 345, -3072, 1508, -3072, 345, -3072, + -3072, -3072, -3072, -3072, 1466, 24376, 24376, 24376, 2236, 2993, + -3072, 1508, -3072, 2367, 2437, -3072, -3072, -3072, -3072, -3072, + 195, 195, 2637, -3072, 2306, -3072, 2109, 1029, 66649, 1746, + -3072, 1746, 25951, 2393, 198, 45876, 2616, -3072, 2616, 2616, + -3072, -3072, -3072, 40620, -3072, -3072, 2738, -3072, 235, -3072, + -3072, -3072, 1648, 345, -3072, -3072, 2730, -3072, -3072, -3072, + -3072, -3072, 178, -3072, -3072, -3072, 1508, 657, -3072, -3072, + -3072, 1508, 1746, 24901, 2399, -3072, 2480, -3072, -3072, -3072, + -3072, -3072, -3072, -3072 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -3017, -3017, -3017, 1837, 82, -3017, -3017, 68, -3017, 930, - -3017, 61, -789, 452, -3017, 86, 2920, 2581, 3525, 1263, - -518, -887, -1258, 28, 88, -1146, 10, -3017, -3017, -3017, - -3017, -1498, -583, 126, -3017, -3017, -720, -2539, -673, -3017, - -2953, -2678, -3017, -3017, -808, -3016, -2069, 90, -3017, -3017, - 95, 2, -2117, -3017, -1676, 64, -2104, 96, 97, 846, - -3017, -2620, 100, -895, -1200, -912, -1207, -3017, -205, -3017, - 357, 101, 1251, 1885, -3017, 4, -2197, -2867, -679, -3017, - -779, -3017, -437, -3017, -726, -3017, -947, -734, -768, -2858, - -1145, -3017, 1532, -489, -3017, 490, -3017, -2589, -3017, -3017, - 478, -3017, -1163, -3017, -2234, 36, -713, -2411, -2567, -2178, - -898, 120, -721, 98, -2131, -1255, -3017, 502, -3017, -705, - -3017, -891, -2495, 102, -3017, -3017, 1421, -930, -3017, 109, - -3017, 390, -3017, -2149, 388, -2106, 1455, -630, 19, 21, - -3017, -3017, -3017, -3017, -3017, -748, 430, -1216, -3017, 366, - -3017, -3017, -3017, -3017, -290, 79, -2268, 11, 3003, -31, - -37, -3017, -32, -3017, -3017, -3017, 537, -3017, -3017, 18, - 42, 1605, -3017, -1027, -3017, -1634, 690, -3017, 1762, 1768, - -2165, -879, -49, -3017, 577, -1671, -2144, -640, 1027, 1595, - 1590, 327, -2965, -3017, -663, -3017, 46, -3017, -3017, 568, - 1071, -1562, -1558, -3017, -2201, -3017, -582, -472, -3017, -3017, - -3017, -3017, -3017, -2529, -2138, -635, 1040, -3017, 1597, -3017, - -3017, -3017, -3017, 60, -1503, 2768, 606, -48, -3017, -3017, - -3017, -3017, 14, -3017, 794, -302, -3017, 2004, -669, -801, - 1805, -611, 237, -1705, -18, 2017, 368, -3017, -3017, 367, - -2062, -1421, 322, -391, 798, -3017, -3017, -1253, -3017, -1865, - -1191, -3017, -3017, -732, 1014, -3017, -3017, -3017, 1151, 1778, - -3017, -3017, 2774, 2790, -3017, -900, 3151, 1176, -1037, 1844, - -931, 1856, -933, -935, -938, 1857, 1858, 1860, 1861, 1863, - 1867, 1876, -1539, 4950, 1052, 945, -2215, -3017, -1583, 915, - 916, 917, 48, -3017, -1399, 76, -3017, -3017, -3017, -3017, - -3017, -2758, -3017, -563, -3017, -555, -3017, -3017, -3017, -1759, - -2749, -1789, -3017, 4393, 725, -3017, -3017, 306, -3017, -3017, - -3017, -3017, -1535, -3017, 5761, 621, -3017, -2017, -3017, -3017, - -981, -850, -731, -998, -1217, -1938, -3017, -3017, -3017, -3017, - -3017, -3017, -1513, -1780, -208, 682, -3017, -3017, 778, -3017, - -3017, -3017, 6, -1434, -1755, -2116, -3017, -3017, -3017, 698, - 1373, -19, -839, -1621, -3017, 755, -2371, -3017, -3017, 318, - -3017, -599, -1122, -2457, 59, 16, -3017, 689, -2551, -3017, - -3017, -740, -2691, -1138, -892, -3017, 116, -3017, 274, 127, - -1651, -3017, 5, -3017, -501, -3017, -3017, -2588, -3017, 128, - 129, 2069, -3017, 1034, -3017, -3017, -3017, -3017, -581, -3017, - -620, -614, -3017, -3017, 32, -902, 1511, -3017, 131, 434, - -3017, 852, -3017, 601, 132, -3017, 1969, -492, 134, 1178, - -3017, -3017, -3017, 29, -602, 278, -3017, 1180, -3017, -3017, - 1646, 564, 138, -3017, 420, 22, -3017, -3017, -3017, 84, - 2777, 139, 12, -2389, 142, -2800, -1683, -7, -3017, -3017, - -3017, -729, -3017, -2526 + -3072, -3072, -3072, 1904, 75, -3072, -3072, 128, -3072, 988, + -3072, 108, -797, 506, -3072, 84, 4198, 2606, 4642, 1435, + -520, -888, -1248, 8, 85, -1157, 3, -3072, -3072, -3072, + -3072, -1496, -544, 180, -3072, -3072, -681, -2591, -634, -3072, + -2874, -3071, -3072, -3072, -779, -3059, -2095, 89, -3072, -3072, + 95, 2, -2128, -3072, -1677, 70, -2123, 99, 102, 895, + -3072, -2622, 107, -895, -1195, -951, -1199, -3072, -164, -3072, + 406, 109, 1203, 1947, -3072, 4, -2198, -2926, -645, -3072, + -748, -3072, -401, -3072, -693, -3072, -837, -697, -730, -2854, + -1174, -3072, 1598, -447, -3072, 549, -3072, -2613, -3072, -3072, + 539, -3072, -1171, -3072, -2260, 96, -675, -2651, -2611, -2214, + -910, 174, -683, 157, -2167, -1115, -3072, 561, -3072, -664, + -3072, -905, -2054, 112, -3072, -3072, 1488, -923, -3072, 113, + -3072, 451, -3072, -2170, 449, -2133, 1525, -620, 10, 11, + -3072, -3072, -3072, -3072, -3072, -738, 492, -1228, -3072, 436, + -3072, -3072, -3072, -3072, -234, 161, -2281, 27, 2441, -40, + -33, -3072, -21, -3072, -3072, -3072, 596, -3072, -3072, 17, + 55, 1676, -3072, -1047, -3072, -1689, 684, -3072, 1846, 1848, + -2192, -873, -59, -3072, 642, -1667, -2163, -626, 1105, 1698, + 1661, -3072, 401, -2490, -3072, -606, -3072, 410, -3072, -3072, + 639, 1151, -1572, -1567, -3072, -2255, -3072, -526, -409, -3072, + -3072, -3072, -3072, -3072, -2484, -2486, -610, 1123, -3072, 1712, + -3072, -3072, -3072, -3072, 28, -1537, 2861, 683, -3072, 68, + -3072, -3072, -3072, -3072, 90, -3072, 878, -228, -3072, -456, + -665, -796, 1908, 220, 223, -1824, -17, -304, 452, -3072, + -3072, 454, -2129, -1427, 408, -321, 883, -3072, -60, -1259, + -3072, -1901, -1190, -3072, -3072, -770, 2093, -3072, -3072, -3072, + 2199, 2330, -3072, -3072, 2558, 2796, -3072, -920, 2991, -678, + -1019, 1919, -917, 1923, -937, -925, -941, 1924, 1927, 1928, + 1929, 1931, 1939, 1943, -1555, 5403, -816, 3645, -2183, -3072, + -1424, -1594, 1001, 1015, 1016, 48, -3072, -1410, 210, -3072, + -3072, -3072, -3072, -3072, -2725, -3072, -487, -3072, -478, -3072, + -3072, -3072, -1755, -2650, -1785, -3072, -100, 825, -3072, -3072, + 407, -3072, -3072, -3072, -3072, -1523, -3072, 6710, 720, -3072, + -2038, -3072, -3072, -974, -822, -1162, -1012, -1235, -1937, -3072, + -3072, -3072, -3072, -3072, -3072, -1527, -1790, -387, 779, -3072, + -3072, 877, -3072, -3072, -3072, 100, -1499, -1761, -2149, -3072, + -3072, -3072, 787, 1482, 63, -828, -1646, -3072, -1561, -3072, + -3072, 840, -2412, -3072, -3072, 398, -2660, -3072, -3072, 105, + -3072, -628, -1144, -2493, 523, 16, -3072, 1144, -2589, -3072, + -3072, -724, -2703, -1140, -897, -3072, 116, -3072, 354, 122, + -1692, -3072, 5, -3072, -436, -3072, -3072, -2631, -3072, 131, + 135, 2172, -3072, 1127, -3072, -3072, -3072, -3072, -557, -3072, + -635, -633, -3072, -3072, 21, -901, 1600, -3072, 137, 376, + -3072, 942, -3072, 631, 138, -3072, 2072, -471, 139, 1267, + -3072, -3072, -3072, 12, -596, 359, -3072, 1270, -3072, -3072, + 1733, 658, 141, -3072, 433, 18, -3072, -3072, -3072, 92, + 142, 7, -3038, 146, -2835, -1681, -7, -3072, -3072, -3072, + -719, -3072, -2579 }; /* 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 -2081 +#define YYTABLE_NINF -2101 static const yytype_int16 yytable[] = { - 525, 1133, 57, 913, 65, 82, 962, 1237, 1200, 719, - 53, 70, 103, 1030, 1165, 871, 525, 1437, 77, 68, - 857, 69, 99, 523, 883, 981, 1256, 884, 885, 94, - 1803, 1307, 1786, 1814, 1346, 1802, 1949, 2201, 77, 523, - 887, 1489, 784, 1310, 718, 888, 1695, 1767, 853, 2168, - 1595, 1411, 778, 2076, 1410, 522, 1409, 2599, 1407, 2124, - 1849, 2307, 2006, 2634, 2037, 1752, 1773, 1363, 525, 525, - 1777, 816, 559, 2487, 1819, 2589, 1352, 1369, 750, 2705, - 1881, 745, 50, 810, 2101, 2102, 51, 869, 52, 825, - 55, 523, 523, 904, 1807, 56, 59, 60, 3038, 818, - 61, 63, 66, 868, 868, 2991, 1671, 3022, 2572, 67, - 2574, 1674, 896, 1236, 1608, 1242, 80, 1246, 850, 2553, - 1256, 2588, 3035, 816, 816, 2627, 3020, 81, 83, 84, - 2993, 90, 91, 972, 93, 810, 810, 1376, 98, 102, - 975, 1012, 104, 2674, 2675, 2676, 1033, 2489, 964, 2688, - -454, 818, 818, 2884, 2819, 2337, -527, 2889, -371, 2333, - 1054, 1572, 1573, 1054, 2221, -1350, -531, -1928, 900, -1928, - 2224, 2172, 2439, 1210, 3434, -2068, -2068, 3233, 1585, 1211, - -864, -869, 1340, 2332, 820, -869, -1291, -1272, 1054, 1421, - 2696, 537, -1919, -872, -1288, -1288, -1936, 982, -1292, -1291, - -2059, -2059, -2054, -2054, -2077, -2077, -1289, -1289, 2126, -1919, - 1210, -1936, -2079, -2079, -1292, -831, 1211, 2706, 2692, -844, - -859, 3220, 2116, 820, 820, 23, 1146, -872, 1769, 2690, - 3168, 1758, 1679, 2697, 2683, 2116, 820, 3515, 3237, 1805, - 861, 1627, 1189, 1926, 1604, -480, 1629, 1192, 1928, 1461, - 981, 2507, 1675, 1356, 820, 953, -527, 1153, 1054, 2782, - 1817, 1340, -229, 3569, 1256, -1124, -531, -229, 820, 1818, - 2155, 2743, 2745, -1124, 2748, 1778, 1637, 1356, 2156, 1701, - 2468, 2469, 1054, 1340, 1212, 1331, 2329, 2234, 1627, 1007, - 875, 2475, 1628, 1629, 1926, 2479, 875, -1145, 1927, 1928, - 3203, 2713, 3179, 1769, 3311, -1145, -664, 1753, 538, 820, - 1639, 1698, 1787, 1627, 2662, 1790, 1791, 1628, 1629, 1154, - 880, 1212, 1033, 1637, 1332, 3394, 1761, 3134, 1966, 3136, - 2449, 1250, 3540, 1577, 1012, 3039, 3151, 3324, 1151, 2451, - 3570, 3507, 2012, 878, 2462, 2463, 2464, 878, 1637, 1587, - 3, 4, 1751, 2313, 1013, 3354, 2165, 1639, -609, 1747, - 1748, 1966, 1370, -609, 2927, 3355, 1676, 2901, 26, 27, - 28, 2856, 2630, 2858, 2103, 838, 3291, 3564, 3293, 3458, - 1712, 876, 1639, 113, -801, 1019, 1778, 876, 3341, 3013, - 3468, 3165, 2898, 1599, 2765, 2452, 2227, 2196, 3402, 880, - -2053, -2053, 1627, 1801, 2564, 3177, 1464, 105, 2857, 2412, - 3438, 3257, 1471, 3141, 879, 1627, 1821, 3231, 879, 2183, - 2656, 1020, 2907, 3454, 3455, 3202, 1862, 1590, 2897, 788, - 3340, 3185, 3571, 2657, -609, 33, 2127, 1462, 2928, 3190, - 2440, 1213, 3227, 3342, 2184, 3234, -527, 1022, 2908, 1591, - 1637, 3142, 3343, 3239, 2880, 2902, -531, 106, 1600, 3553, - 3235, 3403, 1310, 3180, 2128, 3228, 3166, 114, 1514, 3232, - 3522, 1639, 38, 1699, 3420, 3495, 3344, 839, 1213, 1341, - 3178, 1779, 2197, -609, 1639, 1147, 1763, 1155, 1713, 1156, - 1677, 2627, 880, 2627, 1014, 2754, 880, 3367, 3049, 2813, - 1214, 3040, 1595, 1333, 1215, 40, 2166, 1778, 2631, 1210, - 3183, 3322, 2259, 2228, 1808, 1211, 43, -527, 2314, 3508, - -801, 2903, 2929, 2904, 1926, 1251, 3469, -531, 1927, 1928, - 2450, 1776, 3356, 1589, 3523, 3255, 1216, 1240, -684, 2453, - 3565, 1215, 3541, 2321, 1053, 2330, 1820, 1926, 1776, 3345, - 928, 1927, 1928, 3395, 988, -2081, -2081, -2081, 1341, 2124, - 1749, 1148, 3346, 2235, 3064, 1750, 2782, 954, 3481, 3516, - 3169, 46, 1697, 1241, 1048, 3043, 1026, 1806, 3214, 2129, - 1341, 1690, 1616, 2483, 2318, 862, 719, 3572, 2047, 2131, - 3031, 1958, 1779, 2117, 3510, 1463, 2250, 962, 1572, 1573, - 3028, 2076, 1883, 2312, 1754, 1764, 2555, 1217, 1887, 3300, - 911, 3055, 3470, 2836, 912, 948, 1973, 3554, 3044, 1334, - 1212, 950, 877, 1585, 2378, 2009, 981, 3482, 2502, 3542, - 3332, 3312, 2752, 1994, -1124, 2576, -527, 2684, 2685, 2157, - 535, 1342, 1568, 881, 1217, 2221, -531, 881, 2755, 1803, - 2602, 3236, 2663, 2991, 539, 3014, 2420, 789, 3543, 1776, - 819, 2407, 1476, 3192, 3193, 2597, -1145, 2709, 2797, 2704, - 1590, -454, -454, 2413, 2171, -527, 1306, -527, 2993, -371, - -1928, 2384, -1928, 2058, 2059, -531, -1350, -531, 1582, 2698, - 1582, 2591, 1591, -864, -869, 3159, 3303, 1622, 911, -1291, - -1272, 3304, 912, 2441, 1590, -1919, 1592, 1574, 2126, -1936, - 2446, -1292, -1291, 1779, 1477, 2044, 1604, 1001, 1715, 3427, - 1345, 2688, -1919, 871, -1936, 1604, 1591, -1292, 1575, 1256, - 2097, 1256, 1580, -859, 1891, 3277, 1672, 2173, 1797, 2079, - 1594, 975, 2132, 3419, 1660, 1884, 1943, 980, 2480, 3426, - 3217, 3306, 2480, 2133, 1179, 1715, 858, 1004, 1360, 1361, - 3493, 1185, 1798, 3347, 1716, 2776, 3348, -229, -229, 2098, - 3316, 77, 2877, 1577, 871, 784, 1185, 1213, 3551, 1964, - 1776, 2501, 1360, 1361, 1157, 2255, 977, 525, 1657, 1658, - 1659, 1660, 2312, 1587, 1940, 1941, 1942, 1943, 525, 2421, - 2255, 1716, 2635, 1354, 3150, 1778, 1355, 967, 2865, 2422, - 523, 1655, 1656, 1657, 1658, 1659, 1660, 887, 3059, 3576, - 2638, 523, 888, 2766, 2767, 2768, 2769, 2035, 1934, 1393, - 1394, 864, 1717, 525, 525, 2045, 1244, 1187, 1201, 2878, - 1215, 1152, 816, 2447, 2051, 3548, 2256, 3209, 3491, 1038, - 2940, 1797, 1187, 816, 873, 3020, 1180, 525, 541, 1152, - 1039, 2624, 3152, 2866, 890, 1003, 2369, 874, 2401, 1769, - 818, 1709, 1245, 2402, 1792, 1798, 57, 2285, 65, 82, - 1770, 818, 2447, 1718, 53, 70, 103, 2288, 3218, 2284, - 2291, 2783, 77, 68, 1158, 69, 99, 3115, 889, 2119, - 1590, 1188, 2565, 94, 525, 719, 2545, 1166, 1299, 525, - 2991, 1616, 3228, 2636, 1688, 939, 3007, 1689, 3008, 3500, - 1718, 542, 1591, 892, 868, 3098, 850, 850, 3100, 850, - 3102, 850, 2403, 1811, 2546, 2993, 1592, 1778, 2308, 2309, - 2310, 820, 108, 1217, 3421, 1719, 2456, 907, 1399, 1400, - 2377, 2342, 916, 909, 2379, 2139, 50, 2381, 3336, 3566, - 51, 1299, 52, 2524, 55, 1778, 1457, 3309, 2247, 56, - 59, 60, 980, 1468, 61, 63, 66, -1928, 917, 525, - 525, 2076, 1719, 67, 23, 525, 2389, 940, 525, 525, - 80, 525, 525, 525, 525, 2283, 2394, 1352, 1309, 2827, - 77, 81, 83, 84, 784, 90, 91, 525, 93, 1778, - 1769, 1779, 98, 102, 525, 2294, 104, 939, 2911, 1793, - 2301, 1772, 1938, 1939, 1940, 1941, 1942, 1943, 3296, 1794, - 523, 525, 1299, 1560, 915, 1949, 3480, 523, 2577, 3483, - 2578, -2081, -2081, -2081, 918, 1938, 1939, 1940, 1941, 1942, - 1943, 1893, 2672, 525, 2547, 2286, 1054, 3285, 1454, 2548, - 2289, 2914, 816, 2673, 871, 2661, 1895, 1461, 3286, 816, - 1213, 1054, 525, 919, 810, 3501, 1480, 1803, 1776, 2140, - 1484, 810, 2037, 525, 525, 525, 941, 525, 525, 940, - 818, 719, 3125, 2665, 2677, 1888, 2141, 818, 1889, 2259, - 3323, 2142, 1590, 546, 3502, 971, 927, 1882, 2608, 3398, - 3415, 2445, 109, 1385, 1386, 541, 920, 1882, -2050, -2050, - 3249, 2597, 525, 110, 1591, 942, 1610, 26, 27, 28, - 934, 550, 3546, 2637, 541, 2638, -209, 2669, 1594, 2143, - 525, 525, 1210, 1779, 1703, 1704, 2664, 1710, 1211, 888, - 888, 2008, 888, 3388, 2009, 3389, 1152, 2400, 111, -540, - 943, 2404, 2600, 2033, 2406, 2639, 2034, 1054, 1185, 981, - -608, 1779, 1967, 1186, -540, -608, 525, 1968, 542, -540, - 525, 525, 911, 1393, 1394, 1608, 912, 1566, 1836, 46, - 525, 525, 525, 2060, 33, 525, 2505, 542, 2783, 938, - 2061, 2062, 946, 1019, 2063, 2064, 2065, 1583, 1584, 112, - 1776, 944, 2549, 911, 2714, 1779, 1560, 1615, 2159, 3314, - 2722, 1804, 2160, 2550, 2918, 2326, 868, 1837, 2327, 3440, - -540, 38, 1957, 1626, 1959, 1960, 1627, 2792, 1776, 1020, - 1628, 1629, 2395, 921, 1187, 2396, -608, 1042, 1043, 1044, - -540, 1299, 1047, 1212, 922, 1470, 951, 116, 941, 1469, - 1299, 536, 1838, 1474, 40, 1022, 2359, 952, 2360, 749, - 544, 1637, 2543, 2919, 1210, 43, 1140, 1141, -2081, 1143, - 1211, 1145, 1776, 837, 1299, -2051, -2051, 851, 822, 923, - 956, 2920, 2573, 1188, 955, -608, 2144, 942, 2433, -540, - 957, 2434, 1399, 1400, 988, 1639, 1560, 911, -540, -1272, - 1308, 912, 924, 1839, 1843, 2481, 1844, 1846, 2482, 2649, - 2484, 2651, 719, 2482, 1847, 2652, -2052, -2052, 2653, 1308, - 46, 719, 2700, 2646, 2658, 2648, -208, 2659, 3060, 958, - 925, 1210, 3562, 2725, 2076, 968, 2009, 1211, 980, 2789, - 2777, 986, 2482, 2790, 2784, 2793, 2034, 1876, 2794, 987, - 546, 2795, 971, 2872, 2794, 719, 2873, 2894, 989, 2896, - 525, 2127, 77, 930, 3029, 931, 784, 2396, 908, 546, - 3549, 547, 3550, 944, 992, 1212, 3030, 977, 550, 2327, - 3053, 995, 2921, 3054, 1026, 3061, 2611, 996, 3062, 2128, - 1898, 2922, -2081, 2989, 1885, 3116, 1886, 550, 2034, 932, - 1213, 933, 1985, 1463, 1986, 3250, 997, 1988, 2034, -2081, - 525, 525, 1992, 3575, -2081, 1995, 525, 1996, 525, 3525, - 998, 2000, 2938, 525, 525, 525, 525, 999, 2931, 3251, - 2695, 2457, 2482, 2458, 3537, 2459, 1006, 2460, 525, 525, - 1000, 523, 1212, 525, 3006, 525, -2055, -2055, 525, -540, - 2895, 3280, -2081, 525, 2034, 525, 525, 3287, 525, 2246, - 2009, 3297, 525, 1215, 3298, 1001, 523, 2596, 523, -2056, - -2056, 523, 1223, 816, 2814, 2815, 523, 3016, 1040, 523, - 3330, 523, 2930, 2396, 2939, 523, 1035, 3331, 3364, 3573, - 2327, 2034, 1224, 3424, 3574, 1216, 2396, 1046, 816, 3436, - 816, 818, 3437, 816, 2129, -2057, -2057, 1648, 816, 2130, - 810, 816, 810, 816, 2131, 810, 1560, 816, 911, 3384, - 810, 3385, 912, 810, 1045, 810, 818, 1604, 818, 810, - 3462, 818, 1213, 3463, 1608, 1048, 818, 3506, 1225, 818, - 3437, 818, -2058, -2058, 3547, 818, 1836, 3437, 525, 525, - 2803, 2805, 2806, 2802, 2804, 2801, 2800, 525, 525, 1182, - 1049, 1184, 2036, 2040, 1144, 525, 1217, -2060, -2060, 1150, - 77, 2038, 525, 2039, 2043, -2061, -2061, -2062, -2062, -2063, - -2063, 2042, -2064, -2064, 1161, 1837, -2065, -2065, 1167, -2066, - -2066, 2292, -2067, -2067, 1168, 1215, -2069, -2069, 719, 1213, - 1170, 1210, 525, -2070, -2070, 525, 1171, 1211, 1172, -2081, - 1560, 525, 525, 525, 525, 525, 525, 525, 525, 719, - 3222, -2071, -2071, 525, 525, 525, 1174, 2293, 525, 1175, - 2735, 1183, 525, 1202, 1226, 525, 525, 525, 525, 525, - 525, 525, 525, 525, -2072, -2072, 525, 1205, 523, 981, - -2073, -2073, 1207, 525, 2113, 1299, -2074, -2074, 1365, 2597, - -2076, -2076, 1215, 2168, 2203, -2078, -2078, 2132, 1208, 888, - 1209, 1839, -2080, -2080, 525, 1823, 1824, 1221, 2133, 3196, - 2066, 2067, 2068, 1227, 2069, 2070, 2071, 2072, 2073, 2074, - 2222, 2223, 2097, 1228, 1216, -659, -659, 525, 1217, -663, - -663, -662, -662, 1395, 1396, 1229, 1248, 1626, 525, 525, - 1627, 1158, 1212, 1222, 1628, 1629, 1302, -2081, 1399, 1400, - 3160, 3156, 3157, 2938, 1655, 1656, 1657, 1658, 1659, 1660, - 2727, 2729, 3533, 3534, 3559, 3560, 1239, 1230, 1683, 1684, - 2616, 2617, 1305, 1243, 1247, 1637, 1306, 1311, 1560, 1313, - 1317, 1329, -2081, 1327, 1337, 1330, 1338, 719, 1344, 719, - 1348, 1347, 1353, 2888, 1372, 1217, 1371, 1377, 1435, 1451, - 1448, 1458, 1450, 1465, 1466, 2012, 1472, 1473, 1479, 1639, - 1485, 1483, 1562, 1563, 1565, -835, -842, 1574, 3012, 1578, - 3213, 1232, 2271, 1624, 2275, 3052, 46, -684, 3023, 525, - -685, -832, -833, 1299, 1588, -836, 525, 525, 3524, 2251, - 1589, -834, 3526, 3041, -540, 1668, 1233, 1609, 1619, 2260, - 1621, 2263, 1666, 1365, 2274, 1682, 541, 1692, 1670, -540, - 2278, 1691, 2280, 1696, -540, 1235, 1700, 3363, 3276, 1702, - 3127, 1186, 1188, 1737, 2542, 2287, 820, 1299, 1739, 1741, - 2290, -1336, 1775, 1756, 2295, 2296, 2297, 2298, 1781, 2302, - 2303, 2363, 1774, 1776, 1782, 719, 1783, 3567, 1788, 1213, - 1795, 1800, 1299, 525, 1796, 113, -2081, 1810, 1816, 1826, - 1827, 980, 1828, 1832, 1835, -540, 1841, 1842, 1850, 542, - 1851, 1858, 1860, -2081, 1854, 1857, 1861, 1560, -2081, 1863, - 1864, 525, 525, 1365, 525, -540, 1365, 1365, 1877, 1560, - 525, 525, 525, 525, 525, 525, 2597, 1878, 525, 525, - 525, 525, 525, 525, 525, 525, 525, 525, 2299, 2470, - 1882, 1431, 1215, 525, 525, 2473, -2081, 525, 1890, 1560, - 1954, 2989, 1626, 970, 525, 1627, 1560, 1915, 1917, 1628, - 1629, 3512, 1965, 2362, -540, 1918, 1920, 1923, 1946, 1983, - 1955, 1962, 1987, -540, 2300, 1993, 525, 14, 15, 1997, - 525, 1998, 525, 1999, 23, 2004, 525, 1568, 2010, 2867, - 1637, 2007, 2015, 1575, 1560, 1580, 3363, -2081, 1560, 2011, - 525, 1648, 1299, 523, 1560, 2013, 2014, 2016, 2046, 523, - 2047, 1054, 1627, 3197, 3198, 3328, 2080, 2081, 2084, 3188, - 2087, 2090, 2093, 23, 1639, 2092, 2095, 1560, 2094, 2135, - 2136, 545, 541, 2115, 2138, 816, 2162, 2163, 3363, 525, - 525, 816, 2169, 2181, 23, 1217, 3097, 810, 1430, 1894, - 1896, 984, 2182, 810, 1549, 2186, 879, -1336, 2199, 2212, - 2202, 2213, 2211, 818, 2214, 2216, 2215, 2233, 2237, 818, - 2238, 2241, 2248, 2252, 2253, 2254, 880, 525, 2334, 2324, - 525, 546, 1037, 971, 2328, 525, 525, 3363, 2343, 2552, - 2345, 871, 1608, 2346, 2349, 542, 2347, 2350, 2348, 2364, - 548, 2365, 2367, -2081, 2372, 2373, 549, 1142, 2376, 550, - 525, 525, 3417, 2370, 2371, 525, 2374, 2380, 2397, 2405, - 1951, -2081, 1926, 2435, -540, 1950, 2442, 26, 27, 28, - 2443, 525, 2444, 1730, 525, 525, 525, 2466, -2081, 2448, - 2454, 2474, 1431, -2081, 2486, 2488, 2455, 2493, 3379, 2341, - 2472, 2494, 525, 719, 2495, 822, 2497, 2498, 523, 525, - 2499, 2500, 525, 2503, 2511, 2504, 26, 27, 28, 2512, - 2515, 2514, 3174, 1600, 2516, 2517, 2868, 2544, 2518, 525, - 2519, -2081, 2520, 2521, 2539, 523, 2551, 26, 27, 28, - 2522, 1551, 525, 911, 33, 2560, 1170, 912, 2568, 2536, - 2582, 2537, 523, 2561, 2579, 2566, 2567, 2580, 2989, 525, - 525, -2081, 2584, 2585, 2590, 2592, 1557, 816, 1655, 1656, - 1657, 1658, 1659, 1660, 2593, -665, 525, 2603, 525, 810, - 2604, 38, 2606, 33, 816, 2607, 1648, 1549, 2610, 2614, - 1885, 525, 1362, 2615, 35, 818, 810, 2620, 1754, 2623, - 2622, 2618, 1405, 2626, 33, 2645, 2647, 1803, 2678, 719, - 719, 719, 818, 2679, 40, 2660, 37, 2666, 2911, 2052, - 38, 2667, 2668, 2680, 2912, 43, 2681, 546, 2693, 971, - 2694, 2082, 2699, 2083, 3317, 2712, 2711, 2913, 2715, 2716, - 2723, 38, 44, 2719, 2271, 2271, 2271, 2732, 525, 1582, - 2742, 2750, 549, 40, 1299, 550, 2753, 2756, 2773, 2774, - 2099, 2914, 871, 2915, 43, 2785, 45, 2760, 2786, 2759, - 1680, 2761, 2834, 2762, 40, 981, 2810, 1549, 2799, 2823, - 46, 44, 2835, 2791, 1843, 43, 1844, 1846, -2081, 2847, - 719, 2807, 2817, 2848, 1847, 1560, 2824, 2832, 2838, 2853, - 2862, 2879, 44, 2855, 2859, 45, 2881, 2885, 2883, 2893, - 2926, 2942, 2900, 2906, 2899, 525, 3009, 1620, 3010, 46, - 3033, 3011, 1431, 1431, 1551, 1898, 45, 1623, 1431, 3015, - 525, 980, 3018, 3019, 3037, 3026, 3032, 3045, 3046, 719, - 2869, 3027, 3057, 2327, 3050, 3058, 3083, 3063, 1673, 1557, - 3085, 2916, 3089, 3093, 3106, 3103, 3368, 1678, 3370, 2097, - 1223, 3104, 3107, 3149, 2220, 2220, 3128, 3135, 3138, 3147, - 3140, 2718, 3153, 3154, 1898, 3171, 3155, 525, 3161, 3378, - 1224, 3162, 3163, 3167, 3172, 3181, 3173, 3184, 3186, 3187, - 3191, -2049, -2050, -2051, -2052, -2053, -2081, 3205, -2054, -2055, - 523, -2056, -2057, 1655, 1656, 1657, 1658, 1659, 1660, -2058, - -2060, -2061, 3206, -2062, 1551, 3221, -2063, 525, 3207, 2917, - 3380, 3499, 3382, -2064, 2918, -2065, 1225, 3208, 1365, 1924, - 1925, -2066, 816, 1560, 1152, 1945, -2067, -2069, 1365, 1557, - -2070, 1365, 3223, -2071, 871, -2072, 3238, 3204, -2073, 3460, - 525, 3240, -2074, -2075, -2076, -2077, 525, 525, 3453, 3243, - 818, 3464, -2078, -2079, -2080, -1289, 3210, 2850, 525, 3242, - 3252, 3253, 3211, 2919, 3264, 3219, 3224, 3226, 3246, 3256, - 871, 3258, 525, 3270, 3260, 525, 3266, 525, 3267, 3272, - 3275, 2920, 3448, 3271, 1560, 525, 2934, 1549, 525, 525, - 3279, 3294, 3299, 525, 525, 1053, 3295, 3302, 1926, 3305, - 525, 541, 1927, 1928, 3307, 3319, 1929, 1930, 1931, 3320, - 3329, -1288, 1226, 3327, 3335, 525, 3337, 3338, 3351, 3352, - 3353, 2887, 3365, 2829, 3366, 525, -1336, 1365, 521, 532, - 2036, 2040, 3369, 3372, 557, 3373, 3375, 2871, 77, 2038, - 557, 2039, 2043, 3381, 807, 525, 821, 3386, 3180, 2042, - 824, 557, 833, 3406, 3410, 833, 3416, 3412, 852, 856, - 3413, 1227, 856, 3429, 542, 557, 557, 3422, 3430, 3431, - 3434, 1228, 3439, 3229, 1897, 3441, 3443, 3131, 3446, 3447, - 3459, 1549, 2921, 1229, 3450, 3451, 719, 3452, 3466, 2992, - 719, 2922, 719, 3457, 23, 3477, 807, 807, 3461, 2210, - 3478, 3471, 3484, 3504, 525, 3479, 525, 3485, 3494, 3514, - 3486, 3517, 3496, 3538, 2890, 1230, 3498, 2891, 543, 3515, - 3519, 2271, 852, 3535, 1551, 2994, 3516, 2275, 3552, 856, - 557, 856, 856, 856, 3488, 3563, 3557, 544, 3568, 3048, - 1843, 3577, 1844, 1846, 2943, 3021, 3578, 2496, 2941, 1557, - 1847, 1173, 2279, 2643, 2945, 3393, 2874, 3492, 3456, 2996, - 2997, 2998, 2999, 3000, 3001, 3002, 3003, 3004, 3005, 1232, - 3561, 3194, 2734, 3475, 3042, 2382, 1149, 3545, 3315, 3513, - 3520, 3539, 1766, 3350, 2625, 2650, 525, 871, 3036, 1560, - 3511, 3518, 2910, 2621, 1233, 3509, 545, 2995, 1880, 2728, - 2726, 2689, 2739, -208, 3247, 1840, 525, 525, 3017, 1933, - 2609, 525, 1693, 1235, 525, 1455, 2595, 2240, 1551, 1549, - 1733, 1456, 2764, 3497, 2605, 2208, 1734, 3442, 3371, 2239, - 1738, 811, 2581, 2478, 3274, 3092, 1422, 26, 27, 28, - 2757, 525, 2758, 1557, 2788, 3321, 546, 1457, 547, 1005, - 3445, 991, 2492, 2391, 2392, 2393, 525, 3444, 1552, 2534, - 2812, 2598, 525, 525, 2558, 548, 2508, 525, 1560, 1974, - 3111, 549, 525, 1406, 550, 525, 525, 2556, 871, 1934, - 525, 1299, 913, 3139, 525, 1408, 1412, 1413, 525, 1414, - 1415, 2535, 1416, 2826, 2860, 525, 1417, 3432, 985, 2485, - 2322, 1204, 2575, 23, 33, 1418, 1892, 2177, 2670, 2875, - 2179, 523, 1431, 1431, 1431, 1431, 1431, 1431, 897, 0, - 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, - 0, 0, 0, 1812, 0, 2601, 2601, 0, 0, 525, - 0, 38, 0, 816, 0, 0, 0, 525, 0, 0, - 0, 0, 0, 0, 0, 810, 1551, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 525, 0, 1549, 0, - 0, 818, 0, 0, 40, 1560, 0, 0, 0, 0, - 1549, 1557, 0, 2174, 0, 43, 0, 1223, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, - 15, 860, 44, 0, 0, 0, 0, 1224, 0, 2992, - 1549, 0, 3175, 0, 0, 0, 0, 1549, 0, 2414, - 2415, 2416, 2417, 2418, 2419, 0, 45, 2423, 2424, 2425, - 2426, 2427, 2428, 2429, 2430, 2431, 2432, 0, 0, 0, - 46, 1552, 0, 71, 0, 23, 26, 27, 28, 0, - 0, 719, 0, 1225, 2932, 1549, 2243, 2245, 0, 1549, - 0, 0, 0, 71, 2933, 1549, 809, 0, 899, 0, - 902, 0, 906, 0, 0, 0, 1016, 0, 0, 525, - 71, 1017, 871, 0, 3230, 0, 1898, 980, 1549, 870, - 525, 1560, 1935, 1936, 1937, 0, 1938, 1939, 1940, 1941, - 1942, 1943, 1431, 1431, 0, 1551, 525, 0, 0, 0, - 0, 0, 0, 33, 0, 2304, 0, 1551, 809, 809, - 886, 0, 0, 2934, 0, 0, 0, 0, 2319, 2319, - 1557, 1552, 0, 0, 1560, 0, 0, 0, 0, 525, - 1018, 0, 1557, 0, 71, 0, 0, 1551, 0, 1226, - 38, 525, 525, 0, 1551, 525, 0, 525, 0, 0, - 0, 856, 0, 0, 0, 0, 856, 0, 0, 856, - 0, 0, 1557, 0, 0, 0, 0, 557, 0, 1557, - 0, 0, 525, 40, 0, 0, 0, 0, 26, 27, - 28, 0, 1551, 0, 43, 0, 1551, 0, 1227, 0, - 0, 1362, 1551, 0, 0, 0, 525, 2399, 1228, 2540, - 2541, 44, 1019, 0, 0, 0, 0, 1557, 1431, 0, - 1229, 1557, 2935, 2796, 2798, 1551, 0, 1557, 0, 0, - 0, 0, 0, 0, 0, 45, 0, 2992, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1020, 46, - 1557, 0, 1230, 0, 0, 33, 0, 0, 0, 719, - 0, 0, 0, 0, 1021, 0, 35, 0, 0, 0, - 0, -1810, 3333, 0, 1022, 0, 0, 0, 0, 525, - 0, 0, 0, 3318, 0, 0, 0, 0, 37, 525, - 0, 525, 38, 525, 1898, 0, 0, 525, 0, 525, - 0, 525, 523, 0, 3325, 3326, 1232, 0, 1023, 0, - 0, 0, 525, 0, 0, 0, 0, 525, 1016, 525, - 0, 0, 0, 1017, 0, 40, 0, 525, 3339, 1199, - 0, 1233, 0, 0, 816, 0, 43, 0, 0, 0, - 719, 0, 0, 0, 0, 525, 3390, 0, 3392, 0, - 1235, 1552, 2936, 44, 1024, 2937, 0, 0, 0, 0, - 0, 1025, 818, 0, 0, 0, 0, 960, 557, 557, - 0, -1810, 0, 0, 0, 3399, 0, 45, 0, 0, - 0, 0, 1018, 0, 0, 1365, 0, 0, 3425, 0, - 0, 46, 525, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 525, 1026, 3428, 0, 1549, 0, 0, 983, - 532, 0, 0, 0, 525, 521, 0, 856, -1810, 0, - 0, 0, 1027, 0, 0, 0, 807, 0, 525, 0, - 1009, 1009, 0, -1810, 0, 1009, 1032, 0, -1810, 0, - 0, 0, 0, -1810, 0, 1552, 525, 0, 833, 833, - 833, 523, -1810, 833, 1019, 0, 0, -1810, 0, 0, - 0, 0, 0, 833, 833, 1776, 833, 0, 833, 0, - 525, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 856, 0, 0, 816, 0, 525, 557, 0, 0, -1810, - 1020, 1028, 0, 523, 2992, 0, 719, 0, 856, 0, - 929, 0, 0, 0, 0, 936, 1021, 0, 937, -1810, - 0, 818, 856, 821, 0, 0, 1022, 0, 0, 525, - 3099, 0, 0, 0, 0, 816, 0, 0, 0, 3521, - 0, 3399, 0, 525, 525, 525, 0, 0, 0, 0, - 1431, 1431, 523, 1551, 1549, 0, 0, 856, 1304, 1223, - 1023, 0, 0, 818, 0, 3536, 3505, 0, -1810, 1315, - 525, -1810, 0, 856, 856, 856, 856, -1810, 1557, 1224, - 0, 0, 0, 0, 816, 0, 2654, 0, 558, 1336, - 0, 0, 71, 1552, 558, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 558, 1024, 0, 0, 0, - 0, 525, 818, 1025, 0, 1549, 0, -1810, 0, 558, - 558, 1009, 1032, 0, 856, 1225, 0, 1429, 0, 0, - 0, 0, 0, 1009, 1009, 0, 0, 0, 2686, 557, - 0, 0, -1810, 0, 0, 807, 0, 0, 0, 0, - 0, 0, 807, 0, 0, 1026, 2701, 2840, 2841, 0, - 0, 0, 557, 0, 0, 0, 0, 0, 0, 0, - 1365, 0, 0, 0, 1027, 1365, 0, 0, 0, 1564, - 0, 0, 0, 0, 558, 0, 0, 0, 0, 0, - 0, 1551, 0, 0, 0, 0, 0, 0, 0, 0, - 858, 1362, 0, 1901, 0, 0, 0, 0, 0, 0, - 0, 2740, 0, 2741, 0, 0, 1557, 2746, 0, 2749, - 1549, 1226, 1894, 1896, 0, 0, 0, 0, -1810, 0, - 557, 0, 0, 0, 0, 0, 0, 0, -1810, 0, - 0, 23, 1552, 1028, 0, 0, 0, 0, 1431, 0, - 1902, 0, 1551, 0, 1552, 0, 0, 0, -1810, 0, - -1810, -1810, 0, 0, 0, 0, 994, 0, 0, 0, - 1227, 1903, 0, 3086, 0, 0, 0, 1557, 0, 0, - 1228, 1685, 0, 1687, 1552, 0, 0, 0, 0, 1904, - 0, 1552, 1229, 1905, 0, 0, 0, -1810, 557, 557, - -1810, -1810, -1810, 0, 0, 856, 71, 870, 0, 0, - 0, 0, 0, 0, 0, 0, 1906, 0, 3110, 1907, - 1549, 0, 0, 0, 1230, 0, 0, 0, 1429, 1552, - 0, 0, 0, 1552, 0, 1908, 0, 0, 0, 1552, - 856, 1765, 0, 0, 0, 0, 0, 990, 0, 0, - 0, 0, 0, 856, 0, 3056, 0, 1551, 1002, 0, - 0, 1203, 1552, 0, 1554, 0, 0, -1812, 0, 0, - 856, 0, 0, 3391, 856, 0, 0, 0, 1232, 1813, - 1555, 0, 1557, 0, 26, 27, 28, 0, 0, 0, - 0, 0, 0, 722, 0, 0, 1303, 0, 0, 1549, - 0, 0, 0, 1233, 0, 0, 0, 886, 0, 1431, - 0, 0, 1319, 1321, 1324, 1326, 0, 1626, 0, 0, - 1627, 0, 1235, 0, 1628, 1629, 0, 71, 1909, 0, - 0, 1894, 1896, 0, 0, 0, 1910, 1829, 0, 856, - 0, 0, 0, 1365, 0, 0, 0, 0, 856, 0, - 723, 33, 0, 0, 0, 1637, 0, 1551, 1911, 1873, - 0, 0, -2081, 1424, 0, 0, 724, -1812, 960, 2985, - 0, 0, 0, 960, 0, 557, 557, 0, 557, 960, - 0, 0, 1557, 0, 0, 0, 0, 1912, 38, 1639, - 0, 0, 0, 0, 0, 0, 1053, 0, 0, 1926, - 0, 0, 2686, 1927, 1928, 0, 1549, 1929, 1930, 1931, - 0, 0, 0, 0, -1812, 725, 3176, 0, 0, 0, - 0, 40, 0, 0, 0, 726, 0, 0, 0, -1812, - 0, 0, 43, 0, -1812, 71, 1551, 0, 727, -1812, - 1549, 0, 0, 728, 0, 0, 0, 1554, -1812, 44, - 0, 0, 1431, -1812, 2839, 0, 0, 0, 1429, 1429, - 0, 1557, 0, 1555, 1429, 0, 521, 809, 0, 0, - 0, 0, 729, 45, 809, 0, 0, 0, 0, 1009, - 0, 557, 1969, 0, 0, -1812, -2081, 46, 0, 856, - 0, 807, 0, 807, 0, 0, 807, 0, 0, 0, - 0, 807, 0, -2081, 807, -1812, 807, 0, -2081, 1567, - 807, 0, 557, 0, 557, 730, 0, 0, 0, 731, - 0, 1579, 1549, 0, 0, 0, 0, 0, 0, 0, - 0, 558, 0, 0, 0, 0, 0, 1554, 0, 0, - 0, 0, 0, 1551, 0, 0, -2081, 0, 1606, 0, - 0, 0, 0, 1555, -1812, 0, 0, -1812, 0, 3248, - 0, 0, 0, -1812, 0, 1549, 0, 0, 1557, 0, - 0, 0, 3137, 0, 0, 0, 0, 1551, 0, 1757, - 1552, 0, 0, 544, 0, 0, 0, 1932, 0, 732, - 0, 0, 1784, 0, 0, 0, 0, 0, 0, 0, - 1365, 1648, 1557, -1812, 733, 0, 0, 0, 0, 0, - 1933, 0, 0, 1809, 0, 0, 0, 0, 0, 2075, - 0, 0, 0, 0, 0, 0, 0, 0, -1812, 0, - 0, 2086, 0, 0, 886, 886, 0, 886, 0, 734, - 0, 1556, 735, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 736, 0, 0, 737, 0, 0, 1551, - 0, 3377, 0, 0, 0, 0, 0, 0, 1549, 0, - 960, 0, 0, 1429, 738, 0, 0, 0, 1834, 0, - 1934, 0, 0, 0, 1557, 0, 858, 1853, 739, 0, - 0, 0, 0, 0, 740, 741, 0, 0, 0, 0, - 0, 0, 1551, -2081, 0, 742, 0, 0, 0, 0, - 0, 743, 0, 0, -1812, 0, 0, 2175, 1552, 856, - 0, 856, 558, 558, -1812, 0, 0, 1557, 0, 0, - 0, 856, 0, 2191, 0, 0, 0, 0, 0, 744, - 3225, 0, 0, 0, -1812, 1429, -1812, -1812, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1554, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1362, 0, 0, - 856, 0, 557, 1555, 0, 0, 0, 0, 0, 1552, - 0, 0, 0, -1812, 2242, 2244, -1812, -1812, -1812, 0, - 1765, 557, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 557, 2261, 557, 2265, 1551, 557, 71, 0, 0, - 0, -2081, 557, 0, 557, 0, 0, 0, 1655, 1656, - 1657, 1658, 1659, 1660, 1556, 0, 960, 557, 1981, 0, - 1557, 960, 557, 0, 0, 0, 557, 557, 557, 557, - 558, 557, 557, 0, 0, 0, 0, 0, 3292, 0, - 0, 1554, 0, 0, 0, 0, 0, 0, 2323, 0, - 0, 0, 0, 0, 0, 0, 1315, 1555, 856, 856, - 856, 856, 856, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1552, 0, 0, 0, 0, 2352, - 0, 0, 0, 1935, 1936, 1937, 0, 1938, 1939, 1940, - 1941, 1942, 1943, 0, 0, 0, 0, 0, 2375, 0, - 0, 0, 0, 809, 1556, 809, 0, 2985, 809, 0, - 0, 0, 0, 809, 0, 1549, 809, 0, 809, 0, - 0, 0, 809, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, -1827, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1429, 1429, - 1429, 1429, 1429, 1429, 0, 0, 1429, 1429, 1429, 1429, - 1429, 1429, 1429, 1429, 1429, 1429, 0, 0, 0, 0, - 0, 0, 0, 1449, 1552, 0, 0, 0, 0, 1554, - 0, 0, 0, 0, 0, 0, 557, 0, 0, 0, - 0, 0, 0, 0, 0, 1555, 1482, 0, 856, 0, - 0, 0, 0, 0, 0, 71, 0, 0, 807, 0, - 0, 0, 0, 0, 807, 0, 0, 0, 0, 0, - 557, 0, 0, 0, 0, 557, 0, 0, 0, 0, - 0, 0, 3418, -1827, 2490, 2490, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2176, 0, - 2178, 0, 1551, 1552, 0, 0, 0, 0, 1626, 0, - 2188, 1627, 0, 0, 1611, 1628, 1629, 1630, 1631, 1632, - 1633, 1634, 0, 0, 0, 0, 0, 1557, 0, 0, - -1827, 0, 0, 0, 0, 2123, 1635, 0, 0, 0, - 0, 0, 0, 0, 0, -1827, 1637, 0, 0, 2225, - -1827, 0, 0, 1638, 0, -1827, 557, 0, 0, 0, - 2528, 0, 0, 0, -1827, 557, 0, 0, 0, -1827, - 0, 0, 0, 0, 1556, 0, 0, 0, 1554, 0, - 1639, 0, 558, 558, 0, 0, 0, 0, 1429, 1429, - 1554, 0, 0, 0, 1555, 0, 0, 0, 0, 0, - 0, -1827, 0, 0, 886, 0, 1555, 2075, 1626, 0, - 1552, 1627, 0, 1429, 2985, 1628, 1629, 0, 0, 0, - 1554, -1827, 1053, 0, 0, 1926, 0, 1554, 0, 1927, - 1928, 0, 0, 1929, 1930, 1931, 1555, 0, 0, 0, - 807, 0, 0, 1555, 1552, 0, 1637, 2335, 2336, 2338, - 2339, 2340, 557, -2081, 0, 0, 0, 807, 0, 0, - 0, 2191, 0, 0, 0, 1554, 0, 0, 1556, 1554, - -1827, 0, 0, -1827, 0, 1554, 0, 1640, 0, -1827, - 1639, 1555, 0, 0, 0, 1555, 0, 0, 0, 0, - 0, 1555, 0, 0, 1641, 0, 0, 0, 1554, 1642, - 0, 557, 0, 0, 1429, 0, 0, 557, 0, 0, - 0, 0, 0, 0, 1555, 0, 0, 0, 0, -1827, - 0, 0, 1643, 1644, 0, 0, 1552, 1829, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1645, 0, 0, - 0, 2344, 0, 0, -1827, 2842, 0, 0, 0, 0, - 0, 0, 0, 71, 0, 0, 0, 0, 0, 558, - 558, 0, 558, 0, 0, 0, 0, 0, 0, 1552, - 0, 0, 0, 0, 0, 1646, 0, -2081, 1647, 0, - 0, 0, 0, 0, 0, 0, 0, 2461, 0, 0, - 0, 0, 1648, 0, -2081, 1649, 0, 0, 1829, -2081, - 0, 0, 858, 0, 0, 856, 1556, 0, 0, 0, - 0, 0, 0, 2236, 0, 0, 1315, 0, 0, 1829, - 856, 856, 856, 0, 0, 0, 0, 0, 0, 0, - -1827, 0, 0, 557, 0, 856, 1933, -2081, 856, 0, - -1827, 0, 0, 0, 0, 856, 0, 0, 0, 0, - 0, 960, 0, 0, 0, 0, 0, 0, 0, 0, - -1827, 0, -1827, -1827, 0, 558, 0, 0, 0, 0, - 0, 0, 1552, 1829, 1829, 0, 1829, 0, 0, 0, - 809, 0, 0, 0, 0, 0, 809, 0, 0, 0, - 0, 0, 1648, 0, 1650, 0, 2001, 0, 2005, -1827, - 0, 0, -1827, -1827, -1827, 521, 1934, 0, 0, 0, + 525, 914, 57, 53, 65, 82, 872, 103, 1244, 719, + 68, 69, 94, 1140, 884, 1207, 525, 77, 99, 1036, + 1314, 858, 963, 523, 718, 1444, 1263, 70, 1825, 1370, + 1317, 1706, 1960, 1500, 1985, 982, 2184, 77, 784, 523, + 1797, 778, 1353, 1172, 888, 1814, 1778, 1813, 1788, 1418, + 2101, 810, 2217, 1416, 2618, 522, 889, 2591, 2608, 2593, + 2140, 1860, 1784, 1830, 856, 1417, 2323, 2020, 525, 525, + 1763, 817, 1359, 1414, 1606, 50, 2090, 2051, 2653, 1376, + 2117, 2118, 2724, 3046, 51, 52, 3015, 745, 2501, 55, + 1818, 523, 523, 1683, 905, 56, 3017, 1892, 1686, 59, + 870, 3044, 60, 810, 810, 2646, 1243, 61, 1249, 63, + 1253, 2607, 66, 67, 2572, 3062, 80, 3059, 973, 965, + 1263, 976, 81, 817, 817, 2503, 851, 1619, 898, 2707, + 2840, 83, 2693, 2694, 2695, 84, 2908, 90, 91, 93, + 2913, 98, 102, 885, 886, 1014, 104, 1583, 1584, 2188, + -527, 1039, -1313, 2348, -1948, 2142, -1372, -1948, -2074, -2074, + -454, 3137, -2088, -2088, 1596, 2237, 1383, -531, 2353, 2349, + -1313, -371, 2240, 2455, -870, 2482, 2483, 1978, -1310, -1310, + 1347, 1437, 1979, 1061, 3134, 2715, 2489, -875, -1294, -1939, + 2493, -875, 821, -1939, -1956, 1428, 1060, 2725, -1956, -1314, + 1691, -2079, -2079, 1347, -1314, 3264, -2097, -2097, -837, -850, + 3251, -865, -1311, -1311, -878, -2099, -2099, -878, 821, 821, + 1060, 983, 2716, 2711, 2132, 1780, 2709, 3268, 1769, 1022, + 1363, 862, 2521, 819, 1023, 1060, 1816, 1687, 1363, 821, + 876, 537, 1639, 1060, 1153, 2132, 876, 1641, 1060, -480, + -527, 2762, 2764, 1828, 2767, 1937, 3345, 1196, 3575, 1780, + 1939, 982, 1829, -229, 1159, 954, 1764, -531, -229, 1263, + 2681, -1131, 3198, 1199, 1712, 1338, 821, 1649, 1615, -1131, + 1798, 2171, 3604, 1801, 1802, 819, 819, 1008, 1160, 2172, + 3550, 1639, -1152, 1024, 3213, 1640, 1641, 3469, 541, 2345, + -1152, 1588, 2476, 2477, 2478, 2801, 1347, 1789, 3181, 3358, + 2732, 1651, 3234, 1977, 1339, 1257, 3429, 1598, 3265, 3, + 4, 881, -665, 1772, 3503, 3388, 1649, 1039, 881, 3456, + 1726, 877, 3542, 3266, 1157, 3389, 2880, 877, 2882, 1014, + 3063, 2784, 1789, 3209, 1803, 2250, 1015, 3037, 1377, 1006, + 1977, 1688, 3599, 3288, 2026, 2155, 2329, 839, 538, 3605, + 1651, 542, 2951, 1709, 3588, 1025, 2181, 1186, 1568, 1639, + 2702, 3493, 821, 1640, 1641, 3195, 1727, 1758, 1759, 2773, + 2119, -2073, -2073, 2649, 2436, 2922, 2212, 1762, 1937, 1723, + -807, 1192, 1938, 1939, 113, 3171, 3164, 3207, 3166, 105, + 2881, 1026, 3528, 3437, 1649, 2199, 2428, 1780, 1808, 1044, + 879, 3233, 2657, 1487, 2583, 2059, 1639, 1027, 1781, 535, + 1045, 1873, 3515, 3258, 2065, 3518, 3374, 1028, 2465, 1832, + 2200, 2901, 1809, 3172, 3270, 1812, 2952, 2456, 1651, 3325, + -527, 3327, 2964, 1937, 1728, 3259, 2921, 1938, 1939, 106, + 3196, 3606, 1789, 1525, 2904, 1317, 1161, -531, 1162, 840, + 3504, 1029, 3557, 1392, 1393, 1488, 3438, 1194, 3576, 1187, + 1819, 2213, 3208, 1692, 2646, 1689, 2646, 1348, 114, 2156, + -685, 880, 1217, 1774, 2466, 1651, 1016, 3583, 1218, 1804, + 992, 3073, 2832, 1340, 2654, 1729, 2157, 1724, 2902, 1805, + 1348, 2158, 3390, 1154, 3210, 788, 3064, 1030, 1021, 1258, + 3543, -527, 3455, 1790, 1031, 3600, 2182, 2275, 3581, 2650, + 2953, 2330, 3589, 3473, 3267, 1710, -807, 2437, -531, 3088, + 3356, 1606, 2774, 1400, 1401, 989, 559, 2438, 2538, 2159, + 1787, 3340, 750, 546, 3430, 972, 3505, 1831, 1790, 1600, + 789, 2337, 1568, 826, 2023, 3577, 1032, 1730, 2346, 881, + 3350, 3401, 1467, 1765, 2140, 820, 929, 869, 869, 2061, + 3545, 550, 878, 3067, 1817, 1033, 863, 955, 2516, 1155, + 1787, 1760, 3245, 3346, 3578, 1708, 719, 3334, 1630, 1583, + 1584, 2497, 1054, 1219, 3079, 2133, 2328, 1761, 3055, 2266, + 3052, 951, 1775, 1348, 3286, 2655, 3607, 3516, 2682, 1341, + 3068, 1701, 3199, 3038, 1596, 1787, 2574, 2801, 1935, 1936, + 963, 2251, 3551, 3535, 1956, 1894, 1969, 3517, 2467, 2090, + -527, 1898, 901, 2860, 1986, 2595, 1579, 3366, 2771, 1349, + -1131, 2541, 1568, 982, 1034, 2394, 3015, -531, 3558, 3417, + 2173, 2237, 1406, 1407, 865, 2008, 3017, 2621, 1790, 2142, + 2795, -1152, 1352, 1585, 2717, -1313, 2423, -1948, 1814, -527, + -1948, -527, 2187, 2610, 2072, 2073, 1593, -1372, 2429, 1593, + 2400, -454, -454, -1313, 2723, 2728, -531, -870, -531, 1313, + 3337, 1601, -371, 2616, 1601, 3338, 2160, 1102, 1103, 912, + -875, -1294, -1939, 913, 539, 1634, -1939, -1956, 2457, 2707, + 882, -1956, -1314, 1602, 872, 2462, 1602, -1314, 3189, 3308, + 1002, 1586, 1591, 1895, -865, 1787, 1902, 1603, 2816, 976, + 1605, 1684, 2189, 912, 3454, 1367, 1368, 913, 2243, 1808, + 1263, 2113, 1263, 1367, 1368, 1672, 1588, 981, 3222, 3223, + 1220, 3462, 874, 1163, 2058, 1615, 2494, 2271, 1954, 3461, + 2494, 3248, 1220, 1809, 1615, 872, 1598, 3262, -229, -229, + 77, 784, 1610, 2703, 2704, 978, 2925, 2931, 2093, 3536, + 1594, 1595, 2785, 2786, 2787, 2788, 2675, 525, 2328, 2515, + 1975, 1669, 1670, 1671, 1672, 1020, 2889, 821, 525, 2676, + 2049, 1726, 3180, 2932, 1059, 525, 859, 1937, 3537, 2114, + 523, 1938, 1939, 1222, 2271, -2101, -2101, -2101, 2272, 3263, + 1780, 523, 1192, 3357, 888, 2656, 1601, 2657, 523, 1208, + 1893, 1783, 2463, 1004, 525, 525, 889, 1611, 3083, 3423, + 3526, 3424, 817, 1158, 3240, 1223, 3044, 1727, 1602, 2301, + 2691, 2890, 875, 817, 108, 2244, 2692, 2658, 525, 2304, + 817, 1158, 2307, 2385, 2926, 3182, 1568, 1667, 1668, 1669, + 1670, 1671, 1672, 1005, 2463, 2643, 3249, 57, 53, 65, + 82, 931, 103, 932, 1164, 68, 69, 94, 1951, 1952, + 1953, 1954, 77, 99, 2802, 890, 3215, 1439, 1194, 1789, + 2300, 1789, 70, 3259, 3220, 525, 719, 3015, 3122, 1306, + 525, 3124, 3586, 3126, 1639, 3475, 1224, 3017, 891, 912, + 1904, 1173, 3145, 1626, 2143, 1060, 1627, 2135, 2584, 3031, + 2927, 3032, 2928, 3489, 3490, 851, 851, 1789, 851, 2470, + 851, 1949, 1950, 1951, 1952, 1953, 1954, 1195, 2358, 1649, + 50, 3601, 2144, 3611, 893, 2324, 2325, 2326, 2405, 51, + 52, 1568, 1306, 3319, 55, 933, 1729, 934, 2393, 3320, + 56, 2263, 2395, 981, 59, 2397, 3370, 60, 872, 908, + 525, 525, 61, 1651, 63, 3530, 525, 66, 67, 525, + 525, 80, 525, 525, 525, 525, 3343, 81, 2299, 2935, + 77, 784, 2851, 1359, 819, 1316, 83, 2090, 2410, 525, + 84, 525, 90, 91, 93, 819, 98, 102, 2310, 821, + 525, 104, 819, 2317, 109, 3330, 1789, 1822, 1730, 2680, + 1361, 910, 523, 1362, 523, 110, 2417, 525, 1306, 1571, + 1960, 2418, 2938, 523, 810, 1985, 1004, 1601, 917, 912, + -1948, 3450, 2596, 913, 2597, 810, 1400, 1401, 1893, 525, + 1968, 872, 1970, 1971, 817, 2684, 817, 2145, 1192, 1602, + 111, 1906, 2334, 1193, 918, 817, 1060, 2147, 525, 949, + 1402, 1403, 2302, 1603, 1464, 940, 1005, 2305, 1945, 525, + 525, 525, 2696, 525, 525, 1479, 719, 1630, 1568, 916, + 2419, 1814, 2627, 2051, 1439, 1790, 2074, 1790, 912, 2275, + 3155, 1620, 1626, 2075, 2076, -608, 3375, 2077, 2078, 2079, + -608, 112, 2430, 2431, 2432, 2433, 2434, 2435, 928, 525, + 2439, 2440, 2441, 2442, 2443, 2444, 2445, 2446, 2447, 2448, + 919, 2619, 3433, 1790, 1194, 3280, 1060, 525, 525, 935, + 2461, 2683, 2616, 942, 2688, 1714, 1715, 941, 1721, 1601, + -209, 940, 2175, 1720, 1158, 939, 2176, 889, 889, 920, + 889, 3376, 1787, 947, 1787, 1406, 1407, 953, 2416, 1847, + 3377, 1602, 2420, 525, 956, 2422, 1699, 525, 525, 1700, + 982, -608, 943, 1195, 1577, 1605, 46, 525, 525, 525, + 3348, 2733, 525, 957, 3378, 2942, 2802, 2741, 1619, 116, + 1787, 959, 921, 536, 2143, 2375, 23, 2376, 1848, 1147, + 1148, 749, 1150, 1571, 1152, 952, 819, 2719, 819, 1815, + 2148, 1899, 1790, 941, 1900, 838, 958, 819, 2519, 852, + -608, 2149, 2144, 1475, 912, 2811, -1294, 1568, 913, 1482, + 1472, 1480, 969, 3253, 2943, 1485, 942, 2564, 1306, 1568, + 987, 1048, 1049, 1050, 989, 2022, 1053, 1306, 2023, 1007, + 2047, 968, 2944, 2048, 988, 3130, 23, 3379, 945, 2342, + 541, 2411, 2343, 2449, 2412, 2565, 2450, -2070, -2070, 1568, + 3380, 1306, -2071, -2071, 2495, 943, 1568, 2496, 2471, 1787, + 2472, -2101, -2101, -2101, 1850, 1949, 1950, 1951, 1952, 1953, + 1954, 998, 2498, 1571, 2592, 2496, 2562, 2559, 2560, 2671, + 990, 1854, 2672, 1855, 1857, 2677, 1858, 993, 2678, 719, + 944, 996, 1847, 2744, 1439, 1439, 2023, 1568, 719, 922, + 1439, 1568, 2796, 542, 1887, 2808, 2803, 1568, 2496, 2809, + 923, 3084, 2048, -2072, -2072, 981, 2665, 2145, 2667, 26, + 27, 28, 2146, 2812, 1009, 2814, 2813, 2147, 2813, 997, + 1568, 1848, 719, 2945, -2075, -2075, 3597, 525, 77, 784, + 2090, 945, 2946, 978, 999, 924, 1025, 1909, 2896, 869, + 2615, 2897, 3053, -2076, -2076, 2412, 3584, 3560, 3585, 3054, + 3077, 3085, 2343, 3078, 3086, 2566, 1849, 2473, 925, 2474, + 2567, 1217, 3572, -2077, -2077, 3146, 3013, 1218, 2048, 26, + 27, 28, 1026, 2630, 1461, 1472, 33, 525, 525, 1468, + 1469, 1470, 1000, 525, 3281, 525, 926, 2048, 1473, 3610, + 525, 525, 525, 525, 2714, 2668, 1491, 2670, 1028, 3282, + 1495, 3314, 2496, 1001, 2048, 525, 525, 1850, 523, 2962, + 823, 3030, 2955, 38, 525, 3321, 525, 3608, 2023, 525, + 3331, 2919, 3609, 3332, 525, 1315, 525, 525, 3364, 525, + 1002, 2412, 2954, 525, 2963, 1041, 33, 523, 1052, 523, + 817, 3381, 523, 1046, 3382, 3365, 40, 523, 2343, 810, + 523, 810, 523, 1051, 810, 3398, 523, 43, 2048, 810, + 3459, 3040, 810, 2412, 810, 1054, 2833, 2834, 810, 817, + 2148, 817, 1219, 38, 817, 546, 2918, 972, 2920, 817, + 3471, 2149, 817, 3472, 817, -2078, -2078, 1571, 817, 1999, + 1230, 2000, 3497, 3541, 2002, 3498, 3472, 1055, 3582, 2006, + 909, 3472, 2009, 550, 2010, 1151, 40, 3419, 2014, 3420, + 1231, 1025, 46, 2568, 1189, 1167, 1191, 43, 1619, 525, + 525, 2822, 2824, 2825, 2569, 2820, 2050, 1032, 525, 525, + 2183, 1615, 1174, 2052, 2053, 2056, 525, 2821, 2823, 821, + 77, 2057, 1175, 525, 2819, 1177, 1474, 1026, -2080, -2080, + 2054, -2081, -2081, 2080, 2081, 2082, 1232, 2083, 2084, 2085, + 2086, 2087, 2088, 1481, -2082, -2082, 1181, 541, 1178, 719, + 525, 1182, 46, 1028, 525, 1439, 1179, 525, -2083, -2083, + 2238, 2239, 1571, 525, 525, 525, 525, 525, 525, 525, + 525, 719, -1358, 1217, 1209, 525, 525, 525, 1190, 1218, + 525, 1212, 819, 1214, 525, 1215, 2129, 525, 525, 525, + 525, 525, 525, 525, 525, 525, -2084, -2084, 525, 1216, + 523, 1228, 2754, -2085, -2085, 525, 1229, 1306, 1246, 1220, + 542, 819, 2184, 819, 1250, 982, 819, -2086, -2086, 2219, + 1568, 819, -2087, -2087, 819, 525, 819, 869, -2089, -2089, + 819, 889, 1233, -2090, -2090, -2091, -2091, 3227, -2092, -2092, + 14, 15, 2616, -2093, -2093, -2094, -2094, 1254, 525, 1309, + 2113, 1164, -2096, -2096, 1255, 879, -2098, -2098, 1312, 525, + 525, -2100, -2100, 1313, 2357, 1834, 1835, 1318, 1221, 1320, + -609, 1324, 1222, -660, -660, -609, 3190, -664, -664, -663, + -663, 1234, 1032, 1334, 1219, 1336, 23, 1337, 2864, 2865, + 1344, 1235, 1217, 3186, 3187, 2962, 2746, 2748, 1218, 1571, + 1345, 1474, 1351, 1236, 1223, 1406, 1407, 1354, 719, 1355, + 719, 3568, 3569, 3594, 3595, 1695, 1696, 2635, 2636, 1360, + 1378, 1455, 1458, 2287, 1379, 2291, 880, 1465, 1384, 1442, + 1457, 1476, 1217, 2912, 1477, 1237, 1483, 1484, 1218, 1494, + 2026, 1490, 3244, 3047, 1573, 1496, -609, 1574, -841, -848, + 525, 1576, 1585, 3036, 1306, 46, 1568, 525, 525, -685, + 3065, 3076, 1589, -686, -838, -839, -842, 1599, 1439, 1439, + 1439, 1439, 1439, 1439, -840, 1224, 1439, 1439, 1439, 1439, + 1439, 1439, 1439, 1439, 1439, 1439, 1600, 3559, 1621, 1239, + 3157, 3561, 546, 1631, 972, -609, 3307, 3397, 1306, 1633, + 1678, 1680, 1682, 1219, 881, 1896, 1217, 1897, 1702, 1694, + 1707, 1703, 1218, 1711, 1240, 1713, 719, 549, 1193, 1195, + 550, 1748, 1568, 1306, 525, 1750, 1752, 1230, 2379, 26, + 27, 28, 981, 1242, 1217, 1767, 1786, 1794, 1785, 1787, + 1218, 1220, 1792, 1219, 1793, 1799, 3602, 1231, 1571, 1806, + 1811, 1807, 525, 525, 1821, 525, 113, 1827, 1837, 1838, + 1571, 525, 525, 525, 525, 525, 525, 1839, 1843, 525, + 525, 525, 525, 525, 525, 525, 525, 525, 525, 1852, + 1846, 1853, 1861, 1862, 525, 525, 3080, 1865, 525, 1869, + 1571, 1868, 1871, 1232, 1872, 525, 33, 1571, 1874, 1875, + 1247, 1889, 1888, 2616, 1222, 1893, 3013, 35, 1901, 1926, + 1928, 1929, 1931, 1934, 1957, 1996, 1966, 1219, 1965, 525, + 1973, 1976, 2001, 1998, 525, 2007, 525, 1568, 2011, 37, + 525, 2012, 2013, 38, 3218, 2018, 1248, 2021, 1571, 1579, + 1586, 2024, 1571, 1591, 525, 1219, 1306, 523, 1571, 3547, + 3397, 2025, 2029, 523, 2030, 882, 2061, 2027, 2028, 810, + 1220, 2060, 1060, 1439, 1439, 810, 40, 1639, 2094, 2098, + 2095, 1571, 2102, 2108, 3228, 3229, 2105, 43, 2131, 817, + 2107, 3362, 2109, 525, 525, 817, 2152, 1985, 2151, 1233, + 2154, 2110, 3397, 2178, 44, -540, 2179, 2185, 2197, 2484, + 1220, 2198, 880, 1022, 2218, 2487, 2215, 1224, 1023, 2202, + -540, 3121, 2228, 2891, 2229, -540, 2227, 2253, 45, 1251, + 2230, 525, 2231, 1222, 2232, 525, 2249, 1568, 872, 2254, + 525, 525, 46, 2268, 2270, 2340, 2257, 2269, 1234, 2264, + 2344, 3397, 881, 2350, 2359, 2361, 2362, 2363, 1235, 2365, + 2366, 2380, 3206, 1619, 1372, 1252, 525, 525, 2381, 2262, + 1236, 525, 2364, 1222, 3452, 2383, -540, 1024, 23, 2388, + 2386, 2389, 2390, 2387, 1220, 2392, 2413, 525, 2396, 1439, + 525, 525, 525, 2421, 1962, 1937, -540, 3413, 2451, 1961, + 2458, 2459, 1237, 2460, 2464, 1223, 2488, 2468, 525, 719, + 2469, 2480, 1220, 2486, 523, 525, 2500, 2502, 525, 2507, + 2511, 1568, 2508, 2509, 2512, 2518, 2513, 2514, 2545, 2517, + 2525, 2526, 2531, 2529, 1611, 525, 1224, 2528, 2530, 2532, + 2535, 523, 2533, 2308, 2534, -540, 2558, 1222, 525, 1025, + 2536, 819, 3204, 810, -540, 2555, 1239, 819, 523, 2563, + 2579, 2587, 2598, 985, 2541, 525, 525, 2556, 2570, 2580, + 810, 2315, 2585, 817, 2601, 1222, 1224, 3013, 2586, 2309, + 2603, 1240, 525, 2599, 525, 1026, 2604, 2611, 2609, 2612, + 817, -666, 2622, 2625, -1830, 1043, 2623, 525, 541, 2626, + 1242, 1027, 2629, 2633, 1636, 3279, 2634, 2316, 2639, 1765, + 2892, 1028, 2637, 2642, 2645, 719, 719, 719, 2641, 2664, + 1149, 26, 27, 28, 2666, 2697, 2698, 2699, 1568, 2713, + 2287, 2287, 2287, 2679, 2267, 1372, 2685, 2718, 2686, 2687, + 1814, 2700, 3351, 2712, 2276, 1029, 2279, 2730, 2731, 2290, + 1224, 2735, 2734, 2738, 525, 2294, 2742, 2296, 2751, 872, + 1306, 542, 1568, 1593, 2761, 2769, 2003, 2772, 823, 2775, + 2303, 2779, 2792, 2778, 2793, 2306, 2780, 2804, 1224, 2311, + 2312, 2313, 2314, 2781, 2318, 2319, 2805, 2818, 33, 2829, + 1854, 1030, 1855, 1857, -1830, 1858, 719, 2826, 1031, 982, + 2810, 1571, 2837, 2847, 2836, -540, 2856, 2848, 2935, 2858, + 2877, 1909, 2862, 2886, 2936, 1372, 2905, 2859, 1372, 1372, + 2917, 525, 2872, 2909, 2871, 38, 2950, 2937, 2966, 2883, + 1630, 2879, 2903, 2923, 544, 819, 525, 981, 3057, 2907, + 1032, -1830, 2924, 2930, 1568, 719, 3033, 3034, 3035, 3042, + 3039, 2938, 819, 2939, 3043, 1369, -1830, 3050, 40, 1033, + 1909, -1830, 3051, 3056, 3061, 1412, -1830, 3069, 3070, 43, + 3074, 2343, 3081, 3082, 912, -1830, 3087, 1177, 913, 3109, + -1830, 71, 2113, 525, 3113, 3117, 44, 1568, -540, 3107, + 3127, 3128, 3131, 1315, 3132, 3158, 3165, 3168, 3170, 3177, + -208, 71, 3179, -540, 809, 3402, 523, 3404, -540, 3183, + 45, 3412, -1830, 3184, 1439, 1439, 3185, 3191, 71, 3197, + 3201, 525, 3193, 3192, 2893, 3202, 3211, 871, 1034, 3203, + 3214, 3216, -1830, 2004, 3217, 3221, -2069, 1571, 817, 1158, + -2070, 2940, 872, 546, -2071, 547, 3414, -2072, 3416, -2073, + 3236, 1905, 1907, 3534, 525, 3237, 809, 809, 887, -540, + 525, 525, 3495, 3238, 3252, -2074, 2874, -2075, -2076, -2077, + -2078, 550, 3235, -2080, -2081, 525, -2082, -2083, -2084, -540, + 872, -1830, 71, 3254, -1830, 1632, 3499, -2085, -2086, 3488, + -1830, 525, -2087, -2089, 525, 1635, 525, 1568, -2090, -2091, + -2092, -2093, -2094, 1571, 525, -2095, 3239, 525, 525, 2941, + -2096, -2097, 525, 525, 2942, -2098, -2099, 1685, -2100, 525, + -1311, 3241, 3242, 3250, 3269, 3255, 1690, 3483, -540, 3271, + -1830, 2911, 3257, 3273, 525, 3274, 3277, -540, 3283, 3287, + 3284, 3289, 2050, 3295, 525, 3301, 3298, 3302, 3291, 2052, + 2053, 2056, 3297, 521, 532, -1830, 77, 2057, 3303, 557, + 3306, 3310, 1230, 2943, 525, 557, 2054, 3309, 3313, 807, + 3328, 822, 2895, 3329, 3333, 825, 557, 834, 3336, 3339, + 834, 2944, 1231, 854, 854, 3353, 3341, 854, 3354, -1310, + 557, 557, 3361, 3363, 3369, 3371, 3372, 3385, 3386, 3387, + 819, 3406, 3399, 3400, 3403, 719, 3409, 3415, 3016, 719, + 3421, 719, 1439, 859, 3407, 3441, 3210, 3445, 3447, 3448, + 2287, 807, 807, 525, 3018, 525, 2291, 3464, 1232, 3451, + 1022, 3465, 3466, 3457, 3469, 1023, 3474, 1439, 3476, 3478, + 3161, -1830, 3481, 3482, 3487, 1230, 3485, 854, 3486, 3072, + 3492, -1830, 3494, 541, 854, 557, 854, 854, 854, 1854, + 1896, 1855, 1857, 3496, 1858, 1231, 3501, 3506, 3512, 3513, + 3514, -1830, 3519, -1830, -1830, 2066, 3520, 541, -1358, 3521, + 3045, 3539, 2945, 3529, 3531, 3523, 3533, 2096, -540, 2097, + 3549, 2946, 3552, 3554, 1024, 3570, 3573, 872, 2958, 3550, + 3551, 3587, -1358, 3598, 3592, 525, 3603, 3612, 1571, 3066, + -1830, 1232, 2956, -1830, -1830, -1830, 542, 2115, 3613, 1180, + 2969, 2295, 2957, 2662, 1233, 525, 525, 2965, 3428, 2898, + 525, 3527, 3491, 525, 3596, 2398, 3224, 2753, 1059, 1156, + 542, 1937, 3510, 3580, 3349, 1938, 1939, 3548, 2378, 1940, + 1941, 1942, 3555, 1908, 3574, 1777, 3384, 912, 1568, 2644, + 525, 913, 2669, 3546, 3553, 2934, 1025, 3060, 2640, 23, + 543, 3544, 1891, 1234, 1203, 3019, 2747, 2745, 1439, 2708, + 525, 2958, 1851, 1235, 3278, 2628, 525, 525, 2758, 544, + 1704, 525, 1571, 872, 971, 1236, 525, 2614, 1744, 525, + 525, 1462, 1026, 1463, 525, 1306, 2256, 1233, 525, 3041, + 2783, 2624, 525, 722, 914, 3532, 2224, 3477, 1027, 525, + 2236, 2236, 3405, 2255, 811, 2600, 1059, 1237, 1028, 1937, + 3116, 2492, 3305, 1938, 1939, 523, 1745, 1940, 1941, 1942, + 1429, 2737, 2777, 2776, 2807, 3355, 3226, 810, 545, 1413, + 2407, 2506, 1749, 1415, 1419, -208, 1234, 1420, 1421, 1422, + 3480, 1423, 1029, 525, 2408, 2409, 1235, 817, 3479, 1424, + 723, 525, 545, 1425, 2553, 2831, 2617, 2577, 1236, 2522, + 2959, 1239, 2575, 1204, 1372, 1987, 724, 1464, 3140, 3169, + 525, 2554, 2850, 2884, 1372, 3141, 3467, 1372, 546, 1571, + 547, 986, 1903, 2499, 2338, 1211, 1240, 2193, 1030, 2899, + 1237, 2195, 26, 27, 28, 1031, 0, 548, 2689, 0, + 71, 1439, 546, 549, 972, 1242, 550, 1823, 0, 1943, + 0, 0, 0, 3016, 0, 725, 0, 0, 0, 0, + 0, 548, 0, 0, 0, 726, 0, 549, 0, 0, + 550, 0, 1944, 0, 0, 0, 0, 1032, 727, 0, + 0, 0, 0, 728, 1239, 0, 3260, 0, 0, 0, + 0, 0, 0, 0, 0, 719, 1033, 0, 0, 33, + 0, 0, 0, 0, 0, 0, 0, 23, 0, 1240, + 1909, 0, 729, 1372, 0, 0, 0, 872, 0, 0, + 0, 0, 0, 525, 0, 0, 0, 0, 1242, 0, + 2960, 981, 0, 2961, 525, 1571, 38, 2252, 1638, 0, + 0, 1639, 1945, 0, 3261, 1640, 1641, 0, 0, 819, + 525, 0, 0, 0, 0, 730, 0, 0, 0, 731, + 1944, 0, 0, 0, 0, 1034, 0, 0, 0, 40, + 1205, 0, 0, 0, 0, 0, 1649, 0, 1571, 0, + 43, 0, 0, -2101, 525, 0, 0, 2190, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 44, 0, 1560, + 0, 525, 525, 0, 0, 525, 854, 525, 0, 0, + 1651, 854, 0, 0, 854, 0, 0, 2914, 0, 0, + 2915, 45, 557, 544, 0, 23, 0, 0, 0, 732, + 1945, 0, 525, 0, 0, 46, 2510, 0, 0, 0, + 0, 0, 0, 1787, 733, 0, 0, 2967, 0, 0, + 26, 27, 28, 0, 71, 871, 525, 1439, 0, 2259, + 2261, 0, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 3027, + 3028, 3029, 0, 0, 0, 2561, 0, 0, 0, 734, + 0, 0, 735, 0, 0, 0, 0, 0, 3016, 0, + 0, 0, 0, 736, 0, 991, 737, 0, 0, 0, + 0, 0, 0, 0, 0, 1562, 1003, -2101, 0, 0, + 719, 0, 0, 1019, 738, 0, 0, 33, 2320, 0, + 0, 0, 0, 0, -2101, 1909, 0, 0, 739, -2101, + 525, 2335, 2335, 0, 740, 741, 0, 0, 0, 3367, + 525, 0, 525, 0, 525, 742, 0, 0, 525, 0, + 525, 743, 525, 523, 38, 1946, 1947, 1948, 887, 1949, + 1950, 1951, 1952, 1953, 1954, 0, 525, -2101, 26, 27, + 28, 525, 0, 525, 0, 0, 71, 0, 0, 744, + 0, 525, 0, 1560, 0, 817, 0, 40, 0, 0, + 0, 0, 0, 2594, 719, 0, 0, 0, 43, 525, + 0, 0, 0, 0, 1369, 0, 0, 0, 0, 3434, + 2415, 0, 961, 557, 557, 44, 3425, 0, 3427, 0, + 0, 1059, 1660, 0, 1937, 0, 2620, 2620, 1938, 1939, + 0, 0, 1940, 1941, 1942, 33, 1563, 0, 0, 45, + 0, 0, 0, 1946, 1947, 1948, 525, 1949, 1950, 1951, + 1952, 1953, 1954, 46, 984, 532, 525, 0, 3460, 0, + 521, 0, 854, 0, 0, 0, 0, 0, 525, 0, + 0, 807, 38, 1560, 3463, 1011, 1011, 0, 807, 0, + 0, 1011, 1038, 525, 71, 0, 0, 0, 0, 1562, + 0, 0, 0, 0, 834, 834, 834, 0, 0, 834, + 0, 525, 0, 0, 0, 40, 523, 1106, 1106, 834, + 834, 0, 834, 0, 834, 0, 43, 809, 0, 1003, + 3205, 0, 0, 0, -2101, 525, 854, 0, 809, 0, + 0, 0, 557, 44, 0, 0, 0, 0, 817, 0, + 525, 0, 0, 0, 854, 0, 0, 819, 523, 3016, + 0, 719, 0, 0, 0, 0, 0, 45, 854, 822, + 0, 1638, 0, 1578, 1639, 0, 3434, 0, 1640, 1641, + 0, 46, 0, 0, 525, 1590, 0, 0, 0, 1562, + 817, 0, 0, 0, 0, 0, 0, 0, 525, 525, + 525, 0, 0, 854, 1311, 0, 0, 523, 0, 1649, + 3556, 0, 1617, 0, 0, 1322, -2101, 0, 0, 854, + 854, 854, 854, 0, -1832, 525, 0, 0, 0, 0, + 1563, 0, 0, 0, 0, 1343, 3571, 0, 0, 817, + 0, 0, -2101, 1651, 0, 1944, 0, 0, 0, 1667, + 1668, 1669, 1670, 1671, 1672, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 525, 1011, 1038, 0, + 854, 0, 0, 1436, 1565, 0, 0, 0, 0, 1011, + 1011, 0, 0, 0, 0, 0, 557, 0, 0, 0, + 0, 0, 807, 0, 807, 0, 0, 0, 0, 887, + 887, 0, 887, 807, 0, 0, 0, 1560, 2571, 0, + 819, 0, 0, 557, 0, 1945, 0, 0, 0, 0, + 1563, 0, 2815, 2817, -1832, 0, 1059, 0, 0, 1937, + 1575, 1912, 0, 1938, 1939, 0, 0, 1940, 1941, 1942, + -2101, 0, 0, 0, 0, 0, 0, 0, 1059, 0, + 0, 1937, 819, 0, 2853, 1938, 1939, -2101, 0, 1940, + 1941, 1942, -2101, 0, 0, 0, 0, 0, 0, 0, + 0, -1832, 0, 0, 0, 0, 2854, 1638, 1913, 0, + 1639, 557, 0, 0, 1640, 1641, -1832, 0, 0, 0, + 0, -1832, 0, 0, 2673, 0, -1832, 0, 0, 1914, + -2101, 819, 1560, 0, 0, -1832, 0, 3352, 0, 0, + -1832, 0, 0, 1562, 0, 1649, 0, 1915, 0, 0, + 0, 1916, -2101, 0, 0, 0, 0, 0, 0, 3359, + 3360, 0, 0, 0, 1698, 0, 0, 0, 0, 0, + 0, 0, -1832, 0, 1917, 0, 2705, 1918, 0, 1651, + 557, 557, 0, 3373, 0, 1660, 0, 854, 1565, 0, + 0, 0, -1832, 1919, 2720, 0, 0, 0, 0, 0, + 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, + 1436, 1106, 1106, 0, 0, 0, 0, 0, 0, 1372, + 0, 0, 854, 1776, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 854, 0, 0, 1562, 1369, + 0, -1832, 1566, 0, -1832, 0, 0, 0, 0, 2759, + -1832, 2760, 854, 0, 0, 2765, 854, 2768, 1946, 1947, + 1948, 1824, 1949, 1950, 1951, 1952, 1953, 1954, 0, 1560, + 1944, 0, 0, 0, 1563, 0, -2101, 0, 1565, 0, + 0, 0, 0, 0, 0, 0, 1920, -2101, 0, 0, + -1832, 0, 1944, -2101, 1921, 0, 0, 0, -2101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2763, 0, 0, 0, 0, - 0, 0, 0, 856, 856, 856, 0, 0, 0, 0, - 0, 0, 0, 557, 0, 1429, 0, 557, 0, 0, - 0, 0, 0, 557, 0, 1556, 0, 0, 1053, 0, - 0, 1926, 0, 0, 0, 1927, 1928, 1556, 0, 1929, - 1930, 1931, 0, 856, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2830, 2075, 0, 0, - 0, 0, 0, 0, -2081, 0, 0, 1556, 0, 0, - 0, 0, 1651, 0, 1556, 1652, 1653, 1654, 0, 1655, - 1656, 1657, 1658, 1659, 1660, 1606, 1554, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1429, 1429, 2513, 0, - 0, 0, 1555, 0, 0, 2123, 0, 0, 0, 0, - 0, 0, 1556, 0, 0, 0, 1556, 0, 0, 0, - 0, 2562, 1556, 0, 0, 2864, 0, 0, 0, 0, - 0, 2191, 809, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1556, 0, 856, 0, 809, - 0, 557, 0, 0, 0, 557, 557, 0, 0, 557, - 0, 0, 0, 1829, 1765, 1829, 0, 1873, 0, 0, - 0, 0, -2081, 0, 0, 0, 0, 0, 0, 1655, - 1656, 1657, 1658, 1659, 1660, 0, 557, 0, 2944, 1935, - 1936, 1937, 0, 1938, 1939, 1940, 1941, 1942, 1943, 1552, - 0, 557, 557, 557, 557, 557, 557, 557, 557, 557, - 557, 0, 0, 0, 2691, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1554, 0, 558, 0, 0, 2707, - 2708, 2710, 0, 0, 2352, 0, 0, 0, 0, 0, - 1555, 856, 1933, 0, 2721, 558, 0, 2724, 0, 0, - 0, 0, 0, 1765, 2733, 558, 0, 558, 0, 0, - 558, 0, 0, 0, 0, 0, 558, 0, 558, 0, - 0, 0, 0, 1873, 0, 0, 0, 0, 0, 0, - 0, 558, 0, 1829, 0, 1554, 558, 0, 0, 0, - 558, 558, 558, 558, 1429, 558, 558, 0, 0, 0, - 557, 1555, 0, 0, 0, 0, 870, 856, 856, 856, - 856, 0, 1934, 0, 0, 0, 0, 0, 0, 1429, - 0, 0, 1429, 0, 0, 0, 557, 960, 0, 0, - 0, 0, 0, 0, 0, 3101, 0, 0, 0, 0, - 0, 0, 2770, 2771, 2772, 0, 0, 0, 11, 1432, - 0, 0, 0, 0, 1626, 0, 0, 1627, 0, 0, - 0, 1628, 1629, 3108, 0, 2528, 0, 1626, 0, 0, - 1627, 0, 0, 0, 1628, 1629, 14, 15, -2081, -2081, - -2081, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1554, 0, 1637, 0, 3132, 0, 807, 0, 0, -2081, - 0, 0, 1016, 0, 0, 1637, 1555, 1017, 0, 0, - 3144, 0, 1638, 0, 2191, 0, 0, 0, 0, 0, - 2075, 0, 23, 0, 1626, 0, 1639, 1627, 0, 0, - 0, 1628, 1629, 0, 1765, 0, 0, 0, 0, 1639, - 1829, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 558, 0, 0, 960, 557, 1429, 0, 0, 0, 0, - 0, 856, 1637, 1556, 0, 0, 1018, 0, 0, -2081, - 0, 0, 0, 0, 0, 0, 0, 0, 3195, 0, - 0, 0, 0, 0, 2477, 0, 2882, 0, 1606, 2005, - 1554, 2843, 0, 0, 0, 0, 1639, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1555, 0, 0, 1626, - 0, 0, 1627, 0, 0, 0, 1628, 1629, 1630, 1631, - 1632, 1633, 1634, -2081, 1606, 1935, 1936, 1937, 0, 1938, - 1939, 1940, 1941, 1942, 1943, 0, 1640, 1635, 1019, 0, - -2081, 0, 0, 71, 0, -2081, 1196, 1637, 0, 71, - 1432, 0, 0, 1641, 1638, 0, 3212, 0, 1642, 0, - 1829, 3122, 0, 0, 0, 26, 27, 28, 0, 1554, - 558, 0, 0, 2352, 1020, 2886, 0, 0, 0, 1611, - 3025, 1639, 0, -2081, 0, 1555, 0, 0, 0, 0, - 1021, 3244, 0, -2081, 0, 0, 1645, 0, 1429, 0, - 1022, 1556, 0, 0, 0, 0, 0, 0, 0, 0, - -2081, 0, 0, 0, 1053, -2081, 0, 1926, 0, 0, - 0, 1927, 1928, 0, 3261, 1929, 1930, 1931, 0, 0, - 557, 0, 33, 0, 1023, 0, 0, 557, 1648, 0, - 0, 0, 3118, 35, 0, 0, 3065, 3066, 3067, 3068, - 0, 1648, 0, -2081, 0, 1197, 0, 71, 0, 0, - 0, 0, 1556, 0, 0, 37, 558, 0, 0, 38, - 0, 0, 3289, 0, 0, 0, 1554, 0, 1640, 0, - 1024, 0, 0, 0, 0, 0, 71, 1025, 0, 39, - 0, 0, 1555, 3047, 557, 1641, 0, 0, 0, 557, - 1642, 0, 40, 0, 0, 0, 0, 0, 1648, 0, - 1554, 0, 0, 43, 0, 558, 0, 0, 0, 0, - 0, 2613, 0, 1643, 1644, 557, 1555, 0, 0, 1026, - 44, 0, 0, 0, 0, 0, 0, 0, 1645, 0, - -2081, 1606, 0, 0, 0, 0, 557, 557, 1027, 0, - 1115, 1115, 0, 1650, 45, 0, 0, 0, 0, 0, - 0, 0, 0, 856, 0, 1765, 0, 1556, 46, 0, - 557, 0, 0, 0, 0, 0, 1646, 0, 0, 1647, - 1432, 1432, 0, 0, 856, 0, 1432, 3360, 0, 0, - 0, 0, 1554, 1648, 0, 0, 1649, 0, 0, 0, - 3182, 0, 0, 0, 0, 0, 0, 1429, 1555, 0, - -2081, 557, 1009, 0, 1009, 0, 0, 1028, 809, 0, - 0, 1252, 1198, 0, 0, 1294, 1301, 0, 1933, 0, - 0, 0, 870, 0, 0, 1554, 0, 0, 0, 3144, - 0, 0, 0, 0, 0, 0, 856, 558, -2081, 0, - 0, 1555, 0, 0, 0, 1655, 1656, 1657, 1658, 1659, - 1660, 1651, 0, 0, -2081, -2081, -2081, 1556, 1655, 1656, - 1657, 1658, 1659, 1660, 1053, 0, 856, 1926, 1351, 0, - 0, 1927, 1928, 0, 0, 1929, 1930, 1931, 0, 0, - 0, 0, 0, 0, 0, 1650, 1375, 0, 1934, 0, - 0, 0, 1423, 0, 0, 1425, 0, 0, 1436, 1439, - 1444, 1447, 0, 0, 3261, 0, 0, 0, -2081, 0, - 0, 0, 0, 0, 0, 1655, 1656, 1657, 1658, 1659, - 1660, 0, 0, 0, 0, 0, 3360, 0, 1554, 0, - 0, 0, 0, 0, 0, 0, 1556, 0, 1486, 1294, - 0, 0, 0, 0, 1555, 0, 0, 558, 0, 0, - 0, 558, 0, 1765, 0, 0, 0, 2001, 0, 0, - 1570, 0, 0, 0, 0, 960, 960, 0, 3360, 960, - 0, 0, 0, 0, 0, 0, 0, 1969, 0, 1586, - 0, 0, 0, 0, 0, 0, 71, 0, 557, 0, - 1596, 1597, 1598, 1651, 1603, 1607, 1652, 1653, 1654, 0, - 1655, 1656, 1657, 1658, 1659, 1660, 0, 0, 0, 0, - 1765, 2167, 0, 1919, 0, 0, 0, 3360, 0, 0, - 0, 0, 0, 0, 0, 0, 1606, 0, 0, 1669, + 0, 0, 809, 0, 809, -1832, 1922, 809, 0, 1840, + 0, 854, 809, 0, 0, 809, 0, 809, 0, 0, + 854, 809, 0, 0, 0, 1059, -2101, 0, 1937, 0, + 1945, 1884, 1938, 1939, 0, 1923, 1940, 1941, 1942, 0, + 961, 0, 0, 0, 3123, 961, 0, 557, 557, 0, + 557, 961, 1945, 3148, 0, 0, 0, 0, 0, 1563, + 0, 0, 0, 859, 0, 1562, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1660, 0, 0, 0, -2101, 0, 0, 0, 0, + 0, -1832, 1667, 1668, 1669, 1670, 1671, 1672, 0, 0, + 0, -1832, 0, 0, 71, 3540, 0, 0, 1560, 0, + 0, 0, 0, 0, 0, 0, 1566, 0, 0, 0, + 1560, -1832, 0, -1832, -1832, 0, 0, 1567, 0, 0, + 1436, 1436, 0, 0, 0, 0, 1436, 0, 521, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1560, 1011, 0, 557, 1980, 0, 0, 1560, 1106, 1106, + -1832, 854, 0, -1832, -1832, -1832, 0, 807, 0, 807, + 0, 0, 807, 23, 0, 0, 0, 807, 0, 1106, + 807, 0, 807, -2101, 0, 2139, 807, 0, 557, 1372, + 557, 0, 1565, 0, 1372, 0, 1563, 0, 1560, 0, + 3009, 0, 1560, 0, 0, 0, 1566, 0, 1560, 0, + 0, 0, 0, 0, 1562, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1562, 0, 0, 0, + 0, 1560, 0, 2705, 0, 0, 0, 0, 0, 1944, + 0, 1905, 1907, 1946, 1947, 1948, 0, 1949, 1950, 1951, + 1952, 1953, 1954, 887, 0, 0, 1562, 0, 0, 0, + 0, 0, 0, 1562, 0, 1946, 1947, 1948, 0, 1949, + 1950, 1951, 1952, 1953, 1954, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1565, 0, 0, + 0, -2101, 0, 0, 0, 2089, 0, 0, 1667, 1668, + 1669, 1670, 1671, 1672, 1562, 3426, 0, 557, 1562, 1945, + 0, 1567, 0, 0, 1562, 0, 26, 27, 28, 0, + 0, 0, 0, 0, 0, 853, 0, 0, 0, 861, + 0, 0, 0, 0, 0, 0, 0, 1562, 0, 0, + 0, 0, 0, 0, 0, 1563, 0, 961, 0, 0, + 1436, 0, 0, 0, 0, 0, 0, 1563, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1638, 0, + 0, 1639, 0, 0, 0, 1640, 1641, 0, 1106, -2101, + -2101, -2101, 0, 33, 0, 0, 0, 1563, 0, 897, + 2360, 0, 0, 2191, 1563, 854, 900, 854, 903, 0, + 907, 1567, 71, 0, 0, 0, 1649, 854, 3167, 2207, + 0, 0, 0, 1650, 0, 0, 0, 0, 0, 0, + 38, 1436, 0, 0, 1565, 0, 0, 0, 0, 0, + 1566, 0, 0, 0, 0, 1563, 0, 0, 0, 1563, + 1651, 0, 0, 0, 0, 1563, 854, 0, 557, 0, + 0, 0, 0, 40, 0, 0, 1905, 1907, 0, 0, + 2258, 2260, 0, 0, 43, 0, 1776, 557, 1563, 1372, + 0, 0, 0, 0, 0, 0, 0, 557, 2277, 557, + 2281, 44, 557, 0, 0, 0, 0, 0, 557, 0, + 557, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 961, 557, 0, 45, 0, 961, 557, 0, + 0, 0, 557, 557, 557, 557, 0, 557, 557, 46, + 0, 0, 1946, 1947, 1948, 1566, 1949, 1950, 1951, 1952, + 1953, 1954, 809, 0, 2339, 0, 0, 1652, 809, 0, + 0, 0, 1322, 0, 854, 854, 854, 854, 854, 0, + 0, 1560, 0, 0, 1653, 0, 0, 0, 0, 1654, + 0, 0, 0, 0, 0, 2368, 0, 0, 0, 0, + 0, 0, 0, 1565, 0, 0, 3256, 0, 0, 0, + 0, 0, 0, 0, 2391, 1565, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1657, 0, 0, + 0, 0, 0, 1369, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1565, 0, 0, 0, 0, + 0, 0, 1565, 0, 0, 1567, 0, 0, 0, 0, + 0, 0, 0, 0, 1436, 1436, 1436, 1436, 1436, 1436, + 0, 0, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, + 1436, 1436, 1660, 0, 0, 0, 0, 1562, 0, 0, + 0, 0, 1566, 1565, 0, 0, 0, 1565, 0, 1617, + 0, 0, 557, 1565, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 854, 1560, 0, 2139, + 3326, 0, 0, 0, 0, 0, 1565, 807, 0, 1059, + 0, 0, 1937, 807, 0, 2581, 1938, 1939, 1022, 557, + 1940, 1941, 1942, 1023, 557, 0, 809, 0, 0, 0, + 1567, 0, 0, 2504, 2504, 0, 0, 3149, 0, 0, + 1372, 0, 1438, 809, 0, 0, 0, 0, 0, 0, + 0, 0, -1847, 0, 0, 558, 0, 0, 0, 0, + 0, 558, 0, 1560, 1662, 808, 0, 0, 0, 0, + 3009, 0, 558, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1024, 0, 0, 0, 558, 558, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1563, 0, + 0, 0, 0, 1562, 0, 557, 0, 0, 0, 0, + 2547, 0, 0, 0, 0, 557, 0, 808, 808, 0, + 0, 1566, 0, 1059, 0, 0, 1937, 0, 0, 0, + 1938, 1939, 0, 1566, 1940, 1941, 1942, 0, 930, 1436, + 1436, 0, 0, 937, 0, 0, 938, 0, 0, 0, + 0, 558, -1847, 0, 1025, 0, 0, 0, 2089, 0, + 0, 0, 0, 1566, 1436, 0, 0, 1567, 1560, 1562, + 1566, 0, 1663, 0, 0, -2101, -2101, -2101, 0, 1667, + 1668, 1669, 1670, 1671, 1672, 0, 0, 0, 0, 0, + 1026, 807, 0, 0, 0, 0, 0, 0, 3453, -1847, + 871, 0, 0, 557, 0, 0, 1027, 0, 807, 0, + 0, 1566, 2207, 0, -1847, 1566, 1028, 0, 0, -1847, + 0, 1566, 0, 1944, -1847, 0, 0, 0, 0, 0, + 0, 0, 0, -1847, 1563, 0, 0, 0, -1847, 0, + 1741, 0, 0, 0, 1566, 0, 0, 0, 0, 1438, + 1029, 0, 557, 0, 0, 1436, 0, 1106, 557, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1560, 0, + -1847, 1206, 0, 0, 1562, 0, 0, 0, 1840, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -1847, 0, 0, 1945, 0, 0, 1030, 0, 0, 0, + 1563, 0, 0, 1031, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1567, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1565, 0, 1567, 0, + 0, 3009, 0, 0, 0, 0, 0, -2101, 0, -1847, + 0, 0, -1847, 0, 0, 1032, 0, 0, -1847, 1840, + 0, 0, 1560, 0, 0, 0, 854, 0, 1567, 0, + 0, 0, 0, 0, 1033, 1567, 0, 1322, 0, 0, + 1840, 854, 854, 854, 1562, 0, 0, 0, 0, 0, + 0, 0, 0, 1617, 557, 0, 854, 0, -1847, 854, + 0, 0, 0, 0, 995, 0, 854, 0, 0, 0, + 0, 0, 961, 0, 0, 1563, 1567, 1945, 0, 0, + 1567, 0, 0, -1847, 0, 0, 1567, 0, 0, 0, + 0, 1617, 0, 0, 1840, 1840, 0, 1840, 0, 0, + 0, 0, 0, 1034, 0, 0, 0, 0, 0, 1567, + 71, 0, 0, 0, 0, 0, 71, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 521, 0, 1562, 1560, + 0, 0, 1565, 0, 0, 0, 0, 0, 0, 0, + 0, 859, 2910, 0, 2782, 0, 0, 0, 0, 1438, + 1438, 0, 854, 854, 854, 1438, 0, 0, 0, 0, + 1210, 0, 557, 1560, 1436, 0, 557, 0, 0, -1847, + 0, 0, 557, 0, 0, 1563, 1946, 1947, 1948, -1847, + 1949, 1950, 1951, 1952, 1953, 1954, 0, 0, 0, 0, + 0, 0, 854, 0, 0, 1310, 0, 0, 1565, -1847, + 0, -1847, -1847, 0, 0, 0, 2089, 0, 0, 0, + 0, 1326, 1328, 1331, 1333, 0, 0, 557, 0, 0, + 0, 557, 0, 0, 71, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1566, 1562, 0, 0, -1847, 0, + 0, -1847, -1847, -1847, 0, 1560, 0, 0, 0, 0, + 1436, 1436, 0, 71, 0, 0, 0, 0, 0, 1563, + 3071, 0, 1431, 0, 0, 0, 0, 0, 558, 1562, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2888, + 0, 0, 0, 0, 0, 2207, 0, 0, 1560, 0, + 1946, 1947, 1948, 0, 1949, 1950, 1951, 1952, 1953, 1954, + 0, 854, 0, 1565, 0, 557, 0, 1106, 1617, 557, + 557, 0, 0, 557, 0, 0, 0, 1840, 1776, 1840, + 0, 1884, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 557, 0, 2968, 0, 0, 0, 0, 0, 0, 0, + 0, 1562, 0, 0, 0, 557, 557, 557, 557, 557, + 557, 557, 557, 557, 557, 0, 1563, 0, 0, 0, + 1566, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2368, 0, + 809, 0, 0, 0, 1562, 854, 0, 0, 1560, 0, + 1563, 0, 0, 1565, 871, 1638, 0, 1776, 1639, 0, + 0, 0, 1640, 1641, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1884, 0, 1567, + 0, 0, 0, 0, 0, 0, 1566, 1840, 0, 0, + 2226, 0, 0, 1649, 0, 0, 0, 0, 1436, 0, + -2101, 0, 0, 0, 557, 0, 0, 0, 0, 558, + 558, 854, 854, 854, 854, 0, 0, 0, 0, 0, + 0, 0, 0, 1436, 0, 0, 1436, 1651, 0, 0, + 557, 961, 1563, 0, 1768, 0, 0, 1565, 0, 3125, + 0, 0, 0, 0, 0, 0, 0, 1795, 0, 0, + 0, 0, 0, 0, 1562, 0, 0, 0, 0, 0, + 0, 0, 557, 0, 0, 0, 0, 808, 1820, 3133, + 557, 0, 0, 0, 2547, 1563, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1566, 2863, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3162, 0, 807, 0, 0, 0, 0, + 0, 0, 1106, 0, 0, 1567, 0, 0, 71, 3174, + 0, 0, 0, 2207, -2101, 0, 0, 0, 558, 2089, + 0, 0, 0, 1845, 0, 0, 0, 0, 0, 0, + 0, -2101, 1864, 1776, 1565, 0, -2101, 0, 0, 1840, + 0, 0, 0, 0, 0, 0, 0, 0, 1617, 0, + 0, 0, 961, 557, 1436, 0, 0, 0, 0, 0, + 854, 0, 0, 0, 0, 0, 0, 0, 1565, 0, + 0, 1567, 0, 0, -2101, 1563, 0, 3225, 0, 0, + 0, 1566, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1438, 1438, 1438, 1438, 1438, 1438, 1560, + 0, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, + 1438, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1660, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1565, 0, 0, 0, 0, 3243, 0, 0, 0, 1840, + 0, 0, 1456, 0, 0, 1566, 0, 0, 808, 0, + 808, 0, 2368, 1994, 0, 0, 1567, 0, 0, 808, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1493, + 3275, 0, 0, 1565, 0, 0, 0, 1436, 0, 0, + 0, 0, 0, 71, 0, 1562, 0, 0, 0, 1638, + 0, 0, 1639, 0, 0, 0, 1640, 1641, 1642, 1643, + 1644, 1645, 1646, 3292, 3391, 0, 0, 0, 0, 557, + 0, -2101, 0, 0, 0, 0, 557, 1647, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1649, 0, 0, + 0, 0, 0, 3311, 1650, 0, 0, 1622, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1566, 0, 0, 0, 1567, 3323, 0, 0, + 71, 1651, 71, 1638, 0, 0, 1639, 0, 1438, 1438, + 1640, 1641, 1642, 1643, 1644, 1645, 1646, 0, 0, 557, + 0, 0, 0, 1565, 557, 0, 1566, 0, 0, 0, + 0, 1647, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1649, 71, 0, 0, 0, 558, 558, 1650, 0, + 557, 14, 15, 0, 0, 0, 1563, 0, 71, -2101, + 0, 0, 0, 0, 0, 0, 1667, 1668, 1669, 1670, + 1671, 1672, 557, 557, 0, 1651, 0, 0, 0, 0, + 1567, 0, 0, 0, 0, 0, 0, 0, 0, 854, + 0, 1776, 0, 0, 0, 0, 557, 23, 1652, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1566, 0, + 854, 0, 0, 3394, 0, 1653, 0, 0, 0, 0, + 1654, 0, 0, 0, 1438, 0, 0, 2192, 0, 2194, + 0, 0, 0, 1436, 0, 1106, 0, 557, 1011, 2204, + 1011, 0, 0, 1655, 1656, 557, 0, 0, 0, 0, + 0, 1566, 0, 0, 0, 0, 0, 0, 1657, 0, + 0, 0, 0, 0, 1106, 0, 0, 0, 3174, 0, + 0, 0, 1652, 0, 0, 854, 0, 0, 2241, 0, + 0, 0, 0, 0, 71, 0, 0, 1567, 0, 1653, + 0, 0, 0, 0, 1654, 0, 1658, 0, 0, 1659, + 0, 0, 0, 0, 0, 854, 0, 0, 0, 0, + 71, 0, 0, 1660, 0, 0, 1661, 1655, 1656, 0, + 0, 1567, 0, 558, 558, 0, 558, 0, 0, 0, + 0, 0, 1657, 0, 0, 0, 0, 0, 0, 0, + 26, 27, 28, 3292, 0, 0, 0, 0, 0, 0, + 1638, 1106, 0, 1639, 0, 0, 0, 1640, 1641, 0, + 0, 1566, 0, 0, 0, 0, 3394, 0, 0, 0, + 1658, 0, 0, 1659, 0, 0, 2351, 2352, 2354, 2355, + 2356, 0, 0, 0, 1565, 0, 0, 1660, 1649, 0, + 1661, 0, 0, 1776, 0, -2101, 0, 0, 0, 0, + 0, 0, 0, 1567, 0, 961, 961, 33, 3394, 961, + 0, 0, 0, 0, 0, 1662, 0, 1980, 35, 0, + 0, 0, 1651, 0, 0, 0, 0, 0, 557, 558, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1556, 0, 0, 0, 1486, 1486, 0, - 0, 0, 0, 0, 960, 0, 0, 1432, 0, 0, - 0, 0, 0, 0, 0, 0, 1210, 0, 0, 2191, - 0, 0, 1211, 0, 0, 0, 0, 1556, 1933, 0, - 1223, 0, 0, 1708, 0, 558, 0, 1724, 1729, 558, - 558, 0, 3334, 558, 0, 0, 0, 0, 1115, 1115, - 1224, 1935, 1936, 1937, 0, 1938, 1939, 1940, 1941, 1942, - 1943, 1053, 0, 3358, 1926, 0, 0, 0, 1927, 1928, - 558, 0, 1929, 1930, 1931, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 558, 558, 558, 558, 558, - 558, 558, 558, 558, 558, 0, 1225, 0, 1934, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1294, 1556, - 0, 0, 0, 0, 0, 0, 0, 1294, 0, 0, - 0, 0, 0, 0, 71, 3397, 0, 1212, 0, 0, - 0, 0, 0, 0, 0, 1554, 0, 0, 0, 0, - 0, 1294, 0, 0, 0, 3357, 0, 0, 0, 0, - 0, 1555, 1556, 0, 0, 3423, 0, 0, 0, 0, + 37, 0, 0, 808, 38, 808, 1567, 0, 808, 0, + 1776, 0, 0, 808, 0, 0, 808, 3394, 808, 0, + 0, 0, 808, 0, 2015, 0, 2019, 0, 0, 0, + 1386, 1387, 0, 0, 0, 0, 0, 40, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2866, 43, 1662, + 0, 0, 0, 0, 961, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 44, 0, 0, 0, 2207, + 0, 1388, 1389, 0, 0, 1390, 1391, 1638, 2475, -2101, + 1639, 0, 0, 1663, 1640, 1641, 1664, 1665, 1666, 45, + 1667, 1668, 1669, 1670, 1671, 1672, -2101, 0, 0, 0, + 0, -2101, 0, 46, 2527, 0, 0, 0, 0, 1438, + 1438, 0, 0, 0, 0, 1649, 1567, 0, 0, 0, + 0, 0, -2101, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1121, 1121, 0, 0, 0, -2101, + 0, 0, 0, 2100, 0, 0, 0, 0, 0, 1651, + 0, 1392, 1393, 0, 0, 0, 0, 1663, 0, 0, + 1664, 1665, 1666, 0, 1667, 1668, 1669, 1670, 1671, 1672, + 0, 0, 0, 0, 0, 0, 0, 1930, 0, 0, + 0, 0, 1566, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1660, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1259, 0, 0, 0, 1301, + 1308, 0, 0, 0, 2867, 1394, 1395, 1396, 1397, 1398, + 1399, 1400, 1401, 0, 0, 1402, 1403, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -2101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2001, 0, 0, 0, 0, 0, - 0, 0, 1226, 0, 0, 0, 0, 0, 71, 0, - 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2477, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1432, 1432, 1432, 1432, 1432, 1432, 0, 1916, 1432, 1432, - 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 0, 0, - 71, 1227, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1228, 0, 0, 1053, 1556, 71, 1926, 0, 0, - 0, 1927, 1928, 1229, 0, 1929, 1930, 1931, 0, 0, - 0, 0, 0, 0, 0, -2081, 0, 0, 0, 0, - 0, 0, 3119, 0, 1213, 0, 0, 0, 0, 0, - 1444, 0, 1444, 1444, 0, 1230, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1115, 1115, 0, 0, 0, - 0, 1935, 1936, 1937, 0, 1938, 1939, 1940, 1941, 1942, - 1943, 0, 1115, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1358, -2101, 0, 0, 0, 0, -2101, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1382, 0, 0, 0, 558, 0, 1430, 0, 0, 1432, + 0, 0, 1443, 1446, 1451, 1454, -2101, 0, 0, 1404, + 1405, 0, 0, 558, 0, 0, -2101, 1438, 0, 0, + 0, 0, 0, 558, 0, 558, 0, 0, 558, 0, + 0, 0, 0, 0, 558, 0, 558, 0, 0, 0, + 0, 0, 3110, 0, 0, 0, 0, 1497, 1301, 558, + 1406, 1407, 0, 0, 558, 0, 0, 0, 558, 558, + 558, 558, 0, 558, 558, 1637, 0, 0, 0, 1581, + 1638, 1660, 0, 1639, 0, 0, 0, 1640, 1641, 1642, + 1643, 1644, 1645, 1646, 0, 0, 0, 1567, 1597, 0, + 0, 0, 3139, 0, 0, 0, 0, 0, 1647, 1607, + 1608, 1609, 1648, 1614, 1618, 0, 0, 0, 1649, 0, + 0, 0, 0, 0, -2101, 1650, 0, 0, 0, 0, + 0, 1667, 1668, 1669, 1670, 1671, 1672, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1681, + 0, 0, 1651, 0, 0, 0, 1408, 1409, 2710, 0, + 0, 0, 0, 0, 0, 0, 0, 1497, 1497, 0, + 0, 0, 0, 2726, 2727, 2729, 0, 0, 0, 0, + 1410, 1411, 0, -2101, 0, 0, 0, 0, 2740, 0, + 0, 2743, 0, 1438, 0, 0, 0, 0, 2752, 0, + 2032, 0, 1638, 1719, 0, 1639, 0, 1735, 1740, 1640, + 1641, 1642, 1643, 1644, 1645, 1646, 0, 1638, 1121, 1121, + 1639, 0, 11, 0, 1640, 1641, 0, 0, 558, 0, + 1647, 0, 0, 0, 2843, 0, 0, 0, 0, 0, + 1649, 0, 0, 0, 0, 0, 0, 1650, 0, 1652, + 14, 15, 0, 808, 0, 1649, 0, 0, 0, 808, + 0, 0, -2101, 0, 0, 2491, 1653, 0, 0, 0, + 2019, 1654, 0, 0, 1651, 0, 0, 0, 1301, 0, + 0, 0, 0, 0, 2789, 2790, 2791, 1301, 0, 1651, + 0, -2101, 0, 0, 1655, 1656, 23, 0, 1667, 1668, + 1669, 1670, 1671, 1672, 0, 0, 0, 0, 0, 1657, + 0, 1301, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1638, 0, 0, 1639, 0, 0, 1438, 1640, 1641, 1642, + 1643, 1644, 1645, 1646, 0, 0, 0, 1658, 0, 0, + 1659, 2100, 0, 0, 3152, 0, 0, 0, 1647, 0, + 0, 1622, 0, 0, 1660, 0, 0, 1661, 1649, 0, + 0, 1652, 0, 0, 0, 1650, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -2101, 0, 1653, 0, + 0, 0, 0, 1654, 0, 0, 0, 1927, 0, 0, + 0, 0, 1651, -2101, 0, 0, 0, 0, -2101, 0, + 0, 0, 0, 0, 0, 0, 1655, 1656, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1657, 0, 2906, 0, 0, 0, 808, 0, 26, + 27, 28, 0, 0, 0, 0, -2101, 0, 0, 558, + 0, 0, 0, 0, 808, 0, 0, 0, 0, 0, + 1451, 0, 1451, 1451, 0, 0, 1662, 0, 0, 1658, + 0, 0, 1659, 0, 0, 1121, 1121, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1660, 0, 0, 1661, + 0, 0, 0, 0, 0, 0, 1121, 0, 558, 1652, + 0, 1660, 0, 0, 2632, 0, 33, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1653, 35, 0, 0, + 0, 1654, 0, 0, 0, 0, 0, 3049, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, + 0, 0, 0, 38, 1655, 1656, 0, 0, 0, 0, + 0, 0, 3411, 0, 0, 0, 0, 0, 0, 1657, + 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1663, 0, 40, 1664, 1665, 1666, + 0, 1667, 1668, 1669, 1670, 1671, 1672, 43, 1662, 0, + 0, 0, 0, 3089, 3090, 3091, 3092, 1658, 2064, 0, + 1659, 0, 0, -2101, 44, 0, 2067, 0, 0, 0, + 0, 0, 0, 0, 1660, 0, 0, 1661, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, + 558, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2112, 0, 46, 0, 0, 0, 0, 2116, 0, 0, + 0, 0, 0, 2120, 2121, 2122, 2123, 2124, 2125, 2126, + 2127, 0, 0, 0, 0, 2136, 2137, 0, 0, 0, + 2150, 0, 0, 0, 2153, 0, 0, 2161, 2162, 2163, + 2164, 2165, 2166, 2167, 2168, 2169, 0, 0, 2170, 0, + 0, 0, 0, 0, 0, 1121, 1663, 1301, 0, 1664, + 1665, 1666, 0, 1667, 1668, 1669, 1670, 1671, 1672, 0, + 0, -2101, 0, 2106, 0, 2196, 1662, 0, 1667, 1668, + 1669, 1670, 1671, 1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 558, 0, - 0, 0, 0, 1231, 0, 1934, 0, 1215, 0, 1232, + 0, 0, 558, 0, 0, 0, 0, 0, 2015, 1608, + 1609, 0, 3212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1233, 0, 0, 0, 0, 1234, - 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1235, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 71, 0, 0, - 1432, 1432, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1626, 0, 2050, 1627, 0, 0, 0, 1628, - 1629, 0, 2053, 1632, 1633, 1634, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1217, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1637, 0, 0, 0, 0, 0, 0, 1638, 1933, 0, - 0, 0, 2100, 0, 0, 0, 0, 0, 2104, 2105, - 2106, 2107, 2108, 2109, 2110, 2111, 0, 0, 0, 0, - 2120, 2121, 0, 0, 1639, 2134, -46, 0, 0, 2137, - 0, 0, 2145, 2146, 2147, 2148, 2149, 2150, 2151, 2152, - 2153, 0, 1556, 2154, 3269, 0, 0, 0, 1, 0, - 1115, 2477, 1294, 0, 0, 0, 1432, 0, 2, 0, - 3, 4, 0, 0, 0, 0, 0, 0, 1934, 0, - 0, 2180, 0, 5, 0, 0, 0, 0, 6, 0, - 0, 0, 0, 0, 0, 0, 0, 7, 1935, 1936, - 1937, 0, 1938, 1939, 1940, 1941, 1942, 1943, 0, 0, - 0, 8, 0, 0, 0, 1597, 1598, 0, 558, 0, - 9, 0, 10, 558, 0, 0, 0, 0, 0, 0, - 0, 1640, 0, 0, 11, 0, 12, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 13, 1641, 558, - 0, 0, 0, 1642, 0, 0, 0, 0, 0, 0, - 0, 0, 14, 15, 16, 0, 0, 0, 0, 0, - 558, 558, 0, 17, 0, 0, -2081, -2081, 0, 18, - 0, 0, 0, 0, 0, 0, 0, 19, 0, 20, - 21, 1645, 0, 0, 558, 0, 0, 1433, 0, 0, - 0, 0, 0, 0, 22, 0, 2306, 0, 23, 0, - 1294, 0, 1625, 2316, 2317, 0, 0, 1626, 0, 0, - 1627, 0, 0, 0, 1628, 1629, 1630, 1631, 1632, 1633, - 1634, 0, -2081, 0, 24, 558, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1635, 1648, 0, 0, 1636, - -1445, 0, 0, 0, 1294, 1637, 0, 0, 0, 0, - 0, 0, 1638, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 25, 0, 0, 1351, - 2383, 0, 0, 0, 0, 0, 0, 0, 0, 1639, - 0, 1935, 1936, 1937, 0, 1938, 1939, 1940, 1941, 1942, - 1943, 0, 0, 0, 0, 0, 0, 0, 2409, 2410, - 0, 2411, 0, 0, 0, 0, 1663, 0, 0, 0, + 0, 0, 0, 2838, 0, 0, 0, 2100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2437, 2438, 0, 0, 2180, 0, 0, 0, 1650, 0, - 0, 26, 27, 28, 0, 0, 0, 0, 0, 29, - 0, 0, 30, 0, 1663, 0, 0, 0, 0, 0, - 0, 0, 0, 2465, 0, 0, 0, 0, 0, 2471, - 0, 0, 0, 0, 0, 0, 1640, 0, 1432, 1432, - 1016, 0, 0, 31, 0, 1017, 0, 1486, 1433, 1294, - 0, 0, 32, 1641, 0, 0, 0, 0, 1642, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, - 0, 0, 558, 0, 0, 34, 0, 0, 0, 35, - 0, 1643, 1644, 0, 0, 0, 0, 2506, 0, 36, - 0, 0, 0, 0, 0, 0, 1645, 0, 0, 0, - 0, 37, 0, 1663, 1018, 38, 1651, 0, 0, 1652, - 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, - 0, 0, 0, 0, 2523, 39, 0, 2526, 0, 0, - 0, 0, 2532, 2533, 1646, 0, 0, 1647, 40, 0, - 0, 41, 0, 0, 42, 1663, 0, 0, 0, 43, - 0, 1648, 1663, 0, 1649, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, - 0, 1210, 0, 0, 0, 0, 1019, 1211, 2554, 0, - 0, 2557, 0, 2559, 0, 1223, 0, 0, 0, 0, - 45, 0, 0, 0, 0, 0, 0, 0, 0, 2563, - 0, 0, 1663, 0, 46, 1224, 0, -46, 0, 0, - 0, 0, 1020, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1663, 0, 1021, 0, - 0, 0, 0, 0, 0, 0, 1432, 0, 1022, 1708, + 0, 0, 0, 0, 1663, 0, 0, 1664, 1665, 1666, + 0, 1667, 1668, 1669, 1670, 1671, 1672, 0, 0, 0, + 2322, 2106, 0, 0, 1301, 0, 0, 2332, 2333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1225, 0, 1650, 0, 0, 1729, 2152, 0, 0, - 0, 1432, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1023, 0, 1663, 1115, 1663, 0, 1433, 1433, - 0, 1944, 1212, 0, 1433, 0, 0, 1663, 2619, 0, - 1663, 0, 0, 1989, 0, 1663, 0, 0, 1663, 0, - 0, 0, 0, 0, 1626, 0, 0, 1627, 0, 0, - 0, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1024, 0, - 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, - 0, 0, 1635, 0, 0, 0, 2822, 1663, 0, 0, - 0, 0, 1637, 0, 0, 1598, 0, 1226, 0, 1638, - 0, 1294, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1651, 0, 0, 1652, 1653, 1654, 1026, 1655, 1656, - 1657, 1658, 1659, 1660, 0, 0, 1639, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1027, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1227, 1432, 0, 0, - 0, 0, 0, 0, 0, 0, 1228, 0, 0, 0, - 0, 0, 2731, 0, 0, 0, 0, 0, 1229, 0, - 0, 1663, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1626, 0, 0, 1627, 1663, 0, 1213, - 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1663, 1663, 1663, - 1230, 0, 0, 0, 1663, 1028, 0, 0, 1663, 0, - 1990, 1635, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1637, 0, 1640, 0, 0, 0, 0, 1638, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1641, 0, 0, 0, 0, 1642, 0, 0, 2281, 0, - 0, 0, 1215, 0, 1232, 1639, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1643, 1644, - 1663, 0, 0, 0, 0, 0, 0, 0, 0, 1233, - 0, 0, 0, 1645, 2282, 0, 0, 0, 0, 0, - 1432, 0, 0, 0, 0, 0, 0, 2809, 1235, 0, - 0, 0, 0, 2811, 2053, 0, 0, 0, 0, 1663, - 0, 0, 0, 0, 0, 2818, 0, 0, 0, 0, - 0, 1646, 0, 0, 1647, 1663, 0, 0, 0, 2828, - 1663, 0, 2831, 0, 2833, 0, 0, 0, 1648, 0, - 0, 1649, 2837, 0, 0, 0, 0, 1944, 0, 0, - 2844, 2845, 1640, 0, 0, 1217, 0, 2852, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1641, - 0, 0, 2861, 0, 1642, 0, 0, 0, 0, 0, - 1626, 0, 2876, 1627, 0, 0, 0, 1628, 1629, 1630, - 1631, 1632, 1633, 1634, 0, 0, 0, 1643, 1644, 0, - 0, 0, 1115, 0, 0, 0, 0, 0, 1635, 0, - 0, 0, 1645, 0, 0, 0, 0, 0, 1637, 0, - 0, 0, 0, 0, 0, 1638, 0, 0, 0, 0, - 1626, 0, 0, 1627, 0, 0, 0, 1628, 1629, 0, - 1650, 1632, 1633, 1634, 0, 0, 0, 0, 0, 0, - 1646, 0, 1639, 1647, 0, 0, 0, 0, 1635, 0, - 0, 2306, 0, 2306, 0, 0, 0, 1648, 1637, 0, - 1649, 0, 0, 0, 0, 1638, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1432, - 0, 0, 1639, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1663, 0, 0, - 0, 0, 0, 0, 0, 1944, 1944, 0, 1433, 1433, - 1433, 1433, 1433, 1433, 0, 0, 1433, 1433, 1433, 1433, - 1433, 1433, 1433, 1433, 1433, 1433, 1944, 0, 1651, 1640, - 0, 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, - 1660, 0, 0, 3081, 3082, 2091, 1641, 0, 0, 1650, - 0, 1642, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 558, 0, 0, 1638, 558, 558, 1639, 1301, 558, + 0, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1643, 1644, 0, 0, 3105, 1640, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1645, - 0, 0, 0, 3109, 0, 0, 1641, 0, 0, 3112, - 3113, 1642, 0, 0, 3114, 0, 0, 0, 0, 3117, - 0, 0, 3120, 3121, 0, 0, 0, 2306, 1294, 0, - 0, 3129, 0, 0, 1643, 1644, 0, 1646, 0, 0, - 1647, 1663, 1115, 0, 1663, 0, 0, 0, 0, 1645, - 0, 0, 0, 0, 1648, 0, 0, 1649, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1651, 0, 0, - 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, - 0, 0, 0, 0, 2091, 0, 3170, 1646, 0, 0, - 1647, 1663, 0, 0, 0, 1663, 1663, 1663, 1663, 1663, - 1663, 1663, 1663, 0, 1648, 0, 0, 1649, 1433, 1433, - 0, 1663, 1663, 3189, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1663, 0, 0, 1663, 0, - 0, 0, 0, 0, 0, 0, 1663, 1663, 1663, 1663, - 1663, 1663, 1663, 1663, 1663, 1663, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1650, 0, 0, 0, - 0, 0, 0, 0, 0, 1626, 0, 0, 1627, 0, - 0, 1663, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, + 0, 0, 1647, 1358, 2399, 0, 558, 0, 0, 0, + 0, 0, 1649, 0, 0, 0, 0, 0, 0, 1650, + 0, 558, 558, 558, 558, 558, 558, 558, 558, 558, + 558, 0, 2425, 2426, 0, 2427, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1651, 0, 0, 0, + 0, 0, 1217, 0, 0, -46, 0, 0, 1218, 0, + 0, 0, 0, 0, 2453, 2454, 1230, 0, 2196, 1217, + 0, 0, 0, 0, 0, 1218, 0, 1, 0, 0, + 0, 0, 0, 1230, 0, 0, 1231, 2, 0, 3, + 4, 0, 0, 0, 0, 0, 0, 0, 0, 2479, + 0, 0, 5, 1231, 0, 0, 2485, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, + 2015, 0, 0, 0, 1497, 0, 1301, 0, 0, 0, + 8, 0, 1232, 0, 0, 0, 0, 0, 0, 9, + 0, 10, 0, 1652, 0, 0, 2491, 0, 0, 1232, + 0, 3368, 0, 11, 0, 12, 0, 0, 0, 0, + 1653, 0, 0, 1219, 2520, 1654, 13, 0, 0, 0, + 0, 0, 3392, 0, 0, 0, 0, 0, 2100, 0, + 1219, 14, 15, 16, 0, 0, 2100, 0, 1655, 1656, + 0, 0, 17, 0, 0, 0, 0, 0, 18, 0, + 0, 2537, 0, 1657, 0, 2543, 19, 0, 20, 21, + 2551, 2552, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 808, 0, 22, 0, 0, 0, 23, 1233, 0, + 0, 0, 0, 0, 0, 0, 0, 3432, 0, 0, + 0, 1658, 0, 0, 1659, 1233, 0, 0, 0, 0, + 0, 0, 0, 24, 0, 0, 0, 2573, 1660, 0, + 2576, 1661, 2578, 0, 0, 0, 0, 3458, 0, -1467, + 0, 0, 0, 0, 0, 0, 0, 1234, 2582, 558, + 0, 0, 0, 0, 0, 0, 0, 1235, 0, 0, + 0, 0, 0, 0, 1234, 25, 0, 0, 0, 1236, + 0, 0, 0, 0, 1235, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1638, 0, 1236, 1639, 1719, 0, + 1220, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 0, 0, + 0, 1237, 0, 0, 0, 1740, 2168, 1220, 0, 0, + 0, 0, 1647, 0, 0, 0, 0, 0, 1237, 0, + 0, 0, 1649, 0, 1121, 0, 0, 0, 0, 1650, + 1662, 0, 0, 0, 0, 0, 0, 2638, 0, 0, + 26, 27, 28, 0, 0, 0, 0, 0, 29, 1238, + 0, 30, 0, 1222, 0, 1239, 1651, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2297, 0, 0, 0, + 1222, 0, 1239, 0, 0, 0, 0, 1440, 0, 0, + 1240, 0, 31, 0, 0, 1241, 0, 0, 0, 0, + 0, 32, 0, 0, 1609, 0, 0, 1240, 0, 1242, + 1301, 0, 2298, 0, 0, 0, 0, 33, 0, 0, + 0, 0, 0, 0, 34, 0, 1242, 0, 35, 0, + 0, 0, 0, 0, 0, 3300, 0, 0, 36, 0, + 0, 0, 2491, 0, 0, 0, 0, 0, 1663, 0, + 37, 1664, 1665, 1666, 38, 1667, 1668, 1669, 1670, 1671, + 1672, 0, 0, 1652, 0, 2424, 1224, 0, 0, 0, + 0, 2750, 0, 0, 39, 0, 0, 0, 0, 0, + 1653, 0, 0, 1224, 0, 1654, 0, 40, 0, 0, + 41, 0, 0, 42, 0, 0, 0, 0, 43, 0, + 0, 0, 0, 0, 0, 558, 0, 0, 1655, 1656, + 558, 1675, 0, 0, 0, 44, 0, 1638, 0, 0, + 1639, 0, 0, 1657, 1640, 1641, 1642, 1643, 1644, 1645, + 1646, 0, 0, 0, 0, 0, 558, 0, 0, 45, + 0, 0, 0, 0, 0, 1647, 0, 0, 0, 0, + 0, 0, 0, 46, 0, 1649, -46, 0, 558, 558, + 1675, 1658, 1650, 0, 1659, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1660, 0, + 0, 1661, 558, 0, 0, 0, 0, 0, 0, 1651, + 0, 0, 0, 0, 1440, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2828, 0, 0, 0, 0, 0, + 2830, 2067, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 558, 0, 2839, 0, 0, 0, 0, + 0, 2100, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2852, 0, 0, 2855, 0, 2857, 0, 0, 1675, + 0, 0, 0, 0, 2861, 0, 0, 0, 0, 0, + 0, 0, 2868, 2869, 0, 0, 0, 0, 0, 2876, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1635, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1637, 0, 0, 1650, 0, 0, 0, - 1638, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1433, 0, 2731, 0, 0, 0, - 0, 0, 722, 0, 0, 0, 0, 1639, 0, 0, + 1662, 0, 0, 0, 2885, 0, 1652, 0, 0, 0, + 0, 1675, 0, 0, 2900, 0, 0, 0, 1675, 0, + 0, 0, 0, 1653, 0, 0, 0, 0, 1654, 0, + 0, 0, 0, 0, 1121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1607, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1651, 0, 0, 1652, 1653, 1654, - 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, 0, 0, - 0, 2408, 0, 0, 0, 0, 2526, 0, 0, 723, - 0, 0, 0, 0, 0, 0, 0, 1663, 3281, 3282, - 0, 0, 3283, 0, 1598, 724, 0, 1663, 1663, 0, - 0, 0, 0, 0, 1651, 0, 0, 1652, 1653, 1654, - 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, 0, 3301, - 0, 0, 0, 0, 1640, 0, 0, 0, 0, 0, + 0, 1655, 1656, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1657, 0, 1675, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 722, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1641, 0, 3313, 725, 0, 1642, 0, 0, 0, - 0, 0, 0, 0, 726, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1663, 0, 0, 727, 0, 1643, - 1644, 0, 728, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1645, 0, 0, 0, 0, 0, - 1663, 1663, 1663, 0, 0, 1944, 1944, 1944, 1944, 1944, - 1944, 729, 0, 0, 1944, 1944, 1944, 1944, 1944, 1944, - 1944, 1944, 1944, 1944, 0, 0, 0, 0, 1663, 1663, - 0, 0, 1646, 0, 0, 1647, 0, 0, 0, 0, - 3081, 0, 0, 0, 3374, 0, 0, 0, 1115, 1648, - 0, 0, 1649, 0, 730, 0, 1663, 0, 731, 3383, - 0, 0, 1663, 0, 2306, 0, 2306, 0, 0, 0, - 1626, 0, 0, 1627, 1115, 0, 0, 1628, 1629, 1630, - 1631, 1632, 1633, 1634, 0, 0, 0, 0, 0, 0, - 0, 0, 3408, 0, 0, 0, 0, 1663, 1635, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1637, 0, - 0, 0, 0, 0, 1663, 1638, 0, 1663, 0, 0, - 0, 0, 0, 1663, 1663, 0, 0, 0, 732, 0, - 0, 1944, 1944, 0, 0, 0, 0, 0, 0, 3433, - 0, 0, 1639, 733, 0, 1663, 1433, 1433, 1663, 3081, - 1663, 1650, 0, 0, 1663, 0, 0, 0, 0, 0, - 1626, 1115, 0, 1627, 0, 0, 0, 1628, 1629, 1630, - 1631, 1632, 1633, 1634, 0, 0, 0, 0, 734, 0, - 0, 735, 0, 0, 0, 0, 0, 0, 1635, 0, - 0, 0, 736, 3476, 0, 737, 0, 0, 1637, 0, - 0, 0, 0, 0, 0, 1638, 0, 0, 0, 0, - 1663, 0, 0, 738, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 739, 0, 0, - 0, 0, 1639, 0, 741, 0, 0, 0, 0, 1640, - 0, 0, 0, 0, 742, 0, 0, 0, 0, 0, - 743, 0, 0, 0, 0, 0, 1641, 0, 0, 1651, - 0, 1642, 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, - 1659, 1660, 0, 0, 0, 0, 2510, 0, 744, 0, - 3530, 3530, 3530, 0, 1643, 1644, 0, 0, 0, 0, - 0, 0, 0, 1626, 0, 0, 1627, 0, 0, 1645, - 1628, 1629, 1630, 1631, 1632, 1633, 1634, 3530, 0, 0, + 0, 0, 1675, 2322, 0, 2322, 0, 0, 0, 0, + 0, 0, 0, 0, 1658, 0, 0, 1659, 1663, 0, + 0, 1664, 1665, 1666, 0, 1667, 1668, 1669, 1670, 1671, + 1672, 1660, 0, 0, 1661, 2524, 0, 0, 0, 0, + 0, 0, 0, 0, 558, 0, 723, 0, 0, 0, + 1675, 0, 1675, 0, 1440, 1440, 0, 1955, 0, 0, + 1440, 0, 724, 1675, 0, 0, 1675, 0, 0, 0, + 0, 1675, 0, 0, 1675, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1635, 1663, 0, 0, 0, 0, 0, 0, 1640, - 0, 1637, 0, 0, 0, 0, 0, 1646, 1638, 0, - 1647, 0, 0, 0, 1433, 0, 1641, 1378, 3530, 820, - 0, 1642, 0, 0, 1648, 0, 0, 1649, 0, 0, - 0, 0, 0, 0, 0, 1639, 0, 0, 0, 0, - 0, 0, 0, 0, 1643, 1644, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1645, + 0, 1638, 0, 0, 1639, 0, 0, 0, 1640, 1641, + 1642, 1643, 1644, 1645, 1646, 3105, 3106, 0, 0, 0, + 0, 725, 0, 0, 0, 0, 0, 1675, 0, 1647, + 0, 726, 0, 0, 0, 0, 0, 0, 0, 1649, + 0, 0, 0, 1662, 727, 0, 1650, 0, 0, 728, + 3129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1663, 0, 1663, 0, 0, 0, 0, 0, 0, 1663, - 0, 0, 1379, 1380, 0, 0, 0, 0, 0, 1663, - 0, 0, 1663, 0, 1663, 0, 0, 1646, 1663, 0, - 1647, 1944, 1944, 0, 0, 1663, 1663, 0, 0, 0, - 0, 0, 0, 1663, 1648, 0, 0, 1649, 0, 0, - 0, 0, 1663, 1381, 1382, 0, 1650, 1383, 1384, 0, - 0, 0, 1640, 0, 0, 0, 0, 1663, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1641, - 0, 0, 0, 0, 1642, 0, 0, 0, 0, 0, + 3138, 0, 0, 1651, 0, 0, 3142, 3143, 729, 0, + 0, 3144, 0, 0, 0, 0, 3147, 0, 0, 3150, + 3151, 0, 0, 0, 2322, 1301, 0, 0, 3159, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1121, + 0, 1675, 0, 1385, 0, 821, 0, 0, 0, 0, + 0, 730, 0, 0, 0, 731, 0, 1675, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1675, 1675, 1675, + 0, 0, 0, 0, 1675, 0, 0, 0, 1675, 0, + 0, 1663, 0, 3200, 1664, 1665, 1666, 0, 1667, 1668, + 1669, 1670, 1671, 1672, 0, 0, 0, 0, 2557, 0, + 1652, 0, 0, 0, 0, 0, 0, 0, 1386, 1387, + 3219, 0, 0, 0, 0, 0, 0, 1653, 0, 0, + 0, 0, 1654, 0, 0, 732, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1386, 1387, 0, 0, 0, + 733, 1675, 0, 0, 0, 1655, 1656, 0, 0, 1388, + 1389, 0, 0, 1390, 1391, 0, 0, 0, 0, 0, + 1657, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 734, 1388, 1389, 735, 1675, + 1390, 1391, 0, 0, 0, 0, 0, 0, 0, 736, + 0, 0, 737, 0, 0, 1675, 0, 0, 1658, 0, + 1675, 1659, 0, 0, 0, 0, 0, 0, 0, 0, + 738, 0, 0, 0, 0, 1660, 0, 1955, 1661, 0, + 0, 0, 0, 2750, 739, 0, 0, 0, 0, 1392, + 1393, 741, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 742, 0, 0, 0, 0, 0, 743, 0, 0, + 1618, 0, 0, 0, 0, 0, 1392, 1393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1433, 0, 1643, 1644, 0, - 0, 0, 0, 0, 0, 0, 1626, 0, 0, 1627, - 0, 0, 1645, 1628, 1629, 1630, 1631, 1632, 1633, 1634, - 0, 0, 0, 1385, 1386, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1635, 0, 1650, 0, 0, 0, - 0, 0, 0, 0, 1637, 0, 0, 0, 0, 0, - 1646, 1638, 0, 1647, 1651, 0, 0, 1652, 1653, 1654, - 0, 1655, 1656, 1657, 1658, 1659, 1660, 1648, 0, 0, - 1649, 2538, 0, 0, 0, 0, 0, 0, 1639, 0, - 0, 0, 0, 0, 0, 0, 0, 1387, 1388, 1389, - 1390, 1391, 1392, 1393, 1394, 0, 0, 1395, 1396, 0, + 0, 0, 0, 0, 0, 744, 0, 0, 0, 0, + 0, 0, 0, 0, 2543, 0, 0, 0, 0, 0, + 0, 0, 0, 1394, 1395, 1396, 1397, 1398, 1399, 1400, + 1401, 3315, 3316, 1402, 1403, 3317, 0, 1609, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1662, 0, 0, + 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 0, 0, + 1402, 1403, 3335, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3347, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1404, 1405, 0, + 0, 0, 0, 0, 0, 0, 0, 1675, 0, 0, + 0, 0, 0, 0, 0, 1955, 1955, 0, 1440, 1440, + 1440, 1440, 1440, 1440, 1404, 1405, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1955, 0, 1406, 1407, + 0, 0, 0, 0, 0, 1663, 0, 0, 1664, 1665, + 1666, 0, 1667, 1668, 1669, 1670, 1671, 1672, 0, 0, + 0, 0, 2770, 0, 3105, 1406, 1407, 0, 3408, 0, + 1638, 0, 1121, 1639, 0, 0, 0, 1640, 1641, 1642, + 1643, 1644, 1645, 1646, 0, 0, 3418, 0, 0, 0, + 0, 2322, 0, 2322, 0, 0, 0, 0, 1647, 0, + 0, 1121, 0, 0, 0, 0, 0, 0, 1649, 0, + 1638, 0, 0, 1639, 0, 1650, 0, 1640, 1641, 3443, + 0, 1644, 1645, 1646, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1408, 1409, 0, 0, 1647, 0, + 0, 0, 1651, 0, 1675, 0, 0, 1675, 1649, 0, + 0, 0, 0, 0, 0, 1650, 0, 0, 1410, 1411, + 0, 1408, 1409, 0, 0, 0, 3468, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3105, 0, 0, 0, + 0, 0, 1651, 0, 0, 1410, 1411, 0, 1121, 0, + 0, 0, 1675, 0, 0, 0, 1675, 0, 0, 0, + 1675, 1675, 1675, 1675, 1675, 1675, 1675, 1675, 0, 0, + 0, 0, 0, 1440, 1440, 0, 1675, 1675, 0, 0, + 0, 3511, 0, 0, 0, 0, 0, 0, 0, 0, + 1675, 0, 0, 1675, 0, 0, 0, 0, 0, 1652, + 0, 1675, 1675, 1675, 1675, 1675, 1675, 1675, 1675, 1675, + 1675, 0, 0, 0, 0, 0, 1653, 0, 0, 0, + 0, 1654, 1638, 0, 0, 1639, 0, 0, 0, 1640, + 1641, 1642, 1643, 1644, 1645, 1646, 1675, 0, 0, 1652, + 0, 0, 0, 0, 1655, 1656, 0, 0, 0, 0, + 1647, 0, 0, 0, 0, 0, 1653, 0, 0, 1657, + 1649, 1654, 0, 0, 0, 0, 0, 1650, 3565, 3565, + 3565, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1655, 1656, 0, 0, 0, 1440, + 0, 0, 0, 0, 1651, 3565, 0, 1658, 0, 1657, + 1659, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1660, 0, 0, 1661, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1944, 1433, 0, - 0, 0, 0, 0, 1651, 0, 0, 1652, 1653, 1654, - 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, 0, 0, - 0, 2751, 1663, 1663, 0, 0, 0, 0, 0, 1650, - 0, 1397, 1398, 0, 0, 1640, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1663, 0, 0, 0, - 1663, 0, 1641, 1663, 1663, 1663, 0, 1642, 1663, 0, - 0, 1663, 1663, 0, 0, 0, 0, 0, 0, 0, - 1663, 0, 1399, 1400, 0, 0, 0, 0, 0, 0, - 1643, 1644, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1645, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3565, 1658, 0, 0, + 1659, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1660, 0, 0, 1661, 0, 0, + 0, 0, 1675, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1675, 1675, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1663, 0, 0, 0, 0, 0, 1944, 0, 0, + 0, 1652, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1653, 0, + 0, 0, 0, 1654, 0, 0, 1662, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1663, 0, 0, 1646, 0, 0, 1647, 1651, 0, 0, - 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, - 1648, 0, 0, 1649, 2816, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1401, 1402, + 0, 0, 0, 0, 0, 0, 1655, 1656, 0, 1675, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1944, - 0, 0, 1403, 1404, 0, 0, 0, 0, 0, 0, + 0, 1657, 0, 0, 0, 0, 1662, 0, 0, 0, + 0, 0, 0, 0, 0, 1675, 1675, 1675, 0, 0, + 1955, 1955, 1955, 1955, 1955, 1955, 0, 0, 0, 1955, + 1955, 1955, 1955, 1955, 1955, 1955, 1955, 1955, 1955, 1658, + 0, 0, 1659, 1675, 1675, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1660, 0, 0, 1661, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1675, + 0, 0, 0, 0, 1663, 1675, 0, 1664, 1665, 1666, + 0, 1667, 1668, 1669, 1670, 1671, 1672, 0, 0, 0, + 0, 2835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1675, 0, 0, 0, 1663, 0, 0, 1664, 1665, 1666, + 0, 1667, 1668, 1669, 1670, 1671, 1672, 1675, 0, 0, + 0, 0, 0, 1675, 0, 0, 0, 0, 0, 0, + 0, 1675, 1675, 0, 0, 0, 0, 0, 0, 1955, + 1955, 0, 0, 0, 0, 0, 0, 0, 1662, 0, + 0, 0, 0, 1675, 1440, 1440, 1675, 0, 1675, 0, + 0, 0, 1675, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1638, 0, 0, 1639, + 0, 0, 0, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1663, 1663, 1663, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1647, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1649, 0, 0, 0, 1675, 0, + 0, 1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1663, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1650, 0, 1663, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1651, 0, + 0, 0, 0, 0, 0, 0, 1663, 0, 0, 1664, + 1665, 1666, 0, 1667, 1668, 1669, 1670, 1671, 1672, 0, + 0, 1638, 0, 2849, 1639, 0, 0, 0, 1640, 1641, + 1642, 1643, 1644, 1645, 1646, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1647, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1649, + 1638, 0, 0, 1639, 0, 0, 1650, 1640, 1641, 1642, + 1643, 1644, 1645, 1646, 0, 0, 0, 0, 1638, 0, + 1675, 1639, 0, 0, 0, 1640, 1641, 0, 1647, 1644, + 1645, 1646, 0, 1651, 0, 1652, 0, 0, 1649, 0, + 0, 0, 1440, 0, 0, 1650, 1647, 0, 0, 0, + 0, 0, 1653, 0, 0, 0, 1649, 1654, 0, 0, + 0, 0, 0, 1650, 0, 0, 0, 0, 0, 0, + 0, 0, 1651, 0, 0, 0, 0, 0, 0, 0, + 1655, 1656, 0, 0, 0, 0, 0, 0, 0, 0, + 1651, 0, 0, 0, 0, 1657, 0, 0, 1675, 0, + 1675, 0, 0, 0, 0, 0, 0, 0, 0, 1675, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1675, 0, 0, 1675, 0, 1675, 0, 0, + 1652, 1675, 0, 1658, 1955, 1955, 1659, 0, 1675, 1675, + 0, 0, 0, 0, 0, 0, 1675, 1653, 0, 0, + 1660, 0, 1654, 1661, 0, 1675, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1652, + 1675, 0, 0, 0, 0, 1655, 1656, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1653, 1652, 0, 0, + 1657, 1654, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1653, 0, 0, 0, 1440, 1654, + 0, 0, 0, 0, 1655, 1656, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1658, 1657, + 0, 1659, 1655, 1656, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1660, 0, 1657, 1661, 0, + 0, 0, 1662, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1658, 0, 0, + 1659, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1660, 1658, 0, 1661, 1659, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1660, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1663, 0, 0, 0, 0, - 0, 0, 0, 0, 1663, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1662, 0, 0, + 1955, 1440, 0, 0, 0, 0, 0, 0, 0, 0, + 1663, 0, 0, 1664, 1665, 1666, 0, 1667, 1668, 1669, + 1670, 1671, 1672, 0, 0, 1675, 1675, 2916, 0, 0, + 0, 0, 0, 0, 0, 0, 1662, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1675, + 0, 0, 0, 0, 1662, 0, 0, 0, 1675, 0, + 0, 0, 1675, 1675, 1675, 0, 0, 1675, 0, 0, + 1675, 1675, 0, 0, 0, 0, 0, 0, 0, 1675, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1651, 0, 0, 1652, 1653, 1654, 0, 1655, 1656, 1657, - 1658, 1659, 1660, 0, 1663, 0, 0, 2825, 0, 0, + 0, 0, 0, 0, 0, 1663, 0, 0, 1664, 1665, + 1666, 0, 1667, 1668, 1669, 1670, 1671, 1672, 0, 0, + 1675, 0, 3153, 0, 0, 0, 1955, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1675, + 0, 0, 0, 0, 1663, 0, 0, 1664, 1665, 1666, + 0, 1667, 1668, 1669, 1670, 1671, 1672, 0, 0, 0, + 0, 3160, 1663, 0, 0, 1664, 1665, 1666, 0, 1667, + 1668, 1669, 1670, 1671, 1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 117, 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1663, 0, 118, - 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, - 128, 0, 0, 0, 0, 0, 1056, 0, 0, 129, - 130, 131, 0, 132, 133, 134, 135, 136, 137, 138, - 139, 1057, 141, 1058, 1059, 0, 144, 145, 146, 147, - 148, 149, 1060, 790, 150, 151, 152, 153, 1061, 1062, - 156, 1663, 157, 158, 159, 160, 791, 0, 792, 0, - 1063, 164, 165, 166, 167, 168, 169, 170, 171, 172, - 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 1064, - 191, 192, 1065, 194, 1066, 195, 0, 196, 197, 198, - 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, - 0, 206, 207, 1067, 209, 210, 0, 211, 212, 213, - 0, 214, 215, 216, 0, 217, 218, 219, 220, 1068, - 222, 223, 224, 225, 226, 227, 793, 1069, 229, 0, - 230, 231, 1070, 233, 0, 234, 0, 235, 236, 0, - 237, 238, 239, 240, 241, 242, 0, 243, 0, 1071, - 1072, 246, 247, 0, 248, 249, 250, 251, 252, 253, - 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, - 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, - 272, 273, 274, 1073, 1074, 0, 1075, 0, 278, 279, - 280, 281, 282, 283, 284, 285, 286, 287, 288, 0, - 0, 289, 290, 291, 292, 0, 293, 294, 295, 296, - 297, 298, 299, 300, 1076, 302, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 1077, 323, 1078, 325, 326, - 327, 328, 1079, 329, 330, 331, 332, 1080, 795, 334, - 1081, 336, 337, 338, 0, 339, 340, 0, 0, 1082, - 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, - 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, - 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, - 375, 376, 377, 0, 378, 379, 380, 381, 382, 1083, - 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, - 402, 403, 404, 405, 406, 1084, 408, 409, 410, 411, - 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, - 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, - 0, 430, 431, 432, 1085, 434, 0, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, - 448, 800, 0, 0, 450, 451, 0, 452, 453, 454, - 455, 456, 457, 458, 0, 459, 1086, 1087, 0, 0, - 462, 463, 801, 465, 802, 1088, 467, 468, 803, 470, - 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, - 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, - 487, 1089, 489, 0, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, - 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, - 512, 513, 514, 515, 516, 517, 518, 519, 520, 1090, - 0, 0, 0, 0, 0, 0, 1091, 1092, 1093, 0, - 0, 0, 0, 1094, 0, 1095, 0, 0, 0, 0, - 1096, 1097, 1098, 1099, 0, 2671, 117, 1050, 820, 1051, - 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, - 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, - 0, 0, 1056, 0, 0, 129, 130, 131, 0, 132, - 133, 134, 135, 136, 137, 138, 139, 1057, 141, 1058, - 1059, 0, 144, 145, 146, 147, 148, 149, 1060, 790, - 150, 151, 152, 153, 1061, 1062, 156, 0, 157, 158, - 159, 160, 791, 0, 792, 0, 1063, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, - 176, 177, 178, 0, 179, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 1064, 191, 192, 1065, 194, - 1066, 195, 0, 196, 197, 198, 199, 200, 201, 0, - 0, 202, 203, 204, 205, 0, 0, 206, 207, 1067, - 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, - 0, 217, 218, 219, 220, 1068, 222, 223, 224, 225, - 226, 227, 793, 1069, 229, 0, 230, 231, 1070, 233, - 0, 234, 0, 235, 236, 0, 237, 238, 239, 240, - 241, 242, 0, 243, 0, 1071, 1072, 246, 247, 0, - 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, - 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, - 0, 267, 268, 269, 270, 271, 272, 273, 274, 1073, - 1074, 0, 1075, 0, 278, 279, 280, 281, 282, 283, - 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, - 292, 0, 293, 294, 295, 296, 297, 298, 299, 300, - 1076, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 1077, 323, 1078, 325, 326, 327, 328, 1079, 329, - 330, 331, 332, 1080, 795, 334, 1081, 336, 337, 338, - 0, 339, 340, 0, 0, 1082, 342, 343, 0, 0, - 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, - 0, 0, 362, 363, 798, 365, 366, 367, 368, 369, - 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, - 378, 379, 380, 381, 382, 1083, 384, 385, 386, 387, - 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, - 397, 398, 399, 400, 0, 401, 402, 403, 404, 405, - 406, 1084, 408, 409, 410, 411, 412, 413, 414, 415, - 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, - 424, 425, 426, 427, 428, 429, 0, 430, 431, 432, - 1085, 434, 0, 435, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, 447, 448, 800, 0, 0, - 450, 451, 0, 452, 453, 454, 455, 456, 457, 458, - 0, 459, 1086, 1087, 0, 0, 462, 463, 801, 465, - 802, 1088, 467, 468, 803, 470, 471, 472, 473, 474, - 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, - 0, 482, 483, 484, 485, 486, 487, 1089, 489, 0, - 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, - 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, - 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, - 516, 517, 518, 519, 520, 1090, 0, 0, 0, 0, - 0, 0, 1091, 1092, 1093, 0, 0, 0, 0, 1094, - 0, 1095, 0, 0, 0, 0, 1096, 1097, 1098, 1099, - 0, 3284, 117, 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1056, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1057, 141, 1058, 1059, 0, 144, 145, - 146, 147, 148, 149, 1060, 790, 150, 151, 152, 153, - 1061, 1062, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 1063, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1064, 191, 192, 1065, 194, 1066, 195, 0, 196, - 197, 198, 199, 200, 201, 14, 15, 202, 203, 204, - 205, 0, 0, 206, 207, 1067, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1068, 222, 223, 224, 225, 226, 227, 793, 1069, - 229, 0, 230, 231, 1070, 233, 0, 234, 0, 235, - 236, 23, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 1071, 1072, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, 0, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1076, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1077, 323, 1078, - 325, 326, 327, 328, 1079, 329, 330, 331, 332, 1080, - 795, 334, 1081, 336, 337, 338, 0, 339, 340, 0, - 0, 1082, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 26, 27, 28, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1083, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 1084, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 33, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 35, 430, 431, 432, 1085, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 37, 0, 450, 451, 38, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1086, 1087, - 0, 0, 462, 463, 801, 465, 802, 1088, 467, 468, - 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 40, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 804, 1089, 489, 0, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 44, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 1090, 0, 45, 0, 0, 0, 0, 1091, 1092, - 1093, 0, 0, 0, 0, 1094, 0, 1095, 3259, 0, - 0, 0, 1096, 1097, 1098, 1099, 117, 1050, 820, 1051, - 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, - 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, - 0, 0, 1056, 0, 0, 129, 130, 131, 0, 132, - 133, 134, 135, 136, 137, 138, 139, 1057, 141, 1058, - 1059, 0, 144, 145, 146, 147, 148, 149, 1060, 790, - 150, 151, 152, 153, 1061, 1062, 156, 0, 157, 158, - 159, 160, 791, 0, 792, 0, 1063, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, - 176, 177, 178, 0, 179, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 1064, 191, 192, 1065, 194, - 1066, 195, 0, 196, 197, 198, 199, 200, 201, 14, - 15, 202, 203, 204, 205, 0, 0, 206, 207, 1067, - 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, - 0, 217, 218, 219, 220, 1068, 222, 223, 224, 225, - 226, 227, 793, 1069, 229, 0, 230, 231, 1070, 233, - 0, 234, 0, 235, 236, 23, 237, 238, 239, 240, - 241, 242, 0, 243, 0, 1071, 1072, 246, 247, 0, - 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, - 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, - 0, 267, 268, 269, 270, 271, 272, 273, 274, 1073, - 1074, 0, 1075, 0, 278, 279, 280, 281, 282, 283, - 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, - 292, 0, 293, 294, 295, 296, 297, 298, 299, 300, - 1076, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 1077, 323, 1078, 325, 326, 327, 328, 1079, 329, - 330, 331, 332, 1080, 795, 334, 1081, 336, 337, 338, - 0, 339, 340, 0, 0, 1082, 342, 343, 0, 0, - 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, 361, 26, 27, - 28, 0, 362, 363, 798, 365, 366, 367, 368, 369, - 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, - 378, 379, 380, 381, 382, 1083, 384, 385, 386, 387, - 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, - 397, 398, 399, 400, 0, 401, 402, 403, 404, 405, - 406, 1084, 408, 409, 410, 411, 412, 413, 414, 415, - 416, 417, 418, 419, 420, 33, 0, 421, 422, 423, - 424, 425, 426, 427, 428, 429, 35, 430, 431, 432, - 1085, 434, 0, 435, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, 447, 448, 800, 37, 0, - 450, 451, 38, 452, 453, 454, 455, 456, 457, 458, - 0, 459, 1086, 1087, 0, 0, 462, 463, 801, 465, - 802, 1088, 467, 468, 803, 470, 471, 472, 473, 474, - 0, 0, 475, 476, 477, 40, 478, 479, 480, 481, - 0, 482, 483, 484, 485, 486, 804, 1089, 489, 0, - 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, - 0, 499, 0, 44, 500, 501, 502, 503, 504, 505, - 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, - 516, 517, 518, 519, 520, 1090, 0, 45, 0, 0, - 0, 0, 1091, 1092, 1093, 0, 0, 0, 0, 1094, - 0, 1095, 0, 0, 0, 0, 1096, 1097, 1098, 1099, - 117, 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, - 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, - 128, 0, 0, 0, 0, 0, 1056, 0, 0, 129, - 130, 131, 0, 132, 133, 134, 135, 136, 137, 138, - 139, 1057, 141, 1058, 1059, 0, 144, 145, 146, 147, - 148, 149, 1060, 790, 150, 151, 152, 153, 1061, 1062, - 156, 0, 157, 158, 159, 160, 791, 0, 792, 0, - 1063, 164, 165, 166, 167, 168, 169, 170, 171, 172, - 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 1064, - 191, 192, 1065, 194, 1066, 195, 0, 196, 197, 198, - 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, - 0, 206, 207, 1067, 209, 210, 0, 211, 212, 213, - 0, 214, 215, 216, 0, 217, 218, 219, 220, 1068, - 222, 223, 224, 225, 226, 227, 793, 1069, 229, 0, - 230, 231, 1070, 233, 0, 234, 0, 235, 236, 23, - 237, 238, 239, 240, 241, 242, 0, 243, 0, 1071, - 1072, 246, 247, 0, 248, 249, 250, 251, 252, 253, - 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, - 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, - 272, 273, 274, 1073, 1074, 0, 1075, 0, 278, 279, - 280, 281, 282, 283, 284, 285, 286, 287, 288, 0, - 0, 289, 290, 291, 292, 0, 293, 294, 295, 296, - 297, 298, 299, 300, 1076, 302, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 1077, 323, 1078, 325, 326, - 327, 328, 1079, 329, 330, 331, 332, 1080, 795, 334, - 1081, 336, 337, 338, 0, 339, 340, 0, 0, 1082, - 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, - 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, 26, 27, 28, 0, 362, 363, 798, 365, - 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, - 375, 376, 377, 0, 378, 379, 380, 381, 382, 1083, - 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, - 402, 403, 404, 405, 406, 1084, 408, 409, 410, 411, - 412, 413, 414, 415, 416, 417, 418, 419, 420, 33, - 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, - 0, 430, 431, 432, 1085, 434, 0, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, - 448, 800, 0, 0, 450, 451, 38, 452, 453, 454, - 455, 456, 457, 458, 0, 459, 1086, 1087, 0, 0, - 462, 463, 801, 465, 802, 1088, 467, 468, 803, 470, - 471, 472, 473, 474, 0, 0, 475, 476, 477, 40, - 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, - 804, 1089, 489, 0, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 0, 0, 499, 0, 44, 500, 501, - 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, - 512, 513, 514, 515, 516, 517, 518, 519, 520, 1090, - 0, 45, 0, 0, 0, 0, 1091, 1092, 1093, 0, - 0, 0, 0, 1094, 0, 1095, 0, 0, 0, 0, - 1096, 1097, 1098, 1099, 1257, 1050, 820, 1051, 1052, 1053, - 1054, 1055, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1675, 1675, 1675, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1675, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1675, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1675, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1675, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1675, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1675, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 117, 1056, 821, 1057, 1058, 1059, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1675, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 1675, 157, 158, 159, 160, + 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 1072, 195, + 0, 196, 197, 198, 199, 200, 201, 14, 15, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 23, 237, 238, 239, 240, 241, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 1085, 329, 330, 331, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 26, 27, 28, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 33, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 35, 430, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 37, 0, 450, 451, + 38, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 40, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 804, 1095, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 44, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 1096, 0, 45, 0, 0, 0, 0, + 1097, 1098, 1099, 0, 0, 0, 0, 1100, 0, 1101, + 3290, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 117, + 1056, 821, 1057, 1058, 1059, 1060, 1061, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 1062, 0, 0, 129, 130, + 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, + 1063, 141, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 1069, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 1072, 195, 0, 196, 197, 198, 199, + 200, 201, 14, 15, 202, 203, 204, 205, 0, 0, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 236, 23, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1077, 1078, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1082, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1083, 323, 1084, 325, 326, 327, + 328, 1085, 329, 330, 331, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 1088, 342, + 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 26, 27, 28, 0, 362, 363, 798, 365, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 403, 404, 405, 406, 1090, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 33, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 35, + 430, 431, 432, 1091, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 800, 37, 0, 450, 451, 38, 452, 453, 454, 455, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 803, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 40, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 804, + 1095, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 44, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 1096, 0, + 45, 0, 0, 0, 0, 1097, 1098, 1099, 0, 0, + 0, 0, 1100, 0, 1101, 0, 0, 0, 0, 0, + 1102, 1103, 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, - 125, 1258, 126, 127, 128, 0, 0, 0, 1259, 0, - 1056, 0, 0, 1260, 130, 131, 0, 132, 133, 134, - 1261, 136, 137, 138, 139, 1057, 1262, 1058, 1059, 0, - 144, 145, 146, 147, 148, 149, 1060, 790, 150, 151, - 152, 153, 1061, 1062, 156, 0, 157, 158, 159, 160, - 791, 0, 1263, 0, 1264, 164, 165, 166, 167, 168, - 1265, 170, 171, 172, 0, 173, 174, 175, 176, 177, - 178, 0, 1266, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 1064, 191, 192, 1065, 194, 1066, 195, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, - 203, 204, 205, 1267, 0, 206, 207, 1067, 209, 210, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, - 218, 219, 220, 1068, 222, 223, 224, 225, 226, 227, - 793, 1069, 229, 0, 230, 231, 1070, 233, 0, 234, - 0, 235, 1268, 0, 1269, 238, 239, 1270, 1271, 242, - 0, 243, 0, 1071, 1072, 246, 247, 0, 248, 249, - 250, 251, 252, 253, 254, 1272, 256, 257, 258, 259, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 23, 237, 238, 239, 240, 241, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, - 1273, 269, 270, 271, 272, 273, 274, 1073, 1074, 0, - 1075, 0, 278, 1274, 1275, 281, 1276, 283, 284, 285, - 286, 287, 288, 0, 0, 289, 1277, 291, 1278, 0, - 293, 294, 295, 296, 297, 298, 299, 300, 1279, 302, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, 315, 316, 317, 318, 319, 320, 321, 1077, - 1280, 1078, 325, 326, 327, 328, 1079, 329, 330, 1281, - 332, 1080, 795, 334, 1081, 336, 337, 338, 0, 339, - 340, 0, 0, 1082, 342, 343, 0, 0, 344, 345, - 346, 1282, 348, 1283, 797, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, - 362, 363, 798, 1284, 366, 367, 368, 369, 370, 371, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 1085, 329, 330, 331, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 26, 27, 28, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, - 380, 381, 382, 1083, 384, 385, 386, 387, 0, 388, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, - 399, 400, 0, 401, 402, 1285, 404, 405, 406, 1084, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, - 418, 419, 420, 0, 1286, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 1287, 431, 432, 1085, 434, + 418, 419, 420, 33, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 430, 431, 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, - 444, 445, 446, 1288, 448, 800, 0, 0, 450, 451, - 0, 452, 1289, 454, 455, 456, 457, 458, 0, 459, - 1086, 1087, 0, 0, 462, 463, 801, 465, 802, 1088, - 467, 468, 1290, 470, 471, 472, 473, 474, 0, 0, - 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, - 483, 484, 485, 486, 487, 1089, 489, 1291, 490, 1292, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 38, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 40, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 804, 1095, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, - 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 0, 44, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, - 518, 519, 520, 1090, 0, 0, 0, 0, 0, 0, - 1091, 1092, 1093, 0, 0, 0, 0, 1094, 0, 1095, - 1293, 0, 0, 0, 1096, 1097, 1098, 1099, 117, 1050, - 820, 1051, 1052, 0, 1054, 1055, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, - 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, - 0, 0, 0, 0, 1056, 0, 0, 129, 130, 131, - 0, 132, 133, 134, 135, 136, 137, 138, 139, 1057, - 141, 1058, 1059, 0, 144, 145, 146, 147, 148, 149, - 1060, 790, 150, 151, 152, 153, 1061, 1062, 156, 0, - 157, 158, 159, 160, 791, 0, 792, 0, 163, 164, - 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, - 174, 175, 176, 177, 178, 0, 179, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 1064, 191, 192, - 1065, 194, 0, 195, 0, 196, 197, 198, 199, 200, - 201, 14, 15, 202, 203, 204, 205, 0, 0, 206, - 207, 1067, 209, 210, 0, 211, 212, 213, 0, 214, - 215, 216, 0, 217, 218, 219, 220, 1068, 222, 223, - 224, 225, 226, 227, 793, 1069, 229, 0, 230, 231, - 1070, 233, 0, 234, 0, 235, 236, 23, 237, 238, - 239, 240, 241, 242, 0, 243, 0, 1071, 1072, 246, - 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, - 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, - 265, 266, 0, 267, 268, 269, 270, 271, 272, 273, - 274, 1073, 1074, 0, 1075, 0, 278, 279, 280, 281, - 282, 283, 284, 285, 286, 287, 288, 0, 0, 289, - 290, 291, 292, 0, 293, 294, 295, 296, 297, 298, - 299, 300, 1076, 302, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, 321, 1077, 323, 1078, 325, 326, 327, 328, - 0, 329, 330, 331, 332, 1080, 795, 334, 1081, 336, - 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, - 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, - 26, 27, 28, 0, 362, 363, 798, 365, 366, 367, - 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, - 377, 0, 378, 379, 380, 381, 382, 1083, 384, 385, - 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 0, 401, 402, 403, - 404, 405, 406, 1084, 408, 409, 410, 411, 412, 413, - 414, 415, 416, 417, 418, 419, 420, 33, 0, 421, - 422, 423, 424, 425, 426, 427, 428, 429, 35, 430, - 431, 432, 1085, 434, 0, 435, 436, 437, 438, 439, - 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, - 37, 0, 450, 451, 38, 452, 453, 454, 455, 456, - 457, 458, 0, 459, 1086, 1087, 0, 0, 462, 463, - 801, 465, 802, 1088, 467, 468, 803, 470, 471, 472, - 473, 474, 0, 0, 475, 476, 477, 40, 478, 479, - 480, 481, 0, 482, 483, 484, 485, 486, 804, 1089, - 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, - 498, 0, 0, 499, 0, 44, 500, 501, 502, 503, - 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, - 514, 515, 516, 517, 518, 519, 520, 0, 0, 45, - 0, 0, 0, 117, 1050, 820, 1051, 1052, 1053, 1054, - 1055, 1094, 0, 1095, 0, 0, 0, 0, 1096, 1097, - 1098, 1099, 118, 119, 120, 121, 122, 123, 124, 125, - 0, 126, 127, 128, 0, 0, 0, 0, 0, 1056, - 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, - 136, 137, 138, 139, 1057, 141, 1058, 1059, 1440, 144, - 145, 146, 147, 148, 149, 1060, 790, 150, 151, 152, - 153, 1061, 1062, 156, 0, 157, 158, 159, 160, 791, - 0, 792, 0, 1063, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, - 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 1064, 191, 192, 1065, 194, 1066, 195, 0, - 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, - 204, 205, 0, 0, 206, 207, 1067, 209, 210, 0, - 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, - 219, 220, 1068, 222, 223, 224, 225, 226, 227, 793, - 1069, 229, 0, 230, 231, 1070, 233, 0, 234, 0, - 235, 236, 1441, 237, 238, 239, 240, 241, 242, 0, - 243, 0, 1071, 1072, 246, 247, 0, 248, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, - 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, - 269, 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, - 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 0, 1442, 289, 290, 291, 292, 0, 293, - 294, 295, 296, 297, 298, 299, 300, 1076, 302, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, 318, 319, 320, 321, 1077, 323, - 1078, 325, 326, 327, 328, 1079, 329, 330, 331, 332, - 1080, 795, 334, 1081, 336, 337, 338, 0, 339, 340, - 0, 0, 1082, 342, 343, 0, 0, 344, 345, 346, - 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, - 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, - 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, - 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 0, 401, 402, 403, 404, 405, 406, 1084, 408, - 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, - 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, - 427, 428, 429, 0, 430, 431, 432, 1085, 434, 0, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, - 452, 453, 454, 455, 456, 457, 458, 0, 459, 1086, - 1087, 0, 1443, 462, 463, 801, 465, 802, 1088, 467, - 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, - 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, - 484, 485, 486, 487, 1089, 489, 0, 490, 491, 492, - 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, - 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 1090, 0, 0, 0, 0, 0, 0, 1091, - 1092, 1093, 0, 0, 0, 0, 1094, 0, 1095, 0, - 0, 0, 0, 1096, 1097, 1098, 1099, 1257, 1050, 820, - 1051, 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 1259, 0, 1056, 0, 0, 1260, 130, 131, 0, - 132, 133, 134, 1261, 136, 137, 138, 139, 1057, 1262, - 1058, 1059, 0, 144, 145, 146, 147, 148, 149, 1060, - 790, 150, 151, 152, 153, 1061, 1062, 156, 0, 157, - 158, 159, 160, 791, 0, 1263, 0, 1264, 164, 165, - 166, 167, 168, 1265, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 1266, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1064, 191, 192, 1065, - 194, 1066, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1068, 222, 223, 224, - 225, 226, 227, 793, 1069, 229, 0, 230, 231, 1070, - 233, 0, 234, 0, 235, 1268, 0, 1269, 238, 239, - 1270, 1271, 242, 0, 243, 0, 1071, 1072, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 1272, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 1273, 269, 270, 271, 272, 273, 274, - 1073, 1074, 0, 1075, 0, 278, 1274, 1275, 281, 1276, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 1277, - 291, 1278, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1279, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1077, 1280, 1078, 325, 326, 327, 328, 1079, - 329, 330, 1281, 332, 1080, 795, 334, 1081, 336, 337, - 338, 0, 339, 340, 0, 0, 1082, 342, 343, 0, - 0, 344, 345, 346, 1282, 348, 1283, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 1284, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1083, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 1285, 404, - 405, 406, 1084, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 1286, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 1287, 431, - 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 1288, 448, 800, 0, - 0, 450, 451, 0, 452, 1289, 454, 455, 456, 457, - 458, 0, 459, 1086, 1087, 0, 0, 462, 463, 801, - 465, 802, 1088, 467, 468, 1290, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1089, 489, - 2311, 490, 1292, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1090, 0, 0, 0, - 0, 0, 0, 1091, 1092, 1093, 0, 0, 0, 0, - 1094, 0, 1095, 0, 0, 0, 0, 1096, 1097, 1098, - 1099, 1257, 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, - 127, 128, 0, 0, 0, 1259, 0, 1056, 0, 0, - 1260, 130, 131, 0, 132, 133, 134, 1261, 136, 137, - 138, 139, 1057, 1262, 1058, 1059, 0, 144, 145, 146, - 147, 148, 149, 1060, 790, 150, 151, 152, 153, 1061, - 1062, 156, 0, 157, 158, 159, 160, 791, 0, 1263, - 0, 1264, 164, 165, 166, 167, 168, 1265, 170, 171, - 172, 0, 173, 174, 175, 176, 177, 178, 0, 1266, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 1064, 191, 192, 1065, 194, 1066, 195, 0, 196, 197, - 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, - 0, 0, 206, 207, 1067, 209, 210, 0, 211, 212, - 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 1068, 222, 223, 224, 225, 226, 227, 793, 1069, 229, - 0, 230, 231, 1070, 233, 0, 234, 0, 235, 1268, - 0, 1269, 238, 239, 1270, 1271, 242, 0, 243, 0, - 1071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 1272, 256, 257, 258, 259, 0, 260, 261, - 262, 263, 264, 265, 266, 0, 267, 1273, 269, 270, - 271, 272, 273, 274, 1073, 1074, 0, 1075, 0, 278, - 1274, 1275, 281, 1276, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 1277, 291, 1278, 0, 293, 294, 295, - 296, 297, 298, 299, 300, 1279, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 1077, 1280, 1078, 325, - 326, 327, 328, 1079, 329, 330, 1281, 332, 1080, 795, - 334, 1081, 336, 337, 338, 0, 339, 340, 0, 0, - 1082, 342, 343, 0, 0, 344, 345, 346, 1282, 348, - 1283, 797, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, - 1284, 366, 367, 368, 369, 370, 371, 0, 372, 373, - 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, - 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, - 401, 402, 1285, 404, 405, 406, 1084, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 0, 1286, 421, 422, 423, 424, 425, 426, 427, 428, - 429, 0, 1287, 431, 432, 1085, 434, 0, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 1288, 448, 800, 0, 0, 450, 451, 0, 452, 1289, - 454, 455, 456, 457, 458, 0, 459, 1086, 1087, 0, - 0, 462, 463, 801, 465, 802, 1088, 467, 468, 1290, - 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, - 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, - 486, 487, 1089, 489, 0, 490, 1292, 492, 493, 494, - 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 1090, 0, 0, 0, 0, 0, 0, 1091, 1092, 1093, - 0, 0, 0, 0, 1094, 0, 1095, 2368, 0, 0, - 0, 1096, 1097, 1098, 1099, 117, 1050, 820, 1051, 1052, - 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, - 124, 125, -1131, 126, 127, 128, 0, 0, 0, 0, - -1131, 1056, 0, 0, 129, 130, 131, 0, 132, 133, - 134, 135, 136, 137, 138, 139, 1057, 141, 1058, 1059, - 0, 144, 145, 146, 147, 148, 149, 1060, 790, 150, - 151, 152, 153, 1061, 1062, 156, 0, 157, 158, 159, - 160, 791, 0, 792, 0, 1063, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, - 177, 178, 0, 179, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 1064, 191, 192, 1065, 194, 1066, - 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, - 202, 203, 204, 205, 0, 0, 206, 207, 1067, 209, - 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, - 217, 218, 219, 220, 1068, 222, 223, 224, 225, 226, - 227, 793, 1069, 229, 0, 230, 231, 1070, 233, 0, - 234, 0, 235, 236, 0, 237, 238, 239, 240, 241, - 242, 0, 243, 0, 1071, 1072, 246, 247, 0, 248, - 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, - 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, - 267, 268, 269, 270, 271, 272, 273, 274, 1073, 1074, - 0, 1075, 0, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, - 0, 293, 294, 295, 296, 297, 298, 299, 300, 1076, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 1077, 323, 1078, 325, 326, 327, 328, 1079, 329, 330, - 331, 332, 1080, 795, 334, 1081, 336, 337, 338, 0, - 339, 340, 0, 0, 1082, 342, 343, 0, 0, 344, - 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, - 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, - 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, - 379, 380, 381, 382, 1083, 384, 385, 386, 387, 0, - 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 0, 401, 402, 403, 404, 405, 406, - 1084, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 430, 431, 432, 1085, - 434, -1131, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, - 451, 0, 452, 453, 454, 455, 456, 457, 458, 0, - 459, 1086, 1087, 0, 0, 462, 463, 801, 465, 802, - 1088, 467, 468, 803, 470, 471, 472, 473, 474, 0, - 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, - 482, 483, 484, 485, 486, 487, 1089, 489, 0, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, - 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, - 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, - 517, 518, 519, 520, 1090, 0, 0, 0, 0, 0, - 0, 1091, 1092, 1093, 0, 0, 0, 0, 1094, 0, - 1095, 0, 0, 0, 0, 1096, 1097, 1098, 1099, 1257, - 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, 0, + 518, 519, 520, 1096, 0, 45, 0, 0, 0, 0, + 1097, 1098, 1099, 0, 0, 0, 0, 1100, 0, 1101, + 0, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 1264, + 1056, 821, 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, - 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 1259, 0, 1056, 0, 0, 1260, 130, - 131, 0, 132, 133, 134, 1261, 136, 137, 138, 139, - 1057, 1262, 1058, 1059, 0, 144, 145, 146, 147, 148, - 149, 1060, 790, 150, 151, 152, 153, 1061, 1062, 156, - 0, 157, 158, 159, 160, 791, 0, 1263, 0, 1264, - 164, 165, 166, 167, 168, 1265, 170, 171, 172, 0, - 173, 174, 175, 176, 177, 178, 0, 1266, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 1064, 191, - 192, 1065, 194, 1066, 195, 0, 196, 197, 198, 199, - 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, - 206, 207, 1067, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 1068, 222, - 223, 224, 225, 226, 227, 793, 1069, 229, 0, 230, - 231, 1070, 233, 0, 234, 0, 235, 1268, 0, 1269, - 238, 239, 1270, 1271, 242, 0, 243, 0, 1071, 1072, + 120, 121, 122, 123, 124, 125, 1265, 126, 127, 128, + 0, 0, 0, 1266, 0, 1062, 0, 0, 1267, 130, + 131, 0, 132, 133, 134, 1268, 136, 137, 138, 139, + 1063, 1269, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 1270, 0, 1271, + 164, 165, 166, 167, 168, 1272, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 1273, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 1072, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 1274, 0, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 1275, 0, 1276, + 238, 239, 1277, 1278, 242, 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, - 1272, 256, 257, 258, 259, 0, 260, 261, 262, 263, - 264, 265, 266, 0, 267, 1273, 269, 270, 271, 272, - 273, 274, 1073, 1074, 0, 1075, 0, 278, 1274, 1275, - 281, 1276, 283, 284, 285, 286, 287, 288, 0, 0, - 289, 1277, 291, 1278, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 1279, 302, 303, 304, 305, 306, 307, + 1279, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 1280, 269, 270, 271, 272, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 1281, 1282, + 281, 1283, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 1284, 291, 1285, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1286, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 1077, 1280, 1078, 325, 326, 327, - 328, 1079, 329, 330, 1281, 332, 1080, 795, 334, 1081, - 336, 337, 338, 0, 339, 340, 0, 0, 1082, 342, - 343, 0, 0, 344, 345, 346, 1282, 348, 1283, 797, + 318, 319, 320, 321, 1083, 1287, 1084, 325, 326, 327, + 328, 1085, 329, 330, 1288, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 1088, 342, + 343, 0, 0, 344, 345, 346, 1289, 348, 1290, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - 361, 0, 0, 0, 0, 362, 363, 798, 1284, 366, + 361, 0, 0, 0, 0, 362, 363, 798, 1291, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 381, 382, 1083, 384, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 1285, 404, 405, 406, 1084, 408, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 0, 1286, + 1292, 404, 405, 406, 1090, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 1293, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, - 1287, 431, 432, 1085, 434, 0, 435, 436, 437, 438, - 439, 440, 441, 442, 443, 444, 445, 446, 1288, 448, - 800, 0, 0, 450, 451, 0, 452, 1289, 454, 455, - 456, 457, 458, 0, 459, 1086, 1087, 0, 0, 462, - 463, 801, 465, 802, 1088, 467, 468, 1290, 470, 471, + 1294, 431, 432, 1091, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 1295, 448, + 800, 0, 0, 450, 451, 0, 452, 1296, 454, 455, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 1297, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, - 1089, 489, 0, 490, 1292, 492, 493, 494, 495, 496, + 1095, 489, 1298, 490, 1299, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 1090, 0, - 0, 0, 0, 0, 0, 1091, 1092, 1093, 0, 0, - 0, 0, 1094, 0, 1095, 3126, 0, 0, 0, 1096, - 1097, 1098, 1099, 1257, 1050, 820, 1051, 1052, 1053, 1054, - 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, - 0, 126, 127, 128, 0, 0, 0, 1259, 0, 1056, - 0, 0, 1260, 130, 131, 0, 132, 133, 134, 1261, - 136, 137, 138, 139, 1057, 1262, 1058, 1059, 0, 144, - 145, 146, 147, 148, 149, 1060, 790, 150, 151, 152, - 153, 1061, 1062, 156, 0, 157, 158, 159, 160, 791, - 0, 1263, 0, 1264, 164, 165, 166, 167, 168, 1265, - 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, - 0, 1266, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 1064, 191, 192, 1065, 194, 1066, 195, 0, - 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, - 204, 205, 0, 0, 206, 207, 1067, 209, 210, 0, - 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, - 219, 220, 1068, 222, 223, 224, 225, 226, 227, 793, - 1069, 229, 0, 230, 231, 1070, 233, 0, 234, 0, - 235, 1268, 0, 1269, 238, 239, 1270, 1271, 242, 0, - 243, 0, 1071, 1072, 246, 247, 0, 248, 249, 250, - 251, 252, 253, 254, 1272, 256, 257, 258, 259, 0, - 260, 261, 262, 263, 264, 265, 266, 0, 267, 1273, - 269, 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, - 0, 278, 1274, 1275, 281, 1276, 283, 284, 285, 286, - 287, 288, 0, 0, 289, 1277, 291, 1278, 0, 293, - 294, 295, 296, 297, 298, 299, 300, 1279, 302, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, 318, 319, 320, 321, 1077, 1280, - 1078, 325, 326, 327, 328, 1079, 329, 330, 1281, 332, - 1080, 795, 334, 1081, 336, 337, 338, 0, 339, 340, - 0, 0, 1082, 342, 343, 0, 0, 344, 345, 346, - 1282, 348, 1283, 797, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, - 363, 798, 1284, 366, 367, 368, 369, 370, 371, 0, - 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, - 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 0, 401, 402, 1285, 404, 405, 406, 1084, 408, - 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, - 419, 420, 0, 1286, 421, 422, 423, 424, 425, 426, - 427, 428, 429, 0, 1287, 431, 432, 1085, 434, 0, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 1288, 448, 800, 0, 0, 450, 451, 0, - 452, 1289, 454, 455, 456, 457, 458, 0, 459, 1086, - 1087, 0, 0, 462, 463, 801, 465, 802, 1088, 467, - 468, 1290, 470, 471, 472, 473, 474, 0, 0, 475, - 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, - 484, 485, 486, 487, 1089, 489, 0, 490, 1292, 492, - 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, - 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 1090, 0, 0, 0, 0, 0, 0, 1091, - 1092, 1093, 0, 0, 0, 0, 1094, 0, 1095, 0, - 0, 0, 0, 1096, 1097, 1098, 1099, 117, 1050, 820, - 1051, 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 1705, 126, 127, 128, 0, 0, - 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1057, 141, - 1058, 1059, 0, 144, 145, 146, 147, 148, 149, 1060, - 790, 150, 151, 152, 153, 1061, 1062, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 1063, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1064, 191, 192, 1065, - 194, 1066, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1068, 222, 223, 224, - 225, 226, 227, 793, 1069, 229, 0, 230, 231, 1070, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1071, 1072, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1073, 1074, 0, 1075, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1076, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1077, 323, 1078, 325, 326, 327, 328, 1079, - 329, 330, 331, 332, 1080, 795, 334, 1081, 336, 337, - 338, 0, 339, 340, 0, 0, 1082, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1083, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1084, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1086, 1087, 0, 0, 462, 463, 801, - 465, 802, 1088, 467, 468, 803, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1089, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1090, 0, 0, 0, - 0, 0, 0, 1091, 1092, 1093, 0, 0, 0, 0, - 1094, 0, 1095, 0, 0, 0, 0, 1096, 1097, 1098, - 1099, 117, 1720, 820, 1051, 1052, 1053, 1721, 1055, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 118, 119, 120, 121, 122, 123, 124, 125, 1722, 126, - 127, 128, 0, 0, 0, 0, 0, 1056, 0, 0, - 129, 130, 131, 0, 132, 133, 134, 135, 136, 137, - 138, 139, 1057, 141, 1058, 1059, 0, 144, 145, 146, - 147, 148, 149, 1060, 790, 150, 151, 152, 153, 1061, - 1062, 156, 0, 157, 158, 159, 160, 791, 0, 792, - 0, 1063, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 1064, 191, 192, 1065, 194, 1066, 195, 0, 196, 197, - 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, - 0, 0, 206, 207, 1067, 209, 210, 0, 211, 212, - 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 1068, 222, 223, 224, 225, 226, 227, 793, 1069, 229, - 0, 230, 231, 1070, 233, 0, 234, 0, 235, 236, - 0, 237, 238, 239, 240, 241, 242, 0, 243, 0, - 1071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, - 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, - 271, 272, 273, 274, 1073, 1074, 0, 1075, 0, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, - 296, 297, 298, 299, 300, 1076, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 1077, 323, 1078, 325, - 326, 327, 328, 1079, 329, 330, 331, 332, 1080, 795, - 334, 1081, 336, 337, 338, 0, 339, 340, 0, 0, - 1082, 342, 343, 0, 0, 344, 345, 346, 347, 348, - 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, - 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, - 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, - 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, - 401, 402, 403, 404, 405, 406, 1084, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, - 429, 0, 430, 431, 432, 1085, 434, 0, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, - 454, 455, 456, 457, 458, 0, 459, 1086, 1087, 0, - 0, 462, 463, 801, 465, 802, 1088, 467, 468, 803, - 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, - 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, - 486, 487, 1089, 489, 0, 490, 491, 492, 493, 494, - 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 1090, 0, 0, 0, 0, 0, 0, 1091, 1092, 1093, - 0, 0, 0, 0, 1094, 0, 1095, 0, 0, 0, - 0, 1096, 1097, 1098, 1099, 117, 1050, 820, 1051, 1052, - 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, - 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, - 0, 1056, 0, 0, 129, 130, 131, 0, 132, 133, - 134, 135, 136, 137, 138, 139, 1057, 141, 1058, 1059, - 0, 144, 145, 146, 147, 148, 149, 1060, 790, 150, - 151, 152, 153, 1061, 1062, 156, 0, 157, 158, 159, - 160, 791, 0, 792, 0, 1063, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, - 177, 178, 0, 179, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 1064, 191, 192, 1065, 194, 1066, - 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, - 202, 203, 204, 205, 0, 0, 206, 207, 1067, 209, - 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, - 217, 218, 219, 220, 1068, 222, 223, 224, 225, 226, - 227, 793, 1069, 229, 0, 230, 231, 1070, 233, 0, - 234, 0, 235, 236, 1441, 237, 238, 239, 240, 241, - 242, 0, 243, 0, 1071, 1072, 246, 247, 0, 248, - 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, - 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, - 267, 268, 269, 270, 271, 272, 273, 274, 1073, 1074, - 0, 1075, 0, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, - 0, 293, 294, 295, 296, 297, 298, 299, 300, 1076, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 1077, 323, 1078, 325, 326, 327, 328, 1079, 329, 330, - 331, 332, 1080, 795, 334, 1081, 336, 337, 338, 0, - 339, 340, 0, 0, 1082, 342, 343, 0, 0, 344, - 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, - 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, - 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, - 379, 380, 381, 382, 1083, 384, 385, 386, 387, 0, - 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 0, 401, 402, 403, 404, 405, 406, - 1084, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 430, 431, 432, 1085, - 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, - 451, 0, 452, 453, 454, 455, 456, 457, 458, 0, - 459, 1086, 1087, 0, 0, 462, 463, 801, 465, 802, - 1088, 467, 468, 803, 470, 471, 472, 473, 474, 0, - 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, - 482, 483, 484, 485, 486, 487, 1089, 489, 0, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, - 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, - 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, - 517, 518, 519, 520, 1090, 0, 0, 0, 0, 0, - 0, 1091, 1092, 1093, 0, 0, 0, 0, 1094, 0, - 1095, 0, 0, 0, 0, 1096, 1097, 1098, 1099, 117, - 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, 0, + 513, 514, 515, 516, 517, 518, 519, 520, 1096, 0, + 0, 0, 0, 0, 0, 1097, 1098, 1099, 0, 0, + 0, 0, 1100, 0, 1101, 1300, 0, 0, 0, 0, + 1102, 1103, 1104, 1105, 117, 1056, 821, 1057, 1058, 0, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 0, 195, + 0, 196, 197, 198, 199, 200, 201, 14, 15, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 23, 237, 238, 239, 240, 241, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 0, 329, 330, 331, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 26, 27, 28, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 33, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 35, 430, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 37, 0, 450, 451, + 38, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 40, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 804, 1095, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 44, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 0, 0, 45, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1100, 0, 1101, + 0, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 117, + 1056, 821, 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 0, 0, 1056, 0, 0, 129, 130, + 0, 0, 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, - 1057, 141, 1058, 1059, 0, 144, 145, 146, 147, 148, - 149, 1060, 790, 150, 151, 152, 153, 1061, 1062, 156, - 0, 157, 158, 159, 160, 791, 0, 792, 0, 1063, + 1063, 141, 1064, 1065, 1447, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 1064, 191, - 192, 1065, 194, 1066, 195, 0, 196, 197, 198, 199, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, - 206, 207, 1067, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 1068, 222, - 223, 224, 225, 226, 227, 793, 1069, 229, 0, 230, - 231, 1070, 233, 0, 234, 0, 235, 236, 0, 237, - 238, 239, 240, 241, 242, 0, 243, 0, 1071, 1072, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 236, 1448, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, - 273, 274, 1073, 1074, 0, 1075, 0, 278, 279, 280, - 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 1449, 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 1076, 302, 303, 304, 305, 306, 307, + 298, 299, 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 1077, 323, 1078, 325, 326, 327, - 328, 1079, 329, 330, 331, 332, 1080, 795, 334, 1081, - 336, 337, 338, 0, 339, 340, 0, 0, 1082, 342, + 318, 319, 320, 321, 1083, 323, 1084, 325, 326, 327, + 328, 1085, 329, 330, 331, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 381, 382, 1083, 384, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 403, 404, 405, 406, 1084, 408, 409, 410, 411, 412, + 403, 404, 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, - 430, 431, 432, 1085, 434, 0, 435, 436, 437, 438, + 430, 431, 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, - 456, 457, 458, 0, 459, 1086, 1087, 0, 0, 462, - 463, 801, 465, 802, 1088, 467, 468, 803, 470, 471, + 456, 457, 458, 0, 459, 1092, 1093, 0, 1450, 462, + 463, 801, 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, - 1089, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 1095, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 1090, 0, - 0, 0, 0, 0, 0, 1091, 1092, 1093, 0, 0, - 0, 0, 1094, 0, 1095, 2078, 0, 0, 0, 1096, - 1097, 1098, 1099, 117, 1050, 820, 1051, 1052, 1053, 1054, - 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, - 0, 126, 127, 128, 0, 0, 0, 0, 0, 1056, - 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, - 136, 137, 138, 139, 1057, 141, 1058, 1059, 0, 144, - 145, 146, 147, 148, 149, 1060, 790, 150, 151, 152, - 153, 1061, 1062, 156, 0, 157, 158, 159, 160, 791, - 0, 792, 0, 1063, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, - 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 1064, 191, 192, 1065, 194, 1066, 195, 0, - 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, - 204, 205, 0, 0, 206, 207, 1067, 209, 210, 0, - 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, - 219, 220, 1068, 222, 223, 224, 225, 226, 227, 793, - 1069, 229, 0, 230, 231, 1070, 233, 0, 234, 0, - 235, 236, 0, 237, 238, 239, 240, 241, 242, 0, - 243, 0, 1071, 1072, 246, 247, 0, 248, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, - 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, - 269, 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, - 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, - 294, 295, 296, 297, 298, 299, 300, 1076, 302, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, 318, 319, 320, 321, 1077, 323, - 1078, 325, 326, 327, 328, 1079, 329, 330, 331, 332, - 1080, 795, 334, 1081, 336, 337, 338, 0, 339, 340, - 0, 0, 1082, 342, 343, 0, 0, 344, 345, 346, - 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, - 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, - 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, - 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 0, 401, 402, 403, 404, 405, 406, 1084, 408, - 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, - 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, - 427, 428, 429, 0, 430, 431, 432, 1085, 434, 0, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 447, 448, 800, 0, 0, 450, 451, 2730, - 452, 453, 454, 455, 456, 457, 458, 0, 459, 1086, - 1087, 0, 0, 462, 463, 801, 465, 802, 1088, 467, - 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, - 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, - 484, 485, 486, 487, 1089, 489, 0, 490, 491, 492, - 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, - 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 1090, 0, 0, 0, 0, 0, 0, 1091, - 1092, 1093, 0, 0, 0, 0, 1094, 0, 1095, 0, - 0, 0, 0, 1096, 1097, 1098, 1099, 117, 1050, 820, - 1051, 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1057, 141, - 1058, 1059, 0, 144, 145, 146, 147, 148, 149, 1060, - 790, 150, 151, 152, 153, 1061, 1062, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 1063, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1064, 191, 192, 1065, - 194, 1066, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1068, 222, 223, 224, - 225, 226, 227, 793, 1069, 229, 0, 230, 231, 1070, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1071, 1072, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1073, 1074, 0, 1075, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1076, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1077, 323, 1078, 325, 326, 327, 328, 1079, - 329, 330, 331, 332, 1080, 795, 334, 1081, 336, 337, - 338, 0, 339, 340, 0, 0, 1082, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1083, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1084, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1086, 1087, 0, 0, 462, 463, 801, - 465, 802, 1088, 467, 468, 803, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1089, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 0, 2851, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1090, 0, 0, 0, - 0, 0, 0, 1091, 1092, 1093, 0, 0, 0, 0, - 1094, 0, 1095, 0, 0, 0, 0, 1096, 1097, 1098, - 1099, 117, 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 118, 119, 120, 121, 122, 123, 124, 125, 3069, 126, - 127, 128, 0, 0, 0, 0, 0, 1056, 0, 0, - 129, 130, 131, 0, 132, 133, 134, 135, 136, 137, - 138, 139, 1057, 141, 1058, 1059, 0, 144, 145, 146, - 147, 148, 149, 1060, 790, 150, 151, 152, 153, 1061, - 1062, 156, 0, 157, 158, 159, 160, 791, 0, 792, - 0, 1063, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, - 180, 3070, 182, 183, 184, 185, 186, 187, 188, 189, - 1064, 191, 192, 1065, 194, 1066, 195, 0, 196, 197, - 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, - 0, 0, 206, 207, 1067, 209, 210, 0, 211, 212, - 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 1068, 222, 223, 224, 225, 226, 227, 793, 1069, 229, - 0, 230, 231, 1070, 233, 0, 234, 0, 235, 236, - 0, 237, 238, 239, 240, 241, 242, 0, 243, 0, - 3071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, - 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, - 271, 272, 273, 274, 1073, 1074, 0, 1075, 0, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, - 296, 297, 298, 299, 300, 1076, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 1077, 323, 1078, 325, - 326, 327, 328, 1079, 329, 330, 331, 332, 1080, 795, - 334, 1081, 336, 337, 338, 0, 339, 340, 0, 0, - 1082, 342, 343, 0, 0, 344, 345, 346, 347, 348, - 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, - 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, - 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, - 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, - 401, 402, 403, 404, 405, 3072, 1084, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, - 429, 0, 430, 431, 432, 1085, 434, 0, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, - 454, 455, 456, 457, 458, 0, 459, 1086, 1087, 0, - 0, 462, 463, 801, 465, 802, 1088, 467, 468, 803, - 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, - 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, - 486, 487, 1089, 489, 0, 490, 491, 492, 493, 494, - 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 1090, 0, 0, 0, 0, 0, 0, 1091, 1092, 1093, - 0, 0, 0, 0, 1094, 0, 3073, 0, 0, 0, - 0, 1096, 1097, 1098, 1099, 117, 1050, 820, 1051, 1052, - 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, - 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, - 0, 1056, 0, 0, 129, 130, 131, 0, 132, 133, - 134, 135, 136, 137, 138, 139, 1057, 141, 1058, 1059, - 0, 144, 145, 146, 147, 148, 149, 1060, 790, 150, - 151, 152, 153, 1061, 1062, 156, 0, 157, 158, 159, - 160, 791, 0, 792, 0, 1063, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, - 177, 178, 0, 179, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 1064, 191, 192, 1065, 194, 1066, - 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, - 202, 203, 204, 205, 0, 0, 206, 207, 1067, 209, - 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, - 217, 218, 219, 220, 1068, 222, 223, 224, 225, 226, - 227, 793, 1069, 229, 0, 230, 231, 1070, 233, 0, - 234, 0, 235, 236, 0, 237, 238, 239, 240, 241, - 242, 0, 243, 0, 1071, 1072, 246, 247, 0, 248, - 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, - 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, - 267, 268, 269, 270, 271, 272, 273, 274, 1073, 1074, - 0, 1075, 0, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, - 0, 293, 294, 295, 296, 297, 298, 299, 300, 1076, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 1077, 323, 1078, 325, 326, 327, 328, 1079, 329, 330, - 331, 332, 1080, 795, 334, 1081, 336, 337, 338, 0, - 339, 340, 0, 0, 1082, 342, 343, 0, 0, 344, - 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, - 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, - 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, - 379, 380, 381, 382, 1083, 384, 385, 386, 387, 0, - 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 0, 401, 402, 403, 404, 405, 406, - 1084, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 430, 431, 432, 1085, - 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, - 451, 0, 452, 453, 454, 455, 456, 457, 458, 0, - 459, 1086, 1087, 0, 0, 462, 463, 801, 465, 802, - 1088, 467, 468, 803, 470, 471, 472, 473, 474, 0, - 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, - 482, 483, 484, 485, 486, 487, 1089, 489, 0, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, - 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, - 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, - 517, 518, 519, 520, 1090, 0, 0, 0, 0, 0, - 0, 1091, 1092, 1093, 0, 0, 0, 0, 1094, 0, - 1095, 0, 0, 0, 0, 1096, 1097, 1098, 1099, 117, - 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, 0, + 513, 514, 515, 516, 517, 518, 519, 520, 1096, 0, + 0, 0, 0, 0, 0, 1097, 1098, 1099, 0, 0, + 0, 0, 1100, 0, 1101, 0, 0, 0, 0, 0, + 1102, 1103, 1104, 1105, 1264, 1056, 821, 1057, 1058, 1059, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 1266, 0, + 1062, 0, 0, 1267, 130, 131, 0, 132, 133, 134, + 1268, 136, 137, 138, 139, 1063, 1269, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 1270, 0, 1271, 164, 165, 166, 167, 168, + 1272, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 1273, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 1072, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 1275, 0, 1276, 238, 239, 1277, 1278, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 1279, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 1280, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 1281, 1282, 281, 1283, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 1284, 291, 1285, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1286, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 1287, 1084, 325, 326, 327, 328, 1085, 329, 330, 1288, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 1289, 348, 1290, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 1291, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 1292, 404, 405, 406, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 1293, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 1294, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 1295, 448, 800, 0, 0, 450, 451, + 0, 452, 1296, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 1297, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1095, 489, 2327, 490, 1299, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 1096, 0, 0, 0, 0, 0, 0, + 1097, 1098, 1099, 0, 0, 0, 0, 1100, 0, 1101, + 0, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 1264, + 1056, 821, 1057, 1058, 1059, 1060, 1061, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 1266, 0, 1062, 0, 0, 1267, 130, + 131, 0, 132, 133, 134, 1268, 136, 137, 138, 139, + 1063, 1269, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 1270, 0, 1271, + 164, 165, 166, 167, 168, 1272, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 1273, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 1072, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 1275, 0, 1276, + 238, 239, 1277, 1278, 242, 0, 243, 0, 1077, 1078, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 1279, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 1280, 269, 270, 271, 272, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 1281, 1282, + 281, 1283, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 1284, 291, 1285, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1286, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1083, 1287, 1084, 325, 326, 327, + 328, 1085, 329, 330, 1288, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 1088, 342, + 343, 0, 0, 344, 345, 346, 1289, 348, 1290, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 1291, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 1292, 404, 405, 406, 1090, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 1293, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 1294, 431, 432, 1091, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 1295, 448, + 800, 0, 0, 450, 451, 0, 452, 1296, 454, 455, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 1297, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1095, 489, 0, 490, 1299, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 1096, 0, + 0, 0, 0, 0, 0, 1097, 1098, 1099, 0, 0, + 0, 0, 1100, 0, 1101, 2384, 0, 0, 0, 0, + 1102, 1103, 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, -1138, 126, 127, 128, 0, 0, 0, 0, -1138, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 1072, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 1085, 329, 330, 331, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 430, 431, 432, 1091, 434, + -1138, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1095, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 1096, 0, 0, 0, 0, 0, 0, + 1097, 1098, 1099, 0, 0, 0, 0, 1100, 0, 1101, + 0, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 1264, + 1056, 821, 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 0, 0, 1056, 0, 0, 129, 130, + 0, 0, 0, 1266, 0, 1062, 0, 0, 1267, 130, + 131, 0, 132, 133, 134, 1268, 136, 137, 138, 139, + 1063, 1269, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 1270, 0, 1271, + 164, 165, 166, 167, 168, 1272, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 1273, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 1072, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 1275, 0, 1276, + 238, 239, 1277, 1278, 242, 0, 243, 0, 1077, 1078, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 1279, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 1280, 269, 270, 271, 272, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 1281, 1282, + 281, 1283, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 1284, 291, 1285, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1286, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1083, 1287, 1084, 325, 326, 327, + 328, 1085, 329, 330, 1288, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 1088, 342, + 343, 0, 0, 344, 345, 346, 1289, 348, 1290, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 1291, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 1292, 404, 405, 406, 1090, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 1293, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 1294, 431, 432, 1091, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 1295, 448, + 800, 0, 0, 450, 451, 0, 452, 1296, 454, 455, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 1297, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1095, 489, 0, 490, 1299, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 1096, 0, + 0, 0, 0, 0, 0, 1097, 1098, 1099, 0, 0, + 0, 0, 1100, 0, 1101, 3156, 0, 0, 0, 0, + 1102, 1103, 1104, 1105, 1264, 1056, 821, 1057, 1058, 1059, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 1266, 0, + 1062, 0, 0, 1267, 130, 131, 0, 132, 133, 134, + 1268, 136, 137, 138, 139, 1063, 1269, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 1270, 0, 1271, 164, 165, 166, 167, 168, + 1272, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 1273, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 1072, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 1275, 0, 1276, 238, 239, 1277, 1278, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 1279, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 1280, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 1281, 1282, 281, 1283, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 1284, 291, 1285, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1286, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 1287, 1084, 325, 326, 327, 328, 1085, 329, 330, 1288, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 1289, 348, 1290, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 1291, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 1292, 404, 405, 406, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 1293, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 1294, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 1295, 448, 800, 0, 0, 450, 451, + 0, 452, 1296, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 1297, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1095, 489, 0, 490, 1299, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 1096, 0, 0, 0, 0, 0, 0, + 1097, 1098, 1099, 0, 0, 0, 0, 1100, 0, 1101, + 0, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 117, + 1056, 821, 1057, 1058, 1059, 1060, 1061, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 1716, 126, 127, 128, + 0, 0, 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, - 1057, 141, 1058, 1059, 0, 144, 145, 146, 147, 148, - 149, 1060, 790, 150, 151, 152, 153, 1061, 1062, 156, - 0, 157, 158, 159, 160, 791, 0, 792, 0, 1063, + 1063, 141, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 1064, 191, - 192, 1065, 194, 1066, 195, 0, 196, 197, 198, 199, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, - 206, 207, 1067, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 1068, 222, - 223, 224, 225, 226, 227, 793, 1069, 229, 0, 230, - 231, 1070, 233, 0, 234, 0, 235, 236, 0, 237, - 238, 239, 240, 241, 242, 0, 243, 0, 1071, 1072, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, - 273, 274, 1073, 1074, 0, 1075, 0, 278, 279, 280, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 1076, 302, 303, 304, 305, 306, 307, + 298, 299, 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 1077, 323, 1078, 325, 326, 327, - 328, 1079, 329, 330, 331, 332, 1080, 795, 334, 1081, - 336, 337, 338, 0, 339, 340, 0, 0, 1082, 342, + 318, 319, 320, 321, 1083, 323, 1084, 325, 326, 327, + 328, 1085, 329, 330, 331, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 381, 382, 1083, 384, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 403, 404, 405, 406, 1084, 408, 409, 410, 411, 412, + 403, 404, 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, - 430, 431, 432, 1085, 434, 0, 435, 436, 437, 438, + 430, 431, 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, - 456, 457, 458, 0, 459, 1086, 1087, 0, 0, 462, - 463, 801, 465, 802, 1088, 467, 468, 803, 470, 471, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, - 1089, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 1095, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 1090, 0, - 0, 0, 0, 0, 0, 1725, 1726, 1093, 0, 0, - 0, 0, 1094, 0, 1095, 0, 0, 0, 0, 1096, - 1097, 1098, 1099, 117, 2218, 820, 1051, 1052, 1053, 1054, - 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, - 0, 126, 127, 128, 0, 0, 0, 0, 0, 1056, - 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, - 136, 137, 138, 139, 1057, 141, 1058, 1059, 0, 144, - 145, 146, 147, 148, 149, 1060, 790, 150, 151, 152, - 153, 1061, 1062, 156, 0, 157, 158, 159, 160, 791, - 0, 792, 0, 1063, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, - 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 1064, 191, 192, 1065, 194, 1066, 195, 0, - 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, - 204, 205, 0, 0, 206, 207, 1067, 209, 210, 0, - 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, - 219, 220, 1068, 222, 223, 224, 225, 226, 227, 793, - 1069, 229, 0, 230, 231, 1070, 233, 0, 234, 0, - 235, 236, 0, 237, 238, 239, 240, 241, 242, 0, - 243, 0, 1071, 1072, 246, 247, 0, 248, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, - 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, - 269, 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, - 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, - 294, 295, 296, 297, 298, 299, 300, 1076, 302, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, 318, 319, 320, 321, 1077, 323, - 1078, 325, 326, 327, 328, 1079, 329, 330, 331, 332, - 1080, 795, 334, 1081, 336, 337, 338, 0, 339, 340, - 0, 0, 1082, 342, 343, 0, 0, 344, 345, 346, - 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, - 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, - 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, - 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 0, 401, 402, 403, 404, 405, 406, 1084, 408, - 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, - 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, - 427, 428, 429, 0, 430, 431, 432, 1085, 434, 0, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, - 452, 453, 454, 455, 456, 457, 458, 0, 459, 1086, - 1087, 0, 0, 462, 463, 801, 465, 802, 1088, 467, - 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, - 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, - 484, 485, 486, 487, 1089, 489, 0, 490, 491, 492, - 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, - 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 1090, 0, 0, 0, 0, 0, 0, 1091, - 1092, 1093, 0, 0, 0, 0, 1094, 0, 1095, 0, - 0, 0, 0, 1096, 1097, 1098, 1099, 117, 1050, 820, - 1051, 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1057, 141, - 1058, 1059, 0, 144, 145, 146, 147, 148, 149, 1060, - 790, 150, 151, 152, 153, 1061, 1062, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 1063, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1064, 191, 192, 1065, - 194, 1066, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1068, 222, 223, 224, - 225, 226, 227, 793, 1069, 229, 0, 230, 231, 1070, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1071, 1072, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1073, 1074, 0, 1075, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1076, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1077, 323, 1078, 325, 326, 327, 328, 1079, - 329, 330, 331, 332, 1080, 795, 334, 1081, 336, 337, - 338, 0, 339, 340, 0, 0, 1082, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1083, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1084, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1086, 1087, 0, 0, 462, 463, 801, - 465, 802, 1088, 467, 468, 803, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1089, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1090, 0, 0, 0, - 0, 0, 0, 1091, 2305, 1093, 0, 0, 0, 0, - 1094, 0, 1095, 0, 0, 0, 0, 1096, 1097, 1098, - 1099, 117, 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, - 127, 128, 0, 0, 0, 0, 0, 1056, 0, 0, - 129, 130, 131, 0, 132, 133, 134, 135, 136, 137, - 138, 139, 1057, 141, 1058, 1059, 0, 144, 145, 146, - 147, 148, 149, 1060, 790, 150, 151, 152, 153, 1061, - 1062, 156, 0, 157, 158, 159, 160, 791, 0, 792, - 0, 1063, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 1064, 191, 192, 1065, 194, 1066, 195, 0, 196, 197, - 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, - 0, 0, 206, 207, 1067, 209, 210, 0, 211, 212, - 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 1068, 222, 223, 224, 225, 226, 227, 793, 1069, 229, - 0, 230, 231, 1070, 233, 0, 234, 0, 235, 236, - 0, 237, 238, 239, 240, 241, 242, 0, 243, 0, - 1071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, - 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, - 271, 272, 273, 274, 1073, 1074, 0, 1075, 0, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, - 296, 297, 298, 299, 300, 1076, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 1077, 323, 1078, 325, - 326, 327, 328, 1079, 329, 330, 331, 332, 1080, 795, - 334, 1081, 336, 337, 338, 0, 339, 340, 0, 0, - 1082, 342, 343, 0, 0, 344, 345, 346, 347, 348, - 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, - 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, - 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, - 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, - 401, 402, 403, 404, 405, 406, 1084, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, - 429, 0, 430, 431, 432, 1085, 434, 0, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, - 454, 455, 456, 457, 458, 0, 459, 1086, 1087, 0, - 0, 462, 463, 801, 465, 802, 1088, 467, 468, 803, - 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, - 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, - 486, 487, 1089, 489, 0, 490, 491, 492, 493, 494, - 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 1090, 0, 0, 0, 0, 0, 0, 1091, 1092, 1093, - 0, 0, 0, 0, 1094, 0, 2525, 0, 0, 0, - 0, 1096, 1097, 1098, 1099, 117, 1050, 820, 1051, 1052, - 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, - 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, - 0, 1056, 0, 0, 129, 130, 131, 0, 132, 133, - 134, 135, 136, 137, 138, 139, 1057, 141, 1058, 1059, - 0, 144, 145, 146, 147, 148, 149, 1060, 790, 150, - 151, 152, 153, 1061, 1062, 156, 0, 157, 158, 159, - 160, 791, 0, 792, 0, 1063, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, - 177, 178, 0, 179, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 1064, 191, 192, 1065, 194, 1066, - 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, - 202, 203, 204, 205, 0, 0, 206, 207, 1067, 209, - 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, - 217, 218, 219, 220, 1068, 222, 223, 224, 225, 226, - 227, 793, 1069, 229, 0, 230, 231, 1070, 233, 0, - 234, 0, 235, 236, 0, 237, 238, 239, 240, 241, - 242, 0, 243, 0, 1071, 1072, 246, 247, 0, 248, - 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, - 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, - 267, 268, 269, 270, 271, 272, 273, 274, 1073, 1074, - 0, 1075, 0, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, - 0, 293, 294, 295, 296, 297, 298, 299, 300, 1076, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 1077, 323, 1078, 325, 326, 327, 328, 1079, 329, 330, - 331, 332, 1080, 795, 334, 1081, 336, 337, 338, 0, - 339, 340, 0, 0, 1082, 342, 343, 0, 0, 344, - 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, - 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, - 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, - 379, 380, 381, 382, 1083, 384, 385, 386, 387, 0, - 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 0, 401, 402, 403, 404, 405, 406, - 1084, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 430, 431, 432, 1085, - 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, - 451, 0, 452, 453, 454, 455, 456, 457, 458, 0, - 459, 1086, 1087, 0, 0, 462, 463, 801, 465, 802, - 1088, 467, 468, 803, 470, 471, 472, 473, 474, 0, - 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, - 482, 483, 484, 485, 486, 487, 1089, 489, 0, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, - 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, - 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, - 517, 518, 519, 520, 1090, 0, 0, 0, 0, 0, - 0, 1091, 3124, 1093, 0, 0, 0, 0, 1094, 0, - 1095, 0, 0, 0, 0, 1096, 1097, 1098, 1099, 117, - 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, 0, + 513, 514, 515, 516, 517, 518, 519, 520, 1096, 0, + 0, 0, 0, 0, 0, 1097, 1098, 1099, 0, 0, + 0, 0, 1100, 0, 1101, 0, 0, 0, 0, 0, + 1102, 1103, 1104, 1105, 117, 1731, 821, 1057, 1058, 1059, + 1732, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 1733, 126, 127, 128, 0, 0, 0, 0, 0, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 1072, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 1085, 329, 330, 331, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 430, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1095, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 1096, 0, 0, 0, 0, 0, 0, + 1097, 1098, 1099, 0, 0, 0, 0, 1100, 0, 1101, + 0, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 117, + 1056, 821, 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 0, 0, 1056, 0, 0, 129, 130, + 0, 0, 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, - 1057, 141, 1058, 1059, 0, 144, 145, 146, 147, 148, - 149, 1060, 790, 150, 151, 152, 153, 1061, 1062, 156, - 0, 157, 158, 159, 160, 791, 0, 792, 0, 1063, + 1063, 141, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, - 173, 174, 175, 176, 177, 178, 0, 179, 180, 3070, - 182, 183, 184, 185, 186, 187, 188, 189, 1064, 191, - 192, 1065, 194, 1066, 195, 0, 196, 197, 198, 199, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, - 206, 207, 1067, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 1068, 222, - 223, 224, 225, 226, 227, 793, 1069, 229, 0, 230, - 231, 1070, 233, 0, 234, 0, 235, 236, 0, 237, - 238, 239, 240, 241, 242, 0, 243, 0, 3071, 1072, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 236, 1448, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, - 273, 274, 1073, 1074, 0, 1075, 0, 278, 279, 280, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 1076, 302, 303, 304, 305, 306, 307, + 298, 299, 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 1077, 323, 1078, 325, 326, 327, - 328, 1079, 329, 330, 331, 332, 1080, 795, 334, 1081, - 336, 337, 338, 0, 339, 340, 0, 0, 1082, 342, + 318, 319, 320, 321, 1083, 323, 1084, 325, 326, 327, + 328, 1085, 329, 330, 331, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 381, 382, 1083, 384, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 403, 404, 405, 3072, 1084, 408, 409, 410, 411, 412, + 403, 404, 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, - 430, 431, 432, 1085, 434, 0, 435, 436, 437, 438, + 430, 431, 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, - 456, 457, 458, 0, 459, 1086, 1087, 0, 0, 462, - 463, 801, 465, 802, 1088, 467, 468, 803, 470, 471, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, - 1089, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 1095, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 1090, 0, - 0, 0, 0, 0, 0, 1091, 1092, 1093, 0, 0, - 0, 0, 1094, 0, 3073, 0, 0, 0, 0, 1096, - 1097, 1098, 1099, 117, 1050, 820, 1051, 1052, 1053, 1054, - 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, - 0, 126, 127, 128, 0, 0, 0, 0, 0, 1056, - 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, - 136, 137, 138, 3527, 1057, 141, 1058, 1059, 0, 144, - 145, 146, 147, 148, 149, 1060, 790, 150, 151, 152, - 153, 1061, 1062, 156, 0, 157, 158, 159, 160, 791, - 0, 792, 0, 1063, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, - 0, 179, 180, 181, 3528, 183, 184, 185, 186, 187, - 188, 189, 1064, 191, 192, 1065, 194, 1066, 195, 0, - 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, - 204, 205, 0, 0, 206, 207, 1067, 209, 210, 0, - 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, - 219, 220, 1068, 222, 223, 224, 225, 226, 227, 793, - 1069, 229, 0, 230, 231, 1070, 233, 0, 234, 0, - 235, 236, 0, 237, 238, 239, 240, 241, 242, 0, - 243, 0, 1071, 1072, 246, 247, 0, 248, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, - 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, - 269, 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, - 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, - 294, 295, 296, 297, 298, 299, 300, 1076, 302, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, 318, 319, 320, 321, 1077, 323, - 1078, 325, 326, 327, 328, 1079, 329, 330, 331, 332, - 1080, 795, 334, 1081, 336, 337, 338, 0, 339, 340, - 0, 0, 1082, 342, 343, 0, 0, 344, 345, 346, - 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, - 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, - 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, - 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 0, 401, 402, 403, 404, 405, 406, 1084, 408, - 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, - 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, - 427, 428, 429, 0, 430, 431, 432, 1085, 434, 0, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, - 452, 453, 454, 455, 456, 457, 458, 0, 459, 1086, - 1087, 0, 0, 462, 463, 801, 465, 802, 1088, 467, - 468, 803, 470, 471, 3529, 473, 474, 0, 0, 475, - 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, - 484, 485, 486, 487, 1089, 489, 0, 490, 491, 492, - 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, - 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 1090, 0, 0, 0, 0, 0, 0, 1091, - 1092, 1093, 0, 0, 0, 0, 1094, 0, 1095, 0, - 0, 0, 0, 1096, 1097, 1098, 1099, 117, 1050, 820, - 1051, 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1057, 141, - 1058, 1059, 0, 144, 145, 146, 147, 148, 149, 1060, - 790, 150, 151, 152, 153, 1061, 1062, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 1063, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 3528, 183, - 184, 185, 186, 187, 188, 189, 1064, 191, 192, 1065, - 194, 1066, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1068, 222, 223, 224, - 225, 226, 227, 793, 1069, 229, 0, 230, 231, 1070, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1071, 1072, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1073, 1074, 0, 1075, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1076, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1077, 323, 1078, 325, 326, 327, 328, 1079, - 329, 330, 331, 332, 1080, 795, 334, 1081, 336, 337, - 338, 0, 339, 340, 0, 0, 1082, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1083, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1084, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1086, 1087, 0, 0, 462, 463, 801, - 465, 802, 1088, 467, 468, 803, 470, 471, 3529, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1089, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1090, 0, 0, 0, - 0, 0, 0, 1091, 1092, 1093, 0, 0, 0, 0, - 1094, 0, 1095, 0, 0, 0, 0, 1096, 1097, 1098, - 1099, 117, 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, - 127, 128, 0, 0, 0, 0, 0, 1056, 0, 0, - 129, 130, 131, 0, 132, 133, 134, 135, 136, 137, - 138, 139, 1057, 141, 1058, 1059, 0, 144, 145, 146, - 147, 148, 149, 1060, 790, 150, 151, 152, 153, 1061, - 1062, 156, 0, 157, 158, 159, 160, 791, 0, 792, - 0, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 1064, 191, 192, 1065, 194, 0, 195, 0, 196, 197, - 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, - 0, 0, 206, 207, 1067, 209, 210, 0, 211, 212, - 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 1068, 222, 223, 224, 225, 226, 227, 793, 1069, 229, - 0, 230, 231, 1070, 233, 0, 234, 0, 235, 236, - 0, 237, 238, 239, 240, 241, 242, 0, 243, 0, - 1071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, - 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, - 271, 272, 273, 274, 1073, 1074, 0, 1075, 0, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, - 296, 297, 298, 299, 300, 1076, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 1077, 323, 1078, 325, - 326, 327, 328, 0, 329, 330, 331, 332, 1080, 795, - 334, 1081, 336, 337, 338, 0, 339, 340, 0, 0, - 1082, 342, 343, 0, 0, 344, 345, 346, 347, 348, - 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, - 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, - 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, - 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, - 401, 402, 403, 404, 405, 406, 1084, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, - 429, 0, 430, 431, 432, 1085, 434, 0, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, - 454, 455, 456, 457, 458, 0, 459, 1086, 1087, 0, - 0, 462, 463, 801, 465, 802, 1088, 467, 468, 803, - 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, - 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, - 486, 487, 1089, 489, 0, 490, 491, 492, 493, 494, - 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 0, 0, 0, 0, 0, 0, 0, 1427, 1428, 0, - 0, 0, 0, 0, 1094, 0, 1095, 0, 0, 0, - 0, 1096, 1097, 1098, 1099, 117, 1050, 820, 1051, 1052, - 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, - 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, - 0, 1056, 0, 0, 129, 130, 131, 0, 132, 133, - 134, 135, 136, 137, 138, -2081, 1057, 141, 1058, 1059, - 0, 144, 145, 146, 147, 148, 149, 1060, 790, 150, - 151, 152, 153, 1061, 1062, 156, 0, 157, 158, 159, - 160, 791, 0, 792, 0, 1063, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, - 177, 178, 0, 179, 180, 181, 3528, 183, 184, 185, - 186, 187, 188, 189, 1064, 191, 192, 1065, 194, 1066, - 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, - 202, 203, 204, 205, 0, 0, 206, 207, 1067, 209, - 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, - 217, 218, 219, 220, 1068, 222, 223, 224, 225, 226, - 227, 793, 1069, 229, 0, 230, 231, 1070, 233, 0, - 234, 0, 235, 236, 0, 237, 238, 239, 240, -2081, - 242, 0, 243, 0, 1071, 1072, 246, 247, 0, 248, - 249, 250, 251, 252, 253, 254, -2081, 256, 257, 258, - 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, - 267, 268, 269, 270, 271, 272, 273, 274, 1073, 1074, - 0, 1075, 0, 278, 0, 0, 281, 282, 283, 284, - 285, 286, 287, 288, 0, 0, 289, 290, 291, -2081, - 0, 293, 294, 295, 296, 297, 298, 299, 300, 1076, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 1077, 323, 1078, 325, 326, 327, 328, 0, 329, 330, - 0, 332, 1080, 795, 334, 1081, 336, 337, 338, 0, - 339, 340, 0, 0, 1082, 342, 343, 0, 0, 344, - 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, - 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, - 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, - 379, 380, 381, 382, 1083, 384, 385, 386, 387, 0, - 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 0, 401, 402, 403, 404, 405, 406, - 1084, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, -2081, 431, 432, 1085, - 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, - 451, 0, 452, 453, 454, 455, 456, 457, 458, 0, - 459, 1086, 1087, 0, 0, 462, 463, 801, 465, 802, - 1088, 467, 468, 803, 470, 471, 3529, 473, 474, 0, - 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, - 482, 483, 484, 485, 486, 487, 1089, 489, 0, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, - 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, - 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, - 517, 518, 519, 520, -2081, 0, 0, 0, 0, 0, - 0, 1091, 1092, 1093, 0, 0, 0, 0, 1094, 0, - 1095, 0, 0, 0, 0, 1096, 1097, 1098, 1099, 117, - 1050, 820, 1051, 1052, 0, 1054, 1055, 0, 0, 0, + 513, 514, 515, 516, 517, 518, 519, 520, 1096, 0, + 0, 0, 0, 0, 0, 1097, 1098, 1099, 0, 0, + 0, 0, 1100, 0, 1101, 0, 0, 0, 0, 0, + 1102, 1103, 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 1072, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 1085, 329, 330, 331, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 430, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1095, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 1096, 0, 0, 0, 0, 0, 0, + 1097, 1098, 1099, 0, 0, 0, 0, 1100, 0, 1101, + 2092, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 117, + 1056, 821, 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 0, 0, 1056, 0, 0, 129, 130, + 0, 0, 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, - 1057, 141, 1058, 1059, 0, 144, 145, 146, 147, 148, - 149, 1060, 790, 150, 151, 152, 153, 1061, 1062, 156, - 0, 157, 158, 159, 160, 791, 0, 792, 0, 163, + 1063, 141, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 1064, 191, - 192, 1065, 194, 0, 195, 0, 196, 197, 198, 199, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, - 206, 207, 1067, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 1068, 222, - 223, 224, 225, 226, 227, 793, 1069, 229, 0, 230, - 231, 1070, 233, 0, 234, 0, 235, 236, 0, 237, - 238, 239, 240, 241, 242, 0, 243, 0, 1071, 1072, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, - 273, 274, 1073, 1074, 0, 1075, 0, 278, 279, 280, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 1076, 302, 303, 304, 305, 306, 307, + 298, 299, 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 1077, 323, 1078, 325, 326, 327, - 328, 0, 329, 330, 331, 332, 1080, 795, 334, 1081, - 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, + 318, 319, 320, 321, 1083, 323, 1084, 325, 326, 327, + 328, 1085, 329, 330, 331, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 381, 382, 1083, 384, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 403, 404, 405, 406, 2204, 2205, 409, 410, 411, 412, + 403, 404, 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, - 430, 431, 432, 1085, 434, 0, 435, 436, 437, 438, + 430, 431, 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, - 456, 457, 458, 0, 459, 1086, 1087, 0, 0, 462, - 463, 801, 465, 802, 1088, 467, 468, 803, 470, 471, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, - 1089, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 1095, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 0, 0, - 0, 0, 0, 0, 0, 2206, 2207, 0, 0, 0, - 0, 0, 1094, 0, 1095, 0, 0, 0, 0, 1096, - 1097, 1098, 1099, 117, 1050, 820, 1051, 1052, 1053, 1054, - 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, - 0, 126, 127, 128, 0, 0, 0, 0, 0, 1056, - 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, - 136, 137, 138, 139, 1057, 141, 1058, 1059, 0, 144, - 145, 146, 147, 148, 149, 1060, 790, 150, 151, 152, - 153, 1061, 1062, 156, 0, 157, 158, 159, 160, 791, - 0, 792, 0, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, - 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 1064, 191, 192, 1065, 194, 0, 195, 0, - 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, - 204, 205, 0, 0, 206, 207, 1067, 209, 210, 0, - 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, - 219, 220, 1068, 222, 223, 224, 225, 226, 227, 793, - 1069, 229, 0, 230, 231, 1070, 233, 0, 234, 0, - 235, 236, 0, 237, 238, 239, 240, 241, 242, 0, - 243, 0, 1071, 1072, 246, 247, 0, 248, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, - 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, - 269, 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, - 0, 278, 0, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, - 294, 295, 296, 297, 298, 299, 300, 1076, 302, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, 318, 319, 320, 321, 1077, 323, - 1078, 325, 326, 327, 328, 0, 329, 330, 331, 332, - 1080, 795, 334, 1081, 336, 337, 338, 0, 339, 340, - 0, 0, 1082, 342, 343, 0, 0, 344, 345, 346, - 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, - 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, - 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, - 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 0, 401, 402, 403, 404, 405, 406, 1084, 408, - 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, - 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, - 427, 428, 429, 0, 430, 431, 432, 1085, 434, 0, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, - 452, 453, 454, 455, 456, 457, 458, 0, 459, 1086, - 1087, 0, 0, 462, 463, 801, 465, 802, 1088, 467, - 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, - 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, - 484, 485, 486, 487, 1089, 489, 0, 490, 491, 492, - 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, - 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 0, 0, 0, 0, 0, 0, 0, 1427, - 1428, 0, 0, 0, 0, 0, 1094, 0, 1095, 0, - 0, 0, 0, 1096, 1097, 1098, 1099, 117, 1050, 820, - 1051, 1052, 0, 1054, 1055, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1057, 141, - 1058, 1059, 0, 144, 145, 146, 147, 148, 149, 1060, - 790, 150, 151, 152, 153, 1061, 1062, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1064, 191, 192, 1065, - 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1068, 222, 223, 224, - 225, 226, 227, 793, 1069, 229, 0, 230, 231, 1070, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 3090, 1071, 1072, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 513, 514, 515, 516, 517, 518, 519, 520, 1096, 0, + 0, 0, 0, 0, 0, 1097, 1098, 1099, 0, 0, + 0, 0, 1100, 0, 1101, 0, 0, 0, 0, 2690, + 1102, 1103, 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 1072, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 1085, 329, 330, 331, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 430, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 2749, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1095, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 1096, 0, 0, 0, 0, 0, 0, + 1097, 1098, 1099, 0, 0, 0, 0, 1100, 0, 1101, + 0, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 117, + 1056, 821, 1057, 1058, 1059, 1060, 1061, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 1062, 0, 0, 129, 130, + 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, + 1063, 141, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 1069, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 1072, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1077, 1078, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1082, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1083, 323, 1084, 325, 326, 327, + 328, 1085, 329, 330, 331, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 1088, 342, + 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 403, 404, 405, 406, 1090, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 430, 431, 432, 1091, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 803, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1095, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 0, 2875, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 1096, 0, + 0, 0, 0, 0, 0, 1097, 1098, 1099, 0, 0, + 0, 0, 1100, 0, 1101, 0, 0, 0, 0, 0, + 1102, 1103, 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 3093, 126, 127, 128, 0, 0, 0, 0, 0, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 3094, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 1072, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, + 0, 243, 0, 3095, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 1085, 329, 330, 331, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 3096, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 430, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1095, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 1096, 0, 0, 0, 0, 0, 0, + 1097, 1098, 1099, 0, 0, 0, 0, 1100, 0, 3097, + 0, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 117, + 1056, 821, 1057, 1058, 1059, 1060, 1061, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 1062, 0, 0, 129, 130, + 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, + 1063, 141, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 1069, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 1072, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1077, 1078, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1082, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1083, 323, 1084, 325, 326, 327, + 328, 1085, 329, 330, 331, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 1088, 342, + 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 403, 404, 405, 406, 1090, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 430, 431, 432, 1091, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 803, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1095, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 1096, 0, + 0, 0, 0, 0, 0, 1097, 1098, 1099, 0, 0, + 0, 0, 1100, 0, 1101, 0, 0, 0, 0, 3318, + 1102, 1103, 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 1072, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 1085, 329, 330, 331, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 430, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1095, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 1096, 0, 0, 0, 0, 0, 0, + 1097, 1098, 1099, 0, 0, 0, 0, 1100, 0, 1101, + 0, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 117, + 1056, 821, 1057, 1058, 1059, 1060, 1061, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 1062, 0, 0, 129, 130, + 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, + 1063, 141, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 1069, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 1072, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1077, 1078, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1082, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1083, 323, 1084, 325, 326, 327, + 328, 1085, 329, 330, 331, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 1088, 342, + 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 403, 404, 405, 406, 1090, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 430, 431, 432, 1091, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 803, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1095, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 1096, 0, + 0, 0, 0, 0, 0, 1736, 1737, 1099, 0, 0, + 0, 0, 1100, 0, 1101, 0, 0, 0, 0, 0, + 1102, 1103, 1104, 1105, 117, 2234, 821, 1057, 1058, 1059, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 1072, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 1085, 329, 330, 331, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 430, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1095, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 1096, 0, 0, 0, 0, 0, 0, + 1097, 1098, 1099, 0, 0, 0, 0, 1100, 0, 1101, + 0, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 117, + 1056, 821, 1057, 1058, 1059, 1060, 1061, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 1062, 0, 0, 129, 130, + 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, + 1063, 141, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 1069, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 1072, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1077, 1078, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1082, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1083, 323, 1084, 325, 326, 327, + 328, 1085, 329, 330, 331, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 1088, 342, + 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 403, 404, 405, 406, 1090, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 430, 431, 432, 1091, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 803, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1095, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 1096, 0, + 0, 0, 0, 0, 0, 1097, 2321, 1099, 0, 0, + 0, 0, 1100, 0, 1101, 0, 0, 0, 0, 0, + 1102, 1103, 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 1072, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 1085, 329, 330, 331, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 430, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1095, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 1096, 0, 0, 0, 0, 0, 0, + 1097, 1098, 1099, 0, 0, 0, 0, 1100, 0, 2542, + 0, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 117, + 1056, 821, 1057, 1058, 1059, 1060, 1061, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 1062, 0, 0, 129, 130, + 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, + 1063, 141, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 1069, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 1072, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1077, 1078, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1082, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1083, 323, 1084, 325, 326, 327, + 328, 1085, 329, 330, 331, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 1088, 342, + 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 403, 404, 405, 406, 1090, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 430, 431, 432, 1091, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 803, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1095, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 1096, 0, + 0, 0, 0, 0, 0, 1097, 3154, 1099, 0, 0, + 0, 0, 1100, 0, 1101, 0, 0, 0, 0, 0, + 1102, 1103, 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 3094, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 1072, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, + 0, 243, 0, 3095, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 1085, 329, 330, 331, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 3096, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 430, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1095, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 1096, 0, 0, 0, 0, 0, 0, + 1097, 1098, 1099, 0, 0, 0, 0, 1100, 0, 3097, + 0, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 117, + 1056, 821, 1057, 1058, 1059, 1060, 1061, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 1062, 0, 0, 129, 130, + 131, 0, 132, 133, 134, 135, 136, 137, 138, 3562, + 1063, 141, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 1069, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 3563, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 1072, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1077, 1078, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1082, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1083, 323, 1084, 325, 326, 327, + 328, 1085, 329, 330, 331, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 1088, 342, + 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 403, 404, 405, 406, 1090, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 430, 431, 432, 1091, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 803, 470, 471, + 3564, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1095, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 1096, 0, + 0, 0, 0, 0, 0, 1097, 1098, 1099, 0, 0, + 0, 0, 1100, 0, 1101, 0, 0, 0, 0, 0, + 1102, 1103, 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 3563, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 1072, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 1085, 329, 330, 331, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 430, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 3564, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1095, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 1096, 0, 0, 0, 0, 0, 0, + 1097, 1098, 1099, 0, 0, 0, 0, 1100, 0, 1101, + 0, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 117, + 1056, 821, 1057, 1058, 1059, 1060, 1061, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 1062, 0, 0, 129, 130, + 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, + 1063, 141, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 0, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1077, 1078, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1082, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1083, 323, 1084, 325, 326, 327, + 328, 0, 329, 330, 331, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 1088, 342, + 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 403, 404, 405, 406, 1090, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 430, 431, 432, 1091, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 803, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1095, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 0, 0, + 0, 0, 0, 0, 0, 1434, 1435, 0, 0, 0, + 0, 0, 1100, 0, 1101, 0, 0, 0, 0, 0, + 1102, 1103, 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, -2101, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 3563, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 1072, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 0, 237, 238, 239, 240, -2101, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, -2101, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 0, 0, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, -2101, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 0, 329, 330, 0, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, -2101, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 3564, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1095, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, -2101, 0, 0, 0, 0, 0, 0, + 1097, 1098, 1099, 0, 0, 0, 0, 1100, 0, 1101, + 0, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 117, + 1056, 821, 1057, 1058, 0, 1060, 1061, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 1062, 0, 0, 129, 130, + 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, + 1063, 141, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 0, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1077, 1078, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1082, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1083, 323, 1084, 325, 326, 327, + 328, 0, 329, 330, 331, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, + 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 403, 404, 405, 406, 2220, 2221, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 430, 431, 432, 1091, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 803, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1095, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 0, 0, + 0, 0, 0, 0, 0, 2222, 2223, 0, 0, 0, + 0, 0, 1100, 0, 1101, 0, 0, 0, 0, 0, + 1102, 1103, 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 0, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 0, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 0, 329, 330, 331, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 430, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1095, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 0, 0, 0, 0, 0, 0, 0, + 1434, 1435, 0, 0, 0, 0, 0, 1100, 0, 1101, + 0, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 117, + 1056, 821, 1057, 1058, 0, 1060, 1061, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 1062, 0, 0, 129, 130, + 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, + 1063, 141, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 0, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 3114, 1077, 1078, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1082, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1083, 323, 1084, 325, 326, 327, + 328, 0, 329, 330, 331, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, + 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 430, 431, 432, 1091, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 803, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1095, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1100, 0, 2797, 0, 0, 0, 0, 0, + 1102, 1103, 1104, 1105, 117, 1056, 821, 1057, 1058, 0, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 0, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 0, 329, 330, 331, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 407, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 430, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1095, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1100, 0, 2797, + 0, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 117, + 1056, 821, 1057, 1058, 0, 1060, 1061, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 1062, 0, 0, 129, 130, + 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, + 1063, 141, 1064, 1065, 0, 144, 145, 146, 147, 148, + 149, 1066, 790, 150, 151, 152, 153, 1067, 1068, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1070, 191, + 192, 1071, 194, 0, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1074, 222, + 223, 224, 225, 226, 227, 793, 1075, 229, 0, 230, + 231, 1076, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1077, 1078, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, + 273, 274, 1079, 1080, 0, 1081, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1082, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1083, 323, 1084, 325, 326, 327, + 328, 0, 329, 330, 331, 332, 1086, 795, 334, 1087, + 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, + 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1089, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 403, 404, 405, 406, 1090, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 430, 431, 432, 1091, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, + 456, 457, 458, 0, 459, 1092, 1093, 0, 0, 462, + 463, 801, 465, 802, 1094, 467, 468, 803, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1095, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1100, 0, 1101, 0, 0, 0, 0, 0, + 1102, 1103, 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, + 1060, 1061, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 1062, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 0, 1063, 141, 1064, 1065, 0, + 144, 145, 146, 147, 148, 149, 1066, 790, 150, 151, + 152, 153, 1067, 1068, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 1069, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1070, 191, 192, 1071, 194, 1072, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 1073, 209, 210, + 0, 211, 212, 213, 0, 214, 0, 216, 0, 217, + 218, 219, 220, 1074, 222, 223, 224, 225, 226, 227, + 793, 1075, 229, 0, 230, 231, 1076, 233, 0, 234, + 0, 235, 236, 0, 237, 238, 239, 240, 0, 242, + 0, 243, 0, 1077, 1078, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 1079, 1080, 0, + 1081, 0, 278, 0, 0, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 0, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1082, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1083, + 323, 1084, 325, 326, 327, 328, 0, 329, 330, 0, + 332, 1086, 795, 334, 1087, 336, 337, 338, 0, 339, + 340, 0, 0, 1088, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1089, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 1090, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 0, 431, 432, 1091, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 1092, 1093, 0, 0, 462, 463, 801, 465, 802, 1094, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1095, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 0, 0, 0, 0, 0, 0, 0, + 1097, 1098, 1099, 0, 974, 1363, 821, 1100, 0, 1101, + 1060, 0, 0, 0, 0, 1102, 1103, 1104, 1105, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 565, 0, + 0, 0, 0, 570, 130, 131, 0, 132, 133, 134, + 572, 136, 137, 138, 573, 574, 575, 576, 577, 0, + 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, + 152, 153, 581, 582, 156, 0, 157, 158, 159, 160, + 584, 0, 586, 0, 588, 164, 165, 166, 167, 168, + 589, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 592, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 594, 191, 192, 595, 194, 0, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 605, 222, 223, 224, 225, 226, 227, + 606, 1364, 229, 0, 230, 231, 609, 233, 0, 234, + 0, 235, 612, 0, 614, 238, 239, 615, 616, 242, + 0, 243, 0, 619, 620, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 622, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 625, 626, 270, 271, 272, 273, 274, 627, 628, 0, + 630, 0, 278, 632, 633, 281, 634, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 637, 291, 638, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 2401, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 641, + 642, 643, 325, 326, 327, 644, 0, 329, 330, 646, + 332, 0, 648, 334, 649, 336, 337, 338, 0, 339, + 340, 1365, 0, 341, 342, 343, 0, 0, 344, 345, + 655, 656, 348, 657, 658, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 663, 664, 366, 367, 665, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 668, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 671, 404, 405, 406, 672, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 674, 421, 422, 423, 424, 425, + 426, 675, 428, 429, 0, 677, 431, 432, 678, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 680, 448, 681, 0, 0, 450, 451, + 0, 452, 685, 454, 455, 456, 457, 458, 0, 459, + 687, 688, 0, 0, 462, 463, 691, 465, 692, 1366, + 467, 468, 694, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 699, 700, 489, 0, 490, 702, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 707, 708, + 709, 710, 711, 712, 713, 714, 715, 716, 717, 517, + 518, 519, 520, 0, 0, 0, 0, 0, 0, 0, + 1367, 1368, 2402, 117, 0, 0, 0, 2403, 0, 2404, + 1061, 0, 0, 0, 0, 0, 0, 0, 1105, 0, + 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, + 0, 126, 127, 128, 0, 0, 0, 0, 0, 1062, + 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, 0, 144, + 145, 146, 147, 148, 149, 1066, 790, 150, 151, 152, + 153, 154, 155, 156, 0, 157, 158, 159, 160, 791, + 0, 792, 0, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, + 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, + 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, + 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 793, + 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, + 235, 236, 0, 237, 238, 239, 240, 241, 242, 0, + 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, + 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, + 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, + 294, 295, 296, 297, 298, 299, 300, 1082, 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, 0, 329, 330, 331, 332, + 0, 795, 334, 335, 336, 337, 338, 0, 339, 340, + 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, + 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, + 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, + 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, + 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + 400, 0, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 0, 430, 431, 432, 433, 434, 0, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, + 452, 453, 454, 455, 456, 457, 458, 0, 459, 460, + 461, 0, 0, 462, 463, 801, 465, 802, 0, 467, + 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, + 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, + 484, 485, 486, 487, 488, 489, 0, 490, 491, 492, + 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, + 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, + 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, + 519, 520, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 528, 1978, 0, 1100, 0, 2138, 1979, + 1061, 0, 0, 0, 1102, 1103, 1104, 1105, 0, 0, + 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, + 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, + 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, + 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, + 153, 154, 155, 156, 0, 157, 158, 159, 160, 161, + 0, 0, 0, 163, 164, 165, 166, 167, 168, 0, + 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, + 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, + 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, + 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, + 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, + 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, + 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, + 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, + 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, + 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, + 287, 288, 0, 0, 289, 0, 291, 0, 0, 293, + 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, + 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, + 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, + 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, + 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, + 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, + 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, + 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, + 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, + 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, + 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, + 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, + 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, + 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, + 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, + 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, + 519, 520, 0, 0, 0, 0, 0, 528, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1102, 1103, 118, 119, 120, 121, + 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, + 0, 0, 0, 0, 1010, 0, 0, 130, 131, 0, + 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, + 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, + 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, + 158, 159, 160, 161, 0, 0, 0, 163, 164, 165, + 166, 167, 168, 0, 170, 171, 172, 0, 173, 174, + 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, + 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, + 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, + 216, -540, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 0, 229, -540, 230, 231, 232, + 233, -540, 234, 0, 235, 0, 0, 0, 238, 239, + 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, + 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1073, 1074, 0, 1075, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1076, 302, 303, 304, 305, 306, 307, 308, 309, + 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, + 275, 276, -540, 277, 0, 278, 0, 0, 281, 0, + 283, 284, 285, 286, 287, 288, 0, 0, 289, 0, + 291, 0, -540, 293, 294, 295, 296, 297, 298, 299, + 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1077, 323, 1078, 325, 326, 327, 328, 0, - 329, 330, 331, 332, 1080, 795, 334, 1081, 336, 337, - 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, + 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, + 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, + 338, -540, 339, 340, 0, 0, 341, 342, 343, 0, + -540, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, + 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1083, 384, 385, 386, + 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, + 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1086, 1087, 0, 0, 462, 463, 801, - 465, 802, 1088, 467, 468, 803, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1089, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, + 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, + 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, + 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, + 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, + 474, -540, 0, 475, 476, 477, 0, 478, 479, 480, + 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, + 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 0, 0, 0, 0, - 0, 0, 117, 1050, 820, 1051, 1052, 0, 1054, 1055, - 1094, 0, 2778, 0, 0, 0, 0, 1096, 1097, 1098, - 1099, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1056, 0, + 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1177, 0, 118, 119, 120, 121, 122, + 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, + 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, + 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, + 150, 151, 152, 153, 154, 155, 156, 0, 157, 158, + 159, 160, 161, 0, 0, 0, 163, 164, 165, 166, + 167, 168, 0, 170, 171, 172, 0, 173, 174, 175, + 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, + 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, + 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, + 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, + 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, + 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, + 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, + 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, + 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, + 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, + 284, 285, 286, 287, 288, 0, 0, 289, 0, 291, + 0, 0, 293, 294, 295, 296, 297, 298, 299, 300, + 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, + 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, + 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, + 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, + 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, + 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, + 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, + 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, + 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, + 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, + 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, + 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, + 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, + 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, + 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, + 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, + 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, + 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, + 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, + 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, + 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, + 516, 517, 518, 519, 520, 974, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2490, 3304, 0, 118, 119, 120, 121, 122, 123, + 124, 125, 0, 126, 127, 128, 3, 4, 0, 565, + 0, 0, 0, 0, 570, 130, 131, 0, 132, 133, + 134, 572, 136, 137, 138, 573, 574, 575, 576, 577, + 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, + 151, 152, 153, 581, 582, 156, 0, 157, 158, 159, + 160, 584, 0, 586, 0, 588, 164, 165, 166, 167, + 168, 589, 170, 171, 172, 0, 173, 174, 175, 176, + 177, 178, 0, 592, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 594, 191, 192, 595, 194, 0, + 195, 0, 196, 197, 198, 199, 200, 201, 14, 15, + 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, + 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, + 217, 218, 219, 220, 605, 222, 223, 224, 225, 226, + 227, 606, 0, 229, 0, 230, 231, 609, 233, 0, + 234, 0, 235, 612, 23, 614, 238, 239, 615, 616, + 242, 0, 243, 0, 619, 620, 246, 247, 0, 248, + 249, 250, 251, 252, 253, 254, 622, 256, 257, 258, + 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, + 267, 625, 626, 270, 271, 272, 273, 274, 627, 628, + 0, 630, 0, 278, 632, 633, 281, 634, 283, 284, + 285, 286, 287, 288, 0, 0, 289, 637, 291, 638, + 0, 293, 294, 295, 296, 297, 298, 299, 300, 640, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 641, 642, 643, 325, 326, 327, 644, 0, 329, 330, + 646, 332, 0, 648, 334, 649, 336, 337, 338, 0, + 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, + 345, 655, 656, 348, 657, 658, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 26, 27, 28, + 0, 362, 363, 663, 664, 366, 367, 665, 369, 370, + 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, + 379, 380, 381, 382, 668, 384, 385, 386, 387, 0, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 398, 399, 400, 0, 401, 402, 671, 404, 405, 406, + 672, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 33, 674, 421, 422, 423, 424, + 425, 426, 675, 428, 429, 35, 677, 431, 432, 678, + 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 680, 448, 681, 37, 0, 450, + 451, 38, 452, 685, 454, 455, 456, 457, 458, 0, + 459, 687, 688, 0, 0, 462, 463, 691, 465, 692, + 0, 467, 468, 694, 470, 471, 472, 473, 474, 0, + 0, 475, 476, 477, 40, 478, 479, 480, 481, 0, + 482, 483, 484, 485, 486, 975, 700, 489, 0, 490, + 702, 492, 493, 494, 495, 496, 497, 498, 0, 0, + 499, 0, 44, 500, 501, 502, 503, 504, 505, 707, + 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, + 517, 518, 519, 520, 0, 117, 45, 554, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 46, 0, 0, 0, 118, 119, 120, 121, 122, 123, + 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, + 0, 0, 0, 0, 129, 130, 131, 0, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 0, 144, 145, 146, 147, 148, 149, 0, 790, 150, + 151, 152, 153, 154, 155, 156, 0, 157, 158, 159, + 160, 791, 0, 792, 0, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, + 177, 178, 0, 179, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, + 195, 0, 196, 197, 198, 199, 200, 201, 14, 15, + 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, + 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 793, 0, 229, 0, 230, 231, 232, 233, 0, + 234, 0, 235, 236, 23, 237, 238, 239, 240, 241, + 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 0, 277, 0, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 794, 0, 289, 290, 291, 292, + 0, 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, 0, 329, 330, + 331, 332, 0, 795, 334, 335, 336, 337, 338, 0, + 339, 340, 0, 796, 341, 342, 343, 0, 0, 344, + 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 26, 27, 28, + 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, + 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, + 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 398, 399, 400, 0, 401, 402, 403, 404, 405, 406, + 407, 799, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 33, 0, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 35, 430, 431, 432, 433, + 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 447, 448, 800, 37, 0, 450, + 451, 38, 452, 453, 454, 455, 456, 457, 458, 0, + 459, 460, 461, 0, 0, 462, 463, 801, 465, 802, + 0, 467, 468, 803, 470, 471, 472, 473, 474, 0, + 0, 475, 476, 477, 40, 478, 479, 480, 481, 0, + 482, 483, 484, 485, 486, 804, 488, 489, 0, 490, + 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, + 499, 0, 44, 500, 501, 502, 503, 504, 505, 506, + 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, + 517, 518, 519, 520, 0, 117, 45, 554, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 805, 0, 0, 0, 118, 119, 120, 121, 122, 123, + 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, + 0, 0, 0, 0, 129, 130, 131, 0, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 0, 144, 145, 146, 147, 148, 149, 0, 790, 150, + 151, 152, 153, 154, 155, 156, 0, 157, 158, 159, + 160, 791, 0, 792, 0, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, + 177, 178, 0, 179, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, + 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, + 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, + 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 793, 0, 229, 0, 230, 231, 232, 233, 0, + 234, 0, 235, 236, 0, 237, 238, 239, 240, 241, + 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 0, 277, 0, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 794, 0, 289, 290, 291, 292, + 0, 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, 0, 329, 330, + 331, 332, 0, 795, 334, 335, 336, 337, 338, 0, + 339, 340, 0, 796, 341, 342, 343, 0, 0, 344, + 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, + 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, + 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, + 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 398, 399, 400, 0, 401, 402, 403, 404, 405, 406, + 407, 799, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 0, 430, 431, 432, 433, + 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, + 451, 0, 452, 453, 454, 455, 456, 457, 458, 0, + 459, 460, 461, 0, 0, 462, 463, 801, 465, 802, + 0, 467, 468, 803, 470, 471, 472, 473, 474, 0, + 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, + 482, 483, 484, 485, 486, 804, 488, 489, 0, 490, + 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, + 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, + 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, + 517, 518, 519, 520, 117, 0, 554, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 805, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 0, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 0, + 144, 145, 146, 147, 148, 149, 0, 790, 150, 151, + 152, 153, 154, 155, 156, 0, 157, 158, 159, 160, + 791, 0, 792, 0, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, + 793, 0, 229, 0, 230, 231, 232, 233, 0, 234, + 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, + 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 268, 269, 270, 271, 272, 273, 274, 275, 276, 0, + 277, 0, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 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, 0, 329, 330, 331, + 332, 0, 795, 334, 335, 336, 337, 338, 0, 339, + 340, 0, 796, 341, 342, 343, 0, 0, 344, 345, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 407, + 799, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 430, 431, 432, 433, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 460, 461, 0, 0, 462, 463, 801, 465, 802, 0, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 488, 489, 0, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 117, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1018, + 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, + 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, + 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, 0, 144, + 145, 146, 147, 148, 149, 0, 790, 150, 151, 152, + 153, 154, 155, 156, 0, 157, 158, 159, 160, 791, + 0, 792, 0, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, + 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, + 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, + 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 793, + 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, + 235, 236, 0, 237, 238, 239, 240, 241, 242, 0, + 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, + 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, + 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, + 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 0, 0, 289, 290, 291, 292, 0, 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, 0, 329, 330, 331, 332, + 0, 795, 334, 335, 336, 337, 338, 0, 339, 340, + 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, + 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, + 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, + 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, + 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + 400, 0, 401, 402, 403, 404, 405, 406, 407, 799, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 0, 430, 431, 432, 433, 434, 0, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, + 452, 453, 454, 455, 456, 457, 458, 0, 459, 460, + 461, 0, 0, 462, 463, 801, 465, 802, 0, 467, + 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, + 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, + 484, 485, 486, 487, 488, 489, 0, 490, 491, 492, + 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, + 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, + 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, + 519, 520, 117, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, + 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, + 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1057, 141, 1058, 1059, 0, 144, 145, - 146, 147, 148, 149, 1060, 790, 150, 151, 152, 153, - 1061, 1062, 156, 0, 157, 158, 159, 160, 791, 0, + 137, 138, 139, 140, 141, 142, 143, 0, 144, 145, + 146, 147, 148, 149, 0, 790, 150, 151, 152, 153, + 154, 155, 156, 0, 157, 158, 159, 160, 791, 0, 792, 0, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1064, 191, 192, 1065, 194, 0, 195, 0, 196, + 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1067, 209, 210, 0, 211, + 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1068, 222, 223, 224, 225, 226, 227, 793, 1069, - 229, 0, 230, 231, 1070, 233, 0, 234, 0, 235, + 220, 221, 222, 223, 224, 225, 226, 227, 793, 0, + 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 1071, 1072, 246, 247, 0, 248, 249, 250, 251, + 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, 0, + 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1076, 302, 303, 304, + 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, 1077, 323, 1078, - 325, 326, 327, 328, 0, 329, 330, 331, 332, 1080, - 795, 334, 1081, 336, 337, 338, 0, 339, 340, 0, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 0, 329, 330, 331, 332, 0, + 795, 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1083, 384, 385, 386, 387, 0, 388, 389, 390, + 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 430, 431, 432, 1085, 434, 0, 435, + 428, 429, 0, 430, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1086, 1087, - 0, 0, 462, 463, 801, 465, 802, 1088, 467, 468, + 453, 454, 455, 456, 457, 458, 0, 459, 460, 461, + 0, 0, 462, 463, 801, 465, 802, 0, 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1089, 489, 0, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 0, 0, 0, 0, 0, 0, 117, 1050, 820, - 1051, 1052, 0, 1054, 1055, 1094, 0, 2778, 0, 0, - 0, 0, 1096, 1097, 1098, 1099, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1057, 141, - 1058, 1059, 0, 144, 145, 146, 147, 148, 149, 1060, - 790, 150, 151, 152, 153, 1061, 1062, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1064, 191, 192, 1065, - 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1068, 222, 223, 224, - 225, 226, 227, 793, 1069, 229, 0, 230, 231, 1070, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1071, 1072, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1073, 1074, 0, 1075, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1076, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1077, 323, 1078, 325, 326, 327, 328, 0, - 329, 330, 331, 332, 1080, 795, 334, 1081, 336, 337, - 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1083, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1084, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1086, 1087, 0, 0, 462, 463, 801, - 465, 802, 1088, 467, 468, 803, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1089, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 0, 0, 0, 0, - 0, 0, 117, 1050, 820, 1051, 1052, 1053, 1054, 1055, - 1094, 0, 1095, 0, 0, 0, 0, 1096, 1097, 1098, - 1099, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1056, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 0, 1057, 141, 1058, 1059, 0, 144, 145, - 146, 147, 148, 149, 1060, 790, 150, 151, 152, 153, - 1061, 1062, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 1063, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1064, 191, 192, 1065, 194, 1066, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1067, 209, 210, 0, 211, - 212, 213, 0, 214, 0, 216, 0, 217, 218, 219, - 220, 1068, 222, 223, 224, 225, 226, 227, 793, 1069, - 229, 0, 230, 231, 1070, 233, 0, 234, 0, 235, - 236, 0, 237, 238, 239, 240, 0, 242, 0, 243, - 0, 1071, 1072, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, 0, - 278, 0, 0, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 0, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1076, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1077, 323, 1078, - 325, 326, 327, 328, 0, 329, 330, 0, 332, 1080, - 795, 334, 1081, 336, 337, 338, 0, 339, 340, 0, - 0, 1082, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1083, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 1084, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 0, 431, 432, 1085, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1086, 1087, - 0, 0, 462, 463, 801, 465, 802, 1088, 467, 468, - 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1089, 489, 0, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 0, 0, 0, 0, 0, 0, 0, 1091, 1092, - 1093, 0, 973, 1356, 820, 1094, 0, 1095, 1054, 0, - 0, 0, 1096, 1097, 1098, 1099, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 565, 0, 0, 0, - 0, 570, 130, 131, 0, 132, 133, 134, 572, 136, - 137, 138, 573, 574, 575, 576, 577, 0, 144, 145, - 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, - 581, 582, 156, 0, 157, 158, 159, 160, 584, 0, - 586, 0, 588, 164, 165, 166, 167, 168, 589, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 592, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 594, 191, 192, 595, 194, 0, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 605, 222, 223, 224, 225, 226, 227, 606, 1357, - 229, 0, 230, 231, 609, 233, 0, 234, 0, 235, - 612, 0, 614, 238, 239, 615, 616, 242, 0, 243, - 0, 619, 620, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 622, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 625, 626, - 270, 271, 272, 273, 274, 627, 628, 0, 630, 0, - 278, 632, 633, 281, 634, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 637, 291, 638, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 2385, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 641, 642, 643, - 325, 326, 327, 644, 0, 329, 330, 646, 332, 0, - 648, 334, 649, 336, 337, 338, 0, 339, 340, 1358, - 0, 341, 342, 343, 0, 0, 344, 345, 655, 656, - 348, 657, 658, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 663, 664, 366, 367, 665, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 668, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 671, 404, 405, 406, 672, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 674, 421, 422, 423, 424, 425, 426, 675, - 428, 429, 0, 677, 431, 432, 678, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 680, 448, 681, 0, 0, 450, 451, 0, 452, - 685, 454, 455, 456, 457, 458, 0, 459, 687, 688, - 0, 0, 462, 463, 691, 465, 692, 1359, 467, 468, - 694, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 699, 700, 489, 0, 490, 702, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 707, 708, 709, 710, - 711, 712, 713, 714, 715, 716, 717, 517, 518, 519, - 520, 0, 0, 0, 0, 0, 0, 117, 1360, 1361, - 2386, 0, 0, 0, 1055, 2387, 0, 2388, 0, 0, - 0, 0, 0, 0, 0, 1099, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, 0, 144, 145, 146, 147, 148, 149, 1060, - 790, 150, 151, 152, 153, 154, 155, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 793, 0, 229, 0, 230, 231, 232, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 244, 245, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 0, 277, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1076, 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, 0, - 329, 330, 331, 332, 0, 795, 334, 335, 336, 337, - 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 460, 461, 0, 0, 462, 463, 801, - 465, 802, 0, 467, 468, 803, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 0, 0, 0, 0, - 0, 0, 528, 0, 0, 0, 0, 0, 0, 0, - 1094, 0, 2122, 0, 0, 0, 0, 1096, 1097, 1098, - 1099, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 0, 1008, - 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, - 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, - 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, - 154, 155, 156, 0, 157, 158, 159, 160, 161, 0, - 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, -540, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, - 229, -540, 230, 231, 232, 233, -540, 234, 0, 235, - 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, - 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, - 270, 271, 272, 273, 274, 275, 276, -540, 277, 0, - 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 0, 291, 0, -540, 293, 294, - 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, - 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, - 333, 334, 335, 336, 337, 338, -540, 339, 340, 0, - 0, 341, 342, 343, 0, -540, 344, 345, 346, 0, - 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, - 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, - 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, - 469, 470, 471, 472, 473, 474, -540, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, + 485, 486, 487, 488, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1170, 0, + 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3393, 0, 0, + 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, + 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, + 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, + 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, + 155, 156, 0, 157, 158, 159, 160, 161, 0, 0, + 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, + 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, + 198, 199, 200, 201, 14, 15, 202, 203, 204, 205, + 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, + 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, + 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, + 23, 0, 238, 239, 529, 0, 242, 0, 243, 0, + 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, + 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, + 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, + 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, + 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, + 0, 0, 289, 0, 291, 0, 0, 293, 294, 295, + 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, + 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, + 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, + 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, + 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 26, 27, 28, 0, 362, 363, 364, + 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, + 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, + 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, + 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, + 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, + 33, 0, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 35, 0, 431, 432, 433, 434, 0, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 531, 448, 449, 37, 0, 450, 451, 38, 452, 0, + 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, + 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, + 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, + 40, 478, 479, 480, 481, 0, 482, 483, 484, 485, + 486, 804, 488, 489, 0, 490, 0, 492, 493, 494, + 495, 496, 497, 498, 0, 0, 499, 0, 44, 500, + 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, + 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, + 0, 528, 45, 554, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, + 118, 119, 120, 121, 122, 123, 124, 125, 894, 126, + 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, + 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, + 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, + 155, 156, 0, 157, 158, 159, 160, 161, 0, 0, + 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, + 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, + 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, + 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, + 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, + 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, + 23, 0, 238, 239, 529, 0, 242, 0, 243, 0, + 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, + 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, + 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, + 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, + 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, + 0, 0, 289, 0, 291, 0, 0, 293, 294, 295, + 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, + 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, + 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, + 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, + 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 26, 27, 28, 0, 362, 363, 364, + 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, + 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, + 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, + 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, + 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, + 33, 0, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 531, 448, 449, 0, 0, 450, 451, 38, 452, 0, + 454, 455, 456, 457, 458, 0, 459, 895, 461, 0, + 0, 896, 463, 464, 465, 466, 0, 467, 468, 469, + 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, + 40, 478, 479, 480, 481, 0, 482, 483, 484, 485, + 486, 804, 488, 489, 0, 490, 0, 492, 493, 494, + 495, 496, 497, 498, 0, 0, 499, 0, 44, 500, + 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, + 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, + 0, 528, 45, 554, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, + 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, + 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, + 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, + 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, + 155, 156, 0, 157, 158, 159, 160, 161, 0, 0, + 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, + 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, + 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, + 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, + 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, + 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, + 23, 0, 238, 239, 529, 0, 242, 0, 243, 0, + 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, + 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, + 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, + 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, + 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, + 0, 0, 289, 0, 291, 0, 0, 293, 294, 295, + 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, + 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, + 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, + 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, + 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 26, 27, 28, 0, 362, 363, 364, + 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, + 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, + 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, + 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, + 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, + 33, 0, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 531, 448, 449, 0, 0, 450, 451, 38, 452, 0, + 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, + 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, + 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, + 40, 478, 479, 480, 481, 0, 482, 483, 484, 485, + 486, 804, 488, 489, 0, 490, 0, 492, 493, 494, + 495, 496, 497, 498, 0, 0, 499, 0, 44, 500, + 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, + 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, + 0, 528, 45, 554, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, @@ -7448,258 +8135,158 @@ static const yytype_int16 yytable[] = 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 973, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2476, 3273, 0, 118, - 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, - 128, 3, 4, 0, 565, 0, 0, 0, 0, 570, - 130, 131, 0, 132, 133, 134, 572, 136, 137, 138, - 573, 574, 575, 576, 577, 0, 144, 145, 146, 147, - 148, 149, 0, 0, 150, 151, 152, 153, 581, 582, - 156, 0, 157, 158, 159, 160, 584, 0, 586, 0, - 588, 164, 165, 166, 167, 168, 589, 170, 171, 172, - 0, 173, 174, 175, 176, 177, 178, 0, 592, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 594, - 191, 192, 595, 194, 0, 195, 0, 196, 197, 198, - 199, 200, 201, 14, 15, 202, 203, 204, 205, 0, - 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, - 0, 214, 215, 216, 0, 217, 218, 219, 220, 605, - 222, 223, 224, 225, 226, 227, 606, 0, 229, 0, - 230, 231, 609, 233, 0, 234, 0, 235, 612, 23, - 614, 238, 239, 615, 616, 242, 0, 243, 0, 619, - 620, 246, 247, 0, 248, 249, 250, 251, 252, 253, - 254, 622, 256, 257, 258, 259, 0, 260, 261, 262, - 263, 264, 265, 266, 0, 267, 625, 626, 270, 271, - 272, 273, 274, 627, 628, 0, 630, 0, 278, 632, - 633, 281, 634, 283, 284, 285, 286, 287, 288, 0, - 0, 289, 637, 291, 638, 0, 293, 294, 295, 296, - 297, 298, 299, 300, 640, 302, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 641, 642, 643, 325, 326, - 327, 644, 0, 329, 330, 646, 332, 0, 648, 334, - 649, 336, 337, 338, 0, 339, 340, 0, 0, 341, - 342, 343, 0, 0, 344, 345, 655, 656, 348, 657, - 658, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, 26, 27, 28, 0, 362, 363, 663, 664, - 366, 367, 665, 369, 370, 371, 0, 372, 373, 374, - 375, 376, 377, 0, 378, 379, 380, 381, 382, 668, - 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, - 402, 671, 404, 405, 406, 672, 408, 409, 410, 411, - 412, 413, 414, 415, 416, 417, 418, 419, 420, 33, - 674, 421, 422, 423, 424, 425, 426, 675, 428, 429, - 35, 677, 431, 432, 678, 434, 0, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, 680, - 448, 681, 37, 0, 450, 451, 38, 452, 685, 454, - 455, 456, 457, 458, 0, 459, 687, 688, 0, 0, - 462, 463, 691, 465, 692, 0, 467, 468, 694, 470, - 471, 472, 473, 474, 0, 0, 475, 476, 477, 40, - 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, - 974, 700, 489, 0, 490, 702, 492, 493, 494, 495, - 496, 497, 498, 0, 0, 499, 0, 44, 500, 501, - 502, 503, 504, 505, 707, 708, 709, 710, 711, 712, - 713, 714, 715, 716, 717, 517, 518, 519, 520, 0, - 117, 45, 554, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 46, 0, 0, 0, 118, - 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, - 128, 0, 0, 0, 0, 0, 0, 0, 0, 129, - 130, 131, 0, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 0, 144, 145, 146, 147, - 148, 149, 0, 790, 150, 151, 152, 153, 154, 155, - 156, 0, 157, 158, 159, 160, 791, 0, 792, 0, - 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, - 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, - 199, 200, 201, 14, 15, 202, 203, 204, 205, 0, - 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, - 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 793, 0, 229, 0, - 230, 231, 232, 233, 0, 234, 0, 235, 236, 23, - 237, 238, 239, 240, 241, 242, 0, 243, 0, 244, - 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, - 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, - 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, - 272, 273, 274, 275, 276, 0, 277, 0, 278, 279, - 280, 281, 282, 283, 284, 285, 286, 287, 288, 794, - 0, 289, 290, 291, 292, 0, 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, 0, 329, 330, 331, 332, 0, 795, 334, - 335, 336, 337, 338, 0, 339, 340, 0, 796, 341, - 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, - 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, 26, 27, 28, 0, 362, 363, 798, 365, - 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, - 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, - 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, - 402, 403, 404, 405, 406, 407, 799, 409, 410, 411, - 412, 413, 414, 415, 416, 417, 418, 419, 420, 33, - 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, - 35, 430, 431, 432, 433, 434, 0, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, - 448, 800, 37, 0, 450, 451, 38, 452, 453, 454, - 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, - 462, 463, 801, 465, 802, 0, 467, 468, 803, 470, - 471, 472, 473, 474, 0, 0, 475, 476, 477, 40, - 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, - 804, 488, 489, 0, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 0, 0, 499, 0, 44, 500, 501, - 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, - 512, 513, 514, 515, 516, 517, 518, 519, 520, 0, - 117, 45, 554, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 805, 0, 0, 0, 118, + 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 994, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, - 128, 0, 0, 0, 0, 0, 0, 0, 0, 129, - 130, 131, 0, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 0, 144, 145, 146, 147, - 148, 149, 0, 790, 150, 151, 152, 153, 154, 155, - 156, 0, 157, 158, 159, 160, 791, 0, 792, 0, - 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, - 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, + 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, + 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, + 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, + 156, 0, 157, 158, 159, 160, 161, 0, 0, 0, + 163, 164, 165, 166, 167, 168, 0, 170, 171, 172, + 0, 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 793, 0, 229, 0, - 230, 231, 232, 233, 0, 234, 0, 235, 236, 0, - 237, 238, 239, 240, 241, 242, 0, 243, 0, 244, + 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, + 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, + 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, - 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, - 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, - 272, 273, 274, 275, 276, 0, 277, 0, 278, 279, - 280, 281, 282, 283, 284, 285, 286, 287, 288, 794, - 0, 289, 290, 291, 292, 0, 293, 294, 295, 296, - 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, + 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, + 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, + 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, + 0, 289, 0, 291, 0, 0, 293, 294, 295, 296, + 297, 298, 299, 300, 530, 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, 0, 329, 330, 331, 332, 0, 795, 334, - 335, 336, 337, 338, 0, 339, 340, 0, 796, 341, - 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, - 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, + 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, + 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, + 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, + 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, - 402, 403, 404, 405, 406, 407, 799, 409, 410, 411, + 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, - 0, 430, 431, 432, 433, 434, 0, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, - 448, 800, 0, 0, 450, 451, 0, 452, 453, 454, + 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, + 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, - 462, 463, 801, 465, 802, 0, 467, 468, 803, 470, + 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, - 804, 488, 489, 0, 490, 491, 492, 493, 494, 495, + 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, - 512, 513, 514, 515, 516, 517, 518, 519, 520, 117, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 805, 0, 0, 118, 119, + 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, + 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1492, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 0, 0, 0, 0, 0, 129, 130, - 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 0, 144, 145, 146, 147, 148, - 149, 0, 790, 150, 151, 152, 153, 154, 155, 156, - 0, 157, 158, 159, 160, 791, 0, 792, 0, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, - 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, + 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, + 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, + 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, + 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, + 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 793, 0, 229, 0, 230, - 231, 232, 233, 0, 234, 0, 235, 236, 0, 237, - 238, 239, 240, 241, 242, 0, 243, 0, 244, 245, + 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, + 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, + 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, - 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, - 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, - 273, 274, 275, 276, 0, 277, 0, 278, 279, 280, - 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, - 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, + 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, + 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, + 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 530, 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, 0, 329, 330, 331, 332, 0, 795, 334, 335, + 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, + 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, - 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, + 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 403, 404, 405, 406, 407, 799, 409, 410, 411, 412, + 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, - 430, 431, 432, 433, 434, 0, 435, 436, 437, 438, - 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, - 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, + 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, + 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, - 463, 801, 465, 802, 0, 467, 468, 803, 470, 471, + 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, - 488, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 117, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 46, 0, 0, 118, 119, 120, + 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, + 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2099, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, - 0, 0, 0, 0, 0, 0, 0, 129, 130, 131, - 0, 132, 133, 134, 135, 136, 137, 138, 139, 140, - 141, 142, 143, 0, 144, 145, 146, 147, 148, 149, - 0, 790, 150, 151, 152, 153, 154, 155, 156, 0, - 157, 158, 159, 160, 791, 0, 792, 0, 163, 164, - 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, - 174, 175, 176, 177, 178, 0, 179, 180, 181, 182, + 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, + 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, + 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, + 0, 0, 150, 151, 152, 153, 154, 155, 156, 0, + 157, 158, 159, 160, 161, 0, 0, 0, 163, 164, + 165, 166, 167, 168, 0, 170, 171, 172, 0, 173, + 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 793, 0, 229, 0, 230, 231, - 232, 233, 0, 234, 0, 235, 236, 0, 237, 238, - 239, 240, 241, 242, 0, 243, 0, 244, 245, 246, - 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, + 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, + 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, + 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, + 247, 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, - 265, 266, 0, 267, 268, 269, 270, 271, 272, 273, - 274, 275, 276, 0, 277, 0, 278, 279, 280, 281, - 282, 283, 284, 285, 286, 287, 288, 0, 0, 289, - 290, 291, 292, 0, 293, 294, 295, 296, 297, 298, - 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, + 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, + 0, 283, 284, 285, 286, 287, 288, 0, 0, 289, + 0, 291, 0, 0, 293, 294, 295, 296, 297, 298, + 299, 300, 530, 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, - 0, 329, 330, 331, 332, 0, 795, 334, 335, 336, + 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, + 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, - 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, + 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, - 0, 0, 0, 0, 362, 363, 798, 365, 366, 367, + 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 0, 401, 402, 403, + 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, - 422, 423, 424, 425, 426, 427, 428, 429, 0, 430, + 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, - 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, - 0, 0, 450, 451, 0, 452, 453, 454, 455, 456, + 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, + 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, - 801, 465, 802, 0, 467, 468, 803, 470, 471, 472, + 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, - 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, + 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, - 514, 515, 516, 517, 518, 519, 520, 528, 0, 0, + 514, 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3359, 0, 0, 118, 119, 120, 121, + 0, 0, 0, 2246, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, @@ -7710,11 +8297,11 @@ static const yytype_int16 yytable[] = 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, - 14, 15, 202, 203, 204, 205, 0, 0, 206, 207, + 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, - 233, 0, 234, 0, 235, 0, 23, 0, 238, 239, + 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, @@ -7728,29 +8315,29 @@ static const yytype_int16 yytable[] = 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 26, - 27, 28, 0, 362, 363, 364, 0, 366, 367, 368, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, + 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 33, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 35, 0, 431, + 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 531, 448, 449, 37, - 0, 450, 451, 38, 452, 0, 454, 455, 456, 457, + 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, + 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 40, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 804, 488, 489, + 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, + 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 44, 500, 501, 502, 503, 504, + 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 528, 0, 45, 0, + 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 46, 0, 0, 118, 119, 120, 121, 122, - 123, 124, 125, 893, 126, 127, 128, 0, 0, 0, + 0, 0, 2490, 0, 0, 118, 119, 120, 121, 122, + 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, @@ -7764,7 +8351,7 @@ static const yytype_int16 yytable[] = 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, - 0, 234, 0, 235, 0, 23, 0, 238, 239, 529, + 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, @@ -7778,78 +8365,28 @@ static const yytype_int16 yytable[] = 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, 361, 26, 27, - 28, 0, 362, 363, 364, 0, 366, 367, 368, 369, + 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, + 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, - 416, 417, 418, 419, 420, 33, 0, 421, 422, 423, + 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, - 450, 451, 38, 452, 0, 454, 455, 456, 457, 458, - 0, 459, 894, 461, 0, 0, 895, 463, 464, 465, + 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, + 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, - 0, 0, 475, 476, 477, 40, 478, 479, 480, 481, - 0, 482, 483, 484, 485, 486, 804, 488, 489, 0, + 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, + 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, - 0, 499, 0, 44, 500, 501, 502, 503, 504, 505, + 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, - 516, 517, 518, 519, 520, 528, 0, 45, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 46, 0, 0, 118, 119, 120, 121, 122, 123, - 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, - 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, - 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, - 151, 152, 153, 154, 155, 156, 0, 157, 158, 159, - 160, 161, 0, 0, 0, 163, 164, 165, 166, 167, - 168, 0, 170, 171, 172, 0, 173, 174, 175, 176, - 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, - 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, - 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, - 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, - 234, 0, 235, 0, 23, 0, 238, 239, 529, 0, - 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, - 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, - 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, - 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, - 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, - 285, 286, 287, 288, 0, 0, 289, 0, 291, 0, - 0, 293, 294, 295, 296, 297, 298, 299, 300, 530, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, - 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, - 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, - 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 26, 27, 28, - 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, - 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, - 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, - 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, - 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 33, 0, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, - 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, - 451, 38, 452, 0, 454, 455, 456, 457, 458, 0, - 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, - 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, - 0, 475, 476, 477, 40, 478, 479, 480, 481, 0, - 482, 483, 484, 485, 486, 804, 488, 489, 0, 490, - 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, - 499, 0, 44, 500, 501, 502, 503, 504, 505, 506, - 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, - 517, 518, 519, 520, 0, 528, 45, 554, 0, 0, + 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 46, 0, 0, 0, 118, 119, 120, 121, 122, 123, + 0, 2631, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, @@ -7899,7 +8436,7 @@ static const yytype_int16 yytable[] = 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 993, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 2844, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, @@ -7947,8 +8484,8 @@ static const yytype_int16 yytable[] = 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, - 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1481, + 518, 519, 520, 528, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 3299, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, @@ -7997,8 +8534,8 @@ static const yytype_int16 yytable[] = 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2230, 0, + 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2206, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, @@ -8047,308 +8584,277 @@ static const yytype_int16 yytable[] = 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2476, 0, 0, - 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, - 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, - 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, - 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, - 155, 156, 0, 157, 158, 159, 160, 161, 0, 0, - 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, - 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, - 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, - 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, - 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, - 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, - 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, - 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, - 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, - 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, - 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 0, 291, 0, 0, 293, 294, 295, - 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, - 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, - 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, - 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, - 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, - 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, - 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, - 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, - 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, - 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, - 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, - 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, - 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, - 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, - 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, - 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2612, 0, 0, 118, - 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, - 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, - 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, - 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, - 156, 0, 157, 158, 159, 160, 161, 0, 0, 0, - 163, 164, 165, 166, 167, 168, 0, 170, 171, 172, - 0, 173, 174, 175, 176, 177, 178, 0, 0, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, - 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, - 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, - 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, - 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, - 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, - 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, - 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, - 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, - 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, - 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, - 0, 289, 0, 291, 0, 0, 293, 294, 295, 296, - 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, - 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, - 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, - 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, - 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, - 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, - 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, - 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, - 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, - 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, - 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, - 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, - 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, - 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, - 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, - 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, - 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, - 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, - 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 3268, 0, 0, 118, 119, - 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, - 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, - 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, - 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, - 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, - 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, - 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, - 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, - 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, - 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, - 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, - 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, - 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, - 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, - 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, - 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, - 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, - 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, - 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, - 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, - 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, - 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, - 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, - 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, - 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, - 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, - 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, - 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, - 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, - 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, - 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, - 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, + 520, 0, 2970, 1363, 821, 0, 0, 2074, 1060, 0, + 0, 0, 0, 0, 2075, 2076, 0, 3161, 2077, 2078, + 2079, 118, 119, 120, 121, 122, 123, 124, 125, 561, + 126, 127, 128, 562, 563, 564, 2971, 566, 567, 568, + 569, 2972, 130, 131, 571, 132, 133, 134, 2973, 136, + 137, 138, 0, 1505, 2974, 1507, 1508, 578, 144, 145, + 146, 147, 148, 149, 579, 580, 150, 151, 152, 153, + 1509, 1510, 156, 583, 157, 158, 159, 160, 0, 585, + 2975, 587, 2976, 164, 165, 166, 167, 168, 2977, 170, + 171, 172, 590, 173, 174, 175, 176, 177, 178, 591, + 2978, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 1515, 191, 192, 1516, 194, 596, 195, 597, 196, + 197, 198, 199, 200, 201, 598, 599, 202, 203, 204, + 205, 600, 601, 206, 207, 1073, 209, 210, 602, 211, + 212, 213, 603, 214, 215, 216, 604, 217, 218, 219, + 220, 0, 222, 223, 224, 225, 226, 227, 0, 607, + 229, 608, 230, 231, 1517, 233, 610, 234, 611, 235, + 2979, 613, 2980, 238, 239, 2981, 2982, 242, 617, 243, + 618, 0, 0, 246, 247, 621, 248, 249, 250, 251, + 252, 253, 254, 2983, 256, 257, 258, 259, 623, 260, + 261, 262, 263, 264, 265, 266, 624, 267, 2984, 0, + 270, 271, 272, 273, 274, 1523, 1524, 629, 1525, 631, + 278, 2985, 2986, 281, 2987, 283, 284, 285, 286, 287, + 288, 635, 636, 289, 2988, 291, 2989, 639, 293, 294, + 295, 296, 297, 298, 299, 300, 2990, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 1532, 2991, 1534, + 325, 326, 327, 2992, 645, 329, 330, 2993, 332, 647, + 0, 334, 1536, 336, 337, 338, 650, 339, 340, 651, + 652, 2994, 342, 343, 653, 654, 344, 345, 0, 2995, + 348, 2996, 0, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 360, 361, 659, 660, 661, 662, 362, 363, + 0, 2997, 366, 367, 0, 369, 370, 371, 666, 372, + 373, 374, 375, 376, 377, 667, 378, 379, 380, 381, + 382, 1540, 384, 385, 386, 387, 669, 388, 389, 390, + 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, + 670, 401, 402, 2998, 404, 405, 406, 1542, 408, 409, + 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, + 420, 673, 2999, 421, 422, 423, 424, 425, 426, 3000, + 428, 429, 676, 3001, 431, 432, 1546, 434, 679, 435, + 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, + 446, 3002, 448, 0, 682, 683, 450, 451, 684, 452, + 3003, 454, 455, 456, 457, 458, 686, 459, 1549, 1550, + 689, 690, 462, 463, 0, 465, 0, 693, 467, 468, + 3004, 470, 471, 472, 473, 474, 3005, 696, 475, 476, + 477, 697, 478, 479, 480, 481, 698, 482, 483, 484, + 485, 486, 0, 1553, 489, 701, 490, 3006, 492, 493, + 494, 495, 496, 497, 498, 703, 704, 499, 705, 706, + 500, 501, 502, 503, 504, 505, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 517, 518, 519, + 520, 0, 528, 0, 2080, 2081, 2082, 2074, 3007, 3008, + 2085, 2086, 2087, 2088, 2075, 2076, 0, 0, 2077, 2078, + 2079, 118, 119, 120, 121, 122, 123, 124, 125, 0, + 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, + 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, + 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, + 154, 155, 156, 0, 157, 158, 159, 160, 161, 0, + 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, + 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, + 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, + 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, + 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, + 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, + 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, + 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, + 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, + 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, + 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, + 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, + 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, + 288, 0, 0, 289, 0, 291, 0, 0, 293, 294, + 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, + 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, + 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, + 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, + 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, + 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, + 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, + 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, + 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, + 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, + 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, + 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, + 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, + 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, + 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, + 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, + 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, + 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, + 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, + 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, + 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, + 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, + 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, + 520, 0, 0, 0, 2080, 2081, 2082, 0, 2083, 2084, + 2085, 2086, 2087, 2088, 1638, 0, 0, 1639, 0, 0, + 0, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2085, 0, 0, 118, 119, 120, - 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, - 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, - 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, - 0, 0, 150, 151, 152, 153, 154, 155, 156, 0, - 157, 158, 159, 160, 161, 0, 0, 0, 163, 164, - 165, 166, 167, 168, 0, 170, 171, 172, 0, 173, - 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, - 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, - 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, - 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, - 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, - 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, - 247, 0, 248, 249, 250, 251, 252, 253, 254, 0, - 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, - 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, - 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, - 0, 283, 284, 285, 286, 287, 288, 0, 0, 289, - 0, 291, 0, 0, 293, 294, 295, 296, 297, 298, - 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, + 0, 0, 1647, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1649, 1638, 0, 0, 1639, 0, 0, 1650, + 1640, 1641, 1642, 1643, 1644, 1645, 1646, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1647, 0, 0, 0, 0, 1651, 0, 0, 0, + 0, 1649, 1638, 0, 0, 1639, 0, 0, 1650, 1640, + 1641, 1642, 1643, 1644, 1645, 1646, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1647, 0, 0, 0, 0, 1651, 0, 0, 0, 0, + 1649, 0, 0, 0, 0, 0, 0, 1650, 0, 0, + 1638, 0, 0, 1639, 0, 0, 0, 1640, 1641, 1642, + 1643, 1644, 1645, 1646, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1651, 0, 0, 0, 1647, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1649, 1638, + 0, 0, 1639, 1652, 0, 1650, 1640, 1641, 1642, 1643, + 1644, 1645, 1646, 0, 0, 0, 0, 0, 0, 0, + 1653, 0, 0, 0, 0, 1654, 0, 1647, 0, 0, + 0, 0, 1651, 0, 0, 0, 0, 1649, 0, 0, + 0, 0, 1652, 0, 1650, 0, 0, 0, 1655, 1656, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1653, + 0, 0, 0, 1657, 1654, 0, 0, 0, 0, 0, + 0, 1651, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1652, 0, 0, 0, 0, 0, 1655, 1656, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1653, 0, + 0, 1658, 1657, 1654, 1659, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1660, 0, + 0, 1661, 0, 0, 0, 0, 1655, 1656, 0, 1652, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1658, 1657, 0, 1659, 0, 0, 1653, 0, 0, 0, + 0, 1654, 0, 0, 0, 0, 0, 1660, 0, 0, + 1661, 0, 0, 0, 0, 0, 0, 0, 1652, 0, + 0, 0, 0, 0, 1655, 1656, 0, 0, 0, 1658, + 0, 0, 1659, 0, 0, 1653, 0, 0, 0, 1657, + 1654, 0, 0, 0, 0, 0, 1660, 0, 0, 1661, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1655, 1656, 0, 0, 0, 0, 0, + 1662, 0, 0, 0, 0, 0, 0, 1658, 1657, 0, + 1659, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1660, 0, 0, 1661, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1662, + 0, 0, 0, 0, 0, 0, 1658, 0, 0, 1659, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1660, 0, 0, 1661, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1662, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1663, 0, + 0, 1664, 1665, 1666, 0, 1667, 1668, 1669, 1670, 1671, + 1672, 0, 0, 0, 0, 3322, 1662, 0, 0, 0, + 0, 0, 1638, 0, 0, 1639, 0, 0, 0, 1640, + 1641, 1642, 1643, 1644, 1645, 1646, 0, 1663, 0, 0, + 1664, 1665, 1666, 0, 1667, 1668, 1669, 1670, 1671, 1672, + 1647, 0, 0, 0, 3344, 1662, 0, 0, 1638, 0, + 1649, 1639, 0, 0, 0, 1640, 1641, 1650, 0, 1644, + 1645, 1646, 0, 0, 0, 0, 1663, 0, 0, 1664, + 1665, 1666, 0, 1667, 1668, 1669, 1670, 1671, 1672, 0, + 0, 0, 0, 3444, 1651, 0, 1649, 0, 0, 0, + 0, 0, 0, 1650, 0, 0, 0, 0, 0, 1638, + 0, 0, 1639, 0, 0, 0, 1640, 1641, 1642, 1643, + 1644, 1645, 1646, 0, 1663, 0, 0, 1664, 1665, 1666, + 1651, 1667, 1668, 1669, 1670, 1671, 1672, 1647, 0, 0, + 0, 3500, 0, 0, 0, 0, 0, 1649, 1638, 0, + 0, 1639, 0, 0, 1650, 1640, 1641, 1642, 1643, 1644, + 1645, 1646, 0, 1663, 0, 0, 1664, 1665, 1666, 0, + 1667, 1668, 1669, 1670, 1671, 1672, 1647, 0, 0, 0, + 3522, 1651, 0, 0, 0, 0, 1649, 1638, 0, 0, + 1639, 1652, 0, 1650, 1640, 1641, 1642, 1643, 1644, 1645, + 1646, 0, 0, 0, 0, 0, 0, 0, 1653, 0, + 0, 0, 0, 1654, 0, 1647, 0, 0, 0, 0, + 1651, 0, 0, 0, 0, 1649, 0, 1652, 0, 0, + 0, 0, 1650, 0, 0, 0, 1655, 1656, 0, 0, + 0, 0, 0, 0, 1653, 0, 0, 0, 0, 1654, + 0, 1657, 0, 0, 0, 0, 0, 0, 0, 1651, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1655, 1656, 0, 0, 0, 0, 1652, 0, + 0, 0, 0, 0, 0, 0, 0, 1657, 0, 1658, + 0, 0, 1659, 0, 0, 1653, 0, 0, 0, 0, + 1654, 0, 0, 0, 0, 0, 1660, 0, 0, 1661, + 0, 0, 0, 0, 0, 0, 0, 1652, 0, 0, + 0, 0, 0, 1655, 1656, 1658, 0, 0, 1659, 0, + 0, 0, 0, 0, 1653, 0, 0, 0, 1657, 1654, + 0, 0, 1660, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1652, 0, 0, 0, + 0, 0, 1655, 1656, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1653, 0, 0, 1658, 1657, 1654, 1659, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1660, 0, 0, 1661, 0, 0, 0, + 0, 1655, 1656, 0, 0, 0, 0, 0, 1662, 0, + 0, 0, 0, 0, 0, 1658, 1657, 0, 1659, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1660, 0, 0, 1661, 0, 0, 0, 0, + 0, 0, 0, 0, 1662, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1658, 0, 0, 1659, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1660, 0, 0, 1661, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1662, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1663, 0, 0, 1664, + 1665, 1666, 0, 1667, 1668, 1669, 1670, 1671, 1672, 0, + 0, 1826, 0, 0, 1662, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1663, 0, 0, 1664, 1665, 1666, 0, 1667, + 1668, 1669, 1670, 1671, 1672, 0, 0, 0, 0, 0, + 0, 0, 0, 1662, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1663, 0, 0, 1664, 1665, 1666, 0, + 1667, 1668, 1669, 1670, 1671, 1672, 0, 0, 2870, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1663, 0, 0, 1664, 1665, 1666, 0, 1667, + 1668, 1669, 1670, 1671, 1672, 0, 0, 3312, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 560, 0, + 0, 1663, 0, 0, 1664, 1665, 1666, 0, 1667, 1668, + 1669, 1670, 1671, 1672, 0, 0, 3484, 118, 119, 120, + 121, 122, 123, 124, 125, 561, 126, 127, 128, 562, + 563, 564, 565, 566, 567, 568, 569, 570, 130, 131, + 571, 132, 133, 134, 572, 136, 137, 138, 573, 574, + 575, 576, 577, 578, 144, 145, 146, 147, 148, 149, + 579, 580, 150, 151, 152, 153, 581, 582, 156, 583, + 157, 158, 159, 160, 584, 585, 586, 587, 588, 164, + 165, 166, 167, 168, 589, 170, 171, 172, 590, 173, + 174, 175, 176, 177, 178, 591, 592, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 594, 191, 192, + 595, 194, 596, 195, 597, 196, 197, 198, 199, 200, + 201, 598, 599, 202, 203, 204, 205, 600, 601, 206, + 207, 208, 209, 210, 602, 211, 212, 213, 603, 214, + 215, 216, 604, 217, 218, 219, 220, 605, 222, 223, + 224, 225, 226, 227, 606, 607, 229, 608, 230, 231, + 609, 233, 610, 234, 611, 235, 612, 613, 614, 238, + 239, 615, 616, 242, 617, 243, 618, 619, 620, 246, + 247, 621, 248, 249, 250, 251, 252, 253, 254, 622, + 256, 257, 258, 259, 623, 260, 261, 262, 263, 264, + 265, 266, 624, 267, 625, 626, 270, 271, 272, 273, + 274, 627, 628, 629, 630, 631, 278, 632, 633, 281, + 634, 283, 284, 285, 286, 287, 288, 635, 636, 289, + 637, 291, 638, 639, 293, 294, 295, 296, 297, 298, + 299, 300, 640, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, - 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, - 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, - 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, + 319, 320, 321, 641, 642, 643, 325, 326, 327, 644, + 645, 329, 330, 646, 332, 647, 648, 334, 649, 336, + 337, 338, 650, 339, 340, 651, 652, 341, 342, 343, + 653, 654, 344, 345, 655, 656, 348, 657, 658, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, - 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, - 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, - 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, - 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, - 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, - 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, - 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, - 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, - 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, - 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, - 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, - 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, - 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, - 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, - 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, - 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, - 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, - 514, 515, 516, 517, 518, 519, 520, 528, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2190, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, - 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, - 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, - 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, - 158, 159, 160, 161, 0, 0, 0, 163, 164, 165, - 166, 167, 168, 0, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, - 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, - 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, - 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 0, - 291, 0, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, - 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, - 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, - 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, - 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, - 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, - 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, - 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, - 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, - 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 0, 2946, 1356, 820, - 0, 0, 2060, 1054, 0, 0, 0, 0, 0, 2061, - 2062, 0, 3131, 2063, 2064, 2065, 118, 119, 120, 121, - 122, 123, 124, 125, 561, 126, 127, 128, 562, 563, - 564, 2947, 566, 567, 568, 569, 2948, 130, 131, 571, - 132, 133, 134, 2949, 136, 137, 138, 0, 1494, 2950, - 1496, 1497, 578, 144, 145, 146, 147, 148, 149, 579, - 580, 150, 151, 152, 153, 1498, 1499, 156, 583, 157, - 158, 159, 160, 0, 585, 2951, 587, 2952, 164, 165, - 166, 167, 168, 2953, 170, 171, 172, 590, 173, 174, - 175, 176, 177, 178, 591, 2954, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1504, 191, 192, 1505, - 194, 596, 195, 597, 196, 197, 198, 199, 200, 201, - 598, 599, 202, 203, 204, 205, 600, 601, 206, 207, - 1067, 209, 210, 602, 211, 212, 213, 603, 214, 215, - 216, 604, 217, 218, 219, 220, 0, 222, 223, 224, - 225, 226, 227, 0, 607, 229, 608, 230, 231, 1506, - 233, 610, 234, 611, 235, 2955, 613, 2956, 238, 239, - 2957, 2958, 242, 617, 243, 618, 0, 0, 246, 247, - 621, 248, 249, 250, 251, 252, 253, 254, 2959, 256, - 257, 258, 259, 623, 260, 261, 262, 263, 264, 265, - 266, 624, 267, 2960, 0, 270, 271, 272, 273, 274, - 1512, 1513, 629, 1514, 631, 278, 2961, 2962, 281, 2963, - 283, 284, 285, 286, 287, 288, 635, 636, 289, 2964, - 291, 2965, 639, 293, 294, 295, 296, 297, 298, 299, - 300, 2966, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1521, 2967, 1523, 325, 326, 327, 2968, 645, - 329, 330, 2969, 332, 647, 0, 334, 1525, 336, 337, - 338, 650, 339, 340, 651, 652, 2970, 342, 343, 653, - 654, 344, 345, 0, 2971, 348, 2972, 0, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 659, - 660, 661, 662, 362, 363, 0, 2973, 366, 367, 0, - 369, 370, 371, 666, 372, 373, 374, 375, 376, 377, - 667, 378, 379, 380, 381, 382, 1529, 384, 385, 386, - 387, 669, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 670, 401, 402, 2974, 404, - 405, 406, 1531, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 673, 2975, 421, 422, - 423, 424, 425, 426, 2976, 428, 429, 676, 2977, 431, - 432, 1535, 434, 679, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 2978, 448, 0, 682, - 683, 450, 451, 684, 452, 2979, 454, 455, 456, 457, - 458, 686, 459, 1538, 1539, 689, 690, 462, 463, 0, - 465, 0, 693, 467, 468, 2980, 470, 471, 472, 473, - 474, 2981, 696, 475, 476, 477, 697, 478, 479, 480, - 481, 698, 482, 483, 484, 485, 486, 0, 1542, 489, - 701, 490, 2982, 492, 493, 494, 495, 496, 497, 498, - 703, 704, 499, 705, 706, 500, 501, 502, 503, 504, - 505, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 517, 518, 519, 520, 0, 528, 0, 2066, - 2067, 2068, 2060, 2983, 2984, 2071, 2072, 2073, 2074, 2061, - 2062, 0, 0, 2063, 2064, 2065, 118, 119, 120, 121, + 659, 660, 661, 662, 362, 363, 663, 664, 366, 367, + 665, 369, 370, 371, 666, 372, 373, 374, 375, 376, + 377, 667, 378, 379, 380, 381, 382, 668, 384, 385, + 386, 387, 669, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 670, 401, 402, 671, + 404, 405, 406, 672, 408, 409, 410, 411, 412, 413, + 414, 415, 416, 417, 418, 419, 420, 673, 674, 421, + 422, 423, 424, 425, 426, 675, 428, 429, 676, 677, + 431, 432, 678, 434, 679, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, 680, 448, 681, + 682, 683, 450, 451, 684, 452, 685, 454, 455, 456, + 457, 458, 686, 459, 687, 688, 689, 690, 462, 463, + 691, 465, 692, 693, 467, 468, 694, 470, 471, 472, + 473, 474, 695, 696, 475, 476, 477, 697, 478, 479, + 480, 481, 698, 482, 483, 484, 485, 486, 699, 700, + 489, 701, 490, 702, 492, 493, 494, 495, 496, 497, + 498, 703, 704, 499, 705, 706, 500, 501, 502, 503, + 504, 505, 707, 708, 709, 710, 711, 712, 713, 714, + 715, 716, 717, 517, 518, 519, 520, 528, 0, 0, + 0, 0, 0, 0, 0, 0, 2111, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, @@ -8396,172 +8902,349 @@ static const yytype_int16 yytable[] = 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 0, 0, 0, 2066, - 2067, 2068, 0, 2069, 2070, 2071, 2072, 2073, 2074, 1626, - 0, 0, 1627, 0, 0, 0, 1628, 1629, 1630, 1631, - 1632, 1633, 1634, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1635, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1637, 1626, 0, - 0, 1627, 0, 0, 1638, 1628, 1629, 1630, 1631, 1632, - 1633, 1634, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1635, 0, 0, 0, - 0, 1639, 0, 0, 0, 0, 1637, 1626, 0, 0, - 1627, 0, 0, 1638, 1628, 1629, 1630, 1631, 1632, 1633, - 1634, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1635, 0, 0, 0, 0, - 1639, 0, 0, 0, 0, 1637, 0, 0, 0, 0, - 0, 0, 1638, 0, 0, 1626, 0, 0, 1627, 0, - 0, 0, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1639, - 0, 0, 0, 1635, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1637, 1626, 0, 0, 1627, 1640, 0, - 1638, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, 0, - 0, 0, 0, 0, 0, 1641, 0, 0, 0, 0, - 1642, 0, 1635, 0, 0, 0, 0, 1639, 0, 0, - 0, 0, 1637, 0, 0, 0, 0, 1640, 0, 1638, - 0, 0, 0, 1643, 1644, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1641, 0, 0, 0, 1645, 1642, - 0, 0, 0, 0, 0, 0, 1639, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1640, 0, 0, 0, - 0, 0, 1643, 1644, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1641, 0, 0, 1646, 1645, 1642, 1647, + 515, 516, 517, 518, 519, 520, 528, 0, 0, 0, + 0, 0, 0, 0, 0, 2763, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, + 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, + 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, + 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, + 150, 151, 152, 153, 154, 155, 156, 0, 157, 158, + 159, 160, 161, 0, 0, 0, 163, 164, 165, 166, + 167, 168, 0, 170, 171, 172, 0, 173, 174, 175, + 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, + 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, + 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, + 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, + 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, + 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, + 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, + 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, + 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, + 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, + 284, 285, 286, 287, 288, 0, 0, 289, 0, 291, + 0, 0, 293, 294, 295, 296, 297, 298, 299, 300, + 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, + 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, + 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, + 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, + 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, + 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, + 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, + 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, + 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, + 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, + 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, + 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, + 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, + 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, + 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, + 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, + 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, + 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, + 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, + 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, + 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, + 516, 517, 518, 519, 520, 974, 1363, 821, 0, 0, + 0, 1060, 0, 0, 2766, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, + 124, 125, 0, 126, 127, 128, 0, 0, 0, 565, + 0, 0, 0, 0, 570, 130, 131, 0, 132, 133, + 134, 572, 136, 137, 138, 573, 574, 575, 576, 577, + 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, + 151, 152, 153, 581, 582, 156, 0, 157, 158, 159, + 160, 584, 0, 586, 0, 588, 164, 165, 166, 167, + 168, 589, 170, 171, 172, 0, 173, 174, 175, 176, + 177, 178, 0, 592, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 594, 191, 192, 595, 194, 0, + 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, + 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, + 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, + 217, 218, 219, 220, 605, 222, 223, 224, 225, 226, + 227, 606, 1364, 229, 0, 230, 231, 609, 233, 0, + 234, 0, 235, 612, 0, 614, 238, 239, 615, 616, + 242, 0, 243, 0, 619, 620, 246, 247, 0, 248, + 249, 250, 251, 252, 253, 254, 622, 256, 257, 258, + 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, + 267, 625, 626, 270, 271, 272, 273, 274, 627, 628, + 0, 630, 0, 278, 632, 633, 281, 634, 283, 284, + 285, 286, 287, 288, 0, 0, 289, 637, 291, 638, + 0, 293, 294, 295, 296, 297, 298, 299, 300, 640, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 641, 642, 643, 325, 326, 327, 644, 0, 329, 330, + 646, 332, 0, 648, 334, 649, 336, 337, 338, 0, + 339, 340, 1365, 0, 341, 342, 343, 0, 0, 344, + 345, 655, 656, 348, 657, 658, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, + 0, 362, 363, 663, 664, 366, 367, 665, 369, 370, + 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, + 379, 380, 381, 382, 668, 384, 385, 386, 387, 0, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 398, 399, 400, 0, 401, 402, 671, 404, 405, 406, + 672, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 0, 674, 421, 422, 423, 424, + 425, 426, 675, 428, 429, 0, 677, 431, 432, 678, + 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 680, 448, 681, 0, 0, 450, + 451, 0, 452, 685, 454, 455, 456, 457, 458, 0, + 459, 687, 688, 0, 0, 462, 463, 691, 465, 692, + 1366, 467, 468, 694, 470, 471, 472, 473, 474, 0, + 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, + 482, 483, 484, 485, 486, 699, 700, 489, 0, 490, + 702, 492, 493, 494, 495, 496, 497, 498, 0, 0, + 499, 0, 0, 500, 501, 502, 503, 504, 505, 707, + 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, + 517, 518, 519, 520, 0, 0, 1638, 0, 0, 1639, + 0, 1367, 1368, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1648, 0, 0, 1649, 0, 0, 0, - 0, 1643, 1644, 0, 1640, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1646, 1645, 0, 1647, 0, - 0, 1641, 0, 0, 0, 0, 1642, 0, 0, 0, - 0, 0, 1648, 0, 0, 1649, 0, 0, 0, 0, - 0, 0, 0, 1640, 0, 0, 0, 0, 0, 1643, - 1644, 0, 0, 0, 1646, 0, 0, 1647, 0, 0, - 1641, 0, 0, 0, 1645, 1642, 0, 0, 0, 0, - 0, 1648, 0, 0, 1649, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1643, 1644, - 0, 0, 0, 0, 0, 1650, 0, 0, 0, 0, - 0, 0, 1646, 1645, 0, 1647, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1648, - 0, 0, 1649, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1650, 0, 0, 0, 0, 0, - 0, 1646, 0, 0, 1647, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1648, 0, - 0, 1649, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1650, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1647, 0, 0, 0, 0, 2212, + 0, 0, 0, 0, 1649, 1638, 0, 0, 1639, 0, + 0, 1650, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 0, + 0, 0, 0, 1638, 0, 0, 1639, 0, 0, 0, + 1640, 1641, 0, 1647, 1644, 1645, 1646, 0, 1651, 0, + 0, 0, 0, 1649, 1638, 0, 0, 1639, 0, 0, + 1650, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 0, 0, + 0, 1649, 0, 0, 0, 0, 0, 0, 1650, 0, + 0, 0, 1647, 0, 0, 0, 0, 1651, 0, 0, + 0, 0, 1649, 0, 2213, 0, 0, 0, 0, 1650, + 0, 1638, 0, 0, 1639, 1651, 0, 0, 1640, 1641, + 1642, 1643, 1644, 1645, 1646, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1651, 0, 0, 1647, + 0, 0, 0, 1925, 0, 0, 0, 0, 0, 1649, + 0, 0, 0, 0, 0, 1652, 1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1653, 0, 0, 0, 0, 1654, 0, 0, + 0, 0, 0, 1651, 1961, 0, 0, 0, 0, 1962, + 0, 0, 0, 0, 1652, 0, 0, 0, 0, 0, + 1655, 1656, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1653, 1652, 0, 0, 1657, 1654, 0, 0, 0, + 0, 0, 3590, 0, 0, 0, 0, 0, 0, 1653, + 0, 0, 0, 1652, 1654, 0, 0, 0, 0, 1655, + 1656, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1653, 0, 0, 1658, 1657, 1654, 1659, -2101, -2101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1651, 0, 0, 1652, 1653, 1654, 0, - 1655, 1656, 1657, 1658, 1659, 1660, 0, 0, 0, 0, - 2892, 1650, 0, 0, 0, 0, 0, 1626, 0, 0, - 1627, 0, 0, 0, 1628, 1629, 1630, 1631, 1632, 1633, - 1634, 0, 1651, 0, 0, 1652, 1653, 1654, 0, 1655, - 1656, 1657, 1658, 1659, 1660, 1635, 0, 0, 0, 3123, - 1650, 0, 0, 0, 0, 1637, 0, 0, 0, 0, - 0, 0, 1638, 0, 0, 0, 0, 0, 0, 0, - 0, 1651, 0, 0, 1652, 1653, 1654, 0, 1655, 1656, - 1657, 1658, 1659, 1660, 0, 0, 0, 0, 3130, 1639, + 1660, 0, 1657, 1661, 0, 0, 0, 0, 1655, 1656, + 1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1658, 1657, 0, 1659, 0, 1653, 0, 0, + 0, 0, 1654, 0, 0, 0, 0, 0, 0, 1660, + 0, 0, 1661, -2101, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1655, 1656, 1660, 0, 0, + 0, 1658, 0, 0, 1659, 0, 0, 0, 0, 0, + 1657, 0, 0, 0, 0, 0, 0, 0, 1660, 0, + 0, 1661, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1626, 0, 0, 1627, 0, 0, - 0, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, 1651, - 0, 0, 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, - 1659, 1660, 1635, 0, 0, 0, 3288, 0, 0, 0, - 0, 0, 1637, 1626, 0, 0, 1627, 0, 0, 1638, - 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, 1651, 0, - 0, 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, - 1660, 1635, 0, 0, 0, 3310, 1639, 0, 0, 0, - 0, 1637, 1626, 0, 0, 1627, 1640, 0, 1638, 1628, - 1629, 1630, 1631, 1632, 1633, 1634, 0, 0, 0, 0, - 0, 0, 0, 1641, 0, 0, 0, 0, 1642, 0, - 1635, 0, 0, 0, 0, 1639, 0, 0, 0, 0, - 1637, 0, 0, 0, 0, 0, 0, 1638, 0, 0, - 0, 1643, 1644, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1645, 0, 0, 0, - 0, 0, 0, 0, 1639, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1626, - 0, 0, 1627, 1640, 0, 0, 1628, 1629, 1630, 1631, - 1632, 1633, 1634, 0, 1646, 0, 0, 1647, 0, 0, - 1641, 0, 0, 0, 0, 1642, 0, 1635, 0, 0, - 0, 1648, 0, 0, 1649, 0, 0, 1637, 0, 0, - 0, 0, 1640, 0, 1638, 0, 0, 0, 1643, 1644, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1641, - 0, 0, 0, 1645, 1642, 0, 0, 0, 0, 0, - 0, 1639, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1640, 0, 0, 0, 0, 0, 1643, 1644, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1641, 0, - 0, 1646, 1645, 1642, 1647, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1648, 0, - 0, 1649, 0, 0, 0, 0, 1643, 1644, 0, 0, - 0, 0, 0, 1650, 0, 0, 0, 0, 0, 0, - 1646, 1645, 0, 1647, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1648, 0, 0, - 1649, 0, 0, 0, 0, 0, 0, 0, 1640, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1646, - 0, 0, 1647, 0, 0, 1641, 0, 0, 0, 0, - 1642, 0, 0, 0, 0, 0, 1648, 0, 0, 1649, + 0, 0, 1662, 0, 0, 0, 0, 0, 1658, 0, + 3591, 1659, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1660, 0, 0, 1661, 0, + 0, 0, 0, 0, 0, 0, 1638, 0, 0, 1639, + 0, 1662, 0, 1640, 1641, 1642, 1643, 1644, 1645, 1646, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1662, + 0, 0, 0, 0, 1647, 2216, 0, 0, 0, 0, + 0, 0, 0, 0, 1649, 0, 0, 0, 0, 0, + 1662, 1650, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1651, 0, + 1663, 0, 0, 1664, 1665, 1666, 0, 1667, 1668, 1669, + 1670, 1671, 1672, 0, 0, 0, 0, 1662, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1663, + 0, 0, 1664, 1665, 1666, 0, 1667, 1668, 1669, 1670, + 1671, 1672, 0, 0, 0, 0, 0, 1663, 0, 0, + 1664, 1665, 1666, 0, 1667, 1668, 1669, 1670, 1671, 1672, + 0, 0, 0, 0, 0, 0, 0, 0, 1663, 0, + 0, 1664, 1665, 1666, 0, 1667, 1668, 1669, 1670, 1671, + 1672, 0, 0, 0, 0, 1652, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1638, 1653, 0, 1639, 0, 0, 1654, 1640, 1641, + 1642, 1643, 1644, 1645, 1646, 1663, 0, 0, 1664, 1665, + 1666, 0, 1667, 1668, 1669, 1670, 1671, 1672, 0, 1647, + 1655, 1656, 0, 1967, 0, 0, 0, 0, 0, 1649, + 0, 0, 0, 0, 0, 1657, 1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1643, 1644, 0, 0, 0, 0, 0, - 1650, 0, 0, 0, 0, 0, 0, 0, 1645, 0, + 0, 0, 0, 0, 0, 0, 0, 1638, 0, 0, + 1639, 0, 0, 1651, 1640, 1641, 1642, 1643, 1644, 1645, + 1646, 0, 0, 1658, 0, 0, 1659, 0, 0, 0, + 0, 0, 0, 0, 0, 1647, 0, 0, 0, 0, + 1660, 0, 0, 1661, 0, 1649, 0, 0, 0, 0, + 0, 0, 1650, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1932, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1651, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1651, 0, 0, 1652, 1653, 1654, 0, 1655, 1656, - 1657, 1658, 1659, 1660, 0, 0, 0, 0, 3409, 1650, - 0, 0, 0, 0, 0, 0, 1646, 0, 0, 1647, + 0, 0, 0, 0, 0, 0, 1638, 0, 0, 1639, + 0, 0, 0, 1640, 1641, 1642, 1643, 1644, 1645, 1646, + 1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1647, 0, 0, 1653, 1974, 0, + 0, 0, 1654, 0, 1649, 0, 0, 0, 0, 0, + 0, 1650, 1662, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1655, 1656, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1651, 0, + 1657, 1972, 0, 0, 0, 0, 1652, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1653, 0, 0, 0, 0, 1654, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1658, 0, + 0, 1659, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1655, 1656, 0, 0, 1660, 0, 0, 1661, 0, + 0, 0, 0, 0, 0, 0, 1657, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1379, 1380, 1648, 0, 0, 1649, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1626, 0, 1650, 1627, - 0, 0, 0, 1628, 1629, 1630, 1631, 1632, 1633, 1634, + 1663, 0, 0, 1664, 1665, 1666, 0, 1667, 1668, 1669, + 1670, 1671, 1672, 0, 0, 1652, 0, 0, 0, 0, + 0, 0, 0, 0, 1658, 0, 0, 1659, 0, 0, + 0, 0, 1653, 0, 0, 0, 0, 1654, 0, 0, + 0, 1660, 0, 0, 1661, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1638, 0, 0, 1639, 0, + 1655, 1656, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 0, + 0, 0, 0, 0, 0, 1657, 0, 1662, 0, 0, + 0, 0, 0, 1647, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1649, 0, 0, 0, 0, 0, 0, + 1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1638, 1658, 0, 1639, 1659, 0, 0, 1640, + 1641, 1642, 1643, 1644, 1645, 1646, 0, 1651, 0, 0, + 1660, 0, 0, 1661, 0, 0, 0, 0, 0, 0, + 1647, 0, 0, 1662, 0, 0, 0, 0, 0, 0, + 1649, 0, 0, 0, 0, 0, 0, 1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1381, 1382, 1635, 0, 1383, 1384, 1651, 0, - 0, 1652, 1653, 1654, 1637, 1655, 1656, 1657, 1658, 1659, - 1660, 1638, 0, 0, 0, 3465, 0, 0, 0, 0, - 0, 0, 0, 1626, 0, 0, 1627, 0, 0, 0, - 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1651, 1639, 0, - 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, - 0, 1635, 0, 0, 3487, 1650, 0, 0, 0, 0, - 0, 1637, 0, 0, 0, 0, 0, 0, 1638, 0, - 0, 0, 1385, 1386, 0, 0, 1651, 0, 0, 1652, - 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, - 0, 1815, 0, 0, 0, 1639, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1651, 1663, 0, 0, 1664, 1665, + 1666, 0, 1667, 1668, 1669, 1670, 1671, 1672, 0, 1638, + 0, 0, 1639, 0, 0, 0, 1640, 1641, 1642, 1643, + 1644, 1645, 1646, 0, 2104, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1652, 0, 0, 1647, 0, 0, + 0, 2843, 1662, 0, 0, 0, 0, 1649, 0, 0, + 0, 1653, 0, 0, 1650, 0, 1654, 0, 0, 0, + 0, 1663, 0, 0, 1664, 1665, 1666, 0, 1667, 1668, + 1669, 1670, 1671, 1672, 0, 0, 0, 0, 0, 1655, + 1656, 1651, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1652, 0, 0, 1657, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1653, 0, + 0, 0, 0, 1654, 0, 0, 0, 0, 1638, 0, + 0, 1639, 0, 0, 0, 1640, 1641, 1642, 1643, 1644, + 1645, 1646, 1658, 0, 0, 1659, 1655, 1656, 0, 0, + 0, 0, 0, 0, 0, 0, 1647, 0, 0, 1660, + 1663, 1657, 1661, 1664, 1665, 1666, 1649, 1667, 1668, 1669, + 1670, 1671, 1672, 1650, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1652, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1658, + 1651, 0, 1659, 0, 0, 1653, 0, 0, 0, 0, + 1654, 0, 0, 0, 0, 0, 1660, 0, 0, 1661, + 0, 0, 0, 0, 0, 0, 0, 0, 1638, 0, + 0, 1639, 0, 1655, 1656, 1640, 1641, 1642, 1643, 1644, + 1645, 1646, 0, 0, 0, 0, 0, 0, 1657, 0, + 0, 0, 0, 0, 0, 0, 1647, 0, 0, 0, + 0, 1662, 0, 0, 0, 0, 1649, 0, 0, 0, + 0, 0, 0, 1650, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1658, 0, 0, 1659, + 0, 0, 0, 0, 0, 0, 0, 1652, 0, 0, + 1651, 0, 0, 1660, 0, 0, 1661, 0, 0, 0, + 0, 0, 0, 0, 1653, 0, 0, 1638, 1662, 1654, + 1639, 0, 0, 0, 1640, 1641, 1642, 1643, 1644, 1645, + 1646, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1655, 1656, 0, 1647, 0, 0, 0, 0, + 0, 2827, 0, 0, 0, 1649, 0, 1657, 0, 0, + 0, 0, 1650, 0, 0, 0, 0, 0, 0, 1663, + 0, 0, 1664, 1665, 1666, 0, 1667, 1668, 1669, 1670, + 1671, 1672, 0, 0, 0, 0, 0, 0, 0, 1651, + 0, 0, 0, 0, 0, 1658, 0, 1652, 1659, 0, + 0, 0, 0, 0, 0, 1662, 0, 0, 0, 0, + 0, 0, 1660, 0, 1653, 1661, 0, 0, 0, 1654, + 0, 0, 0, 0, 0, 0, 1663, 0, 0, 1664, + 1665, 1666, 0, 1667, 1668, 1669, 1670, 1671, 1672, 0, + 0, 0, 1836, 1656, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1657, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1652, 0, 0, 0, + 0, 0, 0, 0, 0, 1658, 0, 0, 1659, 0, + 0, 0, 0, 1653, 0, 0, 0, 0, 1654, 0, + 0, 0, 1660, 1663, 1662, 1661, 1664, 1665, 1666, 0, + 1667, 1668, 1669, 1670, 1671, 1672, 0, 0, 0, 0, + 0, 1655, 1656, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1657, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1640, 1387, 1388, 1389, 1390, - 1391, 1392, 1393, 1394, 0, 0, 1395, 1396, 0, 0, - 0, 0, 1641, 0, 0, 0, 0, 1642, 0, 0, - 0, 0, 0, 1651, 0, 0, 1652, 1653, 1654, 0, - 1655, 1656, 1657, 1658, 1659, 1660, 0, 0, 2846, 0, - 1643, 1644, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1640, 0, 0, 1645, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1641, - 0, 0, 0, 0, 1642, 0, 0, 0, 0, 0, - 1397, 1398, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1646, 0, 0, 1647, 1643, 1644, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1648, 0, 1645, 1649, 0, 0, 0, 0, 0, 0, - 0, 1399, 1400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1658, 0, 0, 1659, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1646, 0, 0, 1647, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1648, 0, 0, - 1649, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1660, 0, 0, 1661, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1662, 0, 0, 0, 0, 0, + 0, 0, 1663, 0, 0, 1664, 1665, 1666, 0, 1667, + 1668, 1669, 1670, 1671, 1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1650, 0, 0, 0, 0, 1401, 1402, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1403, 1404, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 2018, 0, 0, 0, 0, 0, 0, 0, 1650, + 0, 0, 0, 1662, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1663, 0, 0, 1664, 1665, 1666, 0, 1667, + 1668, 1669, 1670, 1671, 1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1651, 0, 0, 1652, 1653, 1654, 0, 1655, 1656, 1657, - 1658, 1659, 1660, 0, 0, 3278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 560, 0, 2128, 0, 0, + 0, 1663, 0, 0, 1664, 1665, 1666, 0, 1667, 1668, + 1669, 1670, 2233, 1672, 118, 119, 120, 121, 122, 123, + 124, 125, 561, 126, 127, 128, 562, 563, 564, 565, + 566, 567, 568, 569, 570, 130, 131, 571, 132, 133, + 134, 572, 136, 137, 138, 573, 574, 575, 576, 577, + 578, 144, 145, 146, 147, 148, 149, 579, 580, 150, + 151, 152, 153, 581, 582, 156, 583, 157, 158, 159, + 160, 584, 585, 586, 587, 588, 164, 165, 166, 167, + 168, 589, 170, 171, 172, 590, 173, 174, 175, 176, + 177, 178, 591, 592, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 594, 191, 192, 595, 194, 596, + 195, 597, 196, 197, 198, 199, 200, 201, 598, 599, + 202, 203, 204, 205, 600, 601, 206, 207, 208, 209, + 210, 602, 211, 212, 213, 603, 214, 215, 216, 604, + 217, 218, 219, 220, 605, 222, 223, 224, 225, 226, + 227, 606, 607, 229, 608, 230, 231, 609, 233, 610, + 234, 611, 235, 612, 613, 614, 238, 239, 615, 616, + 242, 617, 243, 618, 619, 620, 246, 247, 621, 248, + 249, 250, 251, 252, 253, 254, 622, 256, 257, 258, + 259, 623, 260, 261, 262, 263, 264, 265, 266, 624, + 267, 625, 626, 270, 271, 272, 273, 274, 627, 628, + 629, 630, 631, 278, 632, 633, 281, 634, 283, 284, + 285, 286, 287, 288, 635, 636, 289, 637, 291, 638, + 639, 293, 294, 295, 296, 297, 298, 299, 300, 640, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 641, 642, 643, 325, 326, 327, 644, 645, 329, 330, + 646, 332, 647, 648, 334, 649, 336, 337, 338, 650, + 339, 340, 651, 652, 341, 342, 343, 653, 654, 344, + 345, 655, 656, 348, 657, 658, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 659, 660, 661, + 662, 362, 363, 663, 664, 366, 367, 665, 369, 370, + 371, 666, 372, 373, 374, 375, 376, 377, 667, 378, + 379, 380, 381, 382, 668, 384, 385, 386, 387, 669, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 398, 399, 400, 670, 401, 402, 671, 404, 405, 406, + 672, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 673, 674, 421, 422, 423, 424, + 425, 426, 675, 428, 429, 676, 677, 431, 432, 678, + 434, 679, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 680, 448, 681, 682, 683, 450, + 451, 684, 452, 685, 454, 455, 456, 457, 458, 686, + 459, 687, 688, 689, 690, 462, 463, 691, 465, 692, + 693, 467, 468, 694, 470, 471, 472, 473, 474, 695, + 696, 475, 476, 477, 697, 478, 479, 480, 481, 698, + 482, 483, 484, 485, 486, 699, 700, 489, 701, 490, + 702, 492, 493, 494, 495, 496, 497, 498, 703, 704, + 499, 705, 706, 500, 501, 502, 503, 504, 505, 707, + 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, + 517, 518, 519, 520, 560, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 560, 0, 0, 1651, 0, 0, - 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, - 0, 0, 3449, 118, 119, 120, 121, 122, 123, 124, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 561, 126, 127, 128, 562, 563, 564, 565, 566, 567, 568, 569, 570, 130, 131, 571, 132, 133, 134, 572, 136, 137, 138, 573, 574, 575, 576, 577, 578, @@ -8569,7 +9252,7 @@ static const yytype_int16 yytable[] = 152, 153, 581, 582, 156, 583, 157, 158, 159, 160, 584, 585, 586, 587, 588, 164, 165, 166, 167, 168, 589, 170, 171, 172, 590, 173, 174, 175, 176, 177, - 178, 591, 592, 180, 181, 182, 183, 184, 185, 186, + 178, 591, 592, 180, 181, 182, 183, 184, 185, 593, 187, 188, 189, 594, 191, 192, 595, 194, 596, 195, 597, 196, 197, 198, 199, 200, 201, 598, 599, 202, 203, 204, 205, 600, 601, 206, 207, 208, 209, 210, @@ -8609,349 +9292,109 @@ static const yytype_int16 yytable[] = 492, 493, 494, 495, 496, 497, 498, 703, 704, 499, 705, 706, 500, 501, 502, 503, 504, 505, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 517, - 518, 519, 520, 528, 0, 0, 0, 0, 0, 0, - 0, 0, 2096, 0, 0, 0, 0, 0, 0, 0, + 518, 519, 520, 560, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, - 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, - 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, - 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, - 153, 154, 155, 156, 0, 157, 158, 159, 160, 161, - 0, 0, 0, 163, 164, 165, 166, 167, 168, 0, - 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, - 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, - 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, - 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, - 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, - 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, - 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, - 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, - 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, - 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, - 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, - 287, 288, 0, 0, 289, 0, 291, 0, 0, 293, - 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, + 561, 126, 127, 128, 562, 563, 564, 565, 566, 567, + 568, 569, 570, 130, 131, 571, 132, 133, 134, 572, + 136, 137, 138, 573, 574, 575, 576, 577, 578, 144, + 145, 146, 147, 148, 149, 579, 580, 150, 151, 152, + 153, 581, 582, 156, 583, 157, 158, 159, 160, 584, + 585, 586, 587, 588, 164, 165, 166, 167, 168, 589, + 170, 171, 172, 590, 173, 174, 175, 176, 177, 178, + 591, 592, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 594, 191, 192, 595, 194, 596, 195, 597, + 196, 197, 198, 199, 200, 201, 598, 599, 202, 203, + 204, 205, 600, 601, 206, 207, 208, 209, 210, 602, + 211, 212, 213, 603, 214, 215, 216, 604, 217, 218, + 219, 220, 605, 222, 223, 224, 225, 226, 227, 606, + 607, 229, 608, 230, 231, 609, 233, 610, 234, 611, + 235, 612, 613, 614, 238, 239, 615, 616, 242, 617, + 243, 618, 619, 620, 246, 247, 621, 248, 249, 250, + 251, 252, 950, 254, 622, 256, 257, 258, 259, 623, + 260, 261, 262, 263, 264, 265, 266, 624, 267, 625, + 626, 270, 271, 272, 273, 274, 627, 628, 629, 630, + 631, 278, 632, 633, 281, 634, 283, 284, 285, 286, + 287, 288, 635, 636, 289, 637, 291, 638, 639, 293, + 294, 295, 296, 297, 298, 299, 300, 640, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, - 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, - 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, - 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, - 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, - 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, - 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, - 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, + 314, 315, 316, 317, 318, 319, 320, 321, 641, 642, + 643, 325, 326, 327, 644, 645, 329, 330, 646, 332, + 647, 648, 334, 649, 336, 337, 338, 650, 339, 340, + 651, 652, 341, 342, 343, 653, 654, 344, 345, 655, + 656, 348, 657, 658, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 659, 660, 661, 662, 362, + 363, 663, 664, 366, 367, 665, 369, 370, 371, 666, + 372, 373, 374, 375, 376, 377, 667, 378, 379, 380, + 381, 382, 668, 384, 385, 386, 387, 669, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, + 400, 670, 401, 402, 671, 404, 405, 406, 672, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, - 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, - 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, + 419, 420, 673, 674, 421, 422, 423, 424, 425, 426, + 675, 428, 429, 676, 677, 431, 432, 678, 434, 679, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, - 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, - 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, - 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, - 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, - 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, - 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, - 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, - 0, 2744, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, - 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, - 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, - 154, 155, 156, 0, 157, 158, 159, 160, 161, 0, - 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, - 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, - 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, - 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, - 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, - 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 0, 291, 0, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, + 445, 446, 680, 448, 681, 682, 683, 450, 451, 684, + 452, 685, 454, 455, 456, 457, 458, 686, 459, 687, + 688, 689, 690, 462, 463, 691, 465, 692, 693, 467, + 468, 694, 470, 471, 472, 473, 474, 695, 696, 475, + 476, 477, 697, 478, 479, 480, 481, 698, 482, 483, + 484, 485, 486, 699, 700, 489, 701, 490, 702, 492, + 493, 494, 495, 496, 497, 498, 703, 704, 499, 705, + 706, 500, 501, 502, 503, 504, 505, 707, 708, 709, + 710, 711, 712, 713, 714, 715, 716, 717, 517, 518, + 519, 520, 560, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 118, 119, 120, 121, 122, 123, 124, 125, 561, + 126, 127, 128, 562, 563, 564, 565, 566, 567, 568, + 569, 570, 130, 131, 571, 132, 133, 134, 572, 136, + 137, 138, 573, 574, 575, 576, 577, 578, 144, 145, + 146, 147, 148, 149, 579, 580, 150, 151, 152, 153, + 581, 582, 156, 583, 157, 158, 159, 160, 584, 585, + 586, 587, 588, 164, 165, 166, 167, 168, 589, 170, + 171, 172, 590, 173, 174, 175, 176, 177, 178, 591, + 592, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 594, 191, 192, 595, 194, 596, 195, 597, 196, + 197, 198, 199, 200, 201, 598, 599, 202, 203, 204, + 205, 600, 601, 206, 207, 208, 209, 210, 602, 211, + 212, 213, 603, 214, 215, 216, 604, 217, 218, 219, + 220, 605, 222, 223, 224, 225, 226, 227, 606, 607, + 229, 608, 230, 231, 609, 233, 610, 234, 611, 235, + 612, 613, 614, 238, 239, 615, 616, 242, 617, 243, + 618, 619, 620, 246, 247, 621, 248, 249, 250, 251, + 252, 253, 254, 622, 256, 257, 258, 259, 623, 260, + 261, 262, 263, 264, 265, 266, 624, 267, 625, 626, + 270, 271, 272, 273, 274, 627, 628, 629, 630, 631, + 278, 632, 633, 281, 634, 283, 284, 285, 286, 287, + 288, 635, 636, 289, 637, 291, 638, 639, 293, 294, + 295, 296, 297, 298, 299, 300, 640, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, - 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, - 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, - 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, - 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, + 315, 316, 317, 318, 319, 320, 321, 641, 642, 643, + 325, 326, 327, 644, 645, 329, 330, 646, 332, 647, + 648, 334, 649, 336, 337, 338, 650, 339, 340, 651, + 652, 341, 342, 343, 653, 654, 344, 345, 655, 656, + 348, 657, 658, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 360, 361, 659, 660, 661, 662, 362, 363, + 663, 664, 366, 367, 665, 369, 370, 371, 666, 372, + 373, 374, 375, 376, 377, 667, 378, 379, 380, 381, + 382, 668, 384, 385, 386, 387, 669, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, + 670, 401, 402, 671, 404, 405, 406, 672, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, + 420, 673, 674, 421, 422, 423, 424, 425, 426, 675, + 428, 429, 676, 677, 431, 432, 678, 434, 679, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, - 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, - 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, - 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 973, 1356, 820, 0, 0, 0, 1054, 0, 0, - 2747, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, - 127, 128, 0, 0, 0, 565, 0, 0, 0, 0, - 570, 130, 131, 0, 132, 133, 134, 572, 136, 137, - 138, 573, 574, 575, 576, 577, 0, 144, 145, 146, - 147, 148, 149, 0, 0, 150, 151, 152, 153, 581, - 582, 156, 0, 157, 158, 159, 160, 584, 0, 586, - 0, 588, 164, 165, 166, 167, 168, 589, 170, 171, - 172, 0, 173, 174, 175, 176, 177, 178, 0, 592, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 594, 191, 192, 595, 194, 0, 195, 0, 196, 197, - 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, - 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, - 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 605, 222, 223, 224, 225, 226, 227, 606, 1357, 229, - 0, 230, 231, 609, 233, 0, 234, 0, 235, 612, - 0, 614, 238, 239, 615, 616, 242, 0, 243, 0, - 619, 620, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 622, 256, 257, 258, 259, 0, 260, 261, - 262, 263, 264, 265, 266, 0, 267, 625, 626, 270, - 271, 272, 273, 274, 627, 628, 0, 630, 0, 278, - 632, 633, 281, 634, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 637, 291, 638, 0, 293, 294, 295, - 296, 297, 298, 299, 300, 640, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 641, 642, 643, 325, - 326, 327, 644, 0, 329, 330, 646, 332, 0, 648, - 334, 649, 336, 337, 338, 0, 339, 340, 1358, 0, - 341, 342, 343, 0, 0, 344, 345, 655, 656, 348, - 657, 658, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 0, 0, 0, 0, 362, 363, 663, - 664, 366, 367, 665, 369, 370, 371, 0, 372, 373, - 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, - 668, 384, 385, 386, 387, 0, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, - 401, 402, 671, 404, 405, 406, 672, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 0, 674, 421, 422, 423, 424, 425, 426, 675, 428, - 429, 0, 677, 431, 432, 678, 434, 0, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 680, 448, 681, 0, 0, 450, 451, 0, 452, 685, - 454, 455, 456, 457, 458, 0, 459, 687, 688, 0, - 0, 462, 463, 691, 465, 692, 1359, 467, 468, 694, - 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, - 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, - 486, 699, 700, 489, 0, 490, 702, 492, 493, 494, - 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, - 501, 502, 503, 504, 505, 707, 708, 709, 710, 711, - 712, 713, 714, 715, 716, 717, 517, 518, 519, 520, - 0, 0, 1626, 0, 0, 1627, 0, 1360, 1361, 1628, - 1629, 1630, 1631, 1632, 1633, 1634, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1635, 0, 0, 0, 0, 2196, 0, 0, 0, 0, - 1637, 1626, 0, 0, 1627, 0, 0, 1638, 1628, 1629, - 1630, 1631, 1632, 1633, 1634, 0, 0, 0, 0, 1626, - 0, 0, 1627, 0, 0, 0, 1628, 1629, 0, 1635, - 1632, 1633, 1634, 0, 1639, 0, 0, 0, 0, 1637, - 1626, 0, 0, 1627, 0, 0, 1638, 1628, 1629, 1630, - 1631, 1632, 1633, 1634, 0, 0, 0, 1637, 0, 0, - 0, 0, 0, 0, 1638, 0, 0, 0, 1635, 0, - 0, 0, 0, 1639, 0, 0, 0, 0, 1637, 0, - 2197, 0, 0, 0, 0, 1638, 0, 1626, 0, 0, - 1627, 1639, 0, 0, 1628, 1629, 1630, 1631, 1632, 1633, - 1634, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1639, 0, 0, 1635, 0, 0, 0, 1914, - 0, 0, 0, 0, 0, 1637, 0, 0, 0, 0, - 0, 1640, 1638, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1641, 0, - 0, 0, 0, 1642, 0, 0, 0, 0, 0, 1639, - 1950, 0, 0, 0, 0, 1951, 0, 0, 0, 0, - 1640, 0, 0, 0, 0, 0, 1643, 1644, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1641, 1640, 0, - 0, 1645, 1642, 0, 0, 0, 0, 0, 3555, 0, - 0, 0, 0, 0, 0, 1641, 0, 0, 0, 1640, - 1642, 0, 0, 0, 0, 1643, 1644, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1641, 0, 0, 1646, - 1645, 1642, 1647, 1643, 1644, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1648, 0, 1645, 1649, - 0, 0, 0, 0, 1643, 1644, 1640, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1646, 1645, - 0, 1647, 0, 1641, 0, 0, 0, 0, 1642, 0, - 0, 0, 0, 0, 0, 1648, 1646, 0, 1649, 1647, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1643, 1644, 1648, 0, 0, 0, 1646, 0, 0, - 1647, 0, 0, 0, 0, 0, 1645, 0, 0, 0, - 0, 0, 0, 0, 1648, 0, 0, 1649, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1650, 0, - 0, 0, 0, 0, 1646, 0, 3556, 1647, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1648, 0, 0, 1649, 0, 0, 0, 0, 0, - 0, 0, 1626, 0, 0, 1627, 0, 1650, 0, 1628, - 1629, 1630, 1631, 1632, 1633, 1634, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1650, 0, 0, 0, 0, - 1635, 2200, 0, 0, 0, 0, 0, 0, 0, 0, - 1637, 0, 0, 0, 0, 0, 1650, 1638, 0, 0, - 0, 0, 0, 1379, 1380, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1639, 0, 1651, 0, 0, 1652, - 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, - 0, 0, 0, 1650, 1381, 1382, 0, 0, 1383, 1384, - 0, 1626, 0, 0, 1627, 0, 0, 0, 1628, 1629, - 0, 0, 1632, 1633, 1634, 1651, 0, 0, 1652, 1653, - 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, 1635, - 0, 0, 0, 1651, 0, 0, 1652, 1653, 1654, 1637, - 1655, 1656, 1657, 1658, 1659, 1660, 1638, 0, 0, 0, - 0, 0, 0, 0, 1651, 0, 0, 1652, 1653, 1654, - 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, 0, 0, - 0, 1640, 0, 1639, 1385, 1386, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1626, 1641, 0, - 1627, 0, 0, 1642, 1628, 1629, 1630, 1631, 1632, 1633, - 1634, 1651, 0, 0, 1652, 1653, 1654, 0, 1655, 1656, - 1657, 1658, 1659, 1660, 0, 1635, 1643, 1644, 0, 1956, - 0, 0, 0, 0, 0, 1637, 0, 0, 0, 0, - 0, 1645, 1638, 0, 0, 0, 0, 0, 1387, 1388, - 1389, 1390, 1391, 1392, 1393, 1394, 0, 0, 1395, 1396, - 0, 0, 0, 1626, 0, 0, 1627, 0, 0, 1639, - 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, 0, 1646, - 1640, 0, 1647, 0, 0, 0, 0, 0, 0, 0, - 0, 1635, 0, 0, 0, 0, 1648, 1641, 0, 1649, - 0, 1637, 1642, 0, 0, 0, 0, 0, 1638, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1921, 0, 0, 1643, 1644, 0, 0, 0, - 0, 0, 1397, 1398, 0, 1639, 0, 0, 0, 0, - 1645, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1626, 0, 0, 1627, 0, 0, 0, 1628, - 1629, 1630, 1631, 1632, 1633, 1634, 1640, 0, 0, 0, - 0, 0, 0, 1399, 1400, 0, 0, 0, 1646, 0, - 1635, 1647, 0, 1641, 1963, 0, 0, 0, 1642, 0, - 1637, 0, 0, 0, 0, 1648, 0, 1638, 1650, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1643, 1644, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1639, 0, 1645, 1961, 0, 0, - 0, 0, 1640, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1641, - 0, 0, 0, 0, 1642, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1646, 0, 0, 1647, 0, 1401, - 1402, 0, 0, 0, 0, 0, 0, 1643, 1644, 0, - 0, 1648, 0, 0, 1649, 0, 0, 0, 0, 0, - 0, 0, 1645, 1403, 1404, 0, 0, 1650, 0, 0, - 0, 0, 0, 0, 0, 0, 1651, 0, 0, 1652, - 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, - 0, 1640, 0, 0, 0, 0, 0, 0, 0, 0, - 1646, 0, 0, 1647, 0, 0, 0, 0, 1641, 0, - 0, 0, 0, 1642, 0, 0, 0, 1648, 0, 0, - 1649, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1626, 0, 0, 1627, 0, 1643, 1644, 1628, 1629, - 1630, 1631, 1632, 1633, 1634, 0, 0, 0, 0, 0, - 0, 1645, 0, 1650, 0, 0, 0, 0, 0, 1635, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1637, - 0, 0, 0, 0, 0, 1651, 1638, 0, 1652, 1653, - 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, 1626, 1646, - 0, 1627, 1647, 0, 0, 1628, 1629, 1630, 1631, 1632, - 1633, 1634, 0, 1639, 0, 0, 1648, 0, 0, 1649, - 0, 0, 0, 0, 0, 0, 1635, 0, 0, 1650, - 0, 0, 0, 0, 0, 0, 1637, 0, 0, 0, - 0, 0, 0, 1638, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1639, 1651, 0, 0, 1652, 1653, 1654, 0, 1655, 1656, - 1657, 1658, 1659, 1660, 0, 1626, 0, 0, 1627, 0, - 0, 0, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, - 2089, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1640, 0, 0, 1635, 0, 0, 0, 2822, 1650, 0, - 0, 0, 0, 1637, 0, 0, 0, 1641, 0, 0, - 1638, 0, 1642, 0, 0, 0, 0, 1651, 0, 0, - 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, - 0, 0, 0, 0, 0, 1643, 1644, 1639, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1640, 0, 0, - 1645, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1641, 0, 0, 0, 0, 1642, - 0, 0, 0, 0, 1626, 0, 0, 1627, 0, 0, - 0, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1646, 0, - 0, 1647, 1643, 1644, 0, 0, 0, 0, 0, 0, - 0, 0, 1635, 0, 0, 1648, 1651, 1645, 1649, 1652, - 1653, 1654, 1637, 1655, 1656, 1657, 1658, 1659, 1660, 1638, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1640, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1646, 1639, 0, 1647, 0, - 0, 1641, 0, 0, 0, 0, 1642, 0, 0, 0, - 0, 0, 1648, 0, 0, 1649, 0, 0, 0, 0, - 0, 0, 0, 0, 1626, 0, 0, 1627, 0, 1643, - 1644, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, 0, - 0, 0, 0, 0, 1645, 0, 0, 0, 0, 0, - 0, 0, 1635, 0, 0, 0, 0, 1650, 0, 0, - 0, 0, 1637, 0, 0, 0, 0, 0, 0, 1638, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1646, 0, 0, 1647, 0, 0, 0, 0, - 0, 0, 0, 1640, 0, 0, 1639, 0, 0, 1648, - 0, 0, 1649, 0, 0, 0, 0, 0, 0, 0, - 1641, 0, 0, 1626, 1650, 1642, 1627, 0, 0, 0, - 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1643, 1644, - 0, 1635, 0, 0, 0, 0, 0, 2808, 0, 0, - 0, 1637, 0, 1645, 0, 0, 0, 0, 1638, 0, - 0, 0, 0, 0, 0, 1651, 0, 0, 1652, 1653, - 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, 0, - 0, 0, 0, 0, 0, 1639, 0, 0, 0, 0, - 0, 1646, 0, 1640, 1647, 0, 0, 0, 0, 0, - 0, 1650, 0, 0, 0, 0, 0, 0, 1648, 0, - 1641, 1649, 0, 0, 0, 1642, 0, 0, 0, 0, - 0, 0, 1651, 0, 0, 1652, 1653, 1654, 0, 1655, - 1656, 1657, 1658, 1659, 1660, 0, 0, 0, 1825, 1644, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1645, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1640, 0, 0, 0, 0, 0, 0, 0, - 0, 1646, 0, 0, 1647, 0, 0, 0, 0, 1641, - 0, 0, 0, 0, 1642, 0, 0, 0, 1648, 1651, - 1650, 1649, 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, - 1659, 1660, 0, 0, 0, 0, 0, 1643, 1644, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1645, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1646, 0, 0, 1647, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1648, 0, 0, - 1649, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1650, 0, 0, 0, 0, 0, 0, 0, 1651, 0, - 0, 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, - 1660, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1650, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1651, 0, - 0, 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, - 1660, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 446, 680, 448, 681, 682, 683, 450, 451, 684, 452, + 685, 454, 455, 456, 457, 458, 686, 459, 687, 688, + 689, 690, 462, 463, 691, 465, 692, 693, 467, 468, + 694, 470, 471, 472, 473, 474, 695, 696, 475, 476, + 477, 697, 478, 479, 480, 481, 698, 482, 483, 484, + 485, 486, 699, 700, 489, 701, 490, 702, 492, 493, + 494, 495, 496, 497, 498, 703, 704, 499, 705, 706, + 500, 501, 502, 503, 504, 505, 707, 708, 709, 710, + 711, 712, 713, 714, 715, 716, 717, 517, 518, 519, + 520, 560, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 560, 0, 2112, 0, 0, 0, 1651, 0, 0, - 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 2217, 1660, - 118, 119, 120, 121, 122, 123, 124, 125, 561, 126, + 118, 119, 120, 121, 2282, 123, 124, 125, 561, 126, 127, 128, 562, 563, 564, 565, 566, 567, 568, 569, 570, 130, 131, 571, 132, 133, 134, 572, 136, 137, 138, 573, 574, 575, 576, 577, 578, 144, 145, 146, @@ -8962,7 +9405,7 @@ static const yytype_int16 yytable[] = 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 594, 191, 192, 595, 194, 596, 195, 597, 196, 197, 198, 199, 200, 201, 598, 599, 202, 203, 204, 205, - 600, 601, 206, 207, 208, 209, 210, 602, 211, 212, + 600, 601, 206, 207, 208, 2283, 210, 602, 211, 212, 213, 603, 214, 215, 216, 604, 217, 218, 219, 220, 605, 222, 223, 224, 225, 226, 227, 606, 607, 229, 608, 230, 231, 609, 233, 610, 234, 611, 235, 612, @@ -8987,7 +9430,7 @@ static const yytype_int16 yytable[] = 392, 393, 394, 395, 396, 397, 398, 399, 400, 670, 401, 402, 671, 404, 405, 406, 672, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 673, 674, 421, 422, 423, 424, 425, 426, 675, 428, + 673, 674, 421, 422, 423, 424, 425, 2284, 675, 428, 429, 676, 677, 431, 432, 678, 434, 679, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 680, 448, 681, 682, 683, 450, 451, 684, 452, 685, @@ -8999,425 +9442,425 @@ static const yytype_int16 yytable[] = 495, 496, 497, 498, 703, 704, 499, 705, 706, 500, 501, 502, 503, 504, 505, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 517, 518, 519, 520, - 560, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 974, 0, 821, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, - 119, 120, 121, 122, 123, 124, 125, 561, 126, 127, - 128, 562, 563, 564, 565, 566, 567, 568, 569, 570, - 130, 131, 571, 132, 133, 134, 572, 136, 137, 138, - 573, 574, 575, 576, 577, 578, 144, 145, 146, 147, - 148, 149, 579, 580, 150, 151, 152, 153, 581, 582, - 156, 583, 157, 158, 159, 160, 584, 585, 586, 587, + 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, + 128, 0, 0, 0, 565, 0, 0, 0, 0, 570, + 130, 131, 0, 132, 133, 134, 572, 136, 137, 138, + 573, 574, 575, 576, 577, 0, 144, 145, 146, 147, + 148, 149, 0, 0, 150, 151, 152, 153, 581, 582, + 156, 0, 157, 158, 159, 160, 584, 0, 586, 0, 588, 164, 165, 166, 167, 168, 589, 170, 171, 172, - 590, 173, 174, 175, 176, 177, 178, 591, 592, 180, - 181, 182, 183, 184, 185, 593, 187, 188, 189, 594, - 191, 192, 595, 194, 596, 195, 597, 196, 197, 198, - 199, 200, 201, 598, 599, 202, 203, 204, 205, 600, - 601, 206, 207, 208, 209, 210, 602, 211, 212, 213, - 603, 214, 215, 216, 604, 217, 218, 219, 220, 605, - 222, 223, 224, 225, 226, 227, 606, 607, 229, 608, - 230, 231, 609, 233, 610, 234, 611, 235, 612, 613, - 614, 238, 239, 615, 616, 242, 617, 243, 618, 619, - 620, 246, 247, 621, 248, 249, 250, 251, 252, 253, - 254, 622, 256, 257, 258, 259, 623, 260, 261, 262, - 263, 264, 265, 266, 624, 267, 625, 626, 270, 271, - 272, 273, 274, 627, 628, 629, 630, 631, 278, 632, - 633, 281, 634, 283, 284, 285, 286, 287, 288, 635, - 636, 289, 637, 291, 638, 639, 293, 294, 295, 296, + 0, 173, 174, 175, 176, 177, 178, 0, 592, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 594, + 191, 192, 595, 194, 0, 195, 0, 196, 197, 198, + 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, + 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, + 0, 214, 215, 216, 0, 217, 218, 219, 220, 605, + 222, 223, 224, 225, 226, 227, 606, 1364, 229, 0, + 230, 231, 609, 233, 0, 234, 0, 235, 612, 0, + 614, 238, 239, 615, 616, 242, 0, 243, 0, 619, + 620, 246, 247, 0, 248, 249, 250, 251, 252, 253, + 254, 622, 256, 257, 258, 259, 0, 260, 261, 262, + 263, 264, 265, 266, 0, 267, 625, 626, 270, 271, + 272, 273, 274, 627, 628, 0, 630, 0, 278, 632, + 633, 281, 634, 283, 284, 285, 286, 287, 288, 0, + 0, 289, 637, 291, 638, 0, 293, 294, 295, 296, 297, 298, 299, 300, 640, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 641, 642, 643, 325, 326, - 327, 644, 645, 329, 330, 646, 332, 647, 648, 334, - 649, 336, 337, 338, 650, 339, 340, 651, 652, 341, - 342, 343, 653, 654, 344, 345, 655, 656, 348, 657, + 327, 644, 0, 329, 330, 646, 332, 0, 648, 334, + 649, 336, 337, 338, 0, 339, 340, 1365, 0, 341, + 342, 343, 0, 0, 344, 345, 655, 656, 348, 657, 658, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, 659, 660, 661, 662, 362, 363, 663, 664, - 366, 367, 665, 369, 370, 371, 666, 372, 373, 374, - 375, 376, 377, 667, 378, 379, 380, 381, 382, 668, - 384, 385, 386, 387, 669, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, 399, 400, 670, 401, + 360, 361, 0, 0, 0, 0, 362, 363, 663, 664, + 366, 367, 665, 369, 370, 371, 0, 372, 373, 374, + 375, 376, 377, 0, 378, 379, 380, 381, 382, 668, + 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, + 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 671, 404, 405, 406, 672, 408, 409, 410, 411, - 412, 413, 414, 415, 416, 417, 418, 419, 420, 673, + 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 674, 421, 422, 423, 424, 425, 426, 675, 428, 429, - 676, 677, 431, 432, 678, 434, 679, 435, 436, 437, + 0, 677, 431, 432, 678, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 680, - 448, 681, 682, 683, 450, 451, 684, 452, 685, 454, - 455, 456, 457, 458, 686, 459, 687, 688, 689, 690, - 462, 463, 691, 465, 692, 693, 467, 468, 694, 470, - 471, 472, 473, 474, 695, 696, 475, 476, 477, 697, - 478, 479, 480, 481, 698, 482, 483, 484, 485, 486, - 699, 700, 489, 701, 490, 702, 492, 493, 494, 495, - 496, 497, 498, 703, 704, 499, 705, 706, 500, 501, + 448, 681, 0, 0, 450, 451, 0, 452, 685, 454, + 455, 456, 457, 458, 0, 459, 687, 688, 0, 0, + 462, 463, 691, 465, 692, 1366, 467, 468, 694, 470, + 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, + 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, + 699, 700, 489, 0, 490, 702, 492, 493, 494, 495, + 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 707, 708, 709, 710, 711, 712, - 713, 714, 715, 716, 717, 517, 518, 519, 520, 560, + 713, 714, 715, 716, 717, 517, 518, 519, 520, 974, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, - 120, 121, 122, 123, 124, 125, 561, 126, 127, 128, - 562, 563, 564, 565, 566, 567, 568, 569, 570, 130, - 131, 571, 132, 133, 134, 572, 136, 137, 138, 573, - 574, 575, 576, 577, 578, 144, 145, 146, 147, 148, - 149, 579, 580, 150, 151, 152, 153, 581, 582, 156, - 583, 157, 158, 159, 160, 584, 585, 586, 587, 588, - 164, 165, 166, 167, 168, 589, 170, 171, 172, 590, - 173, 174, 175, 176, 177, 178, 591, 592, 180, 181, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 3, 4, 0, 565, 0, 0, 0, 0, 570, 130, + 131, 0, 132, 133, 134, 572, 136, 137, 138, 573, + 574, 575, 576, 577, 0, 144, 145, 146, 147, 148, + 149, 0, 0, 150, 151, 152, 153, 581, 582, 156, + 0, 157, 158, 159, 160, 584, 0, 586, 0, 588, + 164, 165, 166, 167, 168, 589, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 592, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 594, 191, - 192, 595, 194, 596, 195, 597, 196, 197, 198, 199, - 200, 201, 598, 599, 202, 203, 204, 205, 600, 601, - 206, 207, 208, 209, 210, 602, 211, 212, 213, 603, - 214, 215, 216, 604, 217, 218, 219, 220, 605, 222, - 223, 224, 225, 226, 227, 606, 607, 229, 608, 230, - 231, 609, 233, 610, 234, 611, 235, 612, 613, 614, - 238, 239, 615, 616, 242, 617, 243, 618, 619, 620, - 246, 247, 621, 248, 249, 250, 251, 252, 949, 254, - 622, 256, 257, 258, 259, 623, 260, 261, 262, 263, - 264, 265, 266, 624, 267, 625, 626, 270, 271, 272, - 273, 274, 627, 628, 629, 630, 631, 278, 632, 633, - 281, 634, 283, 284, 285, 286, 287, 288, 635, 636, - 289, 637, 291, 638, 639, 293, 294, 295, 296, 297, + 192, 595, 194, 0, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 605, 222, + 223, 224, 225, 226, 227, 606, 0, 229, 0, 230, + 231, 609, 233, 0, 234, 0, 235, 612, 0, 614, + 238, 239, 615, 616, 242, 0, 243, 0, 619, 620, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 622, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 625, 626, 270, 271, 272, + 273, 274, 627, 628, 0, 630, 0, 278, 632, 633, + 281, 634, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 637, 291, 638, 0, 293, 294, 295, 296, 297, 298, 299, 300, 640, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 641, 642, 643, 325, 326, 327, - 644, 645, 329, 330, 646, 332, 647, 648, 334, 649, - 336, 337, 338, 650, 339, 340, 651, 652, 341, 342, - 343, 653, 654, 344, 345, 655, 656, 348, 657, 658, + 644, 0, 329, 330, 646, 332, 0, 648, 334, 649, + 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, + 343, 0, 0, 344, 345, 655, 656, 348, 657, 658, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - 361, 659, 660, 661, 662, 362, 363, 663, 664, 366, - 367, 665, 369, 370, 371, 666, 372, 373, 374, 375, - 376, 377, 667, 378, 379, 380, 381, 382, 668, 384, - 385, 386, 387, 669, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 670, 401, 402, + 361, 0, 0, 0, 0, 362, 363, 663, 664, 366, + 367, 665, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 668, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 671, 404, 405, 406, 672, 408, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 673, 674, - 421, 422, 423, 424, 425, 426, 675, 428, 429, 676, - 677, 431, 432, 678, 434, 679, 435, 436, 437, 438, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 674, + 421, 422, 423, 424, 425, 426, 675, 428, 429, 0, + 677, 431, 432, 678, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 680, 448, - 681, 682, 683, 450, 451, 684, 452, 685, 454, 455, - 456, 457, 458, 686, 459, 687, 688, 689, 690, 462, - 463, 691, 465, 692, 693, 467, 468, 694, 470, 471, - 472, 473, 474, 695, 696, 475, 476, 477, 697, 478, - 479, 480, 481, 698, 482, 483, 484, 485, 486, 699, - 700, 489, 701, 490, 702, 492, 493, 494, 495, 496, - 497, 498, 703, 704, 499, 705, 706, 500, 501, 502, + 681, 0, 0, 450, 451, 0, 452, 685, 454, 455, + 456, 457, 458, 0, 459, 687, 688, 0, 0, 462, + 463, 691, 465, 692, 0, 467, 468, 694, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 699, + 700, 489, 0, 490, 702, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 707, 708, 709, 710, 711, 712, 713, - 714, 715, 716, 717, 517, 518, 519, 520, 560, 0, + 714, 715, 716, 717, 517, 518, 519, 520, 117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, - 121, 122, 123, 124, 125, 561, 126, 127, 128, 562, - 563, 564, 565, 566, 567, 568, 569, 570, 130, 131, - 571, 132, 133, 134, 572, 136, 137, 138, 573, 574, - 575, 576, 577, 578, 144, 145, 146, 147, 148, 149, - 579, 580, 150, 151, 152, 153, 581, 582, 156, 583, - 157, 158, 159, 160, 584, 585, 586, 587, 588, 164, - 165, 166, 167, 168, 589, 170, 171, 172, 590, 173, - 174, 175, 176, 177, 178, 591, 592, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 594, 191, 192, - 595, 194, 596, 195, 597, 196, 197, 198, 199, 200, - 201, 598, 599, 202, 203, 204, 205, 600, 601, 206, - 207, 208, 209, 210, 602, 211, 212, 213, 603, 214, - 215, 216, 604, 217, 218, 219, 220, 605, 222, 223, - 224, 225, 226, 227, 606, 607, 229, 608, 230, 231, - 609, 233, 610, 234, 611, 235, 612, 613, 614, 238, - 239, 615, 616, 242, 617, 243, 618, 619, 620, 246, - 247, 621, 248, 249, 250, 251, 252, 253, 254, 622, - 256, 257, 258, 259, 623, 260, 261, 262, 263, 264, - 265, 266, 624, 267, 625, 626, 270, 271, 272, 273, - 274, 627, 628, 629, 630, 631, 278, 632, 633, 281, - 634, 283, 284, 285, 286, 287, 288, 635, 636, 289, - 637, 291, 638, 639, 293, 294, 295, 296, 297, 298, - 299, 300, 640, 302, 303, 304, 305, 306, 307, 308, + 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 129, 130, 131, + 0, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 0, 144, 145, 146, 147, 148, 149, + 0, 790, 150, 151, 152, 153, 154, 155, 156, 0, + 157, 158, 159, 160, 791, 0, 792, 0, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, + 174, 175, 176, 177, 178, 0, 179, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, + 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, + 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, + 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 793, 0, 229, 0, 230, 231, + 232, 233, 0, 234, 0, 235, 236, 0, 237, 238, + 239, 240, 241, 242, 0, 243, 0, 244, 245, 246, + 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, + 265, 266, 0, 267, 268, 269, 270, 271, 272, 273, + 274, 275, 276, 0, 277, 0, 278, 279, 280, 281, + 282, 283, 284, 285, 286, 287, 288, 0, 0, 289, + 290, 291, 292, 0, 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, 641, 642, 643, 325, 326, 327, 644, - 645, 329, 330, 646, 332, 647, 648, 334, 649, 336, - 337, 338, 650, 339, 340, 651, 652, 341, 342, 343, - 653, 654, 344, 345, 655, 656, 348, 657, 658, 351, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + 0, 329, 330, 331, 332, 0, 795, 334, 335, 336, + 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, + 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, - 659, 660, 661, 662, 362, 363, 663, 664, 366, 367, - 665, 369, 370, 371, 666, 372, 373, 374, 375, 376, - 377, 667, 378, 379, 380, 381, 382, 668, 384, 385, - 386, 387, 669, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 670, 401, 402, 671, - 404, 405, 406, 672, 408, 409, 410, 411, 412, 413, - 414, 415, 416, 417, 418, 419, 420, 673, 674, 421, - 422, 423, 424, 425, 426, 675, 428, 429, 676, 677, - 431, 432, 678, 434, 679, 435, 436, 437, 438, 439, - 440, 441, 442, 443, 444, 445, 446, 680, 448, 681, - 682, 683, 450, 451, 684, 452, 685, 454, 455, 456, - 457, 458, 686, 459, 687, 688, 689, 690, 462, 463, - 691, 465, 692, 693, 467, 468, 694, 470, 471, 472, - 473, 474, 695, 696, 475, 476, 477, 697, 478, 479, - 480, 481, 698, 482, 483, 484, 485, 486, 699, 700, - 489, 701, 490, 702, 492, 493, 494, 495, 496, 497, - 498, 703, 704, 499, 705, 706, 500, 501, 502, 503, - 504, 505, 707, 708, 709, 710, 711, 712, 713, 714, - 715, 716, 717, 517, 518, 519, 520, 560, 0, 0, + 0, 0, 0, 0, 362, 363, 798, 365, 366, 367, + 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, + 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, + 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 0, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, + 422, 423, 424, 425, 426, 427, 428, 429, 0, 430, + 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, + 0, 0, 450, 451, 0, 452, 453, 454, 455, 456, + 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, + 801, 465, 802, 0, 467, 468, 803, 470, 471, 472, + 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, + 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, + 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, + 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, + 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, + 514, 515, 516, 517, 518, 519, 520, 117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 2266, 123, 124, 125, 561, 126, 127, 128, 562, 563, - 564, 565, 566, 567, 568, 569, 570, 130, 131, 571, - 132, 133, 134, 572, 136, 137, 138, 573, 574, 575, - 576, 577, 578, 144, 145, 146, 147, 148, 149, 579, - 580, 150, 151, 152, 153, 581, 582, 156, 583, 157, - 158, 159, 160, 584, 585, 586, 587, 588, 164, 165, - 166, 167, 168, 589, 170, 171, 172, 590, 173, 174, - 175, 176, 177, 178, 591, 592, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 594, 191, 192, 595, - 194, 596, 195, 597, 196, 197, 198, 199, 200, 201, - 598, 599, 202, 203, 204, 205, 600, 601, 206, 207, - 208, 2267, 210, 602, 211, 212, 213, 603, 214, 215, - 216, 604, 217, 218, 219, 220, 605, 222, 223, 224, - 225, 226, 227, 606, 607, 229, 608, 230, 231, 609, - 233, 610, 234, 611, 235, 612, 613, 614, 238, 239, - 615, 616, 242, 617, 243, 618, 619, 620, 246, 247, - 621, 248, 249, 250, 251, 252, 253, 254, 622, 256, - 257, 258, 259, 623, 260, 261, 262, 263, 264, 265, - 266, 624, 267, 625, 626, 270, 271, 272, 273, 274, - 627, 628, 629, 630, 631, 278, 632, 633, 281, 634, - 283, 284, 285, 286, 287, 288, 635, 636, 289, 637, - 291, 638, 639, 293, 294, 295, 296, 297, 298, 299, - 300, 640, 302, 303, 304, 305, 306, 307, 308, 309, + 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, + 0, 0, 0, 0, 0, 0, 129, 130, 131, 0, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, + 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, + 158, 159, 160, 161, 0, 162, 0, 163, 164, 165, + 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, + 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, + 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, + 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, + 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, + 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, + 240, 241, 242, 0, 243, 0, 244, 245, 246, 247, + 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, + 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 0, 277, 0, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, + 291, 292, 0, 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, 641, 642, 643, 325, 326, 327, 644, 645, - 329, 330, 646, 332, 647, 648, 334, 649, 336, 337, - 338, 650, 339, 340, 651, 652, 341, 342, 343, 653, - 654, 344, 345, 655, 656, 348, 657, 658, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 659, - 660, 661, 662, 362, 363, 663, 664, 366, 367, 665, - 369, 370, 371, 666, 372, 373, 374, 375, 376, 377, - 667, 378, 379, 380, 381, 382, 668, 384, 385, 386, - 387, 669, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 670, 401, 402, 671, 404, - 405, 406, 672, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 673, 674, 421, 422, - 423, 424, 425, 2268, 675, 428, 429, 676, 677, 431, - 432, 678, 434, 679, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 680, 448, 681, 682, - 683, 450, 451, 684, 452, 685, 454, 455, 456, 457, - 458, 686, 459, 687, 688, 689, 690, 462, 463, 691, - 465, 692, 693, 467, 468, 694, 470, 471, 472, 473, - 474, 695, 696, 475, 476, 477, 697, 478, 479, 480, - 481, 698, 482, 483, 484, 485, 486, 699, 700, 489, - 701, 490, 702, 492, 493, 494, 495, 496, 497, 498, - 703, 704, 499, 705, 706, 500, 501, 502, 503, 504, - 505, 707, 708, 709, 710, 711, 712, 713, 714, 715, - 716, 717, 517, 518, 519, 520, 973, 0, 820, 0, + 320, 321, 322, 323, 324, 325, 326, 327, 328, 0, + 329, 330, 331, 332, 0, 333, 334, 335, 336, 337, + 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, + 0, 344, 345, 346, 347, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, + 0, 0, 0, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, + 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, + 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, + 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, + 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 447, 448, 449, 0, + 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, + 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, + 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, + 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, + 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, + 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, + 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, + 515, 516, 517, 518, 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, - 565, 0, 0, 0, 0, 570, 130, 131, 0, 132, - 133, 134, 572, 136, 137, 138, 573, 574, 575, 576, - 577, 0, 144, 145, 146, 147, 148, 149, 0, 0, - 150, 151, 152, 153, 581, 582, 156, 0, 157, 158, - 159, 160, 584, 0, 586, 0, 588, 164, 165, 166, - 167, 168, 589, 170, 171, 172, 0, 173, 174, 175, - 176, 177, 178, 0, 592, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 594, 191, 192, 595, 194, + 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, + 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, + 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, + 150, 151, 152, 153, 154, 155, 156, 1769, 157, 158, + 159, 160, 161, 0, 0, 1770, 163, 164, 165, 166, + 167, 168, 0, 170, 171, 172, 1771, 173, 174, 175, + 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, - 0, 217, 218, 219, 220, 605, 222, 223, 224, 225, - 226, 227, 606, 1357, 229, 0, 230, 231, 609, 233, - 0, 234, 0, 235, 612, 0, 614, 238, 239, 615, - 616, 242, 0, 243, 0, 619, 620, 246, 247, 0, - 248, 249, 250, 251, 252, 253, 254, 622, 256, 257, + 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, + 0, 234, 1772, 235, 0, 0, 0, 238, 239, 529, + 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, + 248, 249, 250, 251, 252, 1773, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, - 0, 267, 625, 626, 270, 271, 272, 273, 274, 627, - 628, 0, 630, 0, 278, 632, 633, 281, 634, 283, - 284, 285, 286, 287, 288, 0, 0, 289, 637, 291, - 638, 0, 293, 294, 295, 296, 297, 298, 299, 300, - 640, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, + 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, + 284, 285, 286, 287, 288, 0, 0, 289, 0, 291, + 0, 0, 293, 294, 295, 296, 297, 298, 299, 300, + 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 641, 642, 643, 325, 326, 327, 644, 0, 329, - 330, 646, 332, 0, 648, 334, 649, 336, 337, 338, - 0, 339, 340, 1358, 0, 341, 342, 343, 0, 0, - 344, 345, 655, 656, 348, 657, 658, 351, 352, 353, + 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, + 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, + 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, + 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, - 0, 0, 362, 363, 663, 664, 366, 367, 665, 369, - 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, - 378, 379, 380, 381, 382, 668, 384, 385, 386, 387, + 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, + 370, 371, 1774, 372, 373, 374, 375, 376, 377, 0, + 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, - 397, 398, 399, 400, 0, 401, 402, 671, 404, 405, - 406, 672, 408, 409, 410, 411, 412, 413, 414, 415, - 416, 417, 418, 419, 420, 0, 674, 421, 422, 423, - 424, 425, 426, 675, 428, 429, 0, 677, 431, 432, - 678, 434, 0, 435, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, 680, 448, 681, 0, 0, - 450, 451, 0, 452, 685, 454, 455, 456, 457, 458, - 0, 459, 687, 688, 0, 0, 462, 463, 691, 465, - 692, 1359, 467, 468, 694, 470, 471, 472, 473, 474, - 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, - 0, 482, 483, 484, 485, 486, 699, 700, 489, 0, - 490, 702, 492, 493, 494, 495, 496, 497, 498, 0, + 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, + 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, + 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, + 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, + 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, + 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, + 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, + 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, + 0, 1775, 475, 476, 477, 0, 478, 479, 480, 481, + 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, + 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, - 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, - 717, 517, 518, 519, 520, 973, 0, 0, 0, 0, + 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, + 516, 517, 518, 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, - 124, 125, 0, 126, 127, 128, 3, 4, 0, 565, - 0, 0, 0, 0, 570, 130, 131, 0, 132, 133, - 134, 572, 136, 137, 138, 573, 574, 575, 576, 577, + 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, + 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, - 151, 152, 153, 581, 582, 156, 0, 157, 158, 159, - 160, 584, 0, 586, 0, 588, 164, 165, 166, 167, - 168, 589, 170, 171, 172, 0, 173, 174, 175, 176, - 177, 178, 0, 592, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 594, 191, 192, 595, 194, 0, + 151, 152, 153, 154, 155, 156, 1769, 157, 158, 159, + 160, 161, 0, 0, 0, 163, 164, 165, 166, 167, + 168, 0, 170, 171, 172, 1771, 173, 174, 175, 176, + 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, - 217, 218, 219, 220, 605, 222, 223, 224, 225, 226, - 227, 606, 0, 229, 0, 230, 231, 609, 233, 0, - 234, 0, 235, 612, 0, 614, 238, 239, 615, 616, - 242, 0, 243, 0, 619, 620, 246, 247, 0, 248, - 249, 250, 251, 252, 253, 254, 622, 256, 257, 258, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, + 234, 1772, 235, 0, 0, 0, 238, 239, 529, 0, + 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, + 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, - 267, 625, 626, 270, 271, 272, 273, 274, 627, 628, - 0, 630, 0, 278, 632, 633, 281, 634, 283, 284, - 285, 286, 287, 288, 0, 0, 289, 637, 291, 638, - 0, 293, 294, 295, 296, 297, 298, 299, 300, 640, + 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, + 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, + 285, 286, 287, 288, 0, 0, 289, 0, 291, 2367, + 0, 293, 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 641, 642, 643, 325, 326, 327, 644, 0, 329, 330, - 646, 332, 0, 648, 334, 649, 336, 337, 338, 0, + 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, + 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, - 345, 655, 656, 348, 657, 658, 351, 352, 353, 354, + 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, - 0, 362, 363, 663, 664, 366, 367, 665, 369, 370, - 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, - 379, 380, 381, 382, 668, 384, 385, 386, 387, 0, + 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, + 371, 1774, 372, 373, 374, 375, 376, 377, 0, 378, + 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 0, 401, 402, 671, 404, 405, 406, - 672, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 0, 674, 421, 422, 423, 424, - 425, 426, 675, 428, 429, 0, 677, 431, 432, 678, + 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, + 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, 680, 448, 681, 0, 0, 450, - 451, 0, 452, 685, 454, 455, 456, 457, 458, 0, - 459, 687, 688, 0, 0, 462, 463, 691, 465, 692, - 0, 467, 468, 694, 470, 471, 472, 473, 474, 0, - 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, - 482, 483, 484, 485, 486, 699, 700, 489, 0, 490, - 702, 492, 493, 494, 495, 496, 497, 498, 0, 0, - 499, 0, 0, 500, 501, 502, 503, 504, 505, 707, - 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, - 517, 518, 519, 520, 117, 0, 0, 0, 0, 0, + 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, + 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, + 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, + 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, + 1775, 475, 476, 477, 0, 478, 479, 480, 481, 0, + 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, + 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, + 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, + 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, + 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, - 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, - 0, 0, 0, 129, 130, 131, 0, 132, 133, 134, - 135, 136, 137, 138, 139, 140, 141, 142, 143, 0, - 144, 145, 146, 147, 148, 149, 0, 790, 150, 151, + 125, 0, 126, 127, 128, 3, 4, 0, 0, 0, + 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, + 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, + 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, 158, 159, 160, - 791, 0, 792, 0, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, - 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, + 161, 0, 0, 0, 163, 164, 165, 166, 167, 168, + 0, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, - 793, 0, 229, 0, 230, 231, 232, 233, 0, 234, - 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, + 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, + 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, - 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, - 268, 269, 270, 271, 272, 273, 274, 275, 276, 0, - 277, 0, 278, 279, 280, 281, 282, 283, 284, 285, - 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, - 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, + 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, + 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 0, 291, 0, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 530, 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, 0, 329, 330, 331, - 332, 0, 795, 334, 335, 336, 337, 338, 0, 339, + 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, + 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, - 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, + 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, - 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, + 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, - 399, 400, 0, 401, 402, 403, 404, 405, 406, 407, + 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 430, 431, 432, 433, 434, + 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, - 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, - 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, - 460, 461, 0, 0, 462, 463, 801, 465, 802, 0, - 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, + 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, + 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, + 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, + 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, - 483, 484, 485, 486, 487, 488, 489, 0, 490, 491, + 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, - 518, 519, 520, 117, 0, 0, 0, 0, 0, 0, + 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, - 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, - 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, 0, 144, + 555, 126, 127, 128, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, + 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, 158, 159, 160, 161, - 0, 162, 0, 163, 164, 165, 166, 167, 168, 169, + 0, 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, - 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, + 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, - 235, 236, 0, 237, 238, 239, 240, 241, 242, 0, + 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, - 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, + 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, + 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, - 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, - 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, + 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, + 287, 288, 0, 0, 289, 0, 291, 0, 0, 293, + 294, 295, 296, 297, 298, 299, 300, 530, 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, 0, 329, 330, 331, 332, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, + 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, - 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, + 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, - 363, 364, 365, 366, 367, 368, 369, 370, 371, 0, + 363, 364, 0, 366, 367, 368, 556, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 0, 401, 402, 403, 404, 405, 406, 407, 408, + 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, - 427, 428, 429, 0, 430, 431, 432, 433, 434, 0, + 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 447, 448, 449, 0, 0, 450, 451, 0, - 452, 453, 454, 455, 456, 457, 458, 0, 459, 460, + 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, + 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, - 484, 485, 486, 487, 488, 489, 0, 490, 491, 492, + 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, + 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, - 154, 155, 156, 1758, 157, 158, 159, 160, 161, 0, - 0, 1759, 163, 164, 165, 166, 167, 168, 0, 170, - 171, 172, 1760, 173, 174, 175, 176, 177, 178, 0, + 154, 155, 156, 0, 157, 158, 159, 160, 161, 0, + 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, + 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, - 229, 0, 230, 231, 232, 233, 0, 234, 1761, 235, + 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, - 252, 1762, 254, 0, 256, 257, 258, 259, 0, 260, + 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, @@ -9427,10 +9870,10 @@ static const yytype_int16 yytable[] = 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, - 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, + 796, 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 364, 0, 366, 367, 368, 369, 370, 371, 1763, 372, + 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, @@ -9442,45 +9885,45 @@ static const yytype_int16 yytable[] = 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, - 469, 470, 471, 472, 473, 474, 0, 1764, 475, 476, + 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, + 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, - 155, 156, 1758, 157, 158, 159, 160, 161, 0, 0, + 155, 156, 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, - 172, 1760, 173, 174, 175, 176, 177, 178, 0, 0, + 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, - 0, 230, 231, 232, 233, 0, 234, 1761, 235, 0, + 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, + 904, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 0, 291, 2351, 0, 293, 294, 295, + 0, 0, 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, - 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, + 334, 335, 336, 337, 338, 0, 339, 340, 0, 796, 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, - 0, 366, 367, 368, 369, 370, 371, 1763, 372, 373, + 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, @@ -9492,7 +9935,7 @@ static const yytype_int16 yytable[] = 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, - 470, 471, 472, 473, 474, 0, 1764, 475, 476, 477, + 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, @@ -9500,8 +9943,8 @@ static const yytype_int16 yytable[] = 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, - 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, - 128, 3, 4, 0, 0, 0, 0, 0, 0, 0, + 119, 120, 121, 122, 123, 124, 125, 948, 126, 127, + 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, @@ -9550,7 +9993,7 @@ static const yytype_int16 yytable[] = 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, - 120, 121, 122, 123, 124, 125, 555, 126, 127, 128, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, @@ -9563,7 +10006,7 @@ static const yytype_int16 yytable[] = 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, + 223, 224, 225, 1184, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, @@ -9576,11 +10019,11 @@ static const yytype_int16 yytable[] = 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, - 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, + 336, 337, 338, 0, 339, 340, 0, 796, 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, - 367, 368, 556, 370, 371, 0, 372, 373, 374, 375, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, @@ -9615,18 +10058,18 @@ static const yytype_int16 yytable[] = 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, - 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, + 239, 529, 0, 1988, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, 289, - 0, 291, 0, 0, 293, 294, 295, 296, 297, 298, + 0, 291, 0, 0, 293, 294, 1989, 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, - 337, 338, 0, 339, 340, 0, 796, 341, 342, 343, + 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, @@ -9639,10 +10082,10 @@ static const yytype_int16 yytable[] = 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, - 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, - 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, + 0, 0, 450, 451, 1990, 452, 0, 454, 1991, 456, + 1992, 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, - 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, + 473, 474, 0, 0, 475, 476, 1993, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, @@ -9666,7 +10109,7 @@ static const yytype_int16 yytable[] = 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, - 0, 248, 249, 250, 251, 252, 903, 254, 0, 256, + 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, @@ -9676,7 +10119,7 @@ static const yytype_int16 yytable[] = 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, - 338, 0, 339, 340, 0, 796, 341, 342, 343, 0, + 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, @@ -9697,10 +10140,10 @@ static const yytype_int16 yytable[] = 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, + 515, 516, 517, 518, 519, 520, 528, 0, 821, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, - 123, 124, 125, 947, 126, 127, 128, 0, 0, 0, + 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, @@ -9747,10 +10190,10 @@ static const yytype_int16 yytable[] = 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, - 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, + 516, 517, 518, 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, - 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, + 124, 125, 827, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, @@ -9762,21 +10205,21 @@ static const yytype_int16 yytable[] = 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 1177, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, - 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, + 828, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, 289, 0, 291, 0, - 0, 293, 294, 295, 296, 297, 298, 299, 300, 530, + 0, 293, 294, 829, 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, - 339, 340, 0, 796, 341, 342, 343, 0, 0, 344, + 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, @@ -9786,19 +10229,19 @@ static const yytype_int16 yytable[] = 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, + 830, 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, - 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, + 459, 831, 461, 0, 0, 832, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, - 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, + 482, 483, 484, 485, 486, 487, 488, 833, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, - 517, 518, 519, 520, 528, 1967, 0, 0, 0, 0, - 1968, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, @@ -9831,7 +10274,7 @@ static const yytype_int16 yytable[] = 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, - 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, + 380, 381, 382, 383, 384, 385, 866, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, @@ -9864,14 +10307,14 @@ static const yytype_int16 yytable[] = 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, - 235, 0, 0, 0, 238, 239, 529, 0, 1975, 0, + 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, - 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, + 251, 252, 899, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, 289, 0, 291, 0, 0, 293, - 294, 1976, 296, 297, 298, 299, 300, 530, 302, 303, + 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, @@ -9888,11 +10331,11 @@ static const yytype_int16 yytable[] = 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 531, 448, 449, 0, 0, 450, 451, 1977, - 452, 0, 454, 1978, 456, 1979, 458, 0, 459, 460, + 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, + 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, - 476, 1980, 0, 478, 479, 480, 481, 0, 482, 483, + 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, @@ -9916,7 +10359,7 @@ static const yytype_int16 yytable[] = 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, + 252, 902, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, @@ -9947,7 +10390,7 @@ static const yytype_int16 yytable[] = 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 528, 0, 820, 0, 0, 0, 0, 0, 0, + 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, @@ -9966,7 +10409,7 @@ static const yytype_int16 yytable[] = 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, + 906, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, @@ -9997,9 +10440,9 @@ static const yytype_int16 yytable[] = 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, - 119, 120, 121, 122, 123, 124, 125, 826, 126, 127, + 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, @@ -10014,13 +10457,13 @@ static const yytype_int16 yytable[] = 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, - 0, 238, 239, 529, 0, 827, 0, 243, 0, 244, - 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, + 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, + 245, 246, 247, 0, 248, 249, 250, 251, 252, 936, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, - 0, 289, 0, 291, 0, 0, 293, 294, 828, 296, + 0, 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, @@ -10035,15 +10478,15 @@ static const yytype_int16 yytable[] = 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, - 0, 421, 422, 423, 424, 829, 426, 427, 428, 429, + 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, - 455, 456, 457, 458, 0, 459, 830, 461, 0, 0, - 831, 463, 464, 465, 466, 0, 467, 468, 469, 470, + 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, + 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, - 487, 488, 832, 0, 490, 0, 492, 493, 494, 495, + 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, @@ -10065,7 +10508,7 @@ static const yytype_int16 yytable[] = 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, - 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 246, 247, 0, 248, 249, 250, 251, 252, 964, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, @@ -10081,7 +10524,7 @@ static const yytype_int16 yytable[] = 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, - 385, 865, 387, 0, 388, 389, 390, 391, 392, 393, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, @@ -10115,7 +10558,7 @@ static const yytype_int16 yytable[] = 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, - 247, 0, 248, 249, 250, 251, 252, 898, 254, 0, + 247, 0, 248, 249, 250, 251, 252, 967, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, @@ -10146,11 +10589,11 @@ static const yytype_int16 yytable[] = 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, - 514, 515, 516, 517, 518, 519, 520, 528, 0, 554, + 514, 515, 516, 517, 518, 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, + 0, 0, 0, 0, 1010, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, @@ -10165,7 +10608,7 @@ static const yytype_int16 yytable[] = 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, - 0, 248, 249, 250, 251, 252, 901, 254, 0, 256, + 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, @@ -10196,11 +10639,11 @@ static const yytype_int16 yytable[] = 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, + 515, 516, 517, 518, 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, + 0, 0, 0, 1037, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, 158, @@ -10215,7 +10658,7 @@ static const yytype_int16 yytable[] = 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, - 248, 249, 250, 251, 252, 905, 254, 0, 256, 257, + 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, @@ -10246,10 +10689,10 @@ static const yytype_int16 yytable[] = 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, - 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, + 516, 517, 518, 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, - 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, + 124, 125, 827, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, @@ -10265,7 +10708,7 @@ static const yytype_int16 yytable[] = 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, - 249, 250, 251, 252, 935, 254, 0, 256, 257, 258, + 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, @@ -10289,7 +10732,7 @@ static const yytype_int16 yytable[] = 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, - 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, + 459, 831, 461, 0, 0, 832, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, @@ -10315,7 +10758,7 @@ static const yytype_int16 yytable[] = 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, - 250, 251, 252, 963, 254, 0, 256, 257, 258, 259, + 250, 251, 252, 1325, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, @@ -10365,7 +10808,7 @@ static const yytype_int16 yytable[] = 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, - 251, 252, 966, 254, 0, 256, 257, 258, 259, 0, + 251, 252, 1327, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, @@ -10396,10 +10839,10 @@ static const yytype_int16 yytable[] = 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, + 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 0, 1008, + 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, @@ -10415,7 +10858,7 @@ static const yytype_int16 yytable[] = 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, + 252, 1330, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, @@ -10446,10 +10889,10 @@ static const yytype_int16 yytable[] = 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, + 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, - 127, 128, 0, 0, 0, 0, 0, 0, 1031, 0, + 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, @@ -10465,7 +10908,7 @@ static const yytype_int16 yytable[] = 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, + 1332, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, @@ -10496,9 +10939,9 @@ static const yytype_int16 yytable[] = 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, - 119, 120, 121, 122, 123, 124, 125, 826, 126, 127, + 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, @@ -10514,7 +10957,7 @@ static const yytype_int16 yytable[] = 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, - 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, + 245, 246, 247, 0, 248, 249, 250, 251, 252, 2278, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, @@ -10538,314 +10981,314 @@ static const yytype_int16 yytable[] = 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, - 455, 456, 457, 458, 0, 459, 830, 461, 0, 0, - 831, 463, 464, 465, 466, 0, 467, 468, 469, 470, + 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, + 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, - 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, - 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, + 512, 513, 514, 515, 516, 517, 518, 519, 520, 1501, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, - 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, - 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, - 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, - 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, - 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, - 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, + 0, 0, 0, 1502, 0, 0, -808, 0, 1503, 130, + 131, 0, 132, 133, 134, 1504, 136, 137, 138, 0, + 1505, 1506, 1507, 1508, 0, 144, 145, 146, 147, 148, + 149, 0, 0, 150, 151, 152, 153, 1509, 1510, 156, + 0, 157, 158, 159, 160, 0, 0, 1511, 0, 1512, + 164, 165, 166, 167, 168, 1513, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 1514, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1515, 191, + 192, 1516, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, - 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, - 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, - 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, - 246, 247, 0, 248, 249, 250, 251, 252, 1318, 254, - 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, - 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, - 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, - 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, - 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, + 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 0, 222, + 223, 224, 225, 226, 227, 0, 0, 229, 0, 230, + 231, 1517, 233, 0, 234, 0, 235, 1518, 0, 1519, + 238, 239, -808, 1520, 242, 0, 243, 0, 0, 0, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 1521, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 1522, 0, 270, 271, 272, + 273, 274, 1523, 1524, 0, 1525, 0, 278, 1526, 1527, + 281, 1528, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 1529, 291, 1530, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1531, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, - 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, + 318, 319, 320, 321, 1532, 1533, 1534, 325, 326, 327, + 0, 0, 329, 330, 1535, 332, 0, 0, 334, 1536, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, - 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, + 343, 0, 0, 344, 345, 0, 1537, 348, 1538, 0, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, - 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, + 361, 0, 0, 0, 0, 362, 363, 0, 1539, 366, + 367, 0, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1540, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, - 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, - 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, - 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, - 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, - 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, - 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, - 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, - 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, - 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, + 1541, 404, 405, 406, 1542, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 1543, + 421, 422, 423, 424, 425, 426, 1544, 428, 429, 0, + 1545, 431, 432, 1546, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 1547, 448, + 0, 0, 0, 450, 451, 0, 452, 1548, 454, 455, + 456, 457, 458, 0, 459, 1549, 1550, 0, 0, 462, + 463, 0, 465, 0, 0, 467, 468, 1551, 470, 471, + 472, 473, 474, 1552, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 0, + 1553, 489, 0, 490, 1554, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, - 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, - 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, - 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, - 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, - 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, - 0, 0, 150, 151, 152, 153, 154, 155, 156, 0, - 157, 158, 159, 160, 161, 0, 0, 0, 163, 164, - 165, 166, 167, 168, 0, 170, 171, 172, 0, 173, - 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, - 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, - 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, - 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, - 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, - 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, - 247, 0, 248, 249, 250, 251, 252, 1320, 254, 0, - 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, - 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, - 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, - 0, 283, 284, 285, 286, 287, 288, 0, 0, 289, - 0, 291, 0, 0, 293, 294, 295, 296, 297, 298, - 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, - 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, - 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, - 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, - 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, - 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, - 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, - 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, - 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, - 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, - 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, - 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, - 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, - 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, - 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, - 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, - 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, - 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, - 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, - 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, - 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, - 514, 515, 516, 517, 518, 519, 520, 528, 0, 554, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, - 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, - 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, - 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, - 158, 159, 160, 161, 0, 0, 0, 163, 164, 165, - 166, 167, 168, 0, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, - 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, - 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, - 0, 248, 249, 250, 251, 252, 1323, 254, 0, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, - 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 0, - 291, 0, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, - 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, - 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, - 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, - 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, - 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, - 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, - 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, - 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, - 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, + 503, 504, 505, 528, 0, 554, 0, 0, 0, 0, + 0, 0, 0, 0, 517, 518, 519, 520, 0, 0, + 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, + 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, + 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, + 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, + 153, 154, 155, 156, 0, 157, 158, 159, 160, 161, + 0, 0, 0, 163, 164, 165, 166, 167, 168, 0, + 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, + 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, + 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, + 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, + 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, + 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, + 251, 252, 3048, 254, 0, 256, 257, 258, 259, 0, + 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, + 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, + 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, + 287, 288, 0, 0, 289, 0, 291, 0, 0, 293, + 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, + 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, + 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, + 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, + 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, + 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, + 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, + 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, + 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, + 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, + 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, + 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, + 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, + 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, + 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, + 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, + 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, - 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, - 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, - 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, - 150, 151, 152, 153, 154, 155, 156, 0, 157, 158, - 159, 160, 161, 0, 0, 0, 163, 164, 165, 166, - 167, 168, 0, 170, 171, 172, 0, 173, 174, 175, - 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, - 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, - 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, - 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, - 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, - 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, - 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, - 248, 249, 250, 251, 252, 1325, 254, 0, 256, 257, - 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, - 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, - 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, - 284, 285, 286, 287, 288, 0, 0, 289, 0, 291, - 0, 0, 293, 294, 295, 296, 297, 298, 299, 300, - 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, - 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, - 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, - 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, - 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, - 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, - 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, - 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, - 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, - 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, - 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, - 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, - 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, - 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, - 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, - 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, - 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, - 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, - 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, - 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, - 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, + 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, + 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, + 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, + 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, + 154, 155, 156, 0, 157, 158, 159, 160, 161, 0, + 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, + 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, + 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, + 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, + 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, + 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, + 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, + 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, + 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, + 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, + 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, + 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, + 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, + 288, 0, 0, 289, 0, 291, 0, 0, 293, 294, + 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, + 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, + 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, + 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, + 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, + 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, + 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, + 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, + 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, + 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, + 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, + 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, + 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, + 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, + 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, + 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, + 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, + 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, + 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, + 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, + 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, + 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, + 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, + 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, - 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, - 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, - 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, - 151, 152, 153, 154, 155, 156, 0, 157, 158, 159, - 160, 161, 0, 0, 0, 163, 164, 165, 166, 167, - 168, 0, 170, 171, 172, 0, 173, 174, 175, 176, - 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, - 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, - 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, - 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, - 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, - 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, - 249, 250, 251, 252, 2262, 254, 0, 256, 257, 258, - 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, - 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, - 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, - 285, 286, 287, 288, 0, 0, 289, 0, 291, 0, - 0, 293, 294, 295, 296, 297, 298, 299, 300, 530, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, - 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, - 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, - 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, - 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, - 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, - 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, - 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, - 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, - 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, - 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, - 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, - 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, - 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, - 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, - 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, - 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, - 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, - 517, 518, 519, 520, 1490, 0, 0, 0, 0, 0, + 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, + 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, + 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, + 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, + 155, 156, 0, 157, 158, 159, 160, 161, 0, 0, + 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, + 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, + 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, + 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, + 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, + 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, + 0, 0, 238, 239, 529, 0, 843, 0, 243, 0, + 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, + 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, + 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, + 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, + 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, + 0, 0, 289, 0, 291, 0, 0, 293, 294, 844, + 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, + 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, + 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, + 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, + 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, + 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, + 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, + 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, + 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, + 411, 845, 413, 414, 415, 416, 417, 418, 419, 420, + 0, 0, 421, 422, 423, 424, 846, 426, 427, 428, + 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, + 454, 455, 456, 457, 458, 0, 459, 847, 461, 0, + 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, + 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, + 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, + 486, 487, 488, 848, 0, 490, 0, 492, 493, 494, + 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, + 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, + 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, + 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, + 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, + 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, + 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, + 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, + 156, 0, 157, 158, 159, 160, 161, 0, 0, 0, + 163, 164, 165, 166, 167, 168, 0, 170, 171, 172, + 0, 173, 174, 175, 176, 177, 178, 0, 0, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, + 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, + 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, + 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, + 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, + 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, + 245, 246, 247, 0, 248, 249, 250, 251, 252, 960, + 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, + 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, + 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, + 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, + 0, 289, 0, 291, 0, 0, 293, 294, 295, 296, + 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, + 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, + 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, + 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, + 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, + 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, + 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, + 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, + 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, + 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, + 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, + 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, + 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, + 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, + 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, + 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, + 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, + 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, + 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, + 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, - 125, 0, 126, 127, 128, 0, 0, 0, 1491, 0, - 0, -802, 0, 1492, 130, 131, 0, 132, 133, 134, - 1493, 136, 137, 138, 0, 1494, 1495, 1496, 1497, 0, - 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, - 152, 153, 1498, 1499, 156, 0, 157, 158, 159, 160, - 0, 0, 1500, 0, 1501, 164, 165, 166, 167, 168, - 1502, 170, 171, 172, 0, 173, 174, 175, 176, 177, - 178, 0, 1503, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 1504, 191, 192, 1505, 194, 0, 195, - 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, - 203, 204, 205, 0, 0, 206, 207, 1067, 209, 210, - 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, - 218, 219, 220, 0, 222, 223, 224, 225, 226, 227, - 0, 0, 229, 0, 230, 231, 1506, 233, 0, 234, - 0, 235, 1507, 0, 1508, 238, 239, -802, 1509, 242, - 0, 243, 0, 0, 0, 246, 247, 0, 248, 249, - 250, 251, 252, 253, 254, 1510, 256, 257, 258, 259, - 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, - 1511, 0, 270, 271, 272, 273, 274, 1512, 1513, 0, - 1514, 0, 278, 1515, 1516, 281, 1517, 283, 284, 285, - 286, 287, 288, 0, 0, 289, 1518, 291, 1519, 0, - 293, 294, 295, 296, 297, 298, 299, 300, 1520, 302, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, 315, 316, 317, 318, 319, 320, 321, 1521, - 1522, 1523, 325, 326, 327, 0, 0, 329, 330, 1524, - 332, 0, 0, 334, 1525, 336, 337, 338, 0, 339, - 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, - 0, 1526, 348, 1527, 0, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, - 362, 363, 0, 1528, 366, 367, 0, 369, 370, 371, - 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, - 380, 381, 382, 1529, 384, 385, 386, 387, 0, 388, - 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, - 399, 400, 0, 401, 402, 1530, 404, 405, 406, 1531, - 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, - 418, 419, 420, 0, 1532, 421, 422, 423, 424, 425, - 426, 1533, 428, 429, 0, 1534, 431, 432, 1535, 434, - 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, - 444, 445, 446, 1536, 448, 0, 0, 0, 450, 451, - 0, 452, 1537, 454, 455, 456, 457, 458, 0, 459, - 1538, 1539, 0, 0, 462, 463, 0, 465, 0, 0, - 467, 468, 1540, 470, 471, 472, 473, 474, 1541, 0, - 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, - 483, 484, 485, 486, 0, 1542, 489, 0, 490, 1543, - 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, - 0, 0, 500, 501, 502, 503, 504, 505, 528, 0, - 554, 0, 0, 0, 0, 0, 0, 0, 0, 517, - 518, 519, 520, 0, 0, 0, 0, 118, 119, 120, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, + 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, + 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, + 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, + 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, + 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, + 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, + 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, + 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, + 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, + 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, + 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, + 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 0, 404, 405, 406, 407, 408, 409, 410, 411, 845, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, + 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, + 456, 457, 458, 0, 459, 847, 461, 0, 0, 462, + 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, @@ -10862,7 +11305,7 @@ static const yytype_int16 yytable[] = 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, - 247, 0, 248, 249, 250, 251, 252, 3024, 254, 0, + 247, 0, 248, 249, 250, 251, 252, 1321, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, @@ -10912,7 +11355,7 @@ static const yytype_int16 yytable[] = 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, + 0, 248, 249, 250, 251, 252, 1342, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, @@ -10947,7 +11390,7 @@ static const yytype_int16 yytable[] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, + 0, 0, 0, 1697, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, 158, @@ -10961,13 +11404,13 @@ static const yytype_int16 yytable[] = 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, - 0, 842, 0, 243, 0, 244, 245, 246, 247, 0, + 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, 289, 0, 291, - 0, 0, 293, 294, 843, 296, 297, 298, 299, 300, + 0, 0, 293, 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, @@ -10980,16 +11423,16 @@ static const yytype_int16 yytable[] = 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, - 406, 407, 408, 409, 410, 411, 844, 413, 414, 415, + 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, - 424, 845, 426, 427, 428, 429, 0, 0, 431, 432, + 424, 425, 0, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, - 0, 459, 846, 461, 0, 0, 462, 463, 464, 465, + 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, - 0, 482, 483, 484, 485, 486, 487, 488, 847, 0, + 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, @@ -11012,7 +11455,7 @@ static const yytype_int16 yytable[] = 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, - 249, 250, 251, 252, 959, 254, 0, 256, 257, 258, + 249, 250, 251, 252, 1883, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, @@ -11062,7 +11505,7 @@ static const yytype_int16 yytable[] = 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, - 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, + 250, 251, 252, 2265, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, @@ -11080,13 +11523,13 @@ static const yytype_int16 yytable[] = 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, - 408, 409, 410, 411, 844, 413, 414, 415, 416, 417, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, - 846, 461, 0, 0, 462, 463, 464, 465, 466, 0, + 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, @@ -11112,7 +11555,7 @@ static const yytype_int16 yytable[] = 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, - 251, 252, 1314, 254, 0, 256, 257, 258, 259, 0, + 251, 252, 2280, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, @@ -11143,1742 +11586,2484 @@ static const yytype_int16 yytable[] = 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, + 519, 520, 1501, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, - 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, + 126, 127, 128, 0, 0, 0, 1502, 0, 0, 0, + 0, 1503, 130, 131, 0, 132, 133, 134, 1504, 136, + 137, 138, 0, 1505, 1506, 1507, 1508, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, - 154, 155, 156, 0, 157, 158, 159, 160, 161, 0, - 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, + 1509, 1510, 156, 0, 157, 158, 159, 160, 0, 0, + 1511, 0, 1512, 164, 165, 166, 167, 168, 1513, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, + 1514, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 1515, 191, 192, 1516, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, + 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, - 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, - 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, - 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, - 252, 1335, 254, 0, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, - 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, - 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 0, 291, 0, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, + 220, 0, 222, 223, 224, 225, 226, 227, 0, 0, + 229, 0, 230, 231, 1517, 233, 0, 234, 0, 235, + 1518, 0, 1519, 238, 239, 0, 1520, 242, 0, 243, + 0, 0, 0, 246, 247, 0, 248, 249, 250, 251, + 252, 253, 254, 1521, 256, 257, 258, 259, 0, 260, + 261, 262, 263, 264, 265, 266, 0, 267, 1522, 0, + 270, 271, 272, 273, 274, 1523, 1524, 0, 1525, 0, + 278, 1526, 1527, 281, 1528, 283, 284, 285, 286, 287, + 288, 0, 0, 289, 1529, 291, 1530, 0, 293, 294, + 295, 296, 297, 298, 299, 300, 1531, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, - 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, - 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, - 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, - 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, + 315, 316, 317, 318, 319, 320, 321, 1532, 1533, 1534, + 325, 326, 327, 0, 0, 329, 330, 1535, 332, 0, + 0, 334, 1536, 336, 337, 338, 0, 339, 340, 0, + 0, 341, 342, 343, 0, 0, 344, 345, 0, 1537, + 348, 1538, 0, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, + 0, 1539, 366, 367, 0, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, + 382, 1540, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, + 0, 401, 402, 1541, 404, 405, 406, 1542, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, + 420, 0, 1543, 421, 422, 423, 424, 425, 426, 1544, + 428, 429, 0, 1545, 431, 432, 1546, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, - 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, - 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, - 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, + 446, 1547, 448, 0, 0, 0, 450, 451, 0, 452, + 1548, 454, 455, 456, 457, 458, 0, 459, 1549, 1550, + 0, 0, 462, 463, 0, 465, 0, 0, 467, 468, + 1551, 470, 471, 472, 473, 474, 1552, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, + 485, 486, 0, 1553, 489, 0, 490, 1554, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, - 127, 128, 0, 0, 0, 0, 0, 0, 1686, 0, - 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, - 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, - 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, - 155, 156, 0, 157, 158, 159, 160, 161, 0, 0, - 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, - 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, - 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, - 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, - 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, - 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, - 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, - 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, - 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, - 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, - 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 0, 291, 0, 0, 293, 294, 295, - 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, - 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, - 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, - 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, - 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, - 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, - 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, - 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, - 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 0, 0, 421, 422, 423, 424, 425, 0, 427, 428, - 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, - 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, - 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, - 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, - 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, - 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, - 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, + 500, 501, 502, 503, 504, 505, 1501, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 517, 518, 519, + 520, 0, 0, 0, 0, 118, 119, 120, 121, 122, + 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, + 1502, 0, 0, 0, 0, 1503, 130, 131, 0, 132, + 133, 134, 1504, 136, 137, 138, 0, 1505, 1506, 1507, + 1508, 0, 144, 145, 146, 147, 148, 149, 0, 0, + 150, 151, 152, 153, 1509, 1510, 156, 0, 157, 158, + 159, 160, 0, 0, 1511, 0, 1512, 164, 165, 166, + 167, 168, 1513, 170, 171, 172, 0, 173, 174, 175, + 176, 177, 178, 0, 1514, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 1515, 191, 192, 1516, 194, + 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, + 0, 202, 203, 204, 205, 0, 0, 206, 207, 1073, + 209, 210, 0, 211, 212, 213, 0, 1859, 215, 216, + 0, 217, 218, 219, 220, 0, 222, 223, 224, 225, + 226, 227, 0, 0, 229, 0, 230, 231, 1517, 233, + 0, 234, 0, 235, 1518, 0, 1519, 238, 239, 0, + 1520, 242, 0, 243, 0, 0, 0, 246, 247, 0, + 248, 249, 250, 251, 252, 253, 254, 1521, 256, 257, + 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, + 0, 267, 1522, 0, 270, 271, 272, 273, 274, 1523, + 1524, 0, 1525, 0, 278, 1526, 1527, 281, 1528, 283, + 284, 285, 286, 287, 288, 0, 0, 289, 1529, 291, + 1530, 0, 293, 294, 295, 296, 297, 298, 299, 300, + 1531, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 1532, 1533, 1534, 325, 326, 327, 0, 0, 329, + 330, 1535, 332, 0, 0, 334, 1536, 336, 337, 338, + 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, + 344, 345, 0, 1537, 348, 1538, 0, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, + 0, 0, 362, 363, 0, 1539, 366, 367, 0, 369, + 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, + 378, 379, 380, 381, 382, 1540, 384, 385, 386, 387, + 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, + 397, 398, 399, 400, 0, 401, 402, 1541, 404, 405, + 406, 1542, 408, 409, 410, 411, 412, 413, 414, 415, + 416, 417, 418, 419, 420, 0, 1543, 421, 422, 423, + 424, 425, 426, 1544, 428, 429, 0, 1545, 431, 432, + 1546, 434, 0, 435, 436, 437, 438, 439, 440, 441, + 442, 443, 444, 445, 446, 1547, 448, 0, 0, 0, + 450, 451, 0, 452, 1548, 454, 455, 456, 457, 458, + 0, 459, 1549, 1550, 0, 0, 462, 463, 0, 465, + 0, 0, 467, 468, 1551, 470, 471, 472, 473, 474, + 1552, 0, 475, 476, 477, 0, 478, 479, 480, 481, + 0, 482, 483, 484, 485, 486, 0, 1553, 489, 0, + 490, 1554, 492, 493, 494, 495, 496, 497, 498, 0, + 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, + 3230, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 517, 518, 519, 520, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, - 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, - 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, - 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, - 156, 0, 157, 158, 159, 160, 161, 0, 0, 0, - 163, 164, 165, 166, 167, 168, 0, 170, 171, 172, - 0, 173, 174, 175, 176, 177, 178, 0, 0, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, + 128, 0, 0, 0, 2971, 0, 0, 0, 0, 2972, + 130, 131, 0, 132, 133, 134, 2973, 136, 137, 138, + 0, 1505, 2974, 1507, 1508, 0, 144, 145, 146, 147, + 148, 149, 0, 0, 150, 151, 152, 153, 1509, 1510, + 156, 0, 157, 158, 159, 160, 0, 0, 2975, 0, + 2976, 164, 165, 166, 167, 168, 2977, 170, 171, 172, + 0, 173, 174, 175, 176, 177, 178, 0, 2978, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 1515, + 191, 192, 1516, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, - 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, - 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, - 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, - 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, - 245, 246, 247, 0, 248, 249, 250, 251, 252, 1872, - 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, - 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, - 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, - 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, - 0, 289, 0, 291, 0, 0, 293, 294, 295, 296, - 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, + 0, 206, 207, 1073, 209, 210, 0, 211, 212, 213, + 0, 214, 215, 216, 0, 217, 218, 219, 220, 0, + 222, 223, 224, 225, 226, 227, 0, 0, 229, 0, + 230, 231, 1517, 233, 0, 234, 0, 235, 2979, 0, + 2980, 238, 239, 2981, 2982, 242, 0, 243, 0, 0, + 0, 246, 247, 0, 248, 249, 250, 251, 252, 253, + 254, 2983, 256, 257, 258, 259, 0, 260, 261, 262, + 263, 264, 265, 266, 0, 267, 2984, 0, 270, 271, + 272, 273, 274, 1523, 1524, 0, 1525, 0, 278, 2985, + 2986, 281, 2987, 283, 284, 285, 286, 287, 288, 0, + 0, 289, 2988, 291, 2989, 0, 293, 294, 295, 296, + 297, 298, 299, 300, 3231, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, - 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, - 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, - 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, - 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, - 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, + 317, 318, 319, 320, 321, 1532, 2991, 1534, 325, 326, + 327, 0, 0, 329, 330, 2993, 332, 0, 0, 334, + 1536, 336, 337, 338, 0, 339, 340, 0, 0, 341, + 342, 343, 0, 0, 344, 345, 0, 2995, 348, 2996, + 0, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 0, 0, 0, 0, 362, 363, 0, 2997, + 366, 367, 0, 369, 370, 371, 0, 372, 373, 374, + 375, 376, 377, 0, 378, 379, 380, 381, 382, 1540, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, - 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, + 402, 2998, 404, 405, 406, 0, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, - 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, - 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, - 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, - 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, - 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, + 2999, 421, 422, 423, 424, 425, 426, 0, 428, 429, + 0, 3001, 431, 432, 1546, 434, 0, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, 3232, + 448, 0, 0, 0, 450, 451, 0, 452, 3003, 454, + 455, 456, 457, 458, 0, 459, 1549, 1550, 0, 0, + 462, 463, 0, 465, 0, 0, 467, 468, 3004, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, - 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, + 0, 1553, 489, 0, 490, 3006, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, - 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, - 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, + 502, 503, 504, 505, 528, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 517, 518, 519, 520, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, + 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, + 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, + 152, 153, 154, 155, 156, 0, 157, 158, 159, 160, + 161, 0, 0, 0, 163, 164, 165, 166, 167, 168, + 0, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, + 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, + 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, + 0, 243, 0, 244, 245, 0, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, + 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 0, 291, 0, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 530, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, + 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, + 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, + 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, + 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, + 356, 0, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 0, 382, 383, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, + 0, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, + 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, + 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, + 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 1796, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, - 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, - 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, - 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, - 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, - 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, - 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, - 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, - 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, - 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, - 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, - 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, - 246, 247, 0, 248, 249, 250, 251, 252, 2249, 254, - 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, - 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, - 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, - 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, - 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, - 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, - 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, - 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, - 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, - 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, - 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, - 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, - 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, - 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, - 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, - 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, - 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, - 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, - 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, - 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, + 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, + 0, 126, 127, 128, 0, 0, 0, 1502, 0, 0, + 0, 0, 1503, 130, 131, 0, 132, 133, 134, 1504, + 136, 137, 138, 0, 1505, 1506, 1507, 1508, 0, 144, + 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, + 153, 1509, 1510, 156, 0, 157, 158, 159, 160, 0, + 0, 1511, 0, 1512, 164, 165, 166, 167, 168, 1513, + 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, + 0, 1514, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 1515, 191, 192, 1516, 194, 0, 195, 0, + 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, + 204, 205, 0, 0, 206, 207, 1073, 209, 210, 0, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 0, 222, 223, 224, 225, 226, 227, 0, + 0, 229, 0, 230, 231, 1517, 233, 0, 234, 0, + 235, 1518, 0, 1519, 238, 239, 0, 1520, 242, 0, + 243, 0, 0, 0, 246, 247, 0, 248, 249, 250, + 251, 252, 253, 254, 1521, 256, 257, 258, 259, 0, + 260, 261, 262, 263, 264, 265, 266, 0, 267, 1522, + 0, 270, 271, 272, 273, 274, 1523, 1524, 0, 1525, + 0, 278, 1526, 1527, 281, 1528, 283, 284, 285, 286, + 287, 288, 0, 0, 289, 1529, 291, 1530, 0, 293, + 294, 295, 296, 297, 298, 299, 300, 0, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 1532, 1533, + 1534, 325, 326, 327, 0, 0, 329, 330, 1535, 332, + 0, 0, 334, 1536, 336, 337, 338, 0, 339, 340, + 0, 0, 341, 342, 343, 0, 0, 344, 345, 0, + 1537, 348, 1538, 0, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, + 363, 0, 1539, 366, 367, 0, 369, 370, 371, 0, + 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, + 381, 382, 1540, 384, 385, 386, 387, 0, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + 400, 0, 401, 402, 1541, 404, 405, 406, 0, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 0, 1543, 421, 422, 423, 424, 425, 426, + 0, 428, 429, 0, 1545, 431, 432, 1546, 434, 0, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 0, 448, 0, 0, 0, 450, 451, 0, + 452, 1548, 454, 455, 456, 457, 458, 0, 459, 1549, + 1550, 0, 0, 462, 463, 0, 465, 0, 0, 467, + 468, 1551, 470, 471, 472, 473, 474, 0, 0, 475, + 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, + 484, 485, 486, 0, 1553, 489, 0, 490, 1554, 492, + 493, 494, 495, 496, 497, 498, 0, 1, 499, 0, + 0, 500, 501, 502, 503, 504, 505, 2, 0, 3, + 4, 0, 0, 0, 0, 1, 0, 0, 517, 518, + 519, 520, 0, 0, 0, 2, 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, 751, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, + 0, 11, 0, 751, 0, 0, 0, 0, 0, 0, + 0, 14, 15, 0, 13, 0, 0, 0, 0, 0, + 0, 0, 752, 0, 0, 0, 0, 0, 18, 14, + 15, 0, 0, 0, 0, 0, 19, 0, 0, 0, + 752, 0, 0, 0, 0, 0, 18, 0, 0, 0, + 0, 0, 0, 22, 19, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, - 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, - 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, - 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, - 0, 0, 150, 151, 152, 153, 154, 155, 156, 0, - 157, 158, 159, 160, 161, 0, 0, 0, 163, 164, - 165, 166, 167, 168, 0, 170, 171, 172, 0, 173, - 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, - 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, - 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, - 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, - 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, - 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, - 247, 0, 248, 249, 250, 251, 252, 2264, 254, 0, - 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, - 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, - 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, - 0, 283, 284, 285, 286, 287, 288, 0, 0, 289, - 0, 291, 0, 0, 293, 294, 295, 296, 297, 298, - 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, - 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, - 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, - 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, - 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, - 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, - 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, - 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, - 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, - 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, - 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, - 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, - 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, - 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, - 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, - 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, - 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, - 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, - 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, - 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, - 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, - 514, 515, 516, 517, 518, 519, 520, 1490, 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, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 1491, 0, 0, 0, 0, 1492, 130, 131, 0, - 132, 133, 134, 1493, 136, 137, 138, 0, 1494, 1495, - 1496, 1497, 0, 144, 145, 146, 147, 148, 149, 0, - 0, 150, 151, 152, 153, 1498, 1499, 156, 0, 157, - 158, 159, 160, 0, 0, 1500, 0, 1501, 164, 165, - 166, 167, 168, 1502, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 1503, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1504, 191, 192, 1505, - 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 0, 222, 223, 224, - 225, 226, 227, 0, 0, 229, 0, 230, 231, 1506, - 233, 0, 234, 0, 235, 1507, 0, 1508, 238, 239, - 0, 1509, 242, 0, 243, 0, 0, 0, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 1510, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 1511, 0, 270, 271, 272, 273, 274, - 1512, 1513, 0, 1514, 0, 278, 1515, 1516, 281, 1517, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 1518, - 291, 1519, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1520, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1521, 1522, 1523, 325, 326, 327, 0, 0, - 329, 330, 1524, 332, 0, 0, 334, 1525, 336, 337, - 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, - 0, 344, 345, 0, 1526, 348, 1527, 0, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 0, 1528, 366, 367, 0, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1529, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 1530, 404, - 405, 406, 1531, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 1532, 421, 422, - 423, 424, 425, 426, 1533, 428, 429, 0, 1534, 431, - 432, 1535, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 1536, 448, 0, 0, - 0, 450, 451, 0, 452, 1537, 454, 455, 456, 457, - 458, 0, 459, 1538, 1539, 0, 0, 462, 463, 0, - 465, 0, 0, 467, 468, 1540, 470, 471, 472, 473, - 474, 1541, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 0, 1542, 489, - 0, 490, 1543, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 1490, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 517, 518, 519, 520, 0, 0, 0, 0, - 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, - 127, 128, 0, 0, 0, 1491, 0, 0, 0, 0, - 1492, 130, 131, 0, 132, 133, 134, 1493, 136, 137, - 138, 0, 1494, 1495, 1496, 1497, 0, 144, 145, 146, - 147, 148, 149, 0, 0, 150, 151, 152, 153, 1498, - 1499, 156, 0, 157, 158, 159, 160, 0, 0, 1500, - 0, 1501, 164, 165, 166, 167, 168, 1502, 170, 171, - 172, 0, 173, 174, 175, 176, 177, 178, 0, 1503, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 1504, 191, 192, 1505, 194, 0, 195, 0, 196, 197, - 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, - 0, 0, 206, 207, 1067, 209, 210, 0, 211, 212, - 213, 0, 1848, 215, 216, 0, 217, 218, 219, 220, - 0, 222, 223, 224, 225, 226, 227, 0, 0, 229, - 0, 230, 231, 1506, 233, 0, 234, 0, 235, 1507, - 0, 1508, 238, 239, 0, 1509, 242, 0, 243, 0, - 0, 0, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 1510, 256, 257, 258, 259, 0, 260, 261, - 262, 263, 264, 265, 266, 0, 267, 1511, 0, 270, - 271, 272, 273, 274, 1512, 1513, 0, 1514, 0, 278, - 1515, 1516, 281, 1517, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 1518, 291, 1519, 0, 293, 294, 295, - 296, 297, 298, 299, 300, 1520, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 1521, 1522, 1523, 325, - 326, 327, 0, 0, 329, 330, 1524, 332, 0, 0, - 334, 1525, 336, 337, 338, 0, 339, 340, 0, 0, - 341, 342, 343, 0, 0, 344, 345, 0, 1526, 348, - 1527, 0, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 0, 0, 0, 0, 362, 363, 0, - 1528, 366, 367, 0, 369, 370, 371, 0, 372, 373, - 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, - 1529, 384, 385, 386, 387, 0, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, - 401, 402, 1530, 404, 405, 406, 1531, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 0, 1532, 421, 422, 423, 424, 425, 426, 1533, 428, - 429, 0, 1534, 431, 432, 1535, 434, 0, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 1536, 448, 0, 0, 0, 450, 451, 0, 452, 1537, - 454, 455, 456, 457, 458, 0, 459, 1538, 1539, 0, - 0, 462, 463, 0, 465, 0, 0, 467, 468, 1540, - 470, 471, 472, 473, 474, 1541, 0, 475, 476, 477, - 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, - 486, 0, 1542, 489, 0, 490, 1543, 492, 493, 494, - 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, - 501, 502, 503, 504, 505, 3199, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 517, 518, 519, 520, - 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, - 124, 125, 0, 126, 127, 128, 0, 0, 0, 2947, - 0, 0, 0, 0, 2948, 130, 131, 0, 132, 133, - 134, 2949, 136, 137, 138, 0, 1494, 2950, 1496, 1497, - 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, - 151, 152, 153, 1498, 1499, 156, 0, 157, 158, 159, - 160, 0, 0, 2951, 0, 2952, 164, 165, 166, 167, - 168, 2953, 170, 171, 172, 0, 173, 174, 175, 176, - 177, 178, 0, 2954, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 1504, 191, 192, 1505, 194, 0, - 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, - 202, 203, 204, 205, 0, 0, 206, 207, 1067, 209, - 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, - 217, 218, 219, 220, 0, 222, 223, 224, 225, 226, - 227, 0, 0, 229, 0, 230, 231, 1506, 233, 0, - 234, 0, 235, 2955, 0, 2956, 238, 239, 2957, 2958, - 242, 0, 243, 0, 0, 0, 246, 247, 0, 248, - 249, 250, 251, 252, 253, 254, 2959, 256, 257, 258, - 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, - 267, 2960, 0, 270, 271, 272, 273, 274, 1512, 1513, - 0, 1514, 0, 278, 2961, 2962, 281, 2963, 283, 284, - 285, 286, 287, 288, 0, 0, 289, 2964, 291, 2965, - 0, 293, 294, 295, 296, 297, 298, 299, 300, 3200, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 1521, 2967, 1523, 325, 326, 327, 0, 0, 329, 330, - 2969, 332, 0, 0, 334, 1525, 336, 337, 338, 0, - 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, - 345, 0, 2971, 348, 2972, 0, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, - 0, 362, 363, 0, 2973, 366, 367, 0, 369, 370, - 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, - 379, 380, 381, 382, 1529, 384, 385, 386, 387, 0, - 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 0, 401, 402, 2974, 404, 405, 406, - 0, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 0, 2975, 421, 422, 423, 424, - 425, 426, 0, 428, 429, 0, 2977, 431, 432, 1535, - 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, 3201, 448, 0, 0, 0, 450, - 451, 0, 452, 2979, 454, 455, 456, 457, 458, 0, - 459, 1538, 1539, 0, 0, 462, 463, 0, 465, 0, - 0, 467, 468, 2980, 470, 471, 472, 473, 474, 0, - 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, - 482, 483, 484, 485, 486, 0, 1542, 489, 0, 490, - 2982, 492, 493, 494, 495, 496, 497, 498, 0, 0, - 499, 0, 0, 500, 501, 502, 503, 504, 505, 528, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -1467, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 517, 518, 519, 520, 0, 0, 0, 0, 118, 119, - 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, - 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, - 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, - 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, - 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, - 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, - 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, - 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, - 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, - 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, - 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, - 0, 247, 0, 248, 249, 250, 251, 252, 253, 254, - 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, - 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, - 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, - 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, - 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, - 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, - 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, - 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, - 351, 352, 353, 354, 355, 356, 0, 358, 359, 360, - 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, - 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 0, 382, 383, 384, - 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 0, 404, 405, 406, 407, 0, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, - 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, - 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, - 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, - 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, - 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, - 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, - 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, - 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, - 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, - 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, - 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 1785, 0, + 0, 0, 0, 0, 0, 0, 0, -1467, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, - 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, - 0, 0, 1491, 0, 0, 0, 0, 1492, 130, 131, - 0, 132, 133, 134, 1493, 136, 137, 138, 0, 1494, - 1495, 1496, 1497, 0, 144, 145, 146, 147, 148, 149, - 0, 0, 150, 151, 152, 153, 1498, 1499, 156, 0, - 157, 158, 159, 160, 0, 0, 1500, 0, 1501, 164, - 165, 166, 167, 168, 1502, 170, 171, 172, 0, 173, - 174, 175, 176, 177, 178, 0, 1503, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 1504, 191, 192, - 1505, 194, 0, 195, 0, 196, 197, 198, 199, 200, - 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, - 207, 1067, 209, 210, 0, 211, 212, 213, 0, 214, - 215, 216, 0, 217, 218, 219, 220, 0, 222, 223, - 224, 225, 226, 227, 0, 0, 229, 0, 230, 231, - 1506, 233, 0, 234, 0, 235, 1507, 0, 1508, 238, - 239, 0, 1509, 242, 0, 243, 0, 0, 0, 246, - 247, 0, 248, 249, 250, 251, 252, 253, 254, 1510, - 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, - 265, 266, 0, 267, 1511, 0, 270, 271, 272, 273, - 274, 1512, 1513, 0, 1514, 0, 278, 1515, 1516, 281, - 1517, 283, 284, 285, 286, 287, 288, 0, 0, 289, - 1518, 291, 1519, 0, 293, 294, 295, 296, 297, 298, - 299, 300, 0, 302, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, 321, 1521, 1522, 1523, 325, 326, 327, 0, - 0, 329, 330, 1524, 332, 0, 0, 334, 1525, 336, - 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, - 0, 0, 344, 345, 0, 1526, 348, 1527, 0, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, - 0, 0, 0, 0, 362, 363, 0, 1528, 366, 367, - 0, 369, 370, 371, 0, 372, 373, 374, 375, 376, - 377, 0, 378, 379, 380, 381, 382, 1529, 384, 385, - 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 0, 401, 402, 1530, - 404, 405, 406, 0, 408, 409, 410, 411, 412, 413, - 414, 415, 416, 417, 418, 419, 420, 0, 1532, 421, - 422, 423, 424, 425, 426, 0, 428, 429, 0, 1534, - 431, 432, 1535, 434, 0, 435, 436, 437, 438, 439, - 440, 441, 442, 443, 444, 445, 446, 0, 448, 0, - 0, 0, 450, 451, 0, 452, 1537, 454, 455, 456, - 457, 458, 0, 459, 1538, 1539, 0, 0, 462, 463, - 0, 465, 0, 0, 467, 468, 1540, 470, 471, 472, - 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, - 480, 481, 0, 482, 483, 484, 485, 486, 0, 1542, - 489, 0, 490, 1543, 492, 493, 494, 495, 496, 497, - 498, 0, 1, 499, 0, 0, 500, 501, 502, 503, - 504, 505, 2, 0, 3, 4, 0, 0, 0, 0, - 1, 0, 0, 517, 518, 519, 520, 0, 0, 0, - 2, 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, - 751, 0, 0, 0, 10, 0, 0, 0, 0, 0, - 0, 13, 0, 0, 0, 0, 11, 0, 751, 0, - 0, 0, 0, 0, 0, 0, 14, 15, 0, 13, - 0, 0, 0, 0, 0, 0, 0, 752, 0, 0, - 0, 0, 0, 18, 14, 15, 0, 0, 0, 0, - 0, 19, 0, 0, 0, 752, 0, 0, 0, 0, - 0, 18, 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, -1445, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, -1445, 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, 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, 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, 36, 0, + 0, 0, 34, 0, 0, 0, 35, 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, 39, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, + 0, 0, 39, 42, 0, 0, 0, 0, 43, 0, + 0, 0, 0, 753, 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, 0, 0, 44, 0, 0, 0, 0, 0, 45, 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, 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, 36, 0, 0, 0, 34, 0, 0, - 0, 35, 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, 39, + 0, 0, 0, 754, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 40, 0, 0, 0, 0, 39, 42, 0, - 0, 0, 0, 43, 0, 0, 0, 0, 753, 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, 0, 0, 44, 0, - 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 754, 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, 840, 0, 521, 0, 0, 746, 902, 887, 16, - 0, 0, 0, 814, 864, 46, 23, 998, 0, 0, - 38, 0, 0, 7, 73, 754, 913, 75, 76, 0, - 1237, 929, 1223, 1249, 964, 1235, 1435, 1708, 20, 23, - 77, 1039, 20, 934, 16, 77, 1168, 1210, 37, 1670, - 1087, 989, 20, 1588, 989, 7, 989, 2201, 989, 1642, - 1313, 1816, 1483, 2260, 1562, 1203, 1212, 979, 75, 76, - 1215, 23, 13, 2011, 1291, 2191, 968, 979, 19, 2347, - 1338, 17, 0, 23, 1623, 1624, 0, 45, 0, 30, - 0, 75, 76, 111, 1240, 0, 0, 0, 2718, 23, - 0, 0, 0, 44, 45, 2656, 1133, 2695, 2170, 0, - 2172, 1138, 101, 902, 1095, 904, 0, 906, 34, 2136, - 1007, 2190, 2711, 75, 76, 2256, 2693, 0, 0, 0, - 2656, 0, 0, 753, 0, 75, 76, 987, 0, 0, - 754, 810, 0, 2308, 2309, 2310, 815, 2012, 747, 2327, - 0, 75, 76, 2610, 2525, 1838, 0, 2614, 0, 1835, - 9, 1061, 1062, 9, 1726, 0, 0, 5, 109, 5, - 1728, 1674, 1952, 26, 80, 13, 14, 3035, 1078, 32, - 5, 5, 63, 1834, 5, 9, 5, 5, 9, 990, - 2339, 55, 5, 5, 13, 14, 5, 778, 5, 5, - 13, 14, 13, 14, 13, 14, 13, 14, 1642, 5, - 26, 5, 13, 14, 5, 5, 32, 2348, 2335, 5, - 5, 3021, 45, 5, 5, 172, 172, 5, 82, 2333, - 119, 74, 1144, 2339, 3, 45, 5, 122, 3038, 93, - 173, 11, 882, 11, 1094, 124, 16, 882, 16, 37, - 979, 139, 3, 4, 5, 107, 100, 859, 9, 2474, - 1258, 63, 4, 104, 1151, 30, 100, 9, 5, 1267, - 30, 2402, 2403, 38, 2405, 245, 46, 4, 38, 1177, - 1985, 1986, 9, 63, 137, 90, 172, 181, 11, 807, - 122, 1996, 15, 16, 11, 2000, 122, 30, 15, 16, - 2991, 288, 119, 82, 191, 38, 291, 172, 172, 5, - 80, 193, 1224, 11, 93, 1227, 1228, 15, 16, 3, - 296, 137, 991, 46, 129, 290, 169, 2856, 1450, 2858, - 313, 291, 63, 1065, 1003, 107, 2875, 3204, 856, 313, - 181, 276, 1533, 147, 1978, 1979, 1980, 147, 46, 1081, - 34, 35, 1202, 193, 382, 64, 368, 80, 162, 1198, - 1199, 1483, 982, 167, 117, 74, 117, 119, 315, 316, - 317, 2572, 40, 2574, 1627, 30, 3134, 117, 3136, 3395, - 164, 213, 80, 108, 40, 173, 245, 213, 30, 107, - 173, 120, 2626, 83, 2456, 369, 279, 41, 409, 296, - 13, 14, 11, 373, 2159, 120, 1017, 433, 2573, 1922, - 3363, 391, 1023, 418, 218, 11, 1295, 149, 218, 250, - 507, 209, 33, 3388, 3389, 2976, 1324, 482, 2625, 108, - 3230, 2926, 273, 520, 238, 382, 132, 225, 191, 2934, - 1953, 294, 3030, 85, 275, 122, 290, 235, 59, 504, - 46, 456, 94, 3041, 2598, 207, 290, 483, 148, 166, - 137, 472, 1353, 280, 160, 3032, 195, 192, 219, 201, - 3486, 80, 419, 355, 3332, 3440, 118, 132, 294, 360, - 195, 451, 126, 287, 80, 431, 329, 171, 272, 173, - 241, 2622, 296, 2624, 522, 132, 296, 3255, 2732, 2516, - 353, 273, 1539, 308, 357, 452, 518, 245, 176, 26, - 2921, 3202, 1765, 396, 373, 32, 463, 361, 358, 454, - 176, 273, 275, 275, 11, 485, 309, 361, 15, 16, - 513, 518, 241, 518, 3487, 3064, 389, 353, 518, 513, - 280, 357, 273, 280, 8, 431, 522, 11, 518, 191, - 539, 15, 16, 518, 167, 19, 20, 21, 360, 2142, - 1200, 507, 204, 457, 2765, 1200, 2781, 419, 3426, 454, - 459, 518, 1174, 389, 520, 2724, 364, 431, 457, 275, - 360, 1162, 1100, 2004, 280, 518, 593, 428, 476, 285, - 2707, 1441, 451, 416, 3461, 383, 1759, 1337, 1498, 1499, - 2704, 2136, 1342, 1820, 469, 448, 416, 460, 1348, 3148, - 516, 2742, 395, 2551, 520, 556, 1455, 324, 2724, 424, - 137, 593, 454, 1523, 1882, 522, 1355, 3427, 454, 360, - 3219, 518, 2412, 1472, 399, 2174, 480, 406, 407, 399, - 290, 522, 467, 447, 460, 2207, 480, 447, 285, 1856, - 2208, 328, 431, 3204, 518, 373, 132, 75, 389, 518, - 108, 1914, 148, 509, 510, 2200, 399, 2350, 517, 2345, - 482, 521, 522, 1926, 1672, 519, 518, 521, 3204, 521, - 518, 1897, 518, 1583, 1584, 519, 521, 521, 526, 2340, - 526, 2194, 504, 518, 518, 2892, 3153, 518, 516, 518, - 518, 3158, 520, 1956, 482, 518, 518, 518, 2142, 518, - 1963, 518, 518, 451, 200, 1565, 1566, 518, 227, 3339, - 522, 2899, 518, 754, 518, 1575, 504, 518, 518, 1616, - 1617, 1618, 518, 518, 1354, 3106, 518, 518, 480, 1589, - 518, 1355, 438, 3331, 514, 1344, 514, 754, 2001, 3338, - 3018, 3162, 2005, 449, 30, 227, 419, 805, 509, 510, - 3438, 162, 504, 405, 273, 2470, 408, 509, 510, 1619, - 3181, 753, 164, 1505, 805, 753, 162, 294, 3527, 1448, - 518, 2034, 509, 510, 468, 457, 754, 794, 511, 512, - 513, 514, 2009, 1525, 511, 512, 513, 514, 805, 275, - 457, 273, 26, 519, 2873, 245, 522, 748, 266, 285, - 794, 509, 510, 511, 512, 513, 514, 854, 2756, 3568, - 359, 805, 854, 2457, 2458, 2459, 2460, 1559, 292, 259, - 260, 518, 341, 840, 841, 1566, 353, 238, 887, 231, - 357, 859, 794, 1965, 1575, 3523, 518, 3012, 3436, 507, - 389, 480, 238, 805, 0, 3422, 132, 864, 178, 877, - 518, 518, 2879, 321, 468, 805, 1864, 521, 275, 82, - 794, 59, 389, 280, 106, 504, 874, 1789, 874, 874, - 93, 805, 2004, 392, 874, 874, 874, 1799, 3019, 1784, - 1802, 2474, 874, 874, 862, 874, 874, 2835, 522, 1639, - 482, 287, 2160, 874, 911, 912, 132, 865, 915, 916, - 3461, 1429, 3479, 137, 519, 174, 2671, 522, 2673, 184, - 392, 241, 504, 214, 865, 2790, 842, 843, 2793, 845, - 2795, 847, 339, 373, 160, 3461, 518, 245, 1817, 1818, - 1819, 5, 203, 460, 3333, 454, 1973, 275, 378, 379, - 1880, 1842, 82, 341, 1884, 53, 874, 1887, 3226, 3547, - 874, 968, 874, 2085, 874, 245, 1014, 3164, 1757, 874, - 874, 874, 979, 1021, 874, 874, 874, 518, 108, 986, - 987, 2516, 454, 874, 172, 992, 1898, 246, 995, 996, - 874, 998, 999, 1000, 1001, 1784, 1898, 1889, 934, 2538, - 982, 874, 874, 874, 982, 874, 874, 1014, 874, 245, - 82, 451, 874, 874, 1021, 1804, 874, 174, 74, 251, - 1809, 93, 509, 510, 511, 512, 513, 514, 3144, 261, - 1014, 1038, 1039, 1040, 518, 2434, 3425, 1021, 2176, 3428, - 2178, 505, 506, 507, 174, 509, 510, 511, 512, 513, - 514, 4, 517, 1060, 280, 1795, 9, 517, 1012, 285, - 1800, 117, 1014, 528, 1095, 373, 4, 37, 528, 1021, - 294, 9, 1079, 203, 1014, 340, 1030, 2284, 518, 177, - 1034, 1021, 2580, 1090, 1091, 1092, 345, 1094, 1095, 246, - 1014, 1098, 2847, 373, 2311, 519, 194, 1021, 522, 2352, - 513, 199, 482, 423, 369, 425, 108, 520, 2230, 3306, - 513, 1961, 373, 189, 190, 178, 246, 520, 13, 14, - 3058, 2656, 1129, 384, 504, 384, 1098, 315, 316, 317, - 355, 451, 3521, 357, 178, 359, 380, 373, 518, 237, - 1147, 1148, 26, 451, 1181, 1182, 2292, 1184, 32, 1181, - 1182, 519, 1184, 3291, 522, 3293, 1174, 1905, 419, 147, - 419, 1909, 4, 519, 1912, 389, 522, 9, 162, 1898, - 162, 451, 4, 167, 162, 167, 1183, 9, 241, 167, - 1187, 1188, 516, 259, 260, 2166, 520, 516, 345, 518, - 1197, 1198, 1199, 8, 382, 1202, 2046, 241, 2781, 380, - 15, 16, 203, 173, 19, 20, 21, 71, 72, 470, - 518, 470, 438, 516, 2359, 451, 1223, 520, 516, 275, - 2365, 1239, 520, 449, 280, 519, 1167, 384, 522, 3367, - 218, 419, 1440, 8, 1442, 1443, 11, 2490, 518, 209, - 15, 16, 519, 373, 238, 522, 238, 827, 828, 829, - 238, 1258, 832, 137, 384, 225, 252, 6, 345, 1022, - 1267, 10, 419, 1026, 452, 235, 480, 436, 482, 18, - 314, 46, 2122, 329, 26, 463, 842, 843, 53, 845, - 32, 847, 518, 32, 1291, 13, 14, 36, 25, 419, - 470, 347, 2171, 287, 419, 287, 394, 384, 519, 287, - 377, 522, 378, 379, 167, 80, 1313, 516, 296, 518, - 373, 520, 442, 470, 1312, 519, 1312, 1312, 522, 2266, - 519, 2268, 1329, 522, 1312, 519, 13, 14, 522, 373, - 518, 1338, 419, 2263, 519, 2265, 380, 522, 2759, 380, - 470, 26, 3539, 519, 2879, 518, 522, 32, 1355, 519, - 2472, 518, 522, 519, 2476, 519, 522, 1329, 522, 518, - 423, 519, 425, 519, 522, 1372, 522, 2622, 518, 2624, - 1377, 132, 1354, 423, 519, 425, 1354, 522, 115, 423, - 3524, 425, 3526, 470, 518, 137, 519, 1355, 451, 522, - 519, 518, 448, 522, 364, 519, 2235, 518, 522, 160, - 1372, 457, 177, 2656, 1345, 519, 1347, 451, 522, 423, - 294, 425, 1460, 383, 1462, 519, 172, 1465, 522, 194, - 1427, 1428, 1470, 3567, 199, 1473, 1433, 1475, 1435, 3491, - 518, 1479, 2639, 1440, 1441, 1442, 1443, 518, 2638, 519, - 2338, 423, 522, 425, 3506, 423, 511, 425, 1455, 1456, - 518, 1435, 137, 1460, 2670, 1462, 13, 14, 1465, 447, - 2623, 519, 237, 1470, 522, 1472, 1473, 519, 1475, 353, - 522, 519, 1479, 357, 522, 518, 1460, 292, 1462, 13, - 14, 1465, 40, 1435, 2521, 2522, 1470, 2687, 518, 1473, - 519, 1475, 2637, 522, 2639, 1479, 504, 519, 519, 3561, - 522, 522, 60, 519, 3566, 389, 522, 224, 1460, 519, - 1462, 1435, 522, 1465, 275, 13, 14, 292, 1470, 280, - 1460, 1473, 1462, 1475, 285, 1465, 1533, 1479, 516, 3284, - 1470, 3286, 520, 1473, 501, 1475, 1460, 2387, 1462, 1479, - 519, 1465, 294, 522, 2525, 520, 1470, 519, 106, 1473, - 522, 1475, 13, 14, 519, 1479, 345, 522, 1565, 1566, - 2498, 2499, 2500, 2498, 2499, 2498, 2497, 1574, 1575, 879, - 290, 881, 1562, 1562, 501, 1582, 460, 13, 14, 520, - 1562, 1562, 1589, 1562, 1562, 13, 14, 13, 14, 13, - 14, 1562, 13, 14, 171, 384, 13, 14, 522, 13, - 14, 353, 13, 14, 518, 357, 13, 14, 1615, 294, - 519, 26, 1619, 13, 14, 1622, 519, 32, 519, 394, - 1627, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1635, 1636, - 419, 13, 14, 1640, 1641, 1642, 172, 389, 1645, 295, - 2380, 59, 1649, 518, 202, 1652, 1653, 1654, 1655, 1656, - 1657, 1658, 1659, 1660, 13, 14, 1663, 420, 1642, 2388, - 13, 14, 501, 1670, 1636, 1672, 13, 14, 979, 3204, - 13, 14, 357, 3294, 1711, 13, 14, 438, 224, 1711, - 152, 470, 13, 14, 1691, 13, 14, 353, 449, 2942, - 505, 506, 507, 251, 509, 510, 511, 512, 513, 514, - 368, 369, 2589, 261, 389, 368, 369, 1714, 460, 368, - 369, 368, 369, 263, 264, 273, 40, 8, 1725, 1726, - 11, 1689, 137, 152, 15, 16, 419, 502, 378, 379, - 2893, 462, 463, 2940, 509, 510, 511, 512, 513, 514, - 2370, 2371, 3501, 3502, 3533, 3534, 152, 305, 1147, 1148, - 2242, 2243, 519, 152, 152, 46, 518, 275, 1765, 40, - 470, 152, 53, 89, 152, 484, 520, 1774, 152, 1776, - 290, 152, 355, 2612, 518, 460, 431, 518, 518, 421, - 519, 220, 518, 225, 300, 2976, 518, 225, 225, 80, - 297, 518, 40, 236, 518, 5, 5, 518, 2677, 325, - 3016, 359, 1774, 1114, 1776, 2735, 518, 518, 2699, 1816, - 518, 5, 5, 1820, 518, 5, 1823, 1824, 3489, 1760, - 518, 5, 3493, 2721, 147, 302, 384, 9, 518, 1770, - 518, 1772, 481, 1144, 1775, 104, 178, 519, 522, 162, - 1781, 522, 1783, 40, 167, 403, 220, 3246, 3101, 389, - 2848, 167, 287, 167, 145, 1796, 5, 1864, 285, 59, - 1801, 203, 431, 236, 1805, 1806, 1807, 1808, 93, 1810, - 1811, 1860, 518, 518, 522, 1882, 431, 3548, 59, 294, - 59, 266, 1889, 1890, 431, 108, 177, 431, 528, 222, - 431, 1898, 431, 480, 380, 218, 152, 100, 275, 241, - 199, 518, 40, 194, 275, 275, 275, 1914, 199, 275, - 518, 1918, 1919, 1224, 1921, 238, 1227, 1228, 152, 1926, - 1927, 1928, 1929, 1930, 1931, 1932, 3461, 172, 1935, 1936, - 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 353, 1987, - 520, 996, 357, 1950, 1951, 1993, 237, 1954, 13, 1956, - 522, 3204, 8, 295, 1961, 11, 1963, 519, 519, 15, - 16, 519, 518, 151, 287, 172, 519, 519, 519, 477, - 519, 519, 225, 296, 389, 225, 1983, 126, 127, 282, - 1987, 282, 1989, 518, 172, 518, 1993, 467, 520, 117, - 46, 522, 520, 518, 2001, 518, 3395, 53, 2005, 518, - 2007, 292, 2009, 1987, 2011, 518, 518, 39, 518, 1993, - 476, 9, 11, 2943, 2944, 3215, 429, 429, 518, 2931, - 355, 517, 528, 172, 80, 522, 527, 2034, 522, 280, - 518, 373, 178, 429, 431, 1987, 181, 163, 3437, 2046, - 2047, 1993, 172, 522, 172, 460, 2786, 1987, 996, 1360, - 1361, 788, 519, 1993, 1040, 457, 218, 203, 522, 227, - 266, 291, 392, 1987, 313, 522, 313, 522, 181, 1993, - 220, 519, 518, 227, 275, 227, 296, 2084, 470, 334, - 2087, 423, 819, 425, 288, 2092, 2093, 3486, 518, 145, - 152, 2122, 3073, 3, 152, 241, 518, 152, 518, 152, - 442, 480, 152, 394, 40, 275, 448, 844, 3, 451, - 2117, 2118, 3328, 522, 522, 2122, 290, 290, 40, 59, - 172, 177, 11, 40, 447, 167, 519, 315, 316, 317, - 519, 2138, 519, 1188, 2141, 2142, 2143, 181, 194, 519, - 518, 167, 1197, 199, 3, 39, 518, 3, 3270, 295, - 518, 516, 2159, 2160, 516, 892, 431, 431, 2142, 2166, - 431, 431, 2169, 519, 519, 517, 315, 316, 317, 519, - 527, 522, 2912, 148, 520, 519, 304, 172, 519, 2186, - 501, 237, 501, 519, 501, 2169, 518, 315, 316, 317, - 519, 1040, 2199, 516, 382, 431, 519, 520, 155, 519, - 477, 519, 2186, 518, 250, 518, 518, 518, 3461, 2216, - 2217, 502, 40, 59, 522, 507, 1040, 2169, 509, 510, - 511, 512, 513, 514, 503, 291, 2233, 291, 2235, 2169, - 454, 419, 522, 382, 2186, 244, 292, 1223, 59, 59, - 2181, 2248, 979, 266, 393, 2169, 2186, 275, 469, 152, - 518, 431, 989, 203, 382, 152, 152, 3464, 282, 2266, - 2267, 2268, 2186, 282, 452, 431, 415, 431, 74, 1580, - 419, 431, 431, 519, 80, 463, 518, 423, 518, 425, - 40, 1592, 355, 1594, 3182, 522, 519, 93, 288, 290, - 40, 419, 480, 480, 2266, 2267, 2268, 152, 2305, 526, - 280, 519, 448, 452, 2311, 451, 172, 518, 59, 186, - 1621, 117, 2343, 119, 463, 167, 504, 519, 80, 518, - 1144, 519, 172, 519, 452, 3054, 143, 1313, 519, 199, - 518, 480, 518, 516, 2332, 463, 2332, 2332, 394, 528, - 2347, 519, 519, 518, 2332, 2352, 522, 519, 519, 301, - 361, 518, 480, 522, 519, 504, 291, 181, 519, 152, - 176, 442, 519, 518, 522, 2372, 519, 1104, 519, 518, - 40, 519, 1427, 1428, 1223, 2347, 504, 1114, 1433, 520, - 2387, 2388, 518, 518, 86, 519, 518, 40, 40, 2396, - 518, 522, 172, 522, 457, 518, 479, 519, 1135, 1223, - 519, 207, 199, 519, 522, 517, 3256, 1144, 3258, 3296, - 40, 517, 519, 507, 1725, 1726, 519, 519, 519, 290, - 463, 2362, 59, 519, 2396, 117, 519, 2434, 519, 3268, - 60, 519, 480, 205, 40, 227, 518, 88, 192, 280, - 280, 520, 520, 520, 520, 520, 502, 431, 520, 520, - 2434, 520, 520, 509, 510, 511, 512, 513, 514, 520, - 520, 520, 431, 520, 1313, 40, 520, 2474, 517, 275, - 3271, 3452, 3273, 520, 280, 520, 106, 517, 1789, 1427, - 1428, 520, 2434, 2490, 2502, 1433, 520, 520, 1799, 1313, - 520, 1802, 275, 520, 2525, 520, 107, 507, 520, 3397, - 2507, 480, 520, 520, 520, 520, 2513, 2514, 3387, 290, - 2434, 3406, 520, 520, 520, 520, 519, 2566, 2525, 419, - 9, 354, 519, 329, 336, 519, 518, 518, 518, 518, - 2561, 518, 2539, 59, 522, 2542, 522, 2544, 519, 199, - 517, 347, 3381, 519, 2551, 2552, 176, 1533, 2555, 2556, - 192, 522, 91, 2560, 2561, 8, 462, 519, 11, 347, - 2567, 178, 15, 16, 518, 40, 19, 20, 21, 152, - 124, 520, 202, 519, 152, 2582, 40, 519, 369, 369, - 40, 2612, 519, 36, 518, 2592, 203, 1898, 7, 8, - 2580, 2580, 518, 40, 13, 522, 457, 2586, 2580, 2580, - 19, 2580, 2580, 518, 23, 2612, 25, 310, 280, 2580, - 29, 30, 31, 518, 249, 34, 442, 191, 37, 38, - 457, 251, 41, 74, 241, 44, 45, 518, 293, 74, - 80, 261, 9, 151, 1371, 519, 519, 518, 371, 519, - 133, 1627, 448, 273, 517, 517, 2653, 59, 273, 2656, - 2657, 457, 2659, 93, 172, 442, 75, 76, 507, 1714, - 40, 290, 293, 462, 2671, 518, 2673, 293, 519, 205, - 518, 290, 519, 389, 2615, 305, 519, 2618, 295, 122, - 290, 2653, 101, 519, 1533, 2657, 454, 2659, 368, 108, - 109, 110, 111, 112, 3434, 25, 148, 314, 36, 2730, - 2698, 368, 2698, 2698, 2645, 2694, 298, 2018, 2640, 1533, - 2698, 874, 1782, 2261, 2653, 3298, 2590, 3437, 3391, 2660, - 2661, 2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 359, - 3538, 2936, 2375, 3412, 2723, 1889, 851, 3516, 3175, 3465, - 3474, 3509, 1210, 3232, 2254, 2267, 2753, 2778, 2712, 2756, - 3463, 3472, 2632, 2251, 384, 3460, 373, 2659, 1337, 2371, - 2370, 2331, 2396, 380, 3054, 1310, 2773, 2774, 2689, 222, - 2233, 2778, 1167, 403, 2781, 1013, 2199, 1750, 1627, 1765, - 1190, 1013, 2455, 3446, 2216, 1714, 1191, 3369, 3260, 1749, - 1193, 23, 2186, 1999, 3096, 2781, 991, 315, 316, 317, - 2433, 2808, 2434, 1627, 2482, 3196, 423, 2855, 425, 805, - 3373, 794, 2014, 1898, 1898, 1898, 2823, 3372, 1040, 2094, - 2514, 2200, 2829, 2830, 2142, 442, 2048, 2834, 2835, 1456, - 2824, 448, 2839, 989, 451, 2842, 2843, 2139, 2869, 292, - 2847, 2848, 3360, 2862, 2851, 989, 989, 989, 2855, 989, - 989, 2096, 989, 2535, 2580, 2862, 989, 3358, 789, 2007, - 1826, 892, 2173, 172, 382, 989, 1355, 1689, 2304, 2591, - 1690, 2855, 1927, 1928, 1929, 1930, 1931, 1932, 101, -1, - 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, - -1, -1, -1, 1247, -1, 2206, 2207, -1, -1, 2906, - -1, 419, -1, 2855, -1, -1, -1, 2914, -1, -1, - -1, -1, -1, -1, -1, 2855, 1765, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 2933, -1, 1914, -1, - -1, 2855, -1, -1, 452, 2942, -1, -1, -1, -1, - 1926, 1765, -1, 1680, -1, 463, -1, 40, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 126, - 127, 41, 480, -1, -1, -1, -1, 60, -1, 2976, - 1956, -1, 2913, -1, -1, -1, -1, 1963, -1, 1927, - 1928, 1929, 1930, 1931, 1932, -1, 504, 1935, 1936, 1937, - 1938, 1939, 1940, 1941, 1942, 1943, 1944, -1, -1, -1, - 518, 1223, -1, 0, -1, 172, 315, 316, 317, -1, - -1, 3018, -1, 106, 107, 2001, 1753, 1754, -1, 2005, - -1, -1, -1, 20, 117, 2011, 23, -1, 108, -1, - 110, -1, 112, -1, -1, -1, 37, -1, -1, 3046, - 37, 42, 3073, -1, 3033, -1, 3018, 3054, 2034, 46, - 3057, 3058, 505, 506, 507, -1, 509, 510, 511, 512, - 513, 514, 2117, 2118, -1, 1914, 3073, -1, -1, -1, - -1, -1, -1, 382, -1, 1812, -1, 1926, 75, 76, - 77, -1, -1, 176, -1, -1, -1, -1, 1825, 1826, - 1914, 1313, -1, -1, 3101, -1, -1, -1, -1, 3106, - 101, -1, 1926, -1, 101, -1, -1, 1956, -1, 202, - 419, 3118, 3119, -1, 1963, 3122, -1, 3124, -1, -1, - -1, 540, -1, -1, -1, -1, 545, -1, -1, 548, - -1, -1, 1956, -1, -1, -1, -1, 556, -1, 1963, - -1, -1, 3149, 452, -1, -1, -1, -1, 315, 316, - 317, -1, 2001, -1, 463, -1, 2005, -1, 251, -1, - -1, 1898, 2011, -1, -1, -1, 3173, 1904, 261, 2117, - 2118, 480, 173, -1, -1, -1, -1, 2001, 2233, -1, - 273, 2005, 275, 2494, 2495, 2034, -1, 2011, -1, -1, - -1, -1, -1, -1, -1, 504, -1, 3204, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 209, 518, - 2034, -1, 305, -1, -1, 382, -1, -1, -1, 3226, - -1, -1, -1, -1, 225, -1, 393, -1, -1, -1, - -1, 0, 3221, -1, 235, -1, -1, -1, -1, 3246, - -1, -1, -1, 3184, -1, -1, -1, -1, 415, 3256, - -1, 3258, 419, 3260, 3226, -1, -1, 3264, -1, 3266, - -1, 3268, 3246, -1, 3205, 3206, 359, -1, 269, -1, - -1, -1, 3279, -1, -1, -1, -1, 3284, 37, 3286, - -1, -1, -1, 42, -1, 452, -1, 3294, 3229, 290, - -1, 384, -1, -1, 3246, -1, 463, -1, -1, -1, - 3307, -1, -1, -1, -1, 3312, 3295, -1, 3297, -1, - 403, 1533, 405, 480, 315, 408, -1, -1, -1, -1, - -1, 322, 3246, -1, -1, -1, -1, 746, 747, 748, - -1, 100, -1, -1, -1, 3307, -1, 504, -1, -1, - -1, -1, 101, -1, -1, 2656, -1, -1, 3337, -1, - -1, 518, 3359, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 3369, 364, 3353, -1, 2352, -1, -1, 788, - 789, -1, -1, -1, 3381, 794, -1, 796, 147, -1, - -1, -1, 383, -1, -1, -1, 805, -1, 3395, -1, - 809, 810, -1, 162, -1, 814, 815, -1, 167, -1, - -1, -1, -1, 172, -1, 1627, 3413, -1, 827, 828, - 829, 3395, 181, 832, 173, -1, -1, 186, -1, -1, - -1, -1, -1, 842, 843, 518, 845, -1, 847, -1, - 3437, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 859, -1, -1, 3395, -1, 3452, 865, -1, -1, 218, - 209, 452, -1, 3437, 3461, -1, 3463, -1, 877, -1, - 540, -1, -1, -1, -1, 545, 225, -1, 548, 238, - -1, 3395, 891, 892, -1, -1, 235, -1, -1, 3486, - 2791, -1, -1, -1, -1, 3437, -1, -1, -1, 3478, - -1, 3463, -1, 3500, 3501, 3502, -1, -1, -1, -1, - 2555, 2556, 3486, 2352, 2490, -1, -1, 926, 927, 40, - 269, -1, -1, 3437, -1, 3504, 3457, -1, 287, 938, - 3527, 290, -1, 942, 943, 944, 945, 296, 2352, 60, - -1, -1, -1, -1, 3486, -1, 2273, -1, 13, 958, - -1, -1, 539, 1765, 19, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 30, 315, -1, -1, -1, - -1, 3568, 3486, 322, -1, 2551, -1, 336, -1, 44, - 45, 990, 991, -1, 993, 106, -1, 996, -1, -1, - -1, -1, -1, 1002, 1003, -1, -1, -1, 2325, 1008, - -1, -1, 361, -1, -1, 1014, -1, -1, -1, -1, - -1, -1, 1021, -1, -1, 364, 2343, 2555, 2556, -1, - -1, -1, 1031, -1, -1, -1, -1, -1, -1, -1, - 2931, -1, -1, -1, 383, 2936, -1, -1, -1, 1048, - -1, -1, -1, -1, 109, -1, -1, -1, -1, -1, - -1, 2490, -1, -1, -1, -1, -1, -1, -1, -1, - 419, 2388, -1, 55, -1, -1, -1, -1, -1, -1, - -1, 2398, -1, 2400, -1, -1, 2490, 2404, -1, 2406, - 2656, 202, 2983, 2984, -1, -1, -1, -1, 447, -1, - 1099, -1, -1, -1, -1, -1, -1, -1, 457, -1, - -1, 172, 1914, 452, -1, -1, -1, -1, 2753, -1, - 102, -1, 2551, -1, 1926, -1, -1, -1, 477, -1, - 479, 480, -1, -1, -1, -1, 796, -1, -1, -1, - 251, 123, -1, 2778, -1, -1, -1, 2551, -1, -1, - 261, 1150, -1, 1152, 1956, -1, -1, -1, -1, 141, - -1, 1963, 273, 145, -1, -1, -1, 516, 1167, 1168, - 519, 520, 521, -1, -1, 1174, 753, 754, -1, -1, - -1, -1, -1, -1, -1, -1, 168, -1, 2823, 171, - 2756, -1, -1, -1, 305, -1, -1, -1, 1197, 2001, - -1, -1, -1, 2005, -1, 187, -1, -1, -1, 2011, - 1209, 1210, -1, -1, -1, -1, -1, 794, -1, -1, - -1, -1, -1, 1222, -1, 2753, -1, 2656, 805, -1, - -1, 891, 2034, -1, 1040, -1, -1, 0, -1, -1, - 1239, -1, -1, 304, 1243, -1, -1, -1, 359, 1248, - 1040, -1, 2656, -1, 315, 316, 317, -1, -1, -1, - -1, -1, -1, 24, -1, -1, 926, -1, -1, 2835, - -1, -1, -1, 384, -1, -1, -1, 854, -1, 2914, - -1, -1, 942, 943, 944, 945, -1, 8, -1, -1, - 11, -1, 403, -1, 15, 16, -1, 874, 280, -1, - -1, 3192, 3193, -1, -1, -1, 288, 1306, -1, 1308, - -1, -1, -1, 3204, -1, -1, -1, -1, 1317, -1, - 81, 382, -1, -1, -1, 46, -1, 2756, 310, 1328, - -1, -1, 53, 993, -1, -1, 97, 100, 1337, 2656, - -1, -1, -1, 1342, -1, 1344, 1345, -1, 1347, 1348, - -1, -1, 2756, -1, -1, -1, -1, 339, 419, 80, - -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, - -1, -1, 2689, 15, 16, -1, 2942, 19, 20, 21, - -1, -1, -1, -1, 147, 146, 2914, -1, -1, -1, - -1, 452, -1, -1, -1, 156, -1, -1, -1, 162, - -1, -1, 463, -1, 167, 982, 2835, -1, 169, 172, - 2976, -1, -1, 174, -1, -1, -1, 1223, 181, 480, - -1, -1, 3057, 186, 145, -1, -1, -1, 1427, 1428, - -1, 2835, -1, 1223, 1433, -1, 1435, 1014, -1, -1, - -1, -1, 203, 504, 1021, -1, -1, -1, -1, 1448, - -1, 1450, 1451, -1, -1, 218, 177, 518, -1, 1458, - -1, 1460, -1, 1462, -1, -1, 1465, -1, -1, -1, - -1, 1470, -1, 194, 1473, 238, 1475, -1, 199, 1056, - 1479, -1, 1481, -1, 1483, 246, -1, -1, -1, 250, - -1, 1068, 3058, -1, -1, -1, -1, -1, -1, -1, - -1, 556, -1, -1, -1, -1, -1, 1313, -1, -1, - -1, -1, -1, 2942, -1, -1, 237, -1, 1095, -1, - -1, -1, -1, 1313, 287, -1, -1, 290, -1, 3057, - -1, -1, -1, 296, -1, 3101, -1, -1, 2942, -1, - -1, -1, 2859, -1, -1, -1, -1, 2976, -1, 1209, - 2352, -1, -1, 314, -1, -1, -1, 199, -1, 320, - -1, -1, 1222, -1, -1, -1, -1, -1, -1, -1, - 3461, 292, 2976, 336, 335, -1, -1, -1, -1, -1, - 222, -1, -1, 1243, -1, -1, -1, -1, -1, 1588, - -1, -1, -1, -1, -1, -1, -1, -1, 361, -1, - -1, 1600, -1, -1, 1181, 1182, -1, 1184, -1, 370, - -1, 1040, 373, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 384, -1, -1, 387, -1, -1, 3058, - -1, 3266, -1, -1, -1, -1, -1, -1, 3204, -1, - 1639, -1, -1, 1642, 405, -1, -1, -1, 1308, -1, - 292, -1, -1, -1, 3058, -1, 419, 1317, 419, -1, - -1, -1, -1, -1, 425, 426, -1, -1, -1, -1, - -1, -1, 3101, 394, -1, 436, -1, -1, -1, -1, - -1, 442, -1, -1, 447, -1, -1, 1686, 2490, 1688, - -1, 1690, 747, 748, 457, -1, -1, 3101, -1, -1, - -1, 1700, -1, 1702, -1, -1, -1, -1, -1, 470, - 3027, -1, -1, -1, 477, 1714, 479, 480, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 1533, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3054, -1, -1, - 1739, -1, 1741, 1533, -1, -1, -1, -1, -1, 2551, - -1, -1, -1, 516, 1753, 1754, 519, 520, 521, -1, - 1759, 1760, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 1770, 1771, 1772, 1773, 3204, 1775, 1354, -1, -1, - -1, 502, 1781, -1, 1783, -1, -1, -1, 509, 510, - 511, 512, 513, 514, 1223, -1, 1795, 1796, 1458, -1, - 3204, 1800, 1801, -1, -1, -1, 1805, 1806, 1807, 1808, - 865, 1810, 1811, -1, -1, -1, -1, -1, 3135, -1, - -1, 1627, -1, -1, -1, -1, -1, -1, 1827, -1, - -1, -1, -1, -1, -1, -1, 1835, 1627, 1837, 1838, - 1839, 1840, 1841, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 2656, -1, -1, -1, -1, 1858, - -1, -1, -1, 505, 506, 507, -1, 509, 510, 511, - 512, 513, 514, -1, -1, -1, -1, -1, 1877, -1, - -1, -1, -1, 1460, 1313, 1462, -1, 3204, 1465, -1, - -1, -1, -1, 1470, -1, 3461, 1473, -1, 1475, -1, - -1, -1, 1479, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 1927, 1928, - 1929, 1930, 1931, 1932, -1, -1, 1935, 1936, 1937, 1938, - 1939, 1940, 1941, 1942, 1943, 1944, -1, -1, -1, -1, - -1, -1, -1, 1008, 2756, -1, -1, -1, -1, 1765, - -1, -1, -1, -1, -1, -1, 1965, -1, -1, -1, - -1, -1, -1, -1, -1, 1765, 1031, -1, 1977, -1, - -1, -1, -1, -1, -1, 1562, -1, -1, 1987, -1, - -1, -1, -1, -1, 1993, -1, -1, -1, -1, -1, - 1999, -1, -1, -1, -1, 2004, -1, -1, -1, -1, - -1, -1, 3329, 100, 2013, 2014, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 1688, -1, - 1690, -1, 3461, 2835, -1, -1, -1, -1, 8, -1, - 1700, 11, -1, -1, 1099, 15, 16, 17, 18, 19, - 20, 21, -1, -1, -1, -1, -1, 3461, -1, -1, - 147, -1, -1, -1, -1, 1642, 36, -1, -1, -1, - -1, -1, -1, -1, -1, 162, 46, -1, -1, 1739, - 167, -1, -1, 53, -1, 172, 2085, -1, -1, -1, - 2089, -1, -1, -1, 181, 2094, -1, -1, -1, 186, - -1, -1, -1, -1, 1533, -1, -1, -1, 1914, -1, - 80, -1, 1167, 1168, -1, -1, -1, -1, 2117, 2118, - 1926, -1, -1, -1, 1914, -1, -1, -1, -1, -1, - -1, 218, -1, -1, 1711, -1, 1926, 2136, 8, -1, - 2942, 11, -1, 2142, 3461, 15, 16, -1, -1, -1, - 1956, 238, 8, -1, -1, 11, -1, 1963, -1, 15, - 16, -1, -1, 19, 20, 21, 1956, -1, -1, -1, - 2169, -1, -1, 1963, 2976, -1, 46, 1837, 1838, 1839, - 1840, 1841, 2181, 53, -1, -1, -1, 2186, -1, -1, - -1, 2190, -1, -1, -1, 2001, -1, -1, 1627, 2005, - 287, -1, -1, 290, -1, 2011, -1, 177, -1, 296, - 80, 2001, -1, -1, -1, 2005, -1, -1, -1, -1, - -1, 2011, -1, -1, 194, -1, -1, -1, 2034, 199, - -1, 2230, -1, -1, 2233, -1, -1, 2236, -1, -1, - -1, -1, -1, -1, 2034, -1, -1, -1, -1, 336, - -1, -1, 222, 223, -1, -1, 3058, 2256, -1, -1, + 7, 521, 0, 0, 0, 0, 46, 0, 903, 16, + 0, 0, 0, 841, 73, 888, 23, 0, 0, 815, + 930, 38, 746, 7, 16, 999, 914, 0, 1256, 980, + 935, 1175, 1442, 1045, 1458, 754, 1682, 20, 20, 23, + 1230, 20, 965, 865, 77, 1244, 1217, 1242, 1222, 990, + 1611, 23, 1719, 990, 2217, 7, 77, 2186, 2207, 2188, + 1654, 1320, 1219, 1298, 37, 990, 1827, 1494, 75, 76, + 1210, 23, 969, 990, 1093, 0, 1599, 1573, 2276, 980, + 1635, 1636, 2363, 2714, 0, 0, 2675, 17, 2025, 0, + 1247, 75, 76, 1140, 111, 0, 2675, 1345, 1145, 0, + 45, 2712, 0, 75, 76, 2272, 903, 0, 905, 0, + 907, 2206, 0, 0, 2152, 2737, 0, 2730, 753, 747, + 1008, 754, 0, 75, 76, 2026, 34, 1101, 101, 2343, + 2542, 0, 2324, 2325, 2326, 0, 2629, 0, 0, 0, + 2633, 0, 0, 75, 76, 810, 0, 1067, 1068, 1686, + 0, 816, 5, 1845, 5, 1654, 0, 5, 13, 14, + 0, 40, 13, 14, 1084, 1737, 988, 0, 1849, 1846, + 5, 0, 1739, 1963, 5, 1999, 2000, 4, 13, 14, + 63, 997, 9, 10, 2844, 2355, 2010, 5, 5, 5, + 2014, 9, 5, 5, 5, 991, 9, 2364, 5, 5, + 1151, 13, 14, 63, 5, 3059, 13, 14, 5, 5, + 3045, 5, 13, 14, 5, 13, 14, 5, 5, 5, + 9, 778, 2355, 2351, 45, 82, 2349, 3062, 74, 37, + 4, 173, 139, 23, 42, 9, 93, 3, 4, 5, + 122, 55, 11, 9, 172, 45, 122, 16, 9, 124, + 100, 2418, 2419, 1265, 2421, 11, 191, 883, 63, 82, + 16, 980, 1274, 4, 860, 107, 172, 100, 9, 1157, + 93, 30, 119, 883, 1184, 90, 5, 46, 1100, 38, + 1231, 30, 104, 1234, 1235, 75, 76, 807, 3, 38, + 122, 11, 30, 101, 2945, 15, 16, 80, 178, 172, + 38, 1071, 1991, 1992, 1993, 2488, 63, 245, 2899, 3235, + 288, 80, 3015, 1457, 129, 291, 290, 1087, 122, 34, + 35, 296, 291, 169, 173, 64, 46, 992, 296, 3367, + 227, 213, 276, 137, 854, 74, 2591, 213, 2593, 1004, + 107, 2470, 245, 119, 106, 181, 382, 107, 983, 805, + 1494, 117, 117, 391, 1544, 53, 193, 30, 172, 181, + 80, 241, 117, 193, 166, 173, 368, 30, 1046, 11, + 3, 3430, 5, 15, 16, 120, 273, 1205, 1206, 132, + 1639, 13, 14, 40, 132, 2645, 41, 1209, 11, 164, + 40, 162, 15, 16, 108, 418, 2880, 120, 2882, 433, + 2592, 209, 3473, 409, 46, 250, 1933, 82, 480, 507, + 147, 3000, 359, 148, 2175, 1577, 11, 225, 93, 290, + 518, 1331, 3460, 3054, 1586, 3463, 3261, 235, 313, 1302, + 275, 164, 504, 456, 3065, 373, 191, 1964, 80, 3164, + 290, 3166, 389, 11, 341, 3056, 2644, 15, 16, 483, + 195, 273, 245, 219, 2617, 1360, 171, 290, 173, 132, + 309, 269, 3521, 189, 190, 200, 472, 238, 273, 132, + 373, 126, 195, 1151, 2641, 241, 2643, 360, 192, 177, + 518, 218, 26, 329, 369, 80, 522, 3558, 32, 251, + 794, 2751, 2530, 308, 26, 392, 194, 272, 231, 261, + 360, 199, 241, 431, 280, 108, 273, 315, 812, 485, + 454, 361, 3366, 451, 322, 280, 518, 1776, 3556, 176, + 275, 358, 324, 3397, 328, 355, 176, 275, 361, 2784, + 3233, 1550, 285, 259, 260, 167, 13, 285, 2099, 237, + 518, 3192, 19, 423, 518, 425, 395, 522, 451, 518, + 75, 280, 1230, 30, 522, 360, 364, 454, 431, 296, + 3211, 3286, 1018, 469, 2158, 108, 539, 44, 45, 476, + 3496, 451, 454, 2743, 431, 383, 518, 419, 454, 507, + 518, 1207, 457, 518, 389, 1181, 593, 3178, 1108, 1509, + 1510, 2018, 520, 137, 2761, 416, 1831, 1207, 2726, 1770, + 2723, 593, 448, 360, 3088, 137, 428, 3461, 431, 424, + 2743, 1168, 459, 373, 1534, 518, 416, 2800, 1434, 1435, + 1344, 457, 454, 184, 1440, 1349, 1448, 3462, 513, 2152, + 480, 1355, 109, 2570, 1462, 2190, 467, 3250, 2428, 522, + 399, 520, 1320, 1362, 452, 1893, 3235, 480, 3522, 3309, + 399, 2223, 378, 379, 518, 1483, 3235, 2224, 451, 2158, + 2484, 399, 522, 518, 2356, 518, 1925, 518, 1867, 519, + 518, 521, 1684, 2210, 1594, 1595, 527, 521, 1937, 527, + 1908, 521, 522, 518, 2361, 2366, 519, 518, 521, 518, + 3183, 482, 521, 2216, 482, 3188, 394, 524, 525, 516, + 518, 518, 518, 520, 518, 518, 518, 518, 1967, 2923, + 447, 518, 518, 504, 754, 1974, 504, 518, 2916, 3131, + 518, 518, 518, 1351, 518, 518, 1361, 518, 517, 1362, + 518, 518, 518, 516, 3365, 509, 510, 520, 279, 480, + 1628, 1629, 1630, 509, 510, 514, 1516, 754, 509, 510, + 294, 3373, 0, 468, 1576, 1577, 2015, 457, 514, 3372, + 2019, 3042, 294, 504, 1586, 805, 1536, 149, 509, 510, + 753, 753, 83, 406, 407, 754, 119, 33, 1600, 340, + 71, 72, 2471, 2472, 2473, 2474, 507, 794, 2023, 2048, + 1455, 511, 512, 513, 514, 812, 266, 5, 805, 520, + 1570, 227, 2897, 59, 8, 812, 419, 11, 369, 1631, + 794, 15, 16, 357, 457, 19, 20, 21, 518, 201, + 82, 805, 162, 513, 857, 357, 482, 359, 812, 888, + 520, 93, 1976, 805, 841, 842, 857, 148, 2775, 3325, + 3471, 3327, 794, 860, 3036, 389, 3457, 273, 504, 1800, + 517, 321, 521, 805, 203, 396, 523, 389, 865, 1810, + 812, 878, 1813, 1875, 207, 2903, 1544, 509, 510, 511, + 512, 513, 514, 805, 2018, 518, 3043, 875, 875, 875, + 875, 423, 875, 425, 863, 875, 875, 875, 511, 512, + 513, 514, 875, 875, 2488, 522, 2950, 997, 238, 245, + 1795, 245, 875, 3514, 2958, 912, 913, 3496, 2809, 916, + 917, 2812, 3562, 2814, 11, 3401, 460, 3496, 468, 516, + 4, 866, 2859, 520, 132, 9, 523, 1651, 2176, 2690, + 273, 2692, 275, 3423, 3424, 843, 844, 245, 846, 1986, + 848, 509, 510, 511, 512, 513, 514, 287, 1853, 46, + 875, 3582, 160, 3603, 214, 1828, 1829, 1830, 1909, 875, + 875, 1639, 969, 517, 875, 423, 392, 425, 1891, 523, + 875, 1768, 1895, 980, 875, 1898, 3257, 875, 1018, 275, + 987, 988, 875, 80, 875, 3475, 993, 875, 875, 996, + 997, 875, 999, 1000, 1001, 1002, 3194, 875, 1795, 74, + 983, 983, 2557, 1900, 794, 935, 875, 2530, 1909, 1016, + 875, 1018, 875, 875, 875, 805, 875, 875, 1815, 5, + 1027, 875, 812, 1820, 373, 3174, 245, 373, 454, 373, + 519, 341, 1016, 522, 1018, 384, 275, 1044, 1045, 1046, + 2450, 280, 117, 1027, 1016, 2469, 1018, 482, 82, 516, + 518, 513, 2192, 520, 2194, 1027, 259, 260, 520, 1066, + 1447, 1101, 1449, 1450, 1016, 373, 1018, 275, 162, 504, + 419, 4, 280, 167, 108, 1027, 9, 285, 1085, 556, + 263, 264, 1806, 518, 1016, 174, 1018, 1811, 292, 1096, + 1097, 1098, 2327, 1100, 1101, 1027, 1103, 1617, 1776, 518, + 339, 2300, 2246, 2599, 1204, 451, 8, 451, 516, 2368, + 2871, 1103, 520, 15, 16, 162, 30, 19, 20, 21, + 167, 470, 1938, 1939, 1940, 1941, 1942, 1943, 108, 1136, + 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, + 174, 4, 3340, 451, 238, 3082, 9, 1154, 1155, 355, + 1972, 2308, 2675, 345, 373, 1188, 1189, 246, 1191, 482, + 380, 174, 516, 59, 1181, 380, 520, 1188, 1189, 203, + 1191, 85, 518, 203, 518, 378, 379, 436, 1916, 345, + 94, 504, 1920, 1190, 419, 1923, 519, 1194, 1195, 522, + 1909, 238, 384, 287, 516, 518, 518, 1204, 1205, 1206, + 275, 2375, 1209, 470, 118, 280, 2800, 2381, 2182, 6, + 518, 380, 246, 10, 132, 480, 172, 482, 384, 843, + 844, 18, 846, 1230, 848, 252, 1016, 419, 1018, 1246, + 438, 519, 451, 246, 522, 32, 377, 1027, 2060, 36, + 287, 449, 160, 1023, 516, 2504, 518, 1925, 520, 1029, + 37, 1028, 518, 419, 329, 1032, 345, 132, 1265, 1937, + 518, 828, 829, 830, 167, 519, 833, 1274, 522, 511, + 519, 748, 347, 522, 518, 2836, 172, 191, 470, 519, + 178, 519, 522, 519, 522, 160, 522, 13, 14, 1967, + 204, 1298, 13, 14, 519, 384, 1974, 522, 423, 518, + 425, 505, 506, 507, 470, 509, 510, 511, 512, 513, + 514, 172, 519, 1320, 2187, 522, 2138, 2133, 2134, 519, + 518, 1319, 522, 1319, 1319, 519, 1319, 518, 522, 1336, + 419, 518, 345, 519, 1434, 1435, 522, 2015, 1345, 373, + 1440, 2019, 2486, 241, 1336, 519, 2490, 2025, 522, 519, + 384, 2778, 522, 13, 14, 1362, 2279, 275, 2281, 315, + 316, 317, 280, 519, 523, 519, 522, 285, 522, 518, + 2048, 384, 1379, 448, 13, 14, 3574, 1384, 1361, 1361, + 2903, 470, 457, 1362, 518, 419, 173, 1379, 519, 866, + 292, 522, 519, 13, 14, 522, 3559, 3526, 3561, 519, + 519, 519, 522, 522, 522, 280, 419, 423, 442, 425, + 285, 26, 3541, 13, 14, 519, 2675, 32, 522, 315, + 316, 317, 209, 2251, 1014, 37, 382, 1434, 1435, 1019, + 1020, 1021, 518, 1440, 519, 1442, 470, 522, 225, 3602, + 1447, 1448, 1449, 1450, 2354, 2282, 1036, 2284, 235, 519, + 1040, 519, 522, 518, 522, 1462, 1463, 470, 1442, 2658, + 25, 2689, 2657, 419, 1471, 519, 1473, 3596, 522, 1476, + 519, 2642, 3601, 522, 1481, 373, 1483, 1484, 519, 1486, + 518, 522, 2656, 1490, 2658, 504, 382, 1471, 224, 1473, + 1442, 405, 1476, 518, 408, 519, 452, 1481, 522, 1471, + 1484, 1473, 1486, 501, 1476, 519, 1490, 463, 522, 1481, + 519, 2706, 1484, 522, 1486, 520, 2535, 2536, 1490, 1471, + 438, 1473, 137, 419, 1476, 423, 2641, 425, 2643, 1481, + 519, 449, 1484, 522, 1486, 13, 14, 1544, 1490, 1471, + 40, 1473, 519, 519, 1476, 522, 522, 290, 519, 1481, + 115, 522, 1484, 451, 1486, 501, 452, 3318, 1490, 3320, + 60, 173, 518, 438, 880, 171, 882, 463, 2542, 1576, + 1577, 2512, 2513, 2514, 449, 2512, 1573, 364, 1585, 1586, + 1680, 2403, 522, 1573, 1573, 1573, 1593, 2512, 2513, 5, + 1573, 1573, 518, 1600, 2511, 519, 383, 209, 13, 14, + 1573, 13, 14, 505, 506, 507, 106, 509, 510, 511, + 512, 513, 514, 225, 13, 14, 172, 178, 519, 1626, + 1627, 295, 518, 235, 1631, 1725, 519, 1634, 13, 14, + 368, 369, 1639, 1640, 1641, 1642, 1643, 1644, 1645, 1646, + 1647, 1648, 203, 26, 518, 1652, 1653, 1654, 59, 32, + 1657, 420, 1442, 501, 1661, 224, 1648, 1664, 1665, 1666, + 1667, 1668, 1669, 1670, 1671, 1672, 13, 14, 1675, 152, + 1654, 353, 2396, 13, 14, 1682, 152, 1684, 152, 294, + 241, 1471, 3328, 1473, 152, 2404, 1476, 13, 14, 1722, + 2368, 1481, 13, 14, 1484, 1702, 1486, 1174, 13, 14, + 1490, 1722, 202, 13, 14, 13, 14, 2966, 13, 14, + 126, 127, 3235, 13, 14, 13, 14, 152, 1725, 419, + 2608, 1700, 13, 14, 40, 147, 13, 14, 519, 1736, + 1737, 13, 14, 518, 295, 13, 14, 275, 353, 40, + 162, 470, 357, 368, 369, 167, 2917, 368, 369, 368, + 369, 251, 364, 89, 137, 152, 172, 484, 2574, 2575, + 152, 261, 26, 462, 463, 2964, 2386, 2387, 32, 1776, + 520, 383, 152, 273, 389, 378, 379, 152, 1785, 290, + 1787, 3536, 3537, 3568, 3569, 1154, 1155, 2258, 2259, 355, + 431, 519, 421, 1785, 518, 1787, 218, 220, 518, 518, + 518, 225, 26, 2631, 300, 305, 518, 225, 32, 518, + 3000, 225, 3040, 2718, 40, 297, 238, 236, 5, 5, + 1827, 518, 518, 2696, 1831, 518, 2504, 1834, 1835, 518, + 2740, 2754, 325, 518, 5, 5, 5, 518, 1938, 1939, + 1940, 1941, 1942, 1943, 5, 460, 1946, 1947, 1948, 1949, + 1950, 1951, 1952, 1953, 1954, 1955, 518, 3524, 9, 359, + 2872, 3528, 423, 518, 425, 287, 3125, 3277, 1875, 518, + 481, 302, 522, 137, 296, 1352, 26, 1354, 522, 104, + 40, 519, 32, 220, 384, 389, 1893, 448, 167, 287, + 451, 167, 2570, 1900, 1901, 285, 59, 40, 1871, 315, + 316, 317, 1909, 403, 26, 236, 431, 431, 518, 518, + 32, 294, 93, 137, 522, 59, 3583, 60, 1925, 59, + 266, 431, 1929, 1930, 431, 1932, 108, 523, 222, 431, + 1937, 1938, 1939, 1940, 1941, 1942, 1943, 431, 480, 1946, + 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, 152, + 380, 100, 275, 199, 1961, 1962, 2772, 275, 1965, 518, + 1967, 275, 40, 106, 275, 1972, 382, 1974, 275, 518, + 353, 172, 152, 3496, 357, 520, 3235, 393, 13, 519, + 519, 172, 519, 519, 519, 477, 519, 137, 522, 1996, + 519, 518, 225, 519, 2001, 225, 2003, 2675, 282, 415, + 2007, 282, 518, 419, 2955, 518, 389, 522, 2015, 467, + 518, 520, 2019, 518, 2021, 137, 2023, 2001, 2025, 519, + 3430, 518, 520, 2007, 39, 447, 476, 518, 518, 2001, + 294, 518, 9, 2133, 2134, 2007, 452, 11, 429, 518, + 429, 2048, 355, 523, 2967, 2968, 517, 463, 429, 2001, + 522, 3246, 522, 2060, 2061, 2007, 518, 3481, 280, 202, + 431, 528, 3472, 181, 480, 147, 163, 172, 522, 2001, + 294, 519, 218, 37, 266, 2007, 522, 460, 42, 457, + 162, 2805, 227, 117, 291, 167, 392, 181, 504, 353, + 313, 2098, 313, 357, 522, 2102, 522, 2775, 2138, 220, + 2107, 2108, 518, 227, 227, 334, 519, 275, 251, 518, + 288, 3521, 296, 470, 518, 152, 3, 518, 261, 152, + 152, 152, 2938, 3097, 980, 389, 2133, 2134, 480, 353, + 273, 2138, 518, 357, 3362, 152, 218, 101, 172, 40, + 522, 275, 290, 522, 294, 3, 40, 2154, 290, 2249, + 2157, 2158, 2159, 59, 172, 11, 238, 3301, 40, 167, + 519, 519, 305, 519, 519, 389, 167, 518, 2175, 2176, + 518, 181, 294, 518, 2158, 2182, 3, 39, 2185, 3, + 431, 2859, 516, 516, 431, 517, 431, 431, 353, 519, + 519, 519, 519, 528, 148, 2202, 460, 522, 520, 519, + 519, 2185, 501, 353, 501, 287, 501, 357, 2215, 173, + 519, 2001, 2936, 2185, 296, 519, 359, 2007, 2202, 172, + 431, 155, 250, 788, 520, 2232, 2233, 519, 518, 518, + 2202, 353, 518, 2185, 477, 357, 460, 3496, 518, 389, + 40, 384, 2249, 518, 2251, 209, 59, 507, 522, 503, + 2202, 291, 291, 522, 0, 820, 454, 2264, 178, 244, + 403, 225, 59, 59, 1120, 3081, 266, 389, 275, 469, + 304, 235, 431, 152, 203, 2282, 2283, 2284, 518, 152, + 845, 315, 316, 317, 152, 282, 282, 519, 2966, 40, + 2282, 2283, 2284, 431, 1771, 1151, 431, 355, 431, 431, + 3499, 518, 3212, 518, 1781, 269, 1783, 519, 522, 1786, + 460, 290, 288, 480, 2321, 1792, 40, 1794, 152, 2359, + 2327, 241, 3000, 527, 280, 519, 290, 172, 893, 518, + 1807, 519, 59, 518, 186, 1812, 519, 167, 460, 1816, + 1817, 1818, 1819, 519, 1821, 1822, 80, 519, 382, 143, + 2348, 315, 2348, 2348, 100, 2348, 2363, 519, 322, 3078, + 516, 2368, 519, 199, 522, 447, 519, 522, 74, 172, + 301, 2363, 519, 361, 80, 1231, 291, 518, 1234, 1235, + 152, 2388, 518, 181, 523, 419, 176, 93, 442, 519, + 2910, 522, 518, 522, 314, 2185, 2403, 2404, 40, 519, + 364, 147, 519, 518, 3082, 2412, 519, 519, 519, 518, + 520, 117, 2202, 119, 518, 980, 162, 519, 452, 383, + 2412, 167, 522, 518, 86, 990, 172, 40, 40, 463, + 457, 522, 172, 518, 516, 181, 519, 519, 520, 519, + 186, 0, 3330, 2450, 199, 519, 480, 3125, 147, 479, + 517, 517, 522, 373, 519, 519, 519, 519, 463, 290, + 380, 20, 507, 162, 23, 3287, 2450, 3289, 167, 59, + 504, 3299, 218, 519, 2574, 2575, 519, 519, 37, 205, + 117, 2488, 480, 519, 518, 40, 227, 46, 452, 518, + 88, 192, 238, 457, 280, 280, 520, 2504, 2450, 2516, + 520, 207, 2542, 423, 520, 425, 3302, 520, 3304, 520, + 431, 1367, 1368, 3487, 2521, 431, 75, 76, 77, 218, + 2527, 2528, 3432, 517, 40, 520, 2585, 520, 520, 520, + 520, 451, 507, 520, 520, 2542, 520, 520, 520, 238, + 2580, 287, 101, 275, 290, 1110, 3441, 520, 520, 3422, + 296, 2558, 520, 520, 2561, 1120, 2563, 3235, 520, 520, + 520, 520, 520, 2570, 2571, 520, 517, 2574, 2575, 275, + 520, 520, 2579, 2580, 280, 520, 520, 1142, 520, 2586, + 520, 519, 519, 519, 107, 518, 1151, 3415, 287, 480, + 336, 2631, 518, 419, 2601, 290, 518, 296, 9, 518, + 354, 518, 2599, 336, 2611, 59, 519, 519, 522, 2599, + 2599, 2599, 522, 7, 8, 361, 2599, 2599, 199, 13, + 517, 519, 40, 329, 2631, 19, 2599, 522, 192, 23, + 522, 25, 2605, 462, 91, 29, 30, 31, 519, 347, + 34, 347, 60, 37, 38, 40, 518, 41, 152, 520, + 44, 45, 519, 124, 152, 40, 519, 369, 369, 40, + 2450, 40, 519, 518, 518, 2672, 457, 518, 2675, 2676, + 310, 2678, 2772, 419, 522, 518, 280, 249, 191, 457, + 2672, 75, 76, 2690, 2676, 2692, 2678, 74, 106, 442, + 37, 293, 74, 518, 80, 42, 9, 2797, 519, 519, + 518, 447, 371, 519, 59, 40, 517, 101, 517, 2749, + 93, 457, 133, 178, 108, 109, 110, 111, 112, 2717, + 2197, 2717, 2717, 507, 2717, 60, 273, 290, 442, 40, + 518, 477, 293, 479, 480, 1591, 293, 178, 203, 518, + 2713, 462, 448, 519, 519, 3469, 519, 1603, 447, 1605, + 205, 457, 290, 290, 101, 519, 389, 2797, 176, 122, + 454, 368, 203, 25, 148, 2772, 36, 368, 2775, 2742, + 516, 106, 107, 519, 520, 521, 241, 1633, 298, 875, + 2672, 1793, 117, 2277, 202, 2792, 2793, 2659, 3332, 2609, + 2797, 3472, 3426, 2800, 3573, 1900, 2960, 2391, 8, 852, + 241, 11, 3447, 3551, 3205, 15, 16, 3500, 151, 19, + 20, 21, 3509, 1378, 3544, 1217, 3263, 516, 3496, 2270, + 2827, 520, 2283, 3498, 3507, 2651, 173, 2731, 2267, 172, + 295, 3495, 1344, 251, 181, 2678, 2387, 2386, 2938, 2347, + 2847, 176, 1317, 261, 3078, 2249, 2853, 2854, 2412, 314, + 1174, 2858, 2859, 2893, 295, 273, 2863, 2215, 1197, 2866, + 2867, 1015, 209, 1015, 2871, 2872, 1761, 202, 2875, 2708, + 2469, 2232, 2879, 24, 3394, 3481, 1725, 3403, 225, 2886, + 1736, 1737, 3291, 1760, 23, 2202, 8, 305, 235, 11, + 2800, 2013, 3120, 15, 16, 2879, 1198, 19, 20, 21, + 992, 2378, 2450, 2449, 2496, 3226, 2966, 2879, 373, 990, + 1909, 2028, 1200, 990, 990, 380, 251, 990, 990, 990, + 3407, 990, 269, 2930, 1909, 1909, 261, 2879, 3406, 990, + 81, 2938, 373, 990, 2109, 2528, 2216, 2158, 273, 2062, + 275, 359, 2155, 290, 1800, 1463, 97, 2879, 2848, 2886, + 2957, 2111, 2554, 2599, 1810, 2850, 3392, 1813, 423, 2966, + 425, 789, 1362, 2021, 1837, 893, 384, 1700, 315, 2610, + 305, 1701, 315, 316, 317, 322, -1, 442, 2320, -1, + 539, 3081, 423, 448, 425, 403, 451, 1254, -1, 199, + -1, -1, -1, 3000, -1, 146, -1, -1, -1, -1, + -1, 442, -1, -1, -1, 156, -1, 448, -1, -1, + 451, -1, 222, -1, -1, -1, -1, 364, 169, -1, + -1, -1, -1, 174, 359, -1, 151, -1, -1, -1, + -1, -1, -1, -1, -1, 3042, 383, -1, -1, 382, + -1, -1, -1, -1, -1, -1, -1, 172, -1, 384, + 3042, -1, 203, 1909, -1, -1, -1, 3097, -1, -1, + -1, -1, -1, 3070, -1, -1, -1, -1, 403, -1, + 405, 3078, -1, 408, 3081, 3082, 419, 199, 8, -1, + -1, 11, 292, -1, 3057, 15, 16, -1, -1, 2879, + 3097, -1, -1, -1, -1, 246, -1, -1, -1, 250, + 222, -1, -1, -1, -1, 452, -1, -1, -1, 452, + 457, -1, -1, -1, -1, -1, 46, -1, 3125, -1, + 463, -1, -1, 53, 3131, -1, -1, 1692, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 480, -1, 1046, + -1, 3148, 3149, -1, -1, 3152, 540, 3154, -1, -1, + 80, 545, -1, -1, 548, -1, -1, 2634, -1, -1, + 2637, 504, 556, 314, -1, 172, -1, -1, -1, 320, + 292, -1, 3179, -1, -1, 518, 2032, -1, -1, -1, + -1, -1, -1, 518, 335, -1, -1, 2664, -1, -1, + 315, 316, 317, -1, 753, 754, 3203, 3297, -1, 1764, + 1765, -1, 2679, 2680, 2681, 2682, 2683, 2684, 2685, 2686, + 2687, 2688, -1, -1, -1, 145, -1, -1, -1, 370, + -1, -1, 373, -1, -1, -1, -1, -1, 3235, -1, + -1, -1, -1, 384, -1, 794, 387, -1, -1, -1, + -1, -1, -1, -1, -1, 1046, 805, 177, -1, -1, + 3257, -1, -1, 812, 405, -1, -1, 382, 1823, -1, + -1, -1, -1, -1, 194, 3257, -1, -1, 419, 199, + 3277, 1836, 1837, -1, 425, 426, -1, -1, -1, 3252, + 3287, -1, 3289, -1, 3291, 436, -1, -1, 3295, -1, + 3297, 442, 3299, 3277, 419, 505, 506, 507, 857, 509, + 510, 511, 512, 513, 514, -1, 3313, 237, 315, 316, + 317, 3318, -1, 3320, -1, -1, 875, -1, -1, 470, + -1, 3328, -1, 1230, -1, 3277, -1, 452, -1, -1, + -1, -1, -1, 2189, 3341, -1, -1, -1, 463, 3346, + -1, -1, -1, -1, 1909, -1, -1, -1, -1, 3341, + 1915, -1, 746, 747, 748, 480, 3329, -1, 3331, -1, + -1, 8, 292, -1, 11, -1, 2222, 2223, 15, 16, + -1, -1, 19, 20, 21, 382, 1046, -1, -1, 504, + -1, -1, -1, 505, 506, 507, 3393, 509, 510, 511, + 512, 513, 514, 518, 788, 789, 3403, -1, 3371, -1, + 794, -1, 796, -1, -1, -1, -1, -1, 3415, -1, + -1, 805, 419, 1320, 3387, 809, 810, -1, 812, -1, + -1, 815, 816, 3430, 983, -1, -1, -1, -1, 1230, + -1, -1, -1, -1, 828, 829, 830, -1, -1, 833, + -1, 3448, -1, -1, -1, 452, 3430, 841, 842, 843, + 844, -1, 846, -1, 848, -1, 463, 1016, -1, 1018, + 2937, -1, -1, -1, 394, 3472, 860, -1, 1027, -1, + -1, -1, 866, 480, -1, -1, -1, -1, 3430, -1, + 3487, -1, -1, -1, 878, -1, -1, 3277, 3472, 3496, + -1, 3498, -1, -1, -1, -1, -1, 504, 892, 893, + -1, 8, -1, 1062, 11, -1, 3498, -1, 15, 16, + -1, 518, -1, -1, 3521, 1074, -1, -1, -1, 1320, + 3472, -1, -1, -1, -1, -1, -1, -1, 3535, 3536, + 3537, -1, -1, 927, 928, -1, -1, 3521, -1, 46, + 3513, -1, 1101, -1, -1, 939, 53, -1, -1, 943, + 944, 945, 946, -1, 0, 3562, -1, -1, -1, -1, + 1230, -1, -1, -1, -1, 959, 3539, -1, -1, 3521, + -1, -1, 502, 80, -1, 222, -1, -1, -1, 509, + 510, 511, 512, 513, 514, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 3603, 991, 992, -1, + 994, -1, -1, 997, 1046, -1, -1, -1, -1, 1003, + 1004, -1, -1, -1, -1, -1, 1010, -1, -1, -1, + -1, -1, 1016, -1, 1018, -1, -1, -1, -1, 1188, + 1189, -1, 1191, 1027, -1, -1, -1, 1544, 145, -1, + 3430, -1, -1, 1037, -1, 292, -1, -1, -1, -1, + 1320, -1, 2508, 2509, 100, -1, 8, -1, -1, 11, + 1054, 55, -1, 15, 16, -1, -1, 19, 20, 21, + 177, -1, -1, -1, -1, -1, -1, -1, 8, -1, + -1, 11, 3472, -1, 36, 15, 16, 194, -1, 19, + 20, 21, 199, -1, -1, -1, -1, -1, -1, -1, + -1, 147, -1, -1, -1, -1, 36, 8, 102, -1, + 11, 1105, -1, -1, 15, 16, 162, -1, -1, -1, + -1, 167, -1, -1, 2289, -1, 172, -1, -1, 123, + 237, 3521, 1639, -1, -1, 181, -1, 3214, -1, -1, + 186, -1, -1, 1544, -1, 46, -1, 141, -1, -1, + -1, 145, 53, -1, -1, -1, -1, -1, -1, 3236, + 3237, -1, -1, -1, 1158, -1, -1, -1, -1, -1, + -1, -1, 218, -1, 168, -1, 2341, 171, -1, 80, + 1174, 1175, -1, 3260, -1, 292, -1, 1181, 1230, -1, + -1, -1, 238, 187, 2359, -1, -1, -1, -1, -1, + -1, -1, 1361, -1, -1, -1, -1, -1, -1, -1, + 1204, 1205, 1206, -1, -1, -1, -1, -1, -1, 2675, + -1, -1, 1216, 1217, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1229, -1, -1, 1639, 2404, + -1, 287, 1046, -1, 290, -1, -1, -1, -1, 2414, + 296, 2416, 1246, -1, -1, 2420, 1250, 2422, 505, 506, + 507, 1255, 509, 510, 511, 512, 513, 514, -1, 1776, + 222, -1, -1, -1, 1544, -1, 177, -1, 1320, -1, + -1, -1, -1, -1, -1, -1, 280, 394, -1, -1, + 336, -1, 222, 194, 288, -1, -1, -1, 199, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 1471, -1, 1473, 361, 310, 1476, -1, 1313, + -1, 1315, 1481, -1, -1, 1484, -1, 1486, -1, -1, + 1324, 1490, -1, -1, -1, 8, 237, -1, 11, -1, + 292, 1335, 15, 16, -1, 339, 19, 20, 21, -1, + 1344, -1, -1, -1, 2810, 1349, -1, 1351, 1352, -1, + 1354, 1355, 292, 36, -1, -1, -1, -1, -1, 1639, + -1, -1, -1, 419, -1, 1776, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 292, -1, -1, -1, 502, -1, -1, -1, -1, + -1, 447, 509, 510, 511, 512, 513, 514, -1, -1, + -1, 457, -1, -1, 1573, 3492, -1, -1, 1925, -1, + -1, -1, -1, -1, -1, -1, 1230, -1, -1, -1, + 1937, 477, -1, 479, 480, -1, -1, 1046, -1, -1, + 1434, 1435, -1, -1, -1, -1, 1440, -1, 1442, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1967, 1455, -1, 1457, 1458, -1, -1, 1974, 1462, 1463, + 516, 1465, -1, 519, 520, 521, -1, 1471, -1, 1473, + -1, -1, 1476, 172, -1, -1, -1, 1481, -1, 1483, + 1484, -1, 1486, 394, -1, 1654, 1490, -1, 1492, 2955, + 1494, -1, 1544, -1, 2960, -1, 1776, -1, 2015, -1, + 2675, -1, 2019, -1, -1, -1, 1320, -1, 2025, -1, + -1, -1, -1, -1, 1925, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 1937, -1, -1, -1, + -1, 2048, -1, 2708, -1, -1, -1, -1, -1, 222, + -1, 3007, 3008, 505, 506, 507, -1, 509, 510, 511, + 512, 513, 514, 1722, -1, -1, 1967, -1, -1, -1, + -1, -1, -1, 1974, -1, 505, 506, 507, -1, 509, + 510, 511, 512, 513, 514, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 1639, -1, -1, + -1, 502, -1, -1, -1, 1599, -1, -1, 509, 510, + 511, 512, 513, 514, 2015, 304, -1, 1611, 2019, 292, + -1, 1230, -1, -1, 2025, -1, 315, 316, 317, -1, + -1, -1, -1, -1, -1, 37, -1, -1, -1, 41, + -1, -1, -1, -1, -1, -1, -1, 2048, -1, -1, + -1, -1, -1, -1, -1, 1925, -1, 1651, -1, -1, + 1654, -1, -1, -1, -1, -1, -1, 1937, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, + -1, 11, -1, -1, -1, 15, 16, -1, 1682, 19, + 20, 21, -1, 382, -1, -1, -1, 1967, -1, 101, + 1859, -1, -1, 1697, 1974, 1699, 108, 1701, 110, -1, + 112, 1320, 1871, -1, -1, -1, 46, 1711, 2883, 1713, + -1, -1, -1, 53, -1, -1, -1, -1, -1, -1, + 419, 1725, -1, -1, 1776, -1, -1, -1, -1, -1, + 1544, -1, -1, -1, -1, 2015, -1, -1, -1, 2019, + 80, -1, -1, -1, -1, 2025, 1750, -1, 1752, -1, + -1, -1, -1, 452, -1, -1, 3222, 3223, -1, -1, + 1764, 1765, -1, -1, 463, -1, 1770, 1771, 2048, 3235, + -1, -1, -1, -1, -1, -1, -1, 1781, 1782, 1783, + 1784, 480, 1786, -1, -1, -1, -1, -1, 1792, -1, + 1794, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 1806, 1807, -1, 504, -1, 1811, 1812, -1, + -1, -1, 1816, 1817, 1818, 1819, -1, 1821, 1822, 518, + -1, -1, 505, 506, 507, 1639, 509, 510, 511, 512, + 513, 514, 2001, -1, 1838, -1, -1, 177, 2007, -1, + -1, -1, 1846, -1, 1848, 1849, 1850, 1851, 1852, -1, + -1, 2368, -1, -1, 194, -1, -1, -1, -1, 199, + -1, -1, -1, -1, -1, 1869, -1, -1, -1, -1, + -1, -1, -1, 1925, -1, -1, 3051, -1, -1, -1, + -1, -1, -1, -1, 1888, 1937, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 237, -1, -1, - -1, 1848, -1, -1, 361, 145, -1, -1, -1, -1, - -1, -1, -1, 1860, -1, -1, -1, -1, -1, 1344, - 1345, -1, 1347, -1, -1, -1, -1, -1, -1, 3101, - -1, -1, -1, -1, -1, 275, -1, 177, 278, -1, - -1, -1, -1, -1, -1, -1, -1, 1977, -1, -1, - -1, -1, 292, -1, 194, 295, -1, -1, 2327, 199, - -1, -1, 419, -1, -1, 2334, 1765, -1, -1, -1, - -1, -1, -1, 199, -1, -1, 2345, -1, -1, 2348, - 2349, 2350, 2351, -1, -1, -1, -1, -1, -1, -1, - 447, -1, -1, 2362, -1, 2364, 222, 237, 2367, -1, - 457, -1, -1, -1, -1, 2374, -1, -1, -1, -1, - -1, 2380, -1, -1, -1, -1, -1, -1, -1, -1, - 477, -1, 479, 480, -1, 1450, -1, -1, -1, -1, - -1, -1, 3204, 2402, 2403, -1, 2405, -1, -1, -1, - 1987, -1, -1, -1, -1, -1, 1993, -1, -1, -1, - -1, -1, 292, -1, 394, -1, 1481, -1, 1483, 516, - -1, -1, 519, 520, 521, 2434, 292, -1, -1, -1, + -1, -1, -1, 3078, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1967, -1, -1, -1, -1, + -1, -1, 1974, -1, -1, 1544, -1, -1, -1, -1, + -1, -1, -1, -1, 1938, 1939, 1940, 1941, 1942, 1943, + -1, -1, 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, + 1954, 1955, 292, -1, -1, -1, -1, 2368, -1, -1, + -1, -1, 1776, 2015, -1, -1, -1, 2019, -1, 2138, + -1, -1, 1976, 2025, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 1990, 2504, -1, 2158, + 3165, -1, -1, -1, -1, -1, 2048, 2001, -1, 8, + -1, -1, 11, 2007, -1, 2174, 15, 16, 37, 2013, + 19, 20, 21, 42, 2018, -1, 2185, -1, -1, -1, + 1639, -1, -1, 2027, 2028, -1, -1, 36, -1, -1, + 3496, -1, 997, 2202, -1, -1, -1, -1, -1, -1, + -1, -1, 0, -1, -1, 13, -1, -1, -1, -1, + -1, 19, -1, 2570, 394, 23, -1, -1, -1, -1, + 3235, -1, 30, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 101, -1, -1, -1, 44, 45, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 2368, -1, + -1, -1, -1, 2504, -1, 2099, -1, -1, -1, -1, + 2104, -1, -1, -1, -1, 2109, -1, 75, 76, -1, + -1, 1925, -1, 8, -1, -1, 11, -1, -1, -1, + 15, 16, -1, 1937, 19, 20, 21, -1, 540, 2133, + 2134, -1, -1, 545, -1, -1, 548, -1, -1, -1, + -1, 109, 100, -1, 173, -1, -1, -1, 2152, -1, + -1, -1, -1, 1967, 2158, -1, -1, 1776, 2675, 2570, + 1974, -1, 502, -1, -1, 505, 506, 507, -1, 509, + 510, 511, 512, 513, 514, -1, -1, -1, -1, -1, + 209, 2185, -1, -1, -1, -1, -1, -1, 3363, 147, + 2359, -1, -1, 2197, -1, -1, 225, -1, 2202, -1, + -1, 2015, 2206, -1, 162, 2019, 235, -1, -1, 167, + -1, 2025, -1, 222, 172, -1, -1, -1, -1, -1, + -1, -1, -1, 181, 2504, -1, -1, -1, 186, -1, + 1195, -1, -1, -1, 2048, -1, -1, -1, -1, 1204, + 269, -1, 2246, -1, -1, 2249, -1, 2251, 2252, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 2775, -1, + 218, 290, -1, -1, 2675, -1, -1, -1, 2272, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 2454, -1, -1, -1, -1, - -1, -1, -1, 2462, 2463, 2464, -1, -1, -1, -1, - -1, -1, -1, 2472, -1, 2474, -1, 2476, -1, -1, - -1, -1, -1, 2482, -1, 1914, -1, -1, 8, -1, - -1, 11, -1, -1, -1, 15, 16, 1926, -1, 19, - 20, 21, -1, 2502, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 36, 2516, -1, -1, - -1, -1, -1, -1, 394, -1, -1, 1956, -1, -1, - -1, -1, 502, -1, 1963, 505, 506, 507, -1, 509, - 510, 511, 512, 513, 514, 2122, 2352, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 2555, 2556, 528, -1, - -1, -1, 2352, -1, -1, 2142, -1, -1, -1, -1, - -1, -1, 2001, -1, -1, -1, 2005, -1, -1, -1, - -1, 2158, 2011, -1, -1, 2584, -1, -1, -1, -1, - -1, 2590, 2169, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 2034, -1, 2606, -1, 2186, - -1, 2610, -1, -1, -1, 2614, 2615, -1, -1, 2618, - -1, -1, -1, 2622, 2623, 2624, -1, 2626, -1, -1, - -1, -1, 502, -1, -1, -1, -1, -1, -1, 509, - 510, 511, 512, 513, 514, -1, 2645, -1, 2647, 505, - 506, 507, -1, 509, 510, 511, 512, 513, 514, 3461, - -1, 2660, 2661, 2662, 2663, 2664, 2665, 2666, 2667, 2668, - 2669, -1, -1, -1, 2334, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 2490, -1, 1741, -1, -1, 2349, - 2350, 2351, -1, -1, 2693, -1, -1, -1, -1, -1, - 2490, 2700, 222, -1, 2364, 1760, -1, 2367, -1, -1, - -1, -1, -1, 2712, 2374, 1770, -1, 1772, -1, -1, - 1775, -1, -1, -1, -1, -1, 1781, -1, 1783, -1, - -1, -1, -1, 2732, -1, -1, -1, -1, -1, -1, - -1, 1796, -1, 2742, -1, 2551, 1801, -1, -1, -1, - 1805, 1806, 1807, 1808, 2753, 1810, 1811, -1, -1, -1, - 2759, 2551, -1, -1, -1, -1, 2343, 2766, 2767, 2768, - 2769, -1, 292, -1, -1, -1, -1, -1, -1, 2778, - -1, -1, 2781, -1, -1, -1, 2785, 2786, -1, -1, - -1, -1, -1, -1, -1, 2794, -1, -1, -1, -1, - -1, -1, 2462, 2463, 2464, -1, -1, -1, 98, 996, - -1, -1, -1, -1, 8, -1, -1, 11, -1, -1, - -1, 15, 16, 2822, -1, 2824, -1, 8, -1, -1, - 11, -1, -1, -1, 15, 16, 126, 127, 19, 20, - 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 2656, -1, 46, -1, 2853, -1, 2855, -1, -1, 53, - -1, -1, 37, -1, -1, 46, 2656, 42, -1, -1, - 2869, -1, 53, -1, 2873, -1, -1, -1, -1, -1, - 2879, -1, 172, -1, 8, -1, 80, 11, -1, -1, - -1, 15, 16, -1, 2893, -1, -1, -1, -1, 80, - 2899, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1965, -1, -1, 2912, 2913, 2914, -1, -1, -1, -1, - -1, 2920, 46, 2352, -1, -1, 101, -1, -1, 53, - -1, -1, -1, -1, -1, -1, -1, -1, 2937, -1, - -1, -1, -1, -1, 1999, -1, 2606, -1, 2525, 2004, - 2756, 145, -1, -1, -1, -1, 80, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 2756, -1, -1, 8, - -1, -1, 11, -1, -1, -1, 15, 16, 17, 18, - 19, 20, 21, 177, 2561, 505, 506, 507, -1, 509, - 510, 511, 512, 513, 514, -1, 177, 36, 173, -1, - 194, -1, -1, 2580, -1, 199, 181, 46, -1, 2586, - 1197, -1, -1, 194, 53, -1, 3015, -1, 199, -1, - 3019, 145, -1, -1, -1, 315, 316, 317, -1, 2835, - 2085, -1, -1, 3032, 209, 2612, -1, -1, -1, 2094, - 2700, 80, -1, 237, -1, 2835, -1, -1, -1, -1, - 225, 3050, -1, 177, -1, -1, 237, -1, 3057, -1, - 235, 2490, -1, -1, -1, -1, -1, -1, -1, -1, - 194, -1, -1, -1, 8, 199, -1, 11, -1, -1, - -1, 15, 16, -1, 3083, 19, 20, 21, -1, -1, - 3089, -1, 382, -1, 269, -1, -1, 3096, 292, -1, - -1, -1, 36, 393, -1, -1, 2766, 2767, 2768, 2769, - -1, 292, -1, 237, -1, 290, -1, 2694, -1, -1, - -1, -1, 2551, -1, -1, 415, 2181, -1, -1, 419, - -1, -1, 3131, -1, -1, -1, 2942, -1, 177, -1, - 315, -1, -1, -1, -1, -1, 2723, 322, -1, 439, - -1, -1, 2942, 2730, 3153, 194, -1, -1, -1, 3158, - 199, -1, 452, -1, -1, -1, -1, -1, 292, -1, - 2976, -1, -1, 463, -1, 2230, -1, -1, -1, -1, - -1, 2236, -1, 222, 223, 3184, 2976, -1, -1, 364, - 480, -1, -1, -1, -1, -1, -1, -1, 237, -1, - 394, 2778, -1, -1, -1, -1, 3205, 3206, 383, -1, - 840, 841, -1, 394, 504, -1, -1, -1, -1, -1, - -1, -1, -1, 3222, -1, 3224, -1, 2656, 518, -1, - 3229, -1, -1, -1, -1, -1, 275, -1, -1, 278, - 1427, 1428, -1, -1, 3243, -1, 1433, 3246, -1, -1, - -1, -1, 3058, 292, -1, -1, 295, -1, -1, -1, - 2920, -1, -1, -1, -1, -1, -1, 3266, 3058, -1, - 394, 3270, 3271, -1, 3273, -1, -1, 452, 2855, -1, - -1, 911, 457, -1, -1, 915, 916, -1, 222, -1, - -1, -1, 2869, -1, -1, 3101, -1, -1, -1, 3298, - -1, -1, -1, -1, -1, -1, 3305, 2362, 502, -1, - -1, 3101, -1, -1, -1, 509, 510, 511, 512, 513, - 514, 502, -1, -1, 505, 506, 507, 2756, 509, 510, - 511, 512, 513, 514, 8, -1, 3335, 11, 968, -1, - -1, 15, 16, -1, -1, 19, 20, 21, -1, -1, - -1, -1, -1, -1, -1, 394, 986, -1, 292, -1, - -1, -1, 992, -1, -1, 995, -1, -1, 998, 999, - 1000, 1001, -1, -1, 3373, -1, -1, -1, 502, -1, - -1, -1, -1, -1, -1, 509, 510, 511, 512, 513, - 514, -1, -1, -1, -1, -1, 3395, -1, 3204, -1, - -1, -1, -1, -1, -1, -1, 2835, -1, 1038, 1039, - -1, -1, -1, -1, 3204, -1, -1, 2472, -1, -1, - -1, 2476, -1, 3422, -1, -1, -1, 2482, -1, -1, - 1060, -1, -1, -1, -1, 3434, 3435, -1, 3437, 3438, - -1, -1, -1, -1, -1, -1, -1, 3446, -1, 1079, - -1, -1, -1, -1, -1, -1, 3033, -1, 3457, -1, - 1090, 1091, 1092, 502, 1094, 1095, 505, 506, 507, -1, + 238, -1, -1, 292, -1, -1, 315, -1, -1, -1, + 2570, -1, -1, 322, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 1925, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 2368, -1, 1937, -1, + -1, 3496, -1, -1, -1, -1, -1, 222, -1, 287, + -1, -1, 290, -1, -1, 364, -1, -1, 296, 2343, + -1, -1, 2859, -1, -1, -1, 2350, -1, 1967, -1, + -1, -1, -1, -1, 383, 1974, -1, 2361, -1, -1, + 2364, 2365, 2366, 2367, 2775, -1, -1, -1, -1, -1, + -1, -1, -1, 2542, 2378, -1, 2380, -1, 336, 2383, + -1, -1, -1, -1, 796, -1, 2390, -1, -1, -1, + -1, -1, 2396, -1, -1, 2675, 2015, 292, -1, -1, + 2019, -1, -1, 361, -1, -1, 2025, -1, -1, -1, + -1, 2580, -1, -1, 2418, 2419, -1, 2421, -1, -1, + -1, -1, -1, 452, -1, -1, -1, -1, -1, 2048, + 2599, -1, -1, -1, -1, -1, 2605, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 2450, -1, 2859, 2966, + -1, -1, 2504, -1, -1, -1, -1, -1, -1, -1, + -1, 419, 2631, -1, 2468, -1, -1, -1, -1, 1434, + 1435, -1, 2476, 2477, 2478, 1440, -1, -1, -1, -1, + 892, -1, 2486, 3000, 2488, -1, 2490, -1, -1, 447, + -1, -1, 2496, -1, -1, 2775, 505, 506, 507, 457, 509, 510, 511, 512, 513, 514, -1, -1, -1, -1, - 3479, 1668, -1, 522, -1, -1, -1, 3486, -1, -1, - -1, -1, -1, -1, -1, -1, 3073, -1, -1, 1129, + -1, -1, 2516, -1, -1, 927, -1, -1, 2570, 477, + -1, 479, 480, -1, -1, -1, 2530, -1, -1, -1, + -1, 943, 944, 945, 946, -1, -1, 2541, -1, -1, + -1, 2545, -1, -1, 2713, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 2368, 2966, -1, -1, 516, -1, + -1, 519, 520, 521, -1, 3082, -1, -1, -1, -1, + 2574, 2575, -1, 2742, -1, -1, -1, -1, -1, 2859, + 2749, -1, 994, -1, -1, -1, -1, -1, 556, 3000, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 2603, + -1, -1, -1, -1, -1, 2609, -1, -1, 3125, -1, + 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, + -1, 2625, -1, 2675, -1, 2629, -1, 2631, 2797, 2633, + 2634, -1, -1, 2637, -1, -1, -1, 2641, 2642, 2643, + -1, 2645, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 2664, -1, 2666, -1, -1, -1, -1, -1, -1, -1, + -1, 3082, -1, -1, -1, 2679, 2680, 2681, 2682, 2683, + 2684, 2685, 2686, 2687, 2688, -1, 2966, -1, -1, -1, + 2504, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 2712, -1, + 2879, -1, -1, -1, 3125, 2719, -1, -1, 3235, -1, + 3000, -1, -1, 2775, 2893, 8, -1, 2731, 11, -1, + -1, -1, 15, 16, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 2751, -1, 2368, + -1, -1, -1, -1, -1, -1, 2570, 2761, -1, -1, + 1725, -1, -1, 46, -1, -1, -1, -1, 2772, -1, + 53, -1, -1, -1, 2778, -1, -1, -1, -1, 747, + 748, 2785, 2786, 2787, 2788, -1, -1, -1, -1, -1, + -1, -1, -1, 2797, -1, -1, 2800, 80, -1, -1, + 2804, 2805, 3082, -1, 1216, -1, -1, 2859, -1, 2813, + -1, -1, -1, -1, -1, -1, -1, 1229, -1, -1, + -1, -1, -1, -1, 3235, -1, -1, -1, -1, -1, + -1, -1, 2836, -1, -1, -1, -1, 805, 1250, 2843, + 2844, -1, -1, -1, 2848, 3125, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 2675, 145, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 2877, -1, 2879, -1, -1, -1, -1, + -1, -1, 2886, -1, -1, 2504, -1, -1, 3057, 2893, + -1, -1, -1, 2897, 177, -1, -1, -1, 866, 2903, + -1, -1, -1, 1315, -1, -1, -1, -1, -1, -1, + -1, 194, 1324, 2917, 2966, -1, 199, -1, -1, 2923, + -1, -1, -1, -1, -1, -1, -1, -1, 3097, -1, + -1, -1, 2936, 2937, 2938, -1, -1, -1, -1, -1, + 2944, -1, -1, -1, -1, -1, -1, -1, 3000, -1, + -1, 2570, -1, -1, 237, 3235, -1, 2961, -1, -1, + -1, 2775, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 1938, 1939, 1940, 1941, 1942, 1943, 3496, + -1, 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, + 1955, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 292, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3082, -1, -1, -1, -1, 3039, -1, -1, -1, 3043, + -1, -1, 1010, -1, -1, 2859, -1, -1, 1016, -1, + 1018, -1, 3056, 1465, -1, -1, 2675, -1, -1, 1027, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 1037, + 3074, -1, -1, 3125, -1, -1, -1, 3081, -1, -1, + -1, -1, -1, 3252, -1, 3496, -1, -1, -1, 8, + -1, -1, 11, -1, -1, -1, 15, 16, 17, 18, + 19, 20, 21, 3107, 3273, -1, -1, -1, -1, 3113, + -1, 394, -1, -1, -1, -1, 3120, 36, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 46, -1, -1, + -1, -1, -1, 3137, 53, -1, -1, 1105, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 2966, -1, -1, -1, 2775, 3161, -1, -1, + 3329, 80, 3331, 8, -1, -1, 11, -1, 2133, 2134, + 15, 16, 17, 18, 19, 20, 21, -1, -1, 3183, + -1, -1, -1, 3235, 3188, -1, 3000, -1, -1, -1, + -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 46, 3371, -1, -1, -1, 1174, 1175, 53, -1, + 3214, 126, 127, -1, -1, -1, 3496, -1, 3387, 502, + -1, -1, -1, -1, -1, -1, 509, 510, 511, 512, + 513, 514, 3236, 3237, -1, 80, -1, -1, -1, -1, + 2859, -1, -1, -1, -1, -1, -1, -1, -1, 3253, + -1, 3255, -1, -1, -1, -1, 3260, 172, 177, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 3082, -1, + 3274, -1, -1, 3277, -1, 194, -1, -1, -1, -1, + 199, -1, -1, -1, 2249, -1, -1, 1699, -1, 1701, + -1, -1, -1, 3297, -1, 3299, -1, 3301, 3302, 1711, + 3304, -1, -1, 222, 223, 3309, -1, -1, -1, -1, + -1, 3125, -1, -1, -1, -1, -1, -1, 237, -1, + -1, -1, -1, -1, 3328, -1, -1, -1, 3332, -1, + -1, -1, 177, -1, -1, 3339, -1, -1, 1750, -1, + -1, -1, -1, -1, 3513, -1, -1, 2966, -1, 194, + -1, -1, -1, -1, 199, -1, 275, -1, -1, 278, + -1, -1, -1, -1, -1, 3369, -1, -1, -1, -1, + 3539, -1, -1, 292, -1, -1, 295, 222, 223, -1, + -1, 3000, -1, 1351, 1352, -1, 1354, -1, -1, -1, + -1, -1, 237, -1, -1, -1, -1, -1, -1, -1, + 315, 316, 317, 3407, -1, -1, -1, -1, -1, -1, + 8, 3415, -1, 11, -1, -1, -1, 15, 16, -1, + -1, 3235, -1, -1, -1, -1, 3430, -1, -1, -1, + 275, -1, -1, 278, -1, -1, 1848, 1849, 1850, 1851, + 1852, -1, -1, -1, 3496, -1, -1, 292, 46, -1, + 295, -1, -1, 3457, -1, 53, -1, -1, -1, -1, + -1, -1, -1, 3082, -1, 3469, 3470, 382, 3472, 3473, + -1, -1, -1, -1, -1, 394, -1, 3481, 393, -1, + -1, -1, 80, -1, -1, -1, -1, -1, 3492, 1457, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 415, -1, -1, 1471, 419, 1473, 3125, -1, 1476, -1, + 3514, -1, -1, 1481, -1, -1, 1484, 3521, 1486, -1, + -1, -1, 1490, -1, 1492, -1, 1494, -1, -1, -1, + 68, 69, -1, -1, -1, -1, -1, 452, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 145, 463, 394, + -1, -1, -1, -1, 3558, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 480, -1, -1, -1, 3573, + -1, 109, 110, -1, -1, 113, 114, 8, 1990, 177, + 11, -1, -1, 502, 15, 16, 505, 506, 507, 504, + 509, 510, 511, 512, 513, 514, 194, -1, -1, -1, + -1, 199, -1, 518, 523, -1, -1, -1, -1, 2574, + 2575, -1, -1, -1, -1, 46, 3235, -1, -1, -1, + -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 841, 842, -1, -1, -1, 237, + -1, -1, -1, 1611, -1, -1, -1, -1, -1, 80, + -1, 189, 190, -1, -1, -1, -1, 502, -1, -1, + 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, + -1, -1, -1, -1, -1, -1, -1, 522, -1, -1, + -1, -1, 3496, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 292, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 912, -1, -1, -1, 916, + 917, -1, -1, -1, 145, 253, 254, 255, 256, 257, + 258, 259, 260, -1, -1, 263, 264, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 177, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 969, 194, -1, -1, -1, -1, 199, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 987, -1, -1, -1, 1752, -1, 993, -1, -1, 996, + -1, -1, 999, 1000, 1001, 1002, 394, -1, -1, 337, + 338, -1, -1, 1771, -1, -1, 237, 2772, -1, -1, + -1, -1, -1, 1781, -1, 1783, -1, -1, 1786, -1, + -1, -1, -1, -1, 1792, -1, 1794, -1, -1, -1, + -1, -1, 2797, -1, -1, -1, -1, 1044, 1045, 1807, + 378, 379, -1, -1, 1812, -1, -1, -1, 1816, 1817, + 1818, 1819, -1, 1821, 1822, 3, -1, -1, -1, 1066, + 8, 292, -1, 11, -1, -1, -1, 15, 16, 17, + 18, 19, 20, 21, -1, -1, -1, 3496, 1085, -1, + -1, -1, 2847, -1, -1, -1, -1, -1, 36, 1096, + 1097, 1098, 40, 1100, 1101, -1, -1, -1, 46, -1, + -1, -1, -1, -1, 502, 53, -1, -1, -1, -1, + -1, 509, 510, 511, 512, 513, 514, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 1136, + -1, -1, 80, -1, -1, -1, 474, 475, 2350, -1, + -1, -1, -1, -1, -1, -1, -1, 1154, 1155, -1, + -1, -1, -1, 2365, 2366, 2367, -1, -1, -1, -1, + 498, 499, -1, 394, -1, -1, -1, -1, 2380, -1, + -1, 2383, -1, 2938, -1, -1, -1, -1, 2390, -1, + 518, -1, 8, 1190, -1, 11, -1, 1194, 1195, 15, + 16, 17, 18, 19, 20, 21, -1, 8, 1205, 1206, + 11, -1, 98, -1, 15, 16, -1, -1, 1976, -1, + 36, -1, -1, -1, 40, -1, -1, -1, -1, -1, + 46, -1, -1, -1, -1, -1, -1, 53, -1, 177, + 126, 127, -1, 2001, -1, 46, -1, -1, -1, 2007, + -1, -1, 53, -1, -1, 2013, 194, -1, -1, -1, + 2018, 199, -1, -1, 80, -1, -1, -1, 1265, -1, + -1, -1, -1, -1, 2476, 2477, 2478, 1274, -1, 80, + -1, 502, -1, -1, 222, 223, 172, -1, 509, 510, + 511, 512, 513, 514, -1, -1, -1, -1, -1, 237, + -1, 1298, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 8, -1, -1, 11, -1, -1, 3081, 15, 16, 17, + 18, 19, 20, 21, -1, -1, -1, 275, -1, -1, + 278, 2099, -1, -1, 145, -1, -1, -1, 36, -1, + -1, 2109, -1, -1, 292, -1, -1, 295, 46, -1, + -1, 177, -1, -1, -1, 53, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 177, -1, 194, -1, + -1, -1, -1, 199, -1, -1, -1, 1384, -1, -1, + -1, -1, 80, 194, -1, -1, -1, -1, 199, -1, + -1, -1, -1, -1, -1, -1, 222, 223, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 237, -1, 2625, -1, -1, -1, 2185, -1, 315, + 316, 317, -1, -1, -1, -1, 237, -1, -1, 2197, + -1, -1, -1, -1, 2202, -1, -1, -1, -1, -1, + 1447, -1, 1449, 1450, -1, -1, 394, -1, -1, 275, + -1, -1, 278, -1, -1, 1462, 1463, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 292, -1, -1, 295, + -1, -1, -1, -1, -1, -1, 1483, -1, 2246, 177, + -1, 292, -1, -1, 2252, -1, 382, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 194, 393, -1, -1, + -1, 199, -1, -1, -1, -1, -1, 2719, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 415, + -1, -1, -1, 419, 222, 223, -1, -1, -1, -1, + -1, -1, 3297, -1, -1, -1, -1, -1, -1, 237, + -1, -1, -1, 439, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 502, -1, 452, 505, 506, 507, + -1, 509, 510, 511, 512, 513, 514, 463, 394, -1, + -1, -1, -1, 2785, 2786, 2787, 2788, 275, 1585, -1, + 278, -1, -1, 394, 480, -1, 1593, -1, -1, -1, + -1, -1, -1, -1, 292, -1, -1, 295, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 504, -1, + 2378, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1627, -1, 518, -1, -1, -1, -1, 1634, -1, -1, + -1, -1, -1, 1640, 1641, 1642, 1643, 1644, 1645, 1646, + 1647, -1, -1, -1, -1, 1652, 1653, -1, -1, -1, + 1657, -1, -1, -1, 1661, -1, -1, 1664, 1665, 1666, + 1667, 1668, 1669, 1670, 1671, 1672, -1, -1, 1675, -1, + -1, -1, -1, -1, -1, 1682, 502, 1684, -1, 505, + 506, 507, -1, 509, 510, 511, 512, 513, 514, -1, + -1, 502, -1, 519, -1, 1702, 394, -1, 509, 510, + 511, 512, 513, 514, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 2486, -1, + -1, -1, 2490, -1, -1, -1, -1, -1, 2496, 1736, + 1737, -1, 2944, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 2541, -1, -1, -1, 2545, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 502, -1, -1, 505, 506, 507, + -1, 509, 510, 511, 512, 513, 514, -1, -1, -1, + 1827, 519, -1, -1, 1831, -1, -1, 1834, 1835, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 2629, -1, -1, 8, 2633, 2634, 11, 1875, 2637, + -1, 15, 16, 17, 18, 19, 20, 21, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 36, 1900, 1901, -1, 2664, -1, -1, -1, + -1, -1, 46, -1, -1, -1, -1, -1, -1, 53, + -1, 2679, 2680, 2681, 2682, 2683, 2684, 2685, 2686, 2687, + 2688, -1, 1929, 1930, -1, 1932, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 80, -1, -1, -1, + -1, -1, 26, -1, -1, 0, -1, -1, 32, -1, + -1, -1, -1, -1, 1961, 1962, 40, -1, 1965, 26, + -1, -1, -1, -1, -1, 32, -1, 22, -1, -1, + -1, -1, -1, 40, -1, -1, 60, 32, -1, 34, + 35, -1, -1, -1, -1, -1, -1, -1, -1, 1996, + -1, -1, 47, 60, -1, -1, 2003, 52, -1, -1, + -1, -1, -1, -1, -1, -1, 61, -1, -1, -1, + 2778, -1, -1, -1, 2021, -1, 2023, -1, -1, -1, + 75, -1, 106, -1, -1, -1, -1, -1, -1, 84, + -1, 86, -1, 177, -1, -1, 2804, -1, -1, 106, + -1, 3253, -1, 98, -1, 100, -1, -1, -1, -1, + 194, -1, -1, 137, 2061, 199, 111, -1, -1, -1, + -1, -1, 3274, -1, -1, -1, -1, -1, 2836, -1, + 137, 126, 127, 128, -1, -1, 2844, -1, 222, 223, + -1, -1, 137, -1, -1, -1, -1, -1, 143, -1, + -1, 2098, -1, 237, -1, 2102, 151, -1, 153, 154, + 2107, 2108, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 2879, -1, 168, -1, -1, -1, 172, 202, -1, + -1, -1, -1, -1, -1, -1, -1, 3339, -1, -1, + -1, 275, -1, -1, 278, 202, -1, -1, -1, -1, + -1, -1, -1, 198, -1, -1, -1, 2154, 292, -1, + 2157, 295, 2159, -1, -1, -1, -1, 3369, -1, 214, + -1, -1, -1, -1, -1, -1, -1, 251, 2175, 2937, + -1, -1, -1, -1, -1, -1, -1, 261, -1, -1, + -1, -1, -1, -1, 251, 240, -1, -1, -1, 273, + -1, -1, -1, -1, 261, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8, -1, 273, 11, 2215, -1, + 294, 15, 16, 17, 18, 19, 20, 21, -1, -1, + -1, 305, -1, -1, -1, 2232, 2233, 294, -1, -1, + -1, -1, 36, -1, -1, -1, -1, -1, 305, -1, + -1, -1, 46, -1, 2251, -1, -1, -1, -1, 53, + 394, -1, -1, -1, -1, -1, -1, 2264, -1, -1, + 315, 316, 317, -1, -1, -1, -1, -1, 323, 353, + -1, 326, -1, 357, -1, 359, 80, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 353, -1, -1, -1, + 357, -1, 359, -1, -1, -1, -1, 997, -1, -1, + 384, -1, 357, -1, -1, 389, -1, -1, -1, -1, + -1, 366, -1, -1, 2321, -1, -1, 384, -1, 403, + 2327, -1, 389, -1, -1, -1, -1, 382, -1, -1, + -1, -1, -1, -1, 389, -1, 403, -1, 393, -1, + -1, -1, -1, -1, -1, 3113, -1, -1, 403, -1, + -1, -1, 3120, -1, -1, -1, -1, -1, 502, -1, + 415, 505, 506, 507, 419, 509, 510, 511, 512, 513, + 514, -1, -1, 177, -1, 519, 460, -1, -1, -1, + -1, 2388, -1, -1, 439, -1, -1, -1, -1, -1, + 194, -1, -1, 460, -1, 199, -1, 452, -1, -1, + 455, -1, -1, 458, -1, -1, -1, -1, 463, -1, + -1, -1, -1, -1, -1, 3183, -1, -1, 222, 223, + 3188, 1121, -1, -1, -1, 480, -1, 8, -1, -1, + 11, -1, -1, 237, 15, 16, 17, 18, 19, 20, + 21, -1, -1, -1, -1, -1, 3214, -1, -1, 504, + -1, -1, -1, -1, -1, 36, -1, -1, -1, -1, + -1, -1, -1, 518, -1, 46, 521, -1, 3236, 3237, + 1170, 275, 53, -1, 278, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 292, -1, + -1, 295, 3260, -1, -1, -1, -1, -1, -1, 80, + -1, -1, -1, -1, 1204, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 2521, -1, -1, -1, -1, -1, + 2527, 2528, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 3301, -1, 2542, -1, -1, -1, -1, + -1, 3309, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 2558, -1, -1, 2561, -1, 2563, -1, -1, 1259, + -1, -1, -1, -1, 2571, -1, -1, -1, -1, -1, + -1, -1, 2579, 2580, -1, -1, -1, -1, -1, 2586, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 2942, -1, -1, -1, 1147, 1148, -1, - -1, -1, -1, -1, 3523, -1, -1, 1714, -1, -1, - -1, -1, -1, -1, -1, -1, 26, -1, -1, 3538, - -1, -1, 32, -1, -1, -1, -1, 2976, 222, -1, - 40, -1, -1, 1183, -1, 2610, -1, 1187, 1188, 2614, - 2615, -1, 3222, 2618, -1, -1, -1, -1, 1198, 1199, - 60, 505, 506, 507, -1, 509, 510, 511, 512, 513, - 514, 8, -1, 3243, 11, -1, -1, -1, 15, 16, - 2645, -1, 19, 20, 21, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 2660, 2661, 2662, 2663, 2664, - 2665, 2666, 2667, 2668, 2669, -1, 106, -1, 292, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 1258, 3058, - -1, -1, -1, -1, -1, -1, -1, 1267, -1, -1, - -1, -1, -1, -1, 3221, 3305, -1, 137, -1, -1, - -1, -1, -1, -1, -1, 3461, -1, -1, -1, -1, - -1, 1291, -1, -1, -1, 3242, -1, -1, -1, -1, - -1, 3461, 3101, -1, -1, 3335, -1, -1, -1, -1, + 394, -1, -1, -1, 2601, -1, 177, -1, -1, -1, + -1, 1301, -1, -1, 2611, -1, -1, -1, 1308, -1, + -1, -1, -1, 194, -1, -1, -1, -1, 199, -1, + -1, -1, -1, -1, 2631, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 222, 223, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 237, -1, 1358, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 2759, -1, -1, -1, -1, -1, - -1, -1, 202, -1, -1, -1, -1, -1, 3295, -1, - 3297, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 2785, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1927, 1928, 1929, 1930, 1931, 1932, -1, 1377, 1935, 1936, - 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, -1, -1, - 3337, 251, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 261, -1, -1, 8, 3204, 3353, 11, -1, -1, - -1, 15, 16, 273, -1, 19, 20, 21, -1, -1, - -1, -1, -1, -1, -1, 222, -1, -1, -1, -1, - -1, -1, 36, -1, 294, -1, -1, -1, -1, -1, - 1440, -1, 1442, 1443, -1, 305, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 1455, 1456, -1, -1, -1, + -1, -1, 1382, 2690, -1, 2692, -1, -1, -1, -1, + -1, -1, -1, -1, 275, -1, -1, 278, 502, -1, -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, - 514, -1, 1472, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 2913, -1, - -1, -1, -1, 353, -1, 292, -1, 357, -1, 359, + 514, 292, -1, -1, 295, 519, -1, -1, -1, -1, + -1, -1, -1, -1, 3492, -1, 81, -1, -1, -1, + 1430, -1, 1432, -1, 1434, 1435, -1, 1437, -1, -1, + 1440, -1, 97, 1443, -1, -1, 1446, -1, -1, -1, + -1, 1451, -1, -1, 1454, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8, -1, -1, 11, -1, -1, -1, 15, 16, + 17, 18, 19, 20, 21, 2792, 2793, -1, -1, -1, + -1, 146, -1, -1, -1, -1, -1, 1497, -1, 36, + -1, 156, -1, -1, -1, -1, -1, -1, -1, 46, + -1, -1, -1, 394, 169, -1, 53, -1, -1, 174, + 2827, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 384, -1, -1, -1, -1, 389, - -1, 3478, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 403, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3504, -1, -1, - 2117, 2118, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 8, -1, 1574, 11, -1, -1, -1, 15, - 16, -1, 1582, 19, 20, 21, -1, -1, -1, -1, + 2847, -1, -1, 80, -1, -1, 2853, 2854, 203, -1, + -1, 2858, -1, -1, -1, -1, 2863, -1, -1, 2866, + 2867, -1, -1, -1, 2871, 2872, -1, -1, 2875, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 2886, + -1, 1581, -1, 3, -1, 5, -1, -1, -1, -1, + -1, 246, -1, -1, -1, 250, -1, 1597, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 1607, 1608, 1609, + -1, -1, -1, -1, 1614, -1, -1, -1, 1618, -1, + -1, 502, -1, 2930, 505, 506, 507, -1, 509, 510, + 511, 512, 513, 514, -1, -1, -1, -1, 519, -1, + 177, -1, -1, -1, -1, -1, -1, -1, 68, 69, + 2957, -1, -1, -1, -1, -1, -1, 194, -1, -1, + -1, -1, 199, -1, -1, 320, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 68, 69, -1, -1, -1, + 335, 1681, -1, -1, -1, 222, 223, -1, -1, 109, + 110, -1, -1, 113, 114, -1, -1, -1, -1, -1, + 237, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 370, 109, 110, 373, 1719, + 113, 114, -1, -1, -1, -1, -1, -1, -1, 384, + -1, -1, 387, -1, -1, 1735, -1, -1, 275, -1, + 1740, 278, -1, -1, -1, -1, -1, -1, -1, -1, + 405, -1, -1, -1, -1, 292, -1, 1757, 295, -1, + -1, -1, -1, 3070, 419, -1, -1, -1, -1, 189, + 190, 426, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 436, -1, -1, -1, -1, -1, 442, -1, -1, + 3097, -1, -1, -1, -1, -1, 189, 190, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 460, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 46, -1, -1, -1, -1, -1, -1, 53, 222, -1, - -1, -1, 1622, -1, -1, -1, -1, -1, 1628, 1629, - 1630, 1631, 1632, 1633, 1634, 1635, -1, -1, -1, -1, - 1640, 1641, -1, -1, 80, 1645, 0, -1, -1, 1649, - -1, -1, 1652, 1653, 1654, 1655, 1656, 1657, 1658, 1659, - 1660, -1, 3461, 1663, 3089, -1, -1, -1, 22, -1, - 1670, 3096, 1672, -1, -1, -1, 2233, -1, 32, -1, - 34, 35, -1, -1, -1, -1, -1, -1, 292, -1, - -1, 1691, -1, 47, -1, -1, -1, -1, 52, -1, - -1, -1, -1, -1, -1, -1, -1, 61, 505, 506, - 507, -1, 509, 510, 511, 512, 513, 514, -1, -1, - -1, 75, -1, -1, -1, 1725, 1726, -1, 3153, -1, - 84, -1, 86, 3158, -1, -1, -1, -1, -1, -1, - -1, 177, -1, -1, 98, -1, 100, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 111, 194, 3184, - -1, -1, -1, 199, -1, -1, -1, -1, -1, -1, - -1, -1, 126, 127, 128, -1, -1, -1, -1, -1, - 3205, 3206, -1, 137, -1, -1, 222, 223, -1, 143, - -1, -1, -1, -1, -1, -1, -1, 151, -1, 153, - 154, 237, -1, -1, 3229, -1, -1, 996, -1, -1, - -1, -1, -1, -1, 168, -1, 1816, -1, 172, -1, - 1820, -1, 3, 1823, 1824, -1, -1, 8, -1, -1, - 11, -1, -1, -1, 15, 16, 17, 18, 19, 20, - 21, -1, 278, -1, 198, 3270, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 36, 292, -1, -1, 40, - 214, -1, -1, -1, 1864, 46, -1, -1, -1, -1, - -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 240, -1, -1, 1889, - 1890, -1, -1, -1, -1, -1, -1, -1, -1, 80, - -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, - 514, -1, -1, -1, -1, -1, -1, -1, 1918, 1919, - -1, 1921, -1, -1, -1, -1, 1115, -1, -1, -1, + -1, -1, -1, -1, -1, 470, -1, -1, -1, -1, + -1, -1, -1, -1, 3131, -1, -1, -1, -1, -1, + -1, -1, -1, 253, 254, 255, 256, 257, 258, 259, + 260, 3148, 3149, 263, 264, 3152, -1, 3154, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 394, -1, -1, + 253, 254, 255, 256, 257, 258, 259, 260, -1, -1, + 263, 264, 3179, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 3203, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1950, 1951, -1, -1, 1954, -1, -1, -1, 394, -1, - -1, 315, 316, 317, -1, -1, -1, -1, -1, 323, - -1, -1, 326, -1, 1163, -1, -1, -1, -1, -1, - -1, -1, -1, 1983, -1, -1, -1, -1, -1, 1989, - -1, -1, -1, -1, -1, -1, 177, -1, 2555, 2556, - 37, -1, -1, 357, -1, 42, -1, 2007, 1197, 2009, - -1, -1, 366, 194, -1, -1, -1, -1, 199, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 382, -1, - -1, -1, 3457, -1, -1, 389, -1, -1, -1, 393, - -1, 222, 223, -1, -1, -1, -1, 2047, -1, 403, - -1, -1, -1, -1, -1, -1, 237, -1, -1, -1, - -1, 415, -1, 1252, 101, 419, 502, -1, -1, 505, - 506, 507, -1, 509, 510, 511, 512, 513, 514, -1, - -1, -1, -1, -1, 2084, 439, -1, 2087, -1, -1, - -1, -1, 2092, 2093, 275, -1, -1, 278, 452, -1, - -1, 455, -1, -1, 458, 1294, -1, -1, -1, 463, - -1, 292, 1301, -1, 295, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 480, -1, -1, -1, - -1, 26, -1, -1, -1, -1, 173, 32, 2138, -1, - -1, 2141, -1, 2143, -1, 40, -1, -1, -1, -1, - 504, -1, -1, -1, -1, -1, -1, -1, -1, 2159, - -1, -1, 1351, -1, 518, 60, -1, 521, -1, -1, - -1, -1, 209, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 1375, -1, 225, -1, - -1, -1, -1, -1, -1, -1, 2753, -1, 235, 2199, + -1, -1, -1, -1, -1, -1, -1, 337, 338, -1, + -1, -1, -1, -1, -1, -1, -1, 1927, -1, -1, + -1, -1, -1, -1, -1, 1935, 1936, -1, 1938, 1939, + 1940, 1941, 1942, 1943, 337, 338, 1946, 1947, 1948, 1949, + 1950, 1951, 1952, 1953, 1954, 1955, 1956, -1, 378, 379, + -1, -1, -1, -1, -1, 502, -1, -1, 505, 506, + 507, -1, 509, 510, 511, 512, 513, 514, -1, -1, + -1, -1, 519, -1, 3291, 378, 379, -1, 3295, -1, + 8, -1, 3299, 11, -1, -1, -1, 15, 16, 17, + 18, 19, 20, 21, -1, -1, 3313, -1, -1, -1, + -1, 3318, -1, 3320, -1, -1, -1, -1, 36, -1, + -1, 3328, -1, -1, -1, -1, -1, -1, 46, -1, + 8, -1, -1, 11, -1, 53, -1, 15, 16, 3346, + -1, 19, 20, 21, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 474, 475, -1, -1, 36, -1, + -1, -1, 80, -1, 2064, -1, -1, 2067, 46, -1, + -1, -1, -1, -1, -1, 53, -1, -1, 498, 499, + -1, 474, 475, -1, -1, -1, 3393, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 3403, -1, -1, -1, + -1, -1, 80, -1, -1, 498, 499, -1, 3415, -1, + -1, -1, 2112, -1, -1, -1, 2116, -1, -1, -1, + 2120, 2121, 2122, 2123, 2124, 2125, 2126, 2127, -1, -1, + -1, -1, -1, 2133, 2134, -1, 2136, 2137, -1, -1, + -1, 3448, -1, -1, -1, -1, -1, -1, -1, -1, + 2150, -1, -1, 2153, -1, -1, -1, -1, -1, 177, + -1, 2161, 2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, + 2170, -1, -1, -1, -1, -1, 194, -1, -1, -1, + -1, 199, 8, -1, -1, 11, -1, -1, -1, 15, + 16, 17, 18, 19, 20, 21, 2196, -1, -1, 177, + -1, -1, -1, -1, 222, 223, -1, -1, -1, -1, + 36, -1, -1, -1, -1, -1, 194, -1, -1, 237, + 46, 199, -1, -1, -1, -1, -1, 53, 3535, 3536, + 3537, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 222, 223, -1, -1, -1, 2249, + -1, -1, -1, -1, 80, 3562, -1, 275, -1, 237, + 278, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 292, -1, -1, 295, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 106, -1, 394, -1, -1, 2216, 2217, -1, -1, - -1, 2778, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 269, -1, 1423, 2235, 1425, -1, 1427, 1428, - -1, 1430, 137, -1, 1433, -1, -1, 1436, 2248, -1, - 1439, -1, -1, 290, -1, 1444, -1, -1, 1447, -1, - -1, -1, -1, -1, 8, -1, -1, 11, -1, -1, - -1, 15, 16, 17, 18, 19, 20, 21, 315, -1, - -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, - -1, -1, 36, -1, -1, -1, 40, 1486, -1, -1, - -1, -1, 46, -1, -1, 2305, -1, 202, -1, 53, - -1, 2311, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 502, -1, -1, 505, 506, 507, 364, 509, 510, - 511, 512, 513, 514, -1, -1, 80, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 383, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 251, 2914, -1, -1, - -1, -1, -1, -1, -1, -1, 261, -1, -1, -1, - -1, -1, 2372, -1, -1, -1, -1, -1, 273, -1, - -1, 1570, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 8, -1, -1, 11, 1586, -1, 294, - 15, 16, 17, 18, 19, 20, 21, 1596, 1597, 1598, - 305, -1, -1, -1, 1603, 452, -1, -1, 1607, -1, - 457, 36, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 46, -1, 177, -1, -1, -1, -1, 53, -1, + -1, -1, -1, -1, -1, -1, 3603, 275, -1, -1, + 278, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 292, -1, -1, 295, -1, -1, + -1, -1, 2322, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 2332, 2333, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 194, -1, -1, -1, -1, 199, -1, -1, 353, -1, - -1, -1, 357, -1, 359, 80, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 222, 223, - 1669, -1, -1, -1, -1, -1, -1, -1, -1, 384, - -1, -1, -1, 237, 389, -1, -1, -1, -1, -1, - 3057, -1, -1, -1, -1, -1, -1, 2507, 403, -1, - -1, -1, -1, 2513, 2514, -1, -1, -1, -1, 1708, - -1, -1, -1, -1, -1, 2525, -1, -1, -1, -1, - -1, 275, -1, -1, 278, 1724, -1, -1, -1, 2539, - 1729, -1, 2542, -1, 2544, -1, -1, -1, 292, -1, - -1, 295, 2552, -1, -1, -1, -1, 1746, -1, -1, - 2560, 2561, 177, -1, -1, 460, -1, 2567, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, - -1, -1, 2582, -1, 199, -1, -1, -1, -1, -1, - 8, -1, 2592, 11, -1, -1, -1, 15, 16, 17, - 18, 19, 20, 21, -1, -1, -1, 222, 223, -1, - -1, -1, 2612, -1, -1, -1, -1, -1, 36, -1, - -1, -1, 237, -1, -1, -1, -1, -1, 46, -1, - -1, -1, -1, -1, -1, 53, -1, -1, -1, -1, - 8, -1, -1, 11, -1, -1, -1, 15, 16, -1, - 394, 19, 20, 21, -1, -1, -1, -1, -1, -1, - 275, -1, 80, 278, -1, -1, -1, -1, 36, -1, - -1, 2671, -1, 2673, -1, -1, -1, 292, 46, -1, - 295, -1, -1, -1, -1, 53, -1, -1, -1, -1, + -1, 177, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 194, -1, + -1, -1, -1, 199, -1, -1, 394, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 3266, - -1, -1, 80, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 1916, -1, -1, - -1, -1, -1, -1, -1, 1924, 1925, -1, 1927, 1928, - 1929, 1930, 1931, 1932, -1, -1, 1935, 1936, 1937, 1938, - 1939, 1940, 1941, 1942, 1943, 1944, 1945, -1, 502, 177, - -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, - 514, -1, -1, 2773, 2774, 519, 194, -1, -1, 394, - -1, 199, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 222, 223, -1, 2399, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 222, 223, -1, -1, 2808, 177, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 237, - -1, -1, -1, 2823, -1, -1, 194, -1, -1, 2829, - 2830, 199, -1, -1, 2834, -1, -1, -1, -1, 2839, - -1, -1, 2842, 2843, -1, -1, -1, 2847, 2848, -1, - -1, 2851, -1, -1, 222, 223, -1, 275, -1, -1, - 278, 2050, 2862, -1, 2053, -1, -1, -1, -1, 237, - -1, -1, -1, -1, 292, -1, -1, 295, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 502, -1, -1, - 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, - -1, -1, -1, -1, 519, -1, 2906, 275, -1, -1, - 278, 2100, -1, -1, -1, 2104, 2105, 2106, 2107, 2108, - 2109, 2110, 2111, -1, 292, -1, -1, 295, 2117, 2118, - -1, 2120, 2121, 2933, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 2134, -1, -1, 2137, -1, - -1, -1, -1, -1, -1, -1, 2145, 2146, 2147, 2148, - 2149, 2150, 2151, 2152, 2153, 2154, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 394, -1, -1, -1, - -1, -1, -1, -1, -1, 8, -1, -1, 11, -1, - -1, 2180, 15, 16, 17, 18, 19, 20, 21, -1, + -1, 237, -1, -1, -1, -1, 394, -1, -1, -1, + -1, -1, -1, -1, -1, 2425, 2426, 2427, -1, -1, + 2430, 2431, 2432, 2433, 2434, 2435, -1, -1, -1, 2439, + 2440, 2441, 2442, 2443, 2444, 2445, 2446, 2447, 2448, 275, + -1, -1, 278, 2453, 2454, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 292, -1, -1, 295, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 2479, + -1, -1, -1, -1, 502, 2485, -1, 505, 506, 507, + -1, 509, 510, 511, 512, 513, 514, -1, -1, -1, + -1, 519, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 46, -1, -1, 394, -1, -1, -1, - 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 2233, -1, 3046, -1, -1, -1, - -1, -1, 24, -1, -1, -1, -1, 80, -1, -1, + 2520, -1, -1, -1, 502, -1, -1, 505, 506, 507, + -1, 509, 510, 511, 512, 513, 514, 2537, -1, -1, + -1, -1, -1, 2543, -1, -1, -1, -1, -1, -1, + -1, 2551, 2552, -1, -1, -1, -1, -1, -1, 2559, + 2560, -1, -1, -1, -1, -1, -1, -1, 394, -1, + -1, -1, -1, 2573, 2574, 2575, 2576, -1, 2578, -1, + -1, -1, 2582, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, + -1, -1, -1, 15, 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 3073, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 502, -1, -1, 505, 506, 507, - -1, 509, 510, 511, 512, 513, 514, -1, -1, -1, - -1, 519, -1, -1, -1, -1, 3106, -1, -1, 81, - -1, -1, -1, -1, -1, -1, -1, 2306, 3118, 3119, - -1, -1, 3122, -1, 3124, 97, -1, 2316, 2317, -1, - -1, -1, -1, -1, 502, -1, -1, 505, 506, 507, - -1, 509, 510, 511, 512, 513, 514, -1, -1, 3149, - -1, -1, -1, -1, 177, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 36, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 46, -1, -1, -1, 2638, -1, + -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 194, -1, 3173, 146, -1, 199, -1, -1, -1, - -1, -1, -1, -1, 156, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 2383, -1, -1, 169, -1, 222, - 223, -1, 174, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 237, -1, -1, -1, -1, -1, - 2409, 2410, 2411, -1, -1, 2414, 2415, 2416, 2417, 2418, - 2419, 203, -1, -1, 2423, 2424, 2425, 2426, 2427, 2428, - 2429, 2430, 2431, 2432, -1, -1, -1, -1, 2437, 2438, - -1, -1, 275, -1, -1, 278, -1, -1, -1, -1, - 3260, -1, -1, -1, 3264, -1, -1, -1, 3268, 292, - -1, -1, 295, -1, 246, -1, 2465, -1, 250, 3279, - -1, -1, 2471, -1, 3284, -1, 3286, -1, -1, -1, - 8, -1, -1, 11, 3294, -1, -1, 15, 16, 17, - 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, - -1, -1, 3312, -1, -1, -1, -1, 2506, 36, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 46, -1, - -1, -1, -1, -1, 2523, 53, -1, 2526, -1, -1, - -1, -1, -1, 2532, 2533, -1, -1, -1, 320, -1, - -1, 2540, 2541, -1, -1, -1, -1, -1, -1, 3359, - -1, -1, 80, 335, -1, 2554, 2555, 2556, 2557, 3369, - 2559, 394, -1, -1, 2563, -1, -1, -1, -1, -1, - 8, 3381, -1, 11, -1, -1, -1, 15, 16, 17, - 18, 19, 20, 21, -1, -1, -1, -1, 370, -1, - -1, 373, -1, -1, -1, -1, -1, -1, 36, -1, - -1, -1, 384, 3413, -1, 387, -1, -1, 46, -1, - -1, -1, -1, -1, -1, 53, -1, -1, -1, -1, - 2619, -1, -1, 405, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 419, -1, -1, - -1, -1, 80, -1, 426, -1, -1, -1, -1, 177, - -1, -1, -1, -1, 436, -1, -1, -1, -1, -1, - 442, -1, -1, -1, -1, -1, 194, -1, -1, 502, - -1, 199, 505, 506, 507, -1, 509, 510, 511, 512, - 513, 514, -1, -1, -1, -1, 519, -1, 470, -1, - 3500, 3501, 3502, -1, 222, 223, -1, -1, -1, -1, - -1, -1, -1, 8, -1, -1, 11, -1, -1, 237, - 15, 16, 17, 18, 19, 20, 21, 3527, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 80, -1, + -1, -1, -1, -1, -1, -1, 502, -1, -1, 505, + 506, 507, -1, 509, 510, 511, 512, 513, 514, -1, + -1, 8, -1, 519, 11, -1, -1, -1, 15, 16, + 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 36, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, + 8, -1, -1, 11, -1, -1, 53, 15, 16, 17, + 18, 19, 20, 21, -1, -1, -1, -1, 8, -1, + 2750, 11, -1, -1, -1, 15, 16, -1, 36, 19, + 20, 21, -1, 80, -1, 177, -1, -1, 46, -1, + -1, -1, 2772, -1, -1, 53, 36, -1, -1, -1, + -1, -1, 194, -1, -1, -1, 46, 199, -1, -1, + -1, -1, -1, 53, -1, -1, -1, -1, -1, -1, + -1, -1, 80, -1, -1, -1, -1, -1, -1, -1, + 222, 223, -1, -1, -1, -1, -1, -1, -1, -1, + 80, -1, -1, -1, -1, 237, -1, -1, 2828, -1, + 2830, -1, -1, -1, -1, -1, -1, -1, -1, 2839, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 36, 2731, -1, -1, -1, -1, -1, -1, 177, - -1, 46, -1, -1, -1, -1, -1, 275, 53, -1, - 278, -1, -1, -1, 2753, -1, 194, 3, 3568, 5, - -1, 199, -1, -1, 292, -1, -1, 295, -1, -1, - -1, -1, -1, -1, -1, 80, -1, -1, -1, -1, + -1, -1, 2852, -1, -1, 2855, -1, 2857, -1, -1, + 177, 2861, -1, 275, 2864, 2865, 278, -1, 2868, 2869, + -1, -1, -1, -1, -1, -1, 2876, 194, -1, -1, + 292, -1, 199, 295, -1, 2885, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 177, + 2900, -1, -1, -1, -1, 222, 223, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 194, 177, -1, -1, + 237, 199, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 194, -1, -1, -1, 2938, 199, -1, -1, -1, -1, 222, 223, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 237, + -1, -1, -1, -1, -1, -1, -1, -1, 275, 237, + -1, 278, 222, 223, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 292, -1, 237, 295, -1, + -1, -1, 394, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 275, -1, -1, + 278, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 292, 275, -1, 295, 278, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 292, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 2809, -1, 2811, -1, -1, -1, -1, -1, -1, 2818, - -1, -1, 68, 69, -1, -1, -1, -1, -1, 2828, - -1, -1, 2831, -1, 2833, -1, -1, 275, 2837, -1, - 278, 2840, 2841, -1, -1, 2844, 2845, -1, -1, -1, - -1, -1, -1, 2852, 292, -1, -1, 295, -1, -1, - -1, -1, 2861, 109, 110, -1, 394, 113, 114, -1, - -1, -1, 177, -1, -1, -1, -1, 2876, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, - -1, -1, -1, -1, 199, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 2914, -1, 222, 223, -1, - -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, - -1, -1, 237, 15, 16, 17, 18, 19, 20, 21, - -1, -1, -1, 189, 190, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 36, -1, 394, -1, -1, -1, - -1, -1, -1, -1, 46, -1, -1, -1, -1, -1, - 275, 53, -1, 278, 502, -1, -1, 505, 506, 507, - -1, 509, 510, 511, 512, 513, 514, 292, -1, -1, - 295, 519, -1, -1, -1, -1, -1, -1, 80, -1, - -1, -1, -1, -1, -1, -1, -1, 253, 254, 255, - 256, 257, 258, 259, 260, -1, -1, 263, 264, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 394, -1, -1, + 3080, 3081, -1, -1, -1, -1, -1, -1, -1, -1, + 502, -1, -1, 505, 506, 507, -1, 509, 510, 511, + 512, 513, 514, -1, -1, 3105, 3106, 519, -1, -1, + -1, -1, -1, -1, -1, -1, 394, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 3129, + -1, -1, -1, -1, 394, -1, -1, -1, 3138, -1, + -1, -1, 3142, 3143, 3144, -1, -1, 3147, -1, -1, + 3150, 3151, -1, -1, -1, -1, -1, -1, -1, 3159, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3056, 3057, -1, + -1, -1, -1, -1, -1, 502, -1, -1, 505, 506, + 507, -1, 509, 510, 511, 512, 513, 514, -1, -1, + 3200, -1, 519, -1, -1, -1, 3206, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 3219, -1, -1, -1, -1, 502, -1, -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, -1, -1, -1, - -1, 519, 3081, 3082, -1, -1, -1, -1, -1, 394, - -1, 337, 338, -1, -1, 177, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 3105, -1, -1, -1, - 3109, -1, 194, 3112, 3113, 3114, -1, 199, 3117, -1, - -1, 3120, 3121, -1, -1, -1, -1, -1, -1, -1, - 3129, -1, 378, 379, -1, -1, -1, -1, -1, -1, - 222, 223, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 237, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 3170, -1, -1, -1, -1, -1, 3176, -1, -1, + -1, 519, 502, -1, -1, 505, 506, 507, -1, 509, + 510, 511, 512, 513, 514, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 3189, -1, -1, 275, -1, -1, 278, 502, -1, -1, - 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, - 292, -1, -1, 295, 519, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 474, 475, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 3279, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 3248, - -1, -1, 498, 499, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 3281, 3282, 3283, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 3315, 3316, 3317, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 3301, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 394, -1, 3313, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 3335, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 3347, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 3374, -1, -1, -1, -1, - -1, -1, -1, -1, 3383, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 3408, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 3418, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 3408, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 502, -1, -1, 505, 506, 507, -1, 509, 510, 511, - 512, 513, 514, -1, 3433, -1, -1, 519, -1, -1, + -1, -1, -1, 3443, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 3468, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3476, -1, 22, - 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, - 33, -1, -1, -1, -1, -1, 39, -1, -1, 42, - 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, - 73, 3530, 75, 76, 77, 78, 79, -1, 81, -1, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, -1, 120, 121, 122, - 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, - -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, - -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, 160, 161, -1, - 163, 164, 165, 166, -1, 168, -1, 170, 171, -1, - 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, - 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, - 203, 204, 205, 206, -1, 208, 209, 210, 211, 212, - 213, 214, 215, 216, 217, -1, 219, -1, 221, 222, - 223, 224, 225, 226, 227, 228, 229, 230, 231, -1, - -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, - 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, -1, -1, -1, -1, 319, 320, 321, 322, - 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, - 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, - 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, - 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, - 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, - -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, - -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, - 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, -1, -1, 417, 418, -1, 420, 421, 422, - 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, - 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, - 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, - 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, - 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, - 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, - 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, - -1, -1, -1, -1, -1, -1, 509, 510, 511, -1, - -1, -1, -1, 516, -1, 518, -1, -1, -1, -1, - 523, 524, 525, 526, -1, 528, 3, 4, 5, 6, - 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, - 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, - -1, -1, 39, -1, -1, 42, 43, 44, -1, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, -1, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, - 77, 78, 79, -1, 81, -1, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, - 97, 98, 99, -1, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, -1, 120, 121, 122, 123, 124, 125, -1, - -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, - 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, - -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, -1, 163, 164, 165, 166, - -1, 168, -1, 170, 171, -1, 173, 174, 175, 176, - 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, - -1, 208, 209, 210, 211, 212, 213, 214, 215, 216, - 217, -1, 219, -1, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, -1, -1, 234, 235, 236, - 237, -1, 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, - -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, - 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, - -1, -1, 319, 320, 321, 322, 323, 324, 325, 326, - 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, - 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, - -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, -1, 362, 363, 364, 365, 366, - 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, - 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, - 387, 388, 389, 390, 391, 392, -1, 394, 395, 396, - 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, - 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, - 417, 418, -1, 420, 421, 422, 423, 424, 425, 426, - -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, - -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, - 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, - -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, - 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, - 497, 498, 499, 500, 501, 502, -1, -1, -1, -1, - -1, -1, 509, 510, 511, -1, -1, -1, -1, 516, - -1, 518, -1, -1, -1, -1, 523, 524, 525, 526, - -1, 528, 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, 172, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, 316, 317, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, 382, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, 415, -1, 417, 418, 419, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, 452, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, 480, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, -1, 504, -1, -1, -1, -1, 509, 510, - 511, -1, -1, -1, -1, 516, -1, 518, 519, -1, - -1, -1, 523, 524, 525, 526, 3, 4, 5, 6, - 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, - 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, - -1, -1, 39, -1, -1, 42, 43, 44, -1, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, -1, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, - 77, 78, 79, -1, 81, -1, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, - 97, 98, 99, -1, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, -1, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, -1, -1, 134, 135, 136, - 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, - -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, -1, 163, 164, 165, 166, - -1, 168, -1, 170, 171, 172, 173, 174, 175, 176, - 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, - -1, 208, 209, 210, 211, 212, 213, 214, 215, 216, - 217, -1, 219, -1, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, -1, -1, 234, 235, 236, - 237, -1, 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, - -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, - 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, -1, 319, 320, 321, 322, 323, 324, 325, 326, - 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, - 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, - -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, -1, 362, 363, 364, 365, 366, - 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, - 377, 378, 379, 380, 381, 382, -1, 384, 385, 386, - 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, - 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, - 407, 408, 409, 410, 411, 412, 413, 414, 415, -1, - 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, - -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - -1, -1, 449, 450, 451, 452, 453, 454, 455, 456, - -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, - 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, - -1, 478, -1, 480, 481, 482, 483, 484, 485, 486, - 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, - 497, 498, 499, 500, 501, 502, -1, 504, -1, -1, - -1, -1, 509, 510, 511, -1, -1, -1, -1, 516, - -1, 518, -1, -1, -1, -1, 523, 524, 525, 526, - 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, - 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, - 33, -1, -1, -1, -1, -1, 39, -1, -1, 42, - 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, - 73, -1, 75, 76, 77, 78, 79, -1, 81, -1, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, -1, 120, 121, 122, - 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, - -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, - -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, 160, 161, -1, - 163, 164, 165, 166, -1, 168, -1, 170, 171, 172, - 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, - 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, - 203, 204, 205, 206, -1, 208, 209, 210, 211, 212, - 213, 214, 215, 216, 217, -1, 219, -1, 221, 222, - 223, 224, 225, 226, 227, 228, 229, 230, 231, -1, - -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, - 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, 315, 316, 317, -1, 319, 320, 321, 322, - 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, - 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, - 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, - 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, - 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, - -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, - -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, - 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, -1, -1, 417, 418, 419, 420, 421, 422, - 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, - 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, -1, -1, 449, 450, 451, 452, - 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, - 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, - 473, 474, 475, -1, -1, 478, -1, 480, 481, 482, - 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, - 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, - -1, 504, -1, -1, -1, -1, 509, 510, 511, -1, - -1, -1, -1, 516, -1, 518, -1, -1, -1, -1, - 523, 524, 525, 526, 3, 4, 5, 6, 7, 8, + -1, -1, -1, -1, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 3511, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 3565, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, 172, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, 382, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, 415, -1, 417, 418, + 419, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, 452, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, 480, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, -1, 504, -1, -1, -1, -1, + 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, + 519, -1, -1, -1, -1, 524, 525, 526, 527, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, 172, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, 382, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, 415, -1, 417, 418, 419, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, 452, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, 480, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, + 504, -1, -1, -1, -1, 509, 510, 511, -1, -1, + -1, -1, 516, -1, 518, -1, -1, -1, -1, -1, + 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, 172, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, 382, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + 419, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, 452, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, 480, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, -1, 504, -1, -1, -1, -1, + 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, + -1, -1, -1, -1, -1, 524, 525, 526, 527, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + -1, -1, -1, 37, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, 132, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, 383, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, + -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, + -1, -1, 516, -1, 518, 519, -1, -1, -1, -1, + 524, 525, 526, 527, 3, 4, 5, 6, 7, -1, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, + -1, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, 172, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, 382, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, 415, -1, 417, 418, + 419, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, 452, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, 480, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, -1, -1, 504, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 516, -1, 518, + -1, -1, -1, -1, -1, 524, 525, 526, 527, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, + 44, -1, 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, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, 172, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, 233, + 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, 432, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, + -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, + -1, -1, 516, -1, 518, -1, -1, -1, -1, -1, + 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, 37, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, 383, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, + 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, + -1, -1, -1, -1, -1, 524, 525, 526, 527, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, 37, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, 383, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, + -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, + -1, -1, 516, -1, 518, 519, -1, -1, -1, -1, + 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, -1, -1, -1, -1, 38, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, + 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, + -1, -1, -1, -1, -1, 524, 525, 526, 527, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, 37, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, 383, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, + -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, + -1, -1, 516, -1, 518, 519, -1, -1, -1, -1, + 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, 37, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, 383, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, + 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, + -1, -1, -1, -1, -1, 524, 525, 526, 527, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, + -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, + -1, -1, 516, -1, 518, -1, -1, -1, -1, -1, + 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, -1, -1, -1, -1, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, + 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, + -1, -1, -1, -1, -1, 524, 525, 526, 527, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, 172, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, + -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, + -1, -1, 516, -1, 518, -1, -1, -1, -1, -1, + 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, + 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, + 519, -1, -1, -1, -1, 524, 525, 526, 527, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, + -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, + -1, -1, 516, -1, 518, -1, -1, -1, -1, 523, + 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + 419, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, + 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, + -1, -1, -1, -1, -1, 524, 525, 526, 527, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, 477, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, + -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, + -1, -1, 516, -1, 518, -1, -1, -1, -1, -1, + 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, -1, -1, -1, -1, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, + 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, + -1, -1, -1, -1, -1, 524, 525, 526, 527, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, + -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, + -1, -1, 516, -1, 518, -1, -1, -1, -1, 523, + 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, + 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, + -1, -1, -1, -1, -1, 524, 525, 526, 527, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, + -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, + -1, -1, 516, -1, 518, -1, -1, -1, -1, -1, + 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, -1, -1, -1, 37, -1, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, @@ -12888,7 +14073,7 @@ static const yytype_int16 yycheck[] = 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, - 129, 130, 131, 132, -1, 134, 135, 136, 137, 138, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, @@ -12904,294 +14089,34 @@ static const yytype_int16 yycheck[] = 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, -1, 288, - 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, - 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, - 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, - -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, - 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, - 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, - 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, - 379, 380, 381, -1, 383, 384, 385, 386, 387, 388, - 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, - -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, - 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, - -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, - 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, - 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, - 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, - 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, - 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, - -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, - 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, - 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, - 519, -1, -1, -1, 523, 524, 525, 526, 3, 4, - 5, 6, 7, -1, 9, 10, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, - 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, - -1, -1, -1, -1, 39, -1, -1, 42, 43, 44, - -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, - 75, 76, 77, 78, 79, -1, 81, -1, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, - 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, - 125, 126, 127, 128, 129, 130, 131, -1, -1, 134, - 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, - 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160, 161, -1, 163, 164, - 165, 166, -1, 168, -1, 170, 171, 172, 173, 174, - 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, - 185, -1, 187, 188, 189, 190, 191, 192, 193, 194, - 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, - 205, 206, -1, 208, 209, 210, 211, 212, 213, 214, - 215, 216, 217, -1, 219, -1, 221, 222, 223, 224, - 225, 226, 227, 228, 229, 230, 231, -1, -1, 234, - 235, 236, 237, -1, 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, - -1, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, - -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, -1, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, - 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, - 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, - 375, 376, 377, 378, 379, 380, 381, 382, -1, 384, - 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, - 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - 415, -1, 417, 418, 419, 420, 421, 422, 423, 424, - 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, -1, -1, 449, 450, 451, 452, 453, 454, - 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, - 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, - 475, -1, -1, 478, -1, 480, 481, 482, 483, 484, - 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, - 495, 496, 497, 498, 499, 500, 501, -1, -1, 504, - -1, -1, -1, 3, 4, 5, 6, 7, 8, 9, - 10, 516, -1, 518, -1, -1, -1, -1, 523, 524, - 525, 526, 22, 23, 24, 25, 26, 27, 28, 29, - -1, 31, 32, 33, -1, -1, -1, -1, -1, 39, - -1, -1, 42, 43, 44, -1, 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, -1, 75, 76, 77, 78, 79, - -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, - -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, -1, - 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, - 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, - 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, -1, 163, 164, 165, 166, -1, 168, -1, - 170, 171, 172, 173, 174, 175, 176, 177, 178, -1, - 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, - 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, - -1, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, -1, 233, 234, 235, 236, 237, -1, 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, -1, 288, 289, - -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, - 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, - 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, - 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, - 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, - 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, - 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, - 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, - 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, - 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, - 430, -1, 432, 433, 434, 435, 436, 437, 438, 439, - 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, - 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, - 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, - 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, - -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, - 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, 502, -1, -1, -1, -1, -1, -1, 509, - 510, 511, -1, -1, -1, -1, 516, -1, 518, -1, - -1, -1, -1, 523, 524, 525, 526, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, 37, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, 383, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, - 526, 3, 4, 5, 6, 7, 8, 9, 10, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, - 32, 33, -1, -1, -1, 37, -1, 39, -1, -1, - 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, - -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, -1, 120, 121, - 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, - -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, - 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, - -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, - 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, - 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, - 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, - 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, - 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, - 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, - 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - -1, 383, 384, 385, 386, 387, 388, 389, 390, 391, - 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, - 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, - -1, 433, 434, 435, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, - -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, - 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, - 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, - 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, - 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - 502, -1, -1, -1, -1, -1, -1, 509, 510, 511, - -1, -1, -1, -1, 516, -1, 518, 519, -1, -1, - -1, 523, 524, 525, 526, 3, 4, 5, 6, 7, - 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, -1, -1, -1, -1, - 38, 39, -1, -1, 42, 43, 44, -1, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - -1, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, - 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, - 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, - 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, - 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, -1, 163, 164, 165, 166, -1, - 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, - 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, - -1, 219, -1, 221, 222, 223, 224, 225, 226, 227, - 228, 229, 230, 231, -1, -1, 234, 235, 236, 237, - -1, 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, -1, - 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, - 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, - -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, - 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, - 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, - 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, - 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, - 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, - 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, - 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, - 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, - 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, - 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, - -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, - 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, - 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, - 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, - 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, - 498, 499, 500, 501, 502, -1, -1, -1, -1, -1, - -1, 509, 510, 511, -1, -1, -1, -1, 516, -1, - 518, -1, -1, -1, -1, 523, 524, 525, 526, 3, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, + 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, + -1, -1, -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, - -1, -1, -1, 37, -1, 39, -1, -1, 42, 43, + -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, @@ -13225,7 +14150,7 @@ static const yytype_int16 yycheck[] = 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, - 374, 375, 376, 377, 378, 379, 380, 381, -1, 383, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, @@ -13239,217 +14164,165 @@ static const yytype_int16 yycheck[] = 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, - -1, -1, 516, -1, 518, 519, -1, -1, -1, 523, - 524, 525, 526, 3, 4, 5, 6, 7, 8, 9, - 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, - -1, 31, 32, 33, -1, -1, -1, 37, -1, 39, - -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, - -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, - -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, -1, - 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, - 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, - 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, -1, 163, 164, 165, 166, -1, 168, -1, - 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, - 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, - 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, - -1, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, - -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, - 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, - 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, - 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, - 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, - 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, - 380, 381, -1, 383, 384, 385, 386, 387, 388, 389, - 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, - 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, - 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, - 430, -1, -1, 433, 434, 435, 436, 437, 438, 439, - 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, - 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, - 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, - 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, - -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, - 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, 502, -1, -1, -1, -1, -1, -1, 509, - 510, 511, -1, -1, -1, -1, 516, -1, 518, -1, - -1, -1, -1, 523, 524, 525, 526, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, - 526, 3, 4, 5, 6, 7, 8, 9, 10, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, - 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, - -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, -1, 120, 121, - 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, - -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, - 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, - -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, - 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, - 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, - 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, - 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, - 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, - 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, - 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, - 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, - 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, - -1, 433, 434, 435, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, - -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, - 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, - 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, - 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, - 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - 502, -1, -1, -1, -1, -1, -1, 509, 510, 511, - -1, -1, -1, -1, 516, -1, 518, -1, -1, -1, - -1, 523, 524, 525, 526, 3, 4, 5, 6, 7, - 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, - 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, - -1, 39, -1, -1, 42, 43, 44, -1, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - -1, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, - 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, - 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, - 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, - 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, -1, 163, 164, 165, 166, -1, - 168, -1, 170, 171, 172, 173, 174, 175, 176, 177, - 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, - -1, 219, -1, 221, 222, 223, 224, 225, 226, 227, - 228, 229, 230, 231, -1, -1, 234, 235, 236, 237, - -1, 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, -1, - 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, - 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, - -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, - 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, - 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, - 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, - 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, - 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, - 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, - 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, - 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, - 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, - 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, - -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, - 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, - 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, - 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, - 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, - 498, 499, 500, 501, 502, -1, -1, -1, -1, -1, - -1, 509, 510, 511, -1, -1, -1, -1, 516, -1, - 518, -1, -1, -1, -1, 523, 524, 525, 526, 3, + -1, -1, 516, -1, 518, -1, -1, -1, -1, -1, + 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, + 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, + -1, -1, -1, -1, -1, 524, 525, 526, 527, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, + -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, + -1, -1, 516, -1, 518, -1, -1, -1, -1, -1, + 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, + 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, + -1, -1, -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, @@ -13501,217 +14374,60 @@ static const yytype_int16 yycheck[] = 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, - -1, -1, 516, -1, 518, 519, -1, -1, -1, 523, - 524, 525, 526, 3, 4, 5, 6, 7, 8, 9, - 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, - -1, 31, 32, 33, -1, -1, -1, -1, -1, 39, - -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, - -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, - -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, -1, - 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, - 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, - 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, -1, 163, 164, 165, 166, -1, 168, -1, - 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, - 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, - 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, - -1, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, - -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, - 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, - 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, - 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, - 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, - 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, - 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, - 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, - 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, -1, -1, 417, 418, 419, - 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, - 430, -1, -1, 433, 434, 435, 436, 437, 438, 439, - 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, - 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, - 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, - 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, - -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, - 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, 502, -1, -1, -1, -1, -1, -1, 509, - 510, 511, -1, -1, -1, -1, 516, -1, 518, -1, - -1, -1, -1, 523, 524, 525, 526, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, 477, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, - 526, 3, 4, 5, 6, 7, 8, 9, 10, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, - 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, - -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, -1, 120, 121, - 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, - -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, - 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, - -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, - 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, - 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, - 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, - 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, - 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, - 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, - 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, - 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, - 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, - -1, 433, 434, 435, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, - -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, - 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, - 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, - 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, - 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - 502, -1, -1, -1, -1, -1, -1, 509, 510, 511, - -1, -1, -1, -1, 516, -1, 518, -1, -1, -1, - -1, 523, 524, 525, 526, 3, 4, 5, 6, 7, - 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, - 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, - -1, 39, -1, -1, 42, 43, 44, -1, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - -1, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, - 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, - 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, - 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, - 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, -1, 163, 164, 165, 166, -1, - 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, - 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, - -1, 219, -1, 221, 222, 223, 224, 225, 226, 227, - 228, 229, 230, 231, -1, -1, 234, 235, 236, 237, - -1, 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, -1, - 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, - 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, - -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, - 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, - 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, - 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, - 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, - 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, - 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, - 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, - 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, - 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, - 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, - -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, - 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, - 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, - 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, - 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, - 498, 499, 500, 501, 502, -1, -1, -1, -1, -1, - -1, 509, 510, 511, -1, -1, -1, -1, 516, -1, - 518, -1, -1, -1, -1, 523, 524, 525, 526, 3, + -1, -1, 516, -1, 518, -1, -1, -1, -1, -1, + 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, + 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, + -1, -1, -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, @@ -13723,7 +14439,7 @@ static const yytype_int16 yycheck[] = 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, @@ -13739,7 +14455,7 @@ static const yytype_int16 yycheck[] = 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, + 274, -1, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, @@ -13761,220 +14477,63 @@ static const yytype_int16 yycheck[] = 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, - -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, - -1, -1, 516, -1, 518, -1, -1, -1, -1, 523, - 524, 525, 526, 3, 4, 5, 6, 7, 8, 9, - 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, - -1, 31, 32, 33, -1, -1, -1, -1, -1, 39, - -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, - -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, - -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, -1, - 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, - 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, - 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, -1, 163, 164, 165, 166, -1, 168, -1, - 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, - 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, - 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, - -1, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, - -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, - 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, - 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, - 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, - 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, - 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, - 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, - 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, - 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, - 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, - 430, -1, -1, 433, 434, 435, 436, 437, 438, 439, - 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, - 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, - 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, - 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, - -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, - 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, 502, -1, -1, -1, -1, -1, -1, 509, - 510, 511, -1, -1, -1, -1, 516, -1, 518, -1, - -1, -1, -1, 523, 524, 525, 526, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, - 526, 3, 4, 5, 6, 7, 8, 9, 10, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, - 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, - 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, - -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, -1, 120, 121, - 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, - -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, - 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, - -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, - 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, - 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, - 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, - 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, - 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, - 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, - 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, - 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, - 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, - -1, 433, 434, 435, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, - -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, - 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, - 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, - 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, - 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - 502, -1, -1, -1, -1, -1, -1, 509, 510, 511, - -1, -1, -1, -1, 516, -1, 518, -1, -1, -1, - -1, 523, 524, 525, 526, 3, 4, 5, 6, 7, - 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, - 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, - -1, 39, -1, -1, 42, 43, 44, -1, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - -1, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, - 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, - 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, - 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, - 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, -1, 163, 164, 165, 166, -1, - 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, - 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, - -1, 219, -1, 221, 222, 223, 224, 225, 226, 227, - 228, 229, 230, 231, -1, -1, 234, 235, 236, 237, - -1, 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, -1, - 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, - 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, - -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, - 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, - 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, - 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, - 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, - 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, - 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, - 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, - 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, - 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, - 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, - -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, - 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, - 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, - 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, - 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, - 498, 499, 500, 501, 502, -1, -1, -1, -1, -1, - -1, 509, 510, 511, -1, -1, -1, -1, 516, -1, - 518, -1, -1, -1, -1, 523, 524, 525, 526, 3, - 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + 494, 495, 496, 497, 498, 499, 500, 501, -1, -1, + -1, -1, -1, -1, -1, 509, 510, -1, -1, -1, + -1, -1, 516, -1, 518, -1, -1, -1, -1, -1, + 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, -1, -1, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 276, 277, -1, + 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, + 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, + -1, -1, -1, -1, -1, 524, 525, 526, 527, 3, + 4, 5, 6, 7, -1, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, @@ -13985,7 +14544,7 @@ static const yytype_int16 yycheck[] = 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, @@ -14001,7 +14560,7 @@ static const yytype_int16 yycheck[] = 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, + 274, -1, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, @@ -14023,219 +14582,167 @@ static const yytype_int16 yycheck[] = 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, - -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, - -1, -1, 516, -1, 518, -1, -1, -1, -1, 523, - 524, 525, 526, 3, 4, 5, 6, 7, 8, 9, - 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, - -1, 31, 32, 33, -1, -1, -1, -1, -1, 39, - -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, - -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, - -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, -1, - 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, - 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, - 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, -1, 163, 164, 165, 166, -1, 168, -1, - 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, - 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, - 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, - -1, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, - -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, - 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, - 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, - 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, - 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, - 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, - 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, - 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, - 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, - 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, - 430, -1, -1, 433, 434, 435, 436, 437, 438, 439, - 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, - 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, - 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, - 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, - -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, - 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, 502, -1, -1, -1, -1, -1, -1, 509, - 510, 511, -1, -1, -1, -1, 516, -1, 518, -1, - -1, -1, -1, 523, 524, 525, 526, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, - 526, 3, 4, 5, 6, 7, 8, 9, 10, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, - 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, - 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, - -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, - 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, - -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, - 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, - -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, - 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, - 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, 280, 281, - 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, - 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, - 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, - 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, - 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, - 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, - 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, - 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, - -1, 433, 434, 435, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, - -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, - 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, - 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, - 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, - 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - -1, -1, -1, -1, -1, -1, -1, 509, 510, -1, - -1, -1, -1, -1, 516, -1, 518, -1, -1, -1, - -1, 523, 524, 525, 526, 3, 4, 5, 6, 7, - 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, - 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, - -1, 39, -1, -1, 42, 43, 44, -1, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - -1, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, - 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, - 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, - 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, - 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, -1, 163, 164, 165, 166, -1, - 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, - 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, - -1, 219, -1, 221, -1, -1, 224, 225, 226, 227, - 228, 229, 230, 231, -1, -1, 234, 235, 236, 237, - -1, 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, -1, 276, 277, - -1, 279, 280, 281, 282, 283, 284, 285, 286, -1, - 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, - 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, - -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, - 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, - 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, - 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, - 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, - 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, - 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, - 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, - 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, - 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, - 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, - -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, - 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, - 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, - 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, - 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, - 498, 499, 500, 501, 502, -1, -1, -1, -1, -1, - -1, 509, 510, 511, -1, -1, -1, -1, 516, -1, - 518, -1, -1, -1, -1, 523, 524, 525, 526, 3, + 494, 495, 496, 497, 498, 499, 500, 501, -1, -1, + -1, -1, -1, -1, -1, 509, 510, -1, -1, -1, + -1, -1, 516, -1, 518, -1, -1, -1, -1, -1, + 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, -1, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, -1, -1, -1, -1, -1, -1, -1, + 509, 510, -1, -1, -1, -1, -1, 516, -1, 518, + -1, -1, -1, -1, -1, 524, 525, 526, 527, 3, + 4, 5, 6, 7, -1, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, 181, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, 280, 281, 282, 283, + 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 516, -1, 518, -1, -1, -1, -1, -1, + 524, 525, 526, 527, 3, 4, 5, 6, 7, -1, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 516, -1, 518, + -1, -1, -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, 6, 7, -1, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, @@ -14286,10 +14793,112 @@ static const yytype_int16 yycheck[] = 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, -1, -1, - -1, -1, -1, -1, -1, 509, 510, -1, -1, -1, - -1, -1, 516, -1, 518, -1, -1, -1, -1, 523, - 524, 525, 526, 3, 4, 5, 6, 7, 8, 9, - 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 516, -1, 518, -1, -1, -1, -1, -1, + 524, 525, 526, 527, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, -1, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, -1, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, -1, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, -1, -1, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, -1, -1, + 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, -1, 276, 277, -1, + 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, -1, -1, -1, -1, -1, -1, -1, + 509, 510, 511, -1, 3, 4, 5, 516, -1, 518, + 9, -1, -1, -1, -1, 524, 525, 526, 527, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, 37, -1, + -1, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 276, 277, 278, + 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, + 289, 290, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, 383, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, -1, -1, -1, -1, -1, -1, -1, + 509, 510, 511, 3, -1, -1, -1, 516, -1, 518, + 10, -1, -1, -1, -1, -1, -1, -1, 527, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, @@ -14304,19 +14913,19 @@ static const yytype_int16 yycheck[] = 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, -1, 163, 164, 165, 166, -1, 168, -1, + -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, - -1, 221, -1, 223, 224, 225, 226, 227, 228, 229, + -1, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, - 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, + -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, @@ -14331,225 +14940,421 @@ static const yytype_int16 yycheck[] = 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, - 430, -1, -1, 433, 434, 435, 436, 437, 438, 439, + 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, -1, -1, -1, -1, -1, -1, -1, 509, - 510, -1, -1, -1, -1, -1, 516, -1, 518, -1, - -1, -1, -1, 523, 524, 525, 526, 3, 4, 5, - 6, 7, -1, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, 181, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, - 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, - 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, -1, -1, -1, -1, - -1, -1, 3, 4, 5, 6, 7, -1, 9, 10, - 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, - 526, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, -1, -1, -1, -1, -1, -1, 3, 4, 5, - 6, 7, -1, 9, 10, 516, -1, 518, -1, -1, - -1, -1, 523, 524, 525, 526, 22, 23, 24, 25, + 500, 501, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 3, 4, -1, 516, -1, 518, 9, + 10, -1, -1, -1, 524, 525, 526, 527, -1, -1, + -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, + -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, + 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, + 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, + 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, + -1, -1, -1, 83, 84, 85, 86, 87, 88, -1, + 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, + -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, + 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, + 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, + 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, + 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, + 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, + 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, + 200, 201, 202, 203, 204, 205, 206, -1, 208, -1, + 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, + -1, 221, -1, -1, 224, -1, 226, 227, 228, 229, + 230, 231, -1, -1, 234, -1, 236, -1, -1, 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, -1, + 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, + -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, + -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, + -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, + 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, + 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, + 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, + 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, + 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, + 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, + 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, + 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, + 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, + 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, + 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, + 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, + -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, + 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, + 500, 501, -1, -1, -1, -1, -1, 3, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 524, 525, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, + -1, -1, -1, -1, 40, -1, -1, 43, 44, -1, + 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, + 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, + -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, + 76, 77, 78, 79, -1, -1, -1, 83, 84, 85, + 86, 87, 88, -1, 90, 91, 92, -1, 94, 95, + 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, -1, 161, 162, 163, 164, 165, + 166, 167, 168, -1, 170, -1, -1, -1, 174, 175, + 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, + -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 239, 240, 241, 242, 243, 244, 245, + 206, -1, 208, -1, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, -1, 221, -1, -1, 224, -1, + 226, 227, 228, 229, 230, 231, -1, -1, 234, -1, + 236, -1, 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, -1, - 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, - 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 266, 267, 268, -1, 270, 271, 272, 273, 274, -1, + 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, + 286, 287, 288, 289, -1, -1, 292, 293, 294, -1, + 296, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, + -1, -1, -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, + 356, 357, 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, + 386, 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, + -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, + 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, + 446, 447, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, + -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, -1, -1, -1, -1, - -1, -1, 3, 4, 5, 6, 7, 8, 9, 10, - 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, - 526, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, -1, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, -1, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, -1, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, -1, -1, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, -1, -1, 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, -1, 276, 277, -1, 279, 280, - 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, -1, -1, -1, -1, -1, -1, -1, 509, 510, - 511, -1, 3, 4, 5, 516, -1, 518, 9, -1, - -1, -1, 523, 524, 525, 526, -1, -1, -1, -1, + 496, 497, 498, 499, 500, 501, 3, -1, 5, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 519, -1, 22, 23, 24, 25, 26, + 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, + 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, + 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, + 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, + 77, 78, 79, -1, -1, -1, 83, 84, 85, 86, + 87, 88, -1, 90, 91, 92, -1, 94, 95, 96, + 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, + -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, + 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, + -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, + -1, 168, -1, 170, -1, -1, -1, 174, 175, 176, + -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, + 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, + 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, + -1, 208, -1, 210, 211, 212, 213, 214, 215, 216, + 217, -1, 219, -1, 221, -1, -1, 224, -1, 226, + 227, 228, 229, 230, 231, -1, -1, 234, -1, 236, + -1, -1, 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, -1, 270, 271, 272, 273, 274, -1, 276, + 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, + -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, + 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, + -1, -1, 319, 320, 321, -1, 323, 324, 325, 326, + 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, + 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, + -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, -1, 362, 363, -1, 365, 366, + 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, + 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, + 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, + 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, + -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, + 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, + -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, + -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, + 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, + -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, + 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 518, 519, -1, 22, 23, 24, 25, 26, 27, + 28, 29, -1, 31, 32, 33, 34, 35, -1, 37, + -1, -1, -1, -1, 42, 43, 44, -1, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, + 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, + 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, + 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, + 118, -1, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, + 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, + 168, -1, 170, 171, 172, 173, 174, 175, 176, 177, + 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + -1, 219, -1, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, -1, -1, 234, 235, 236, 237, + -1, 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, -1, 276, 277, + 278, 279, -1, 281, 282, 283, 284, 285, 286, -1, + 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, + 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, + 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, + 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, + 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 360, -1, 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, -1, 400, 401, 402, 403, 404, 405, 406, 407, + 408, 409, 410, 411, 412, 413, 414, 415, -1, 417, + 418, 419, 420, 421, 422, 423, 424, 425, 426, -1, + 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, + -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, + -1, 449, 450, 451, 452, 453, 454, 455, 456, -1, + 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, + 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, + 478, -1, 480, 481, 482, 483, 484, 485, 486, 487, + 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, + 498, 499, 500, 501, -1, 3, 504, 5, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 518, -1, -1, -1, 22, 23, 24, 25, 26, 27, + 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, + -1, -1, -1, -1, 42, 43, 44, -1, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + -1, 59, 60, 61, 62, 63, 64, -1, 66, 67, + 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, + 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, + 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, + 118, -1, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, + 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, + 168, -1, 170, 171, 172, 173, 174, 175, 176, 177, + 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + -1, 219, -1, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, 232, -1, 234, 235, 236, 237, + -1, 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, -1, 276, 277, + 278, 279, -1, 281, 282, 283, 284, 285, 286, -1, + 288, 289, -1, 291, 292, 293, 294, -1, -1, 297, + 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, + 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, + 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, + 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, + 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, 382, -1, 384, 385, 386, 387, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, + 408, 409, 410, 411, 412, 413, 414, 415, -1, 417, + 418, 419, 420, 421, 422, 423, 424, 425, 426, -1, + 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, + -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, + -1, 449, 450, 451, 452, 453, 454, 455, 456, -1, + 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, + 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, + 478, -1, 480, 481, 482, 483, 484, 485, 486, 487, + 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, + 498, 499, 500, 501, -1, 3, 504, 5, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 518, -1, -1, -1, 22, 23, 24, 25, 26, 27, + 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, + -1, -1, -1, -1, 42, 43, 44, -1, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + -1, 59, 60, 61, 62, 63, 64, -1, 66, 67, + 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, + 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, + 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, + 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, + 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, + 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, + 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, + 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + -1, 219, -1, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, 232, -1, 234, 235, 236, 237, + -1, 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, -1, 276, 277, + 278, 279, -1, 281, 282, 283, 284, 285, 286, -1, + 288, 289, -1, 291, 292, 293, 294, -1, -1, 297, + 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, + -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, + 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, + 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, + 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, + 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, + 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, + 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, + 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, + 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, + 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, + -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, + -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, + 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, + 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, + 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, + 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, + 498, 499, 500, 501, 3, -1, 5, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 518, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, + -1, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, -1, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, -1, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 276, 277, 278, + 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, + 289, -1, 291, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 518, + -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, + -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, + -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, + 60, 61, 62, 63, 64, -1, 66, 67, 68, 69, + 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, + -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, + -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, + 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, + 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, + 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, + 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, + 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, + 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, + -1, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, + -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, + -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, + 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, + 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, + 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, + 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, + 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, + 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, + 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, + 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, + 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, + 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, + 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, + 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, + 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, + -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, + 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, + 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, 37, -1, -1, -1, + 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, + 61, 62, 63, 64, -1, 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, @@ -14558,7 +15363,7 @@ static const yytype_int16 yycheck[] = 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, @@ -14571,7 +15376,7 @@ static const yytype_int16 yycheck[] = 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, -1, 276, 277, 278, 279, -1, - 281, 282, 283, 284, 285, 286, -1, 288, 289, 290, + 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, @@ -14581,121 +15386,170 @@ static const yytype_int16 yycheck[] = 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, 383, 384, 385, 386, 387, 388, 389, 390, + 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, + -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, -1, -1, -1, -1, -1, -1, 3, 509, 510, - 511, -1, -1, -1, 10, 516, -1, 518, -1, -1, - -1, -1, -1, -1, -1, 526, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, - 276, 277, 278, 279, -1, 281, 282, 283, 284, 285, - 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, -1, -1, -1, -1, - -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, - 526, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, -1, 40, - -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, - 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, - 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - -1, -1, 83, 84, 85, 86, 87, 88, -1, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, - 161, 162, 163, 164, 165, 166, 167, 168, -1, 170, - -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, -1, 210, - 211, 212, 213, 214, 215, 216, 217, 218, 219, -1, - 221, -1, -1, 224, -1, 226, 227, 228, 229, 230, - 231, -1, -1, 234, -1, 236, -1, 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, -1, 270, - 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, - 281, 282, 283, 284, 285, 286, 287, 288, 289, -1, - -1, 292, 293, 294, -1, 296, 297, 298, 299, -1, - 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, - 441, 442, 443, 444, 445, 446, 447, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 519, -1, + 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, + 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, + 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, + 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, + 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, + 72, 73, -1, 75, 76, 77, 78, 79, -1, -1, + -1, 83, 84, 85, 86, 87, 88, -1, 90, 91, + 92, -1, 94, 95, 96, 97, 98, 99, -1, -1, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, + 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, + -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, + 172, -1, 174, 175, 176, -1, 178, -1, 180, -1, + 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, + 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, + 202, 203, 204, 205, 206, -1, 208, -1, 210, 211, + 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, + -1, -1, 224, -1, 226, 227, 228, 229, 230, 231, + -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, + 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, + 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, + 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, + -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, -1, 319, 320, 321, + -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, + 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, + 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, + 382, -1, 384, 385, 386, 387, 388, 389, 390, 391, + 392, 393, -1, 395, 396, 397, 398, -1, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, + 412, 413, 414, 415, -1, 417, 418, 419, 420, -1, + 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, + -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, + 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, + 452, 453, 454, 455, 456, -1, 458, 459, 460, 461, + 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, + 472, 473, 474, 475, -1, -1, 478, -1, 480, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, + -1, 3, 504, 5, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 518, -1, -1, -1, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, + 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, + 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, + 72, 73, -1, 75, 76, 77, 78, 79, -1, -1, + -1, 83, 84, 85, 86, 87, 88, -1, 90, 91, + 92, -1, 94, 95, 96, 97, 98, 99, -1, -1, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, + 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, + -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, + 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, + -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, + 172, -1, 174, 175, 176, -1, 178, -1, 180, -1, + 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, + 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, + 202, 203, 204, 205, 206, -1, 208, -1, 210, 211, + 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, + -1, -1, 224, -1, 226, 227, 228, 229, 230, 231, + -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, + 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, + 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, + 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, + -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, -1, 319, 320, 321, + -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, + 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, + 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, + 382, -1, 384, 385, 386, 387, 388, 389, 390, 391, + 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, + 412, 413, 414, -1, -1, 417, 418, 419, 420, -1, + 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, + -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, + 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, + 452, 453, 454, 455, 456, -1, 458, 459, 460, 461, + 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, + 472, 473, 474, 475, -1, -1, 478, -1, 480, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, + -1, 3, 504, 5, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 518, -1, -1, -1, + 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, + 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, + 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, + 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, + 72, 73, -1, 75, 76, 77, 78, 79, -1, -1, + -1, 83, 84, 85, 86, 87, 88, -1, 90, 91, + 92, -1, 94, 95, 96, 97, 98, 99, -1, -1, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, + 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, + -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, + 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, + -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, + 172, -1, 174, 175, 176, -1, 178, -1, 180, -1, + 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, + 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, + 202, 203, 204, 205, 206, -1, 208, -1, 210, 211, + 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, + -1, -1, 224, -1, 226, 227, 228, 229, 230, 231, + -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, + 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, + 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, + 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, + -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, -1, 319, 320, 321, + -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, + 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, + 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, + 382, -1, 384, 385, 386, 387, 388, 389, 390, 391, + 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, + 412, 413, 414, -1, -1, 417, 418, 419, 420, -1, + 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, + -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, + 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, + 452, 453, 454, 455, 456, -1, 458, 459, 460, 461, + 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, + 472, 473, 474, 475, -1, -1, 478, -1, 480, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, + -1, 3, 504, 5, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 518, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, @@ -14744,256 +15598,156 @@ static const yytype_int16 yycheck[] = 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 518, 519, -1, 22, + 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, - 33, 34, 35, -1, 37, -1, -1, -1, -1, 42, - 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, + 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, + 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, - 73, -1, 75, 76, 77, 78, 79, -1, 81, -1, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, - 123, 124, 125, 126, 127, 128, 129, 130, 131, -1, - -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, - -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, - 163, 164, 165, 166, -1, 168, -1, 170, 171, 172, - 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, - 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, - 203, 204, 205, 206, -1, 208, 209, 210, 211, 212, - 213, 214, 215, 216, 217, -1, 219, -1, 221, 222, - 223, 224, 225, 226, 227, 228, 229, 230, 231, -1, - -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, -1, 281, 282, - 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, - 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, 315, 316, 317, -1, 319, 320, 321, 322, - 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, - 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, - 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, -1, 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, -1, 400, 401, 402, - 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, 415, -1, 417, 418, 419, 420, 421, 422, - 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, - 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, - 443, 444, 445, 446, -1, -1, 449, 450, 451, 452, - 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, - 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, - 473, 474, 475, -1, -1, 478, -1, 480, 481, 482, - 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, - 493, 494, 495, 496, 497, 498, 499, 500, 501, -1, - 3, 504, 5, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 518, -1, -1, -1, 22, - 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, - 33, -1, -1, -1, -1, -1, -1, -1, -1, 42, - 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, - 63, 64, -1, 66, 67, 68, 69, 70, 71, 72, - 73, -1, 75, 76, 77, 78, 79, -1, 81, -1, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, - 123, 124, 125, 126, 127, 128, 129, 130, 131, -1, - -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, - -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, - 163, 164, 165, 166, -1, 168, -1, 170, 171, 172, - 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, - 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, - 203, 204, 205, 206, -1, 208, 209, 210, 211, 212, - 213, 214, 215, 216, 217, -1, 219, -1, 221, 222, - 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, - -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, -1, 281, 282, - 283, 284, 285, 286, -1, 288, 289, -1, 291, 292, - 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, 315, 316, 317, -1, 319, 320, 321, 322, - 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, - 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, - 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, - 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, - 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, - -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, -1, 400, 401, 402, - 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, 415, -1, 417, 418, 419, 420, 421, 422, - 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, - 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, - 443, 444, 445, 446, -1, -1, 449, 450, 451, 452, - 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, - 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, - 473, 474, 475, -1, -1, 478, -1, 480, 481, 482, - 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, - 493, 494, 495, 496, 497, 498, 499, 500, 501, -1, - 3, 504, 5, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 518, -1, -1, -1, 22, - 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, - 33, -1, -1, -1, -1, -1, -1, -1, -1, 42, - 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, - 63, 64, -1, 66, 67, 68, 69, 70, 71, 72, - 73, -1, 75, 76, 77, 78, 79, -1, 81, -1, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, + 73, -1, 75, 76, 77, 78, 79, -1, -1, -1, + 83, 84, 85, 86, 87, 88, -1, 90, 91, 92, + -1, 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, - 163, 164, 165, 166, -1, 168, -1, 170, 171, -1, - 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, + 163, 164, 165, 166, -1, 168, -1, 170, -1, -1, + -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, - 203, 204, 205, 206, -1, 208, 209, 210, 211, 212, - 213, 214, 215, 216, 217, -1, 219, -1, 221, 222, - 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, - -1, 234, 235, 236, 237, -1, 239, 240, 241, 242, + 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, + 203, 204, 205, 206, -1, 208, -1, 210, 211, 212, + 213, 214, 215, 216, 217, -1, 219, -1, 221, -1, + -1, 224, -1, 226, 227, 228, 229, 230, 231, -1, + -1, 234, -1, 236, -1, -1, 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, -1, 276, 277, 278, 279, -1, 281, 282, - 283, 284, 285, 286, -1, 288, 289, -1, 291, 292, - 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, + 263, 264, 265, 266, 267, 268, -1, 270, 271, 272, + 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, + 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, + 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, -1, -1, -1, -1, 319, 320, 321, 322, + 313, 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, - 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, + 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, - -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, + -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, -1, -1, 417, 418, -1, 420, 421, 422, + 413, 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, - 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, + 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, - -1, -1, -1, -1, -1, -1, -1, -1, 42, 43, - 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, - 64, -1, 66, 67, 68, 69, 70, 71, 72, 73, - -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, - 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, + 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, + 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, + 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, -1, -1, 83, + 84, 85, 86, 87, 88, -1, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, - 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, - 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 164, 165, 166, -1, 168, -1, 170, -1, -1, -1, + 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, - 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, - 234, 235, 236, 237, -1, 239, 240, 241, 242, 243, + -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, -1, -1, + 224, -1, 226, 227, 228, 229, 230, 231, -1, -1, + 234, -1, 236, -1, -1, 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, -1, 276, 277, 278, 279, -1, 281, 282, 283, + 264, 265, 266, 267, 268, -1, 270, 271, 272, 273, + 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, - 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, - 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, - 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, - 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, - 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, - -1, -1, -1, -1, -1, -1, -1, 42, 43, 44, - -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, - -1, 66, 67, 68, 69, 70, 71, 72, 73, -1, - 75, 76, 77, 78, 79, -1, 81, -1, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, - 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, + -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, + -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, + -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, + -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, + 75, 76, 77, 78, 79, -1, -1, -1, 83, 84, + 85, 86, 87, 88, -1, 90, 91, 92, -1, 94, + 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, - 165, 166, -1, 168, -1, 170, 171, -1, 173, 174, - 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, - 185, -1, 187, 188, 189, 190, 191, 192, 193, 194, + 165, 166, -1, 168, -1, 170, -1, -1, -1, 174, + 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, + 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, - 205, 206, -1, 208, 209, 210, 211, 212, 213, 214, - 215, 216, 217, -1, 219, -1, 221, 222, 223, 224, - 225, 226, 227, 228, 229, 230, 231, -1, -1, 234, - 235, 236, 237, -1, 239, 240, 241, 242, 243, 244, + 205, 206, -1, 208, -1, 210, 211, 212, 213, 214, + 215, 216, 217, -1, 219, -1, 221, -1, -1, 224, + -1, 226, 227, 228, 229, 230, 231, -1, -1, 234, + -1, 236, -1, -1, 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, - -1, 276, 277, 278, 279, -1, 281, 282, 283, 284, + 265, 266, 267, 268, -1, 270, 271, 272, 273, 274, + -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, - -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, + -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - -1, -1, -1, -1, 319, 320, 321, 322, 323, 324, + -1, -1, -1, -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, + 355, 356, 357, 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, - 385, 386, 387, 388, 389, 390, 391, 392, -1, 394, + 385, 386, 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - -1, -1, 417, 418, -1, 420, 421, 422, 423, 424, + -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, - 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, + 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, - 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, + 495, 496, 497, 498, 499, 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, @@ -15006,11 +15760,11 @@ static const yytype_int16 yycheck[] = 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, -1, -1, 134, 135, + -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, -1, 172, -1, 174, 175, + 166, -1, 168, -1, 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, @@ -15024,29 +15778,29 @@ static const yytype_int16 yycheck[] = 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, -1, 319, 320, 321, -1, 323, 324, 325, + 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, + -1, -1, -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, 382, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, 393, -1, 395, + 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, + 386, 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, - -1, 417, 418, 419, 420, -1, 422, 423, 424, 425, + 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, + -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, 452, 453, 454, 455, + 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, 480, 481, 482, 483, 484, 485, + -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 3, -1, 504, -1, + 496, 497, 498, 499, 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, -1, -1, -1, + 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, @@ -15060,7 +15814,7 @@ static const yytype_int16 yycheck[] = 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, - -1, 168, -1, 170, -1, 172, -1, 174, 175, 176, + -1, 168, -1, 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, @@ -15074,26 +15828,26 @@ static const yytype_int16 yycheck[] = 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, -1, 319, 320, 321, -1, 323, 324, 325, 326, + 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, + -1, -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, - 377, 378, 379, 380, 381, 382, -1, 384, 385, 386, + 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, - 417, 418, 419, 420, -1, 422, 423, 424, 425, 426, + 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, - -1, -1, 449, 450, 451, 452, 453, 454, 455, 456, + -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, - -1, 478, -1, 480, 481, 482, 483, 484, 485, 486, + -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, - 497, 498, 499, 500, 501, 3, -1, 504, -1, -1, + 497, 498, 499, 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, @@ -15110,56 +15864,6 @@ static const yytype_int16 yycheck[] = 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, - 168, -1, 170, -1, 172, -1, 174, 175, 176, -1, - 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, - 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, - 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, - 208, -1, 210, 211, 212, 213, 214, 215, 216, 217, - -1, 219, -1, 221, -1, -1, 224, -1, 226, 227, - 228, 229, 230, 231, -1, -1, 234, -1, 236, -1, - -1, 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, -1, 270, 271, 272, 273, 274, -1, 276, 277, - -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, - 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, - 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, - 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, - 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, - 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, - 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, - 378, 379, 380, 381, 382, -1, 384, 385, 386, 387, - 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, - 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, - 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, - 418, 419, 420, -1, 422, 423, 424, 425, 426, -1, - 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, - -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, - -1, 449, 450, 451, 452, 453, 454, 455, 456, -1, - 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, - -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, - 478, -1, 480, 481, 482, 483, 484, 485, 486, 487, - 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, - 498, 499, 500, 501, -1, 3, 504, 5, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 518, -1, -1, -1, 22, 23, 24, 25, 26, 27, - 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, - 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, - -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, - 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, - 78, 79, -1, -1, -1, 83, 84, 85, 86, 87, - 88, -1, 90, 91, 92, -1, 94, 95, 96, 97, - 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, - 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, - 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, - 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, @@ -15243,7 +15947,7 @@ static const yytype_int16 yycheck[] = 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 499, 500, 501, 3, -1, 5, -1, -1, -1, -1, + 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, @@ -15293,7 +15997,7 @@ static const yytype_int16 yycheck[] = 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, + 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, @@ -15331,320 +16035,289 @@ static const yytype_int16 yycheck[] = 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, - 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, - 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, - 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, - 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, - 72, 73, -1, 75, 76, 77, 78, 79, -1, -1, - -1, 83, 84, 85, 86, 87, 88, -1, 90, 91, - 92, -1, 94, 95, 96, 97, 98, 99, -1, -1, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, - 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, - -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, - 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, - -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, - -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, - 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, - 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, - 202, 203, 204, 205, 206, -1, 208, -1, 210, 211, - 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, - -1, -1, 224, -1, 226, 227, 228, 229, 230, 231, - -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, - 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, - 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, - 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, - -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, - -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, - 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, - 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, - 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, - 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, -1, -1, 417, 418, -1, 420, -1, - 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, - -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, - 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, - -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, - 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, - 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, - 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, - 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, - 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, - 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, - 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, - 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, - 73, -1, 75, 76, 77, 78, 79, -1, -1, -1, - 83, 84, 85, 86, 87, 88, -1, 90, 91, 92, - -1, 94, 95, 96, 97, 98, 99, -1, -1, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, - 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, - -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, - -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, - 163, 164, 165, 166, -1, 168, -1, 170, -1, -1, - -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, - 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, - 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, - 203, 204, 205, 206, -1, 208, -1, 210, 211, 212, - 213, 214, 215, 216, 217, -1, 219, -1, 221, -1, - -1, 224, -1, 226, 227, 228, 229, 230, 231, -1, - -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, - 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, - 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, - 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, -1, -1, -1, -1, 319, 320, 321, -1, - 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, - 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, - 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, - 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, - 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, - -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, - -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, - 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, -1, -1, 417, 418, -1, 420, -1, 422, - 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, - 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, - 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, - 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, - 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, - 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, - 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, - 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, + 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, + 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, + 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, + 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, + -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, + -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, + 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, + 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, + 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, + 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, + 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, + 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, + 501, -1, 3, 4, 5, -1, -1, 8, 9, -1, + -1, -1, -1, -1, 15, 16, -1, 518, 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, -1, 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, -1, 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, -1, 153, 154, 155, 156, 157, 158, -1, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, -1, -1, 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, -1, + 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, + -1, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, -1, 300, + 301, 302, -1, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + -1, 322, 323, 324, -1, 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, -1, 415, 416, 417, 418, 419, 420, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, + 431, 432, 433, 434, -1, 436, -1, 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, -1, 464, 465, 466, 467, 468, 469, 470, + 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, + 481, 482, 483, 484, 485, 486, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 498, 499, 500, + 501, -1, 3, -1, 505, 506, 507, 8, 509, 510, + 511, 512, 513, 514, 15, 16, -1, -1, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, -1, + 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, + 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, + 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, + 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, + -1, -1, 83, 84, 85, 86, 87, 88, -1, 90, + 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, + -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, + 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, + 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, + 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, + 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, + -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, + -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, + 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, + 201, 202, 203, 204, 205, 206, -1, 208, -1, 210, + 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, + 221, -1, -1, 224, -1, 226, 227, 228, 229, 230, + 231, -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, + 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, + 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, + -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, + 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, + 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, + 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, + 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, + 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, + 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, + 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, + -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, + -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, + 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, + 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, + 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, + 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, + 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, + 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, + 501, -1, -1, -1, 505, 506, 507, -1, 509, 510, + 511, 512, 513, 514, 8, -1, -1, 11, -1, -1, + -1, 15, 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 518, -1, -1, 22, 23, - 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, - 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, - 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, - 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, - -1, 75, 76, 77, 78, 79, -1, -1, -1, 83, - 84, 85, 86, 87, 88, -1, 90, 91, 92, -1, - 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, - 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, - 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, - 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, - 164, 165, 166, -1, 168, -1, 170, -1, -1, -1, - 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, - 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, - -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, - 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, - 214, 215, 216, 217, -1, 219, -1, 221, -1, -1, - 224, -1, 226, 227, 228, 229, 230, 231, -1, -1, - 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, - 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, - 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, - 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, - 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, - 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, - 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, - -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, - 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, - 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, - -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, - 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, - 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, - 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, - 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, - 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, - 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, - 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, - 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, - 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, + -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 46, 8, -1, -1, 11, -1, -1, 53, + 15, 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, - 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, - -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, - -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, - -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, - 75, 76, 77, 78, 79, -1, -1, -1, 83, 84, - 85, 86, 87, 88, -1, 90, 91, 92, -1, 94, - 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, + -1, 36, -1, -1, -1, -1, 80, -1, -1, -1, + -1, 46, 8, -1, -1, 11, -1, -1, 53, 15, + 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 36, -1, -1, -1, -1, 80, -1, -1, -1, -1, + 46, -1, -1, -1, -1, -1, -1, 53, -1, -1, + 8, -1, -1, 11, -1, -1, -1, 15, 16, 17, + 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 80, -1, -1, -1, 36, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 46, 8, + -1, -1, 11, 177, -1, 53, 15, 16, 17, 18, + 19, 20, 21, -1, -1, -1, -1, -1, -1, -1, + 194, -1, -1, -1, -1, 199, -1, 36, -1, -1, + -1, -1, 80, -1, -1, -1, -1, 46, -1, -1, + -1, -1, 177, -1, 53, -1, -1, -1, 222, 223, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, + -1, -1, -1, 237, 199, -1, -1, -1, -1, -1, + -1, 80, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 177, -1, -1, -1, -1, -1, 222, 223, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 194, -1, + -1, 275, 237, 199, 278, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 292, -1, + -1, 295, -1, -1, -1, -1, 222, 223, -1, 177, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 275, 237, -1, 278, -1, -1, 194, -1, -1, -1, + -1, 199, -1, -1, -1, -1, -1, 292, -1, -1, + 295, -1, -1, -1, -1, -1, -1, -1, 177, -1, + -1, -1, -1, -1, 222, 223, -1, -1, -1, 275, + -1, -1, 278, -1, -1, 194, -1, -1, -1, 237, + 199, -1, -1, -1, -1, -1, 292, -1, -1, 295, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 222, 223, -1, -1, -1, -1, -1, + 394, -1, -1, -1, -1, -1, -1, 275, 237, -1, + 278, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 292, -1, -1, 295, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 394, + -1, -1, -1, -1, -1, -1, 275, -1, -1, 278, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 292, -1, -1, 295, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 394, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 502, -1, + -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, + 514, -1, -1, -1, -1, 519, 394, -1, -1, -1, + -1, -1, 8, -1, -1, 11, -1, -1, -1, 15, + 16, 17, 18, 19, 20, 21, -1, 502, -1, -1, + 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, + 36, -1, -1, -1, 519, 394, -1, -1, 8, -1, + 46, 11, -1, -1, -1, 15, 16, 53, -1, 19, + 20, 21, -1, -1, -1, -1, 502, -1, -1, 505, + 506, 507, -1, 509, 510, 511, 512, 513, 514, -1, + -1, -1, -1, 519, 80, -1, 46, -1, -1, -1, + -1, -1, -1, 53, -1, -1, -1, -1, -1, 8, + -1, -1, 11, -1, -1, -1, 15, 16, 17, 18, + 19, 20, 21, -1, 502, -1, -1, 505, 506, 507, + 80, 509, 510, 511, 512, 513, 514, 36, -1, -1, + -1, 519, -1, -1, -1, -1, -1, 46, 8, -1, + -1, 11, -1, -1, 53, 15, 16, 17, 18, 19, + 20, 21, -1, 502, -1, -1, 505, 506, 507, -1, + 509, 510, 511, 512, 513, 514, 36, -1, -1, -1, + 519, 80, -1, -1, -1, -1, 46, 8, -1, -1, + 11, 177, -1, 53, 15, 16, 17, 18, 19, 20, + 21, -1, -1, -1, -1, -1, -1, -1, 194, -1, + -1, -1, -1, 199, -1, 36, -1, -1, -1, -1, + 80, -1, -1, -1, -1, 46, -1, 177, -1, -1, + -1, -1, 53, -1, -1, -1, 222, 223, -1, -1, + -1, -1, -1, -1, 194, -1, -1, -1, -1, 199, + -1, 237, -1, -1, -1, -1, -1, -1, -1, 80, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 222, 223, -1, -1, -1, -1, 177, -1, + -1, -1, -1, -1, -1, -1, -1, 237, -1, 275, + -1, -1, 278, -1, -1, 194, -1, -1, -1, -1, + 199, -1, -1, -1, -1, -1, 292, -1, -1, 295, + -1, -1, -1, -1, -1, -1, -1, 177, -1, -1, + -1, -1, -1, 222, 223, 275, -1, -1, 278, -1, + -1, -1, -1, -1, 194, -1, -1, -1, 237, 199, + -1, -1, 292, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 177, -1, -1, -1, + -1, -1, 222, 223, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 194, -1, -1, 275, 237, 199, 278, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 292, -1, -1, 295, -1, -1, -1, + -1, 222, 223, -1, -1, -1, -1, -1, 394, -1, + -1, -1, -1, -1, -1, 275, 237, -1, 278, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 292, -1, -1, 295, -1, -1, -1, -1, + -1, -1, -1, -1, 394, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 275, -1, -1, 278, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 292, -1, -1, 295, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 394, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 502, -1, -1, 505, + 506, 507, -1, 509, 510, 511, 512, 513, 514, -1, + -1, 517, -1, -1, 394, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 502, -1, -1, 505, 506, 507, -1, 509, + 510, 511, 512, 513, 514, -1, -1, -1, -1, -1, + -1, -1, -1, 394, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 502, -1, -1, 505, 506, 507, -1, + 509, 510, 511, 512, 513, 514, -1, -1, 517, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 502, -1, -1, 505, 506, 507, -1, 509, + 510, 511, 512, 513, 514, -1, -1, 517, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 3, -1, + -1, 502, -1, -1, 505, 506, 507, -1, 509, 510, + 511, 512, 513, 514, -1, -1, 517, 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, + 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, -1, 118, -1, 120, 121, 122, 123, 124, - 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, - 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, - 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, - 165, 166, -1, 168, -1, 170, -1, -1, -1, 174, - 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, - 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, - 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, - 205, 206, -1, 208, -1, 210, 211, 212, 213, 214, - 215, 216, 217, -1, 219, -1, 221, -1, -1, 224, - -1, 226, 227, 228, 229, 230, 231, -1, -1, 234, - -1, 236, -1, -1, 239, 240, 241, 242, 243, 244, + 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, -1, 270, 271, 272, 273, 274, - -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, - 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, - -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, + 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, - -1, -1, -1, -1, 319, 320, 321, -1, 323, 324, - 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, - 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, -1, 362, 363, -1, - 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, - 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, - 385, 386, 387, 388, 389, 390, 391, 392, -1, -1, - 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, + 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, - -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, - 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, - 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, - 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, - 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, - 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, - 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, + 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, 3, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 518, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, - 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, - 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, - -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, -1, -1, 83, 84, 85, - 86, 87, 88, -1, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, -1, -1, -1, 174, 175, - 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, -1, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, -1, -1, 224, -1, - 226, 227, 228, 229, 230, 231, -1, -1, 234, -1, - 236, -1, -1, 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, -1, 270, 271, 272, 273, 274, -1, - 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, - 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, -1, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, -1, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, -1, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, -1, 3, 4, 5, - -1, -1, 8, 9, -1, -1, -1, -1, -1, 15, - 16, -1, 518, 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, -1, 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, -1, 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, -1, 153, 154, 155, - 156, 157, 158, -1, 160, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, -1, -1, 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, -1, 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, -1, 282, 283, 284, 285, - 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, - 296, 297, 298, -1, 300, 301, 302, -1, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, -1, 322, 323, 324, -1, - 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, -1, 415, - 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 430, 431, 432, 433, 434, -1, - 436, -1, 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, -1, 464, 465, - 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, - 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, - 486, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 498, 499, 500, 501, -1, 3, -1, 505, - 506, 507, 8, 509, 510, 511, 512, 513, 514, 15, - 16, -1, -1, 19, 20, 21, 22, 23, 24, 25, + -1, -1, -1, -1, -1, -1, 511, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, @@ -15692,561 +16365,498 @@ static const yytype_int16 yycheck[] = -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, -1, -1, -1, 505, - 506, 507, -1, 509, 510, 511, 512, 513, 514, 8, - -1, -1, 11, -1, -1, -1, 15, 16, 17, 18, - 19, 20, 21, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 36, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 46, 8, -1, - -1, 11, -1, -1, 53, 15, 16, 17, 18, 19, - 20, 21, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 36, -1, -1, -1, - -1, 80, -1, -1, -1, -1, 46, 8, -1, -1, - 11, -1, -1, 53, 15, 16, 17, 18, 19, 20, - 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 36, -1, -1, -1, -1, - 80, -1, -1, -1, -1, 46, -1, -1, -1, -1, - -1, -1, 53, -1, -1, 8, -1, -1, 11, -1, - -1, -1, 15, 16, 17, 18, 19, 20, 21, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, - -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 46, 8, -1, -1, 11, 177, -1, - 53, 15, 16, 17, 18, 19, 20, 21, -1, -1, - -1, -1, -1, -1, -1, 194, -1, -1, -1, -1, - 199, -1, 36, -1, -1, -1, -1, 80, -1, -1, - -1, -1, 46, -1, -1, -1, -1, 177, -1, 53, - -1, -1, -1, 222, 223, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 194, -1, -1, -1, 237, 199, - -1, -1, -1, -1, -1, -1, 80, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 177, -1, -1, -1, - -1, -1, 222, 223, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 194, -1, -1, 275, 237, 199, 278, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 292, -1, -1, 295, -1, -1, -1, - -1, 222, 223, -1, 177, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 275, 237, -1, 278, -1, - -1, 194, -1, -1, -1, -1, 199, -1, -1, -1, - -1, -1, 292, -1, -1, 295, -1, -1, -1, -1, - -1, -1, -1, 177, -1, -1, -1, -1, -1, 222, - 223, -1, -1, -1, 275, -1, -1, 278, -1, -1, - 194, -1, -1, -1, 237, 199, -1, -1, -1, -1, - -1, 292, -1, -1, 295, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 222, 223, - -1, -1, -1, -1, -1, 394, -1, -1, -1, -1, - -1, -1, 275, 237, -1, 278, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 292, - -1, -1, 295, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 394, -1, -1, -1, -1, -1, - -1, 275, -1, -1, 278, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 292, -1, - -1, 295, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 394, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 502, -1, -1, 505, 506, 507, -1, - 509, 510, 511, 512, 513, 514, -1, -1, -1, -1, - 519, 394, -1, -1, -1, -1, -1, 8, -1, -1, - 11, -1, -1, -1, 15, 16, 17, 18, 19, 20, - 21, -1, 502, -1, -1, 505, 506, 507, -1, 509, - 510, 511, 512, 513, 514, 36, -1, -1, -1, 519, - 394, -1, -1, -1, -1, 46, -1, -1, -1, -1, - -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, - -1, 502, -1, -1, 505, 506, 507, -1, 509, 510, - 511, 512, 513, 514, -1, -1, -1, -1, 519, 80, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 8, -1, -1, 11, -1, -1, - -1, 15, 16, 17, 18, 19, 20, 21, -1, 502, - -1, -1, 505, 506, 507, -1, 509, 510, 511, 512, - 513, 514, 36, -1, -1, -1, 519, -1, -1, -1, - -1, -1, 46, 8, -1, -1, 11, -1, -1, 53, - 15, 16, 17, 18, 19, 20, 21, -1, 502, -1, - -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, - 514, 36, -1, -1, -1, 519, 80, -1, -1, -1, - -1, 46, 8, -1, -1, 11, 177, -1, 53, 15, - 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, - -1, -1, -1, 194, -1, -1, -1, -1, 199, -1, - 36, -1, -1, -1, -1, 80, -1, -1, -1, -1, - 46, -1, -1, -1, -1, -1, -1, 53, -1, -1, - -1, 222, 223, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 237, -1, -1, -1, - -1, -1, -1, -1, 80, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, - -1, -1, 11, 177, -1, -1, 15, 16, 17, 18, - 19, 20, 21, -1, 275, -1, -1, 278, -1, -1, - 194, -1, -1, -1, -1, 199, -1, 36, -1, -1, - -1, 292, -1, -1, 295, -1, -1, 46, -1, -1, - -1, -1, 177, -1, 53, -1, -1, -1, 222, 223, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, - -1, -1, -1, 237, 199, -1, -1, -1, -1, -1, - -1, 80, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 177, -1, -1, -1, -1, -1, 222, 223, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 194, -1, - -1, 275, 237, 199, 278, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 292, -1, - -1, 295, -1, -1, -1, -1, 222, 223, -1, -1, - -1, -1, -1, 394, -1, -1, -1, -1, -1, -1, - 275, 237, -1, 278, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 292, -1, -1, - 295, -1, -1, -1, -1, -1, -1, -1, 177, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 275, - -1, -1, 278, -1, -1, 194, -1, -1, -1, -1, - 199, -1, -1, -1, -1, -1, 292, -1, -1, 295, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 222, 223, -1, -1, -1, -1, -1, - 394, -1, -1, -1, -1, -1, -1, -1, 237, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 502, -1, -1, 505, 506, 507, -1, 509, 510, - 511, 512, 513, 514, -1, -1, -1, -1, 519, 394, - -1, -1, -1, -1, -1, -1, 275, -1, -1, 278, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 68, 69, 292, -1, -1, 295, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 8, -1, 394, 11, - -1, -1, -1, 15, 16, 17, 18, 19, 20, 21, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 109, 110, 36, -1, 113, 114, 502, -1, - -1, 505, 506, 507, 46, 509, 510, 511, 512, 513, - 514, 53, -1, -1, -1, 519, -1, -1, -1, -1, - -1, -1, -1, 8, -1, -1, 11, -1, -1, -1, - 15, 16, 17, 18, 19, 20, 21, 502, 80, -1, - 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, - -1, 36, -1, -1, 519, 394, -1, -1, -1, -1, - -1, 46, -1, -1, -1, -1, -1, -1, 53, -1, - -1, -1, 189, 190, -1, -1, 502, -1, -1, 505, - 506, 507, -1, 509, 510, 511, 512, 513, 514, -1, - -1, 517, -1, -1, -1, 80, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 177, 253, 254, 255, 256, - 257, 258, 259, 260, -1, -1, 263, 264, -1, -1, - -1, -1, 194, -1, -1, -1, -1, 199, -1, -1, - -1, -1, -1, 502, -1, -1, 505, 506, 507, -1, - 509, 510, 511, 512, 513, 514, -1, -1, 517, -1, - 222, 223, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 177, -1, -1, 237, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, - -1, -1, -1, -1, 199, -1, -1, -1, -1, -1, - 337, 338, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 275, -1, -1, 278, 222, 223, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 292, -1, 237, 295, -1, -1, -1, -1, -1, -1, - -1, 378, 379, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 275, -1, -1, 278, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 292, -1, -1, - 295, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 394, -1, -1, -1, -1, 474, 475, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 498, 499, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 518, -1, -1, -1, -1, -1, -1, -1, 394, + 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, + -1, -1, -1, -1, -1, 511, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, + 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, + 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, + 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, + 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, + 77, 78, 79, -1, -1, -1, 83, 84, 85, 86, + 87, 88, -1, 90, 91, 92, -1, 94, 95, 96, + 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, + -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, + 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, + -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, + -1, 168, -1, 170, -1, -1, -1, 174, 175, 176, + -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, + 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, + 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, + -1, 208, -1, 210, 211, 212, 213, 214, 215, 216, + 217, -1, 219, -1, 221, -1, -1, 224, -1, 226, + 227, 228, 229, 230, 231, -1, -1, 234, -1, 236, + -1, -1, 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, -1, 270, 271, 272, 273, 274, -1, 276, + 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, + -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, + 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, + -1, -1, 319, 320, 321, -1, 323, 324, 325, 326, + 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, + 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, + -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, -1, 362, 363, -1, 365, 366, + 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, + 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, + 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, + 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, + -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, + 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, + -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, + -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, + 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, + -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, + 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 499, 500, 501, 3, 4, 5, -1, -1, + -1, 9, -1, -1, 511, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, + 28, 29, -1, 31, 32, 33, -1, -1, -1, 37, + -1, -1, -1, -1, 42, 43, 44, -1, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, + 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, + 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, + 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, + 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, + 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, + 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, -1, 163, 164, 165, 166, -1, + 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, + 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + -1, 219, -1, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, -1, -1, 234, 235, 236, 237, + -1, 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, -1, 276, 277, + 278, 279, -1, 281, 282, 283, 284, 285, 286, -1, + 288, 289, 290, -1, 292, 293, 294, -1, -1, 297, + 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, + -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, + 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, + 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, + 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, + 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, -1, 383, 384, 385, 386, 387, + 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, + 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, + 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, + 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, + 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, + -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, + 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, + 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, + 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, + 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, + 498, 499, 500, 501, -1, -1, 8, -1, -1, 11, + -1, 509, 510, 15, 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 36, -1, -1, -1, -1, 41, + -1, -1, -1, -1, 46, 8, -1, -1, 11, -1, + -1, 53, 15, 16, 17, 18, 19, 20, 21, -1, + -1, -1, -1, 8, -1, -1, 11, -1, -1, -1, + 15, 16, -1, 36, 19, 20, 21, -1, 80, -1, + -1, -1, -1, 46, 8, -1, -1, 11, -1, -1, + 53, 15, 16, 17, 18, 19, 20, 21, -1, -1, + -1, 46, -1, -1, -1, -1, -1, -1, 53, -1, + -1, -1, 36, -1, -1, -1, -1, 80, -1, -1, + -1, -1, 46, -1, 126, -1, -1, -1, -1, 53, + -1, 8, -1, -1, 11, 80, -1, -1, 15, 16, + 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 80, -1, -1, 36, + -1, -1, -1, 40, -1, -1, -1, -1, -1, 46, + -1, -1, -1, -1, -1, 177, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 194, -1, -1, -1, -1, 199, -1, -1, + -1, -1, -1, 80, 167, -1, -1, -1, -1, 172, + -1, -1, -1, -1, 177, -1, -1, -1, -1, -1, + 222, 223, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 194, 177, -1, -1, 237, 199, -1, -1, -1, + -1, -1, 166, -1, -1, -1, -1, -1, -1, 194, + -1, -1, -1, 177, 199, -1, -1, -1, -1, 222, + 223, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 194, -1, -1, 275, 237, 199, 278, 222, 223, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 292, -1, 237, 295, -1, -1, -1, -1, 222, 223, + 177, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 275, 237, -1, 278, -1, 194, -1, -1, + -1, -1, 199, -1, -1, -1, -1, -1, -1, 292, + -1, -1, 295, 278, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 222, 223, 292, -1, -1, + -1, 275, -1, -1, 278, -1, -1, -1, -1, -1, + 237, -1, -1, -1, -1, -1, -1, -1, 292, -1, + -1, 295, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 394, -1, -1, -1, -1, -1, 275, -1, + 324, 278, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 292, -1, -1, 295, -1, + -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, + -1, 394, -1, 15, 16, 17, 18, 19, 20, 21, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 394, + -1, -1, -1, -1, 36, 457, -1, -1, -1, -1, + -1, -1, -1, -1, 46, -1, -1, -1, -1, -1, + 394, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 80, -1, 502, -1, -1, 505, 506, 507, -1, 509, 510, 511, - 512, 513, 514, -1, -1, 517, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 512, 513, 514, -1, -1, -1, -1, 394, -1, -1, -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, 502, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 502, + -1, -1, 505, 506, 507, -1, 509, 510, 511, 512, + 513, 514, -1, -1, -1, -1, -1, 502, -1, -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, - -1, -1, 517, 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, 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, 3, -1, -1, -1, -1, -1, -1, - -1, -1, 511, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, - -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, - 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, - 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, - 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, - -1, -1, -1, 83, 84, 85, 86, 87, 88, -1, - 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, - -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, - 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, - 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, - 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, - 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, - 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, - 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, - 200, 201, 202, 203, 204, 205, 206, -1, 208, -1, - 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, - -1, 221, -1, -1, 224, -1, 226, 227, 228, 229, - 230, 231, -1, -1, 234, -1, 236, -1, -1, 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, -1, - 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, - -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, - -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, - -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, - 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, - 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, - 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, - 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, - 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, - 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, - 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, - 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, - 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, - 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, - 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, - 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, - 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, - -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, - 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, - -1, 511, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, - 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, - 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - -1, -1, 83, 84, 85, 86, 87, 88, -1, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, -1, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, -1, -1, 224, -1, 226, 227, 228, 229, 230, - 231, -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, - 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, - 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, - 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 3, 4, 5, -1, -1, -1, 9, -1, -1, - 511, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, - 32, 33, -1, -1, -1, 37, -1, -1, -1, -1, - 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, - 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, - 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, - -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, - 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, - -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, - 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, - -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, - 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, - 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, -1, 281, - 282, 283, 284, 285, 286, -1, 288, 289, 290, -1, - 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, - 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, - 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, - 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, - 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - -1, 383, 384, 385, 386, 387, 388, 389, 390, 391, - 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, - 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, - -1, 433, 434, 435, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, - -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, - 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, - 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, - 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, - 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - -1, -1, 8, -1, -1, 11, -1, 509, 510, 15, - 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 502, -1, + -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, + 514, -1, -1, -1, -1, 177, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 36, -1, -1, -1, -1, 41, -1, -1, -1, -1, - 46, 8, -1, -1, 11, -1, -1, 53, 15, 16, - 17, 18, 19, 20, 21, -1, -1, -1, -1, 8, - -1, -1, 11, -1, -1, -1, 15, 16, -1, 36, - 19, 20, 21, -1, 80, -1, -1, -1, -1, 46, - 8, -1, -1, 11, -1, -1, 53, 15, 16, 17, - 18, 19, 20, 21, -1, -1, -1, 46, -1, -1, - -1, -1, -1, -1, 53, -1, -1, -1, 36, -1, - -1, -1, -1, 80, -1, -1, -1, -1, 46, -1, - 126, -1, -1, -1, -1, 53, -1, 8, -1, -1, - 11, 80, -1, -1, 15, 16, 17, 18, 19, 20, - 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 80, -1, -1, 36, -1, -1, -1, 40, - -1, -1, -1, -1, -1, 46, -1, -1, -1, -1, - -1, 177, 53, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 194, -1, - -1, -1, -1, 199, -1, -1, -1, -1, -1, 80, - 167, -1, -1, -1, -1, 172, -1, -1, -1, -1, - 177, -1, -1, -1, -1, -1, 222, 223, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 194, 177, -1, - -1, 237, 199, -1, -1, -1, -1, -1, 166, -1, - -1, -1, -1, -1, -1, 194, -1, -1, -1, 177, - 199, -1, -1, -1, -1, 222, 223, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 194, -1, -1, 275, - 237, 199, 278, 222, 223, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 292, -1, 237, 295, - -1, -1, -1, -1, 222, 223, 177, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 275, 237, - -1, 278, -1, 194, -1, -1, -1, -1, 199, -1, - -1, -1, -1, -1, -1, 292, 275, -1, 295, 278, + -1, 8, 194, -1, 11, -1, -1, 199, 15, 16, + 17, 18, 19, 20, 21, 502, -1, -1, 505, 506, + 507, -1, 509, 510, 511, 512, 513, 514, -1, 36, + 222, 223, -1, 40, -1, -1, -1, -1, -1, 46, + -1, -1, -1, -1, -1, 237, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 222, 223, 292, -1, -1, -1, 275, -1, -1, - 278, -1, -1, -1, -1, -1, 237, -1, -1, -1, - -1, -1, -1, -1, 292, -1, -1, 295, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, + 11, -1, -1, 80, 15, 16, 17, 18, 19, 20, + 21, -1, -1, 275, -1, -1, 278, -1, -1, -1, + -1, -1, -1, -1, -1, 36, -1, -1, -1, -1, + 292, -1, -1, 295, -1, 46, -1, -1, -1, -1, + -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 318, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 394, -1, - -1, -1, -1, -1, 275, -1, 324, 278, -1, -1, + -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, + -1, -1, -1, 15, 16, 17, 18, 19, 20, 21, + 177, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 36, -1, -1, 194, 40, -1, + -1, -1, 199, -1, 46, -1, -1, -1, -1, -1, + -1, 53, 394, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 222, 223, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 80, -1, + 237, 172, -1, -1, -1, -1, 177, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 292, -1, -1, 295, -1, -1, -1, -1, -1, - -1, -1, 8, -1, -1, 11, -1, 394, -1, 15, - 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 394, -1, -1, -1, -1, - 36, 457, -1, -1, -1, -1, -1, -1, -1, -1, - 46, -1, -1, -1, -1, -1, 394, 53, -1, -1, - -1, -1, -1, 68, 69, -1, -1, -1, -1, -1, + -1, -1, -1, 194, -1, -1, -1, -1, 199, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 275, -1, + -1, 278, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 222, 223, -1, -1, 292, -1, -1, 295, -1, + -1, -1, -1, -1, -1, -1, 237, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 80, -1, 502, -1, -1, 505, - 506, 507, -1, 509, 510, 511, 512, 513, 514, -1, - -1, -1, -1, 394, 109, 110, -1, -1, 113, 114, - -1, 8, -1, -1, 11, -1, -1, -1, 15, 16, - -1, -1, 19, 20, 21, 502, -1, -1, 505, 506, - 507, -1, 509, 510, 511, 512, 513, 514, -1, 36, - -1, -1, -1, 502, -1, -1, 505, 506, 507, 46, - 509, 510, 511, 512, 513, 514, 53, -1, -1, -1, - -1, -1, -1, -1, 502, -1, -1, 505, 506, 507, - -1, 509, 510, 511, 512, 513, 514, -1, -1, -1, - -1, 177, -1, 80, 189, 190, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 8, 194, -1, - 11, -1, -1, 199, 15, 16, 17, 18, 19, 20, - 21, 502, -1, -1, 505, 506, 507, -1, 509, 510, - 511, 512, 513, 514, -1, 36, 222, 223, -1, 40, - -1, -1, -1, -1, -1, 46, -1, -1, -1, -1, - -1, 237, 53, -1, -1, -1, -1, -1, 253, 254, - 255, 256, 257, 258, 259, 260, -1, -1, 263, 264, - -1, -1, -1, 8, -1, -1, 11, -1, -1, 80, - 15, 16, 17, 18, 19, 20, 21, -1, -1, 275, - 177, -1, 278, -1, -1, -1, -1, -1, -1, -1, - -1, 36, -1, -1, -1, -1, 292, 194, -1, 295, - -1, 46, 199, -1, -1, -1, -1, -1, 53, -1, + 502, -1, -1, 505, 506, 507, -1, 509, 510, 511, + 512, 513, 514, -1, -1, 177, -1, -1, -1, -1, + -1, -1, -1, -1, 275, -1, -1, 278, -1, -1, + -1, -1, 194, -1, -1, -1, -1, 199, -1, -1, + -1, 292, -1, -1, 295, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8, -1, -1, 11, -1, + 222, 223, 15, 16, 17, 18, 19, 20, 21, -1, + -1, -1, -1, -1, -1, 237, -1, 394, -1, -1, + -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 46, -1, -1, -1, -1, -1, -1, + 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 8, 275, -1, 11, 278, -1, -1, 15, + 16, 17, 18, 19, 20, 21, -1, 80, -1, -1, + 292, -1, -1, 295, -1, -1, -1, -1, -1, -1, + 36, -1, -1, 394, -1, -1, -1, -1, -1, -1, + 46, -1, -1, -1, -1, -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 318, -1, -1, 222, 223, -1, -1, -1, - -1, -1, 337, 338, -1, 80, -1, -1, -1, -1, - 237, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 8, -1, -1, 11, -1, -1, -1, 15, - 16, 17, 18, 19, 20, 21, 177, -1, -1, -1, - -1, -1, -1, 378, 379, -1, -1, -1, 275, -1, - 36, 278, -1, 194, 40, -1, -1, -1, 199, -1, - 46, -1, -1, -1, -1, 292, -1, 53, 394, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 222, 223, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 80, -1, 237, 172, -1, -1, - -1, -1, 177, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, - -1, -1, -1, -1, 199, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 275, -1, -1, 278, -1, 474, - 475, -1, -1, -1, -1, -1, -1, 222, 223, -1, - -1, 292, -1, -1, 295, -1, -1, -1, -1, -1, - -1, -1, 237, 498, 499, -1, -1, 394, -1, -1, + -1, -1, -1, -1, 80, 502, -1, -1, 505, 506, + 507, -1, 509, 510, 511, 512, 513, 514, -1, 8, + -1, -1, 11, -1, -1, -1, 15, 16, 17, 18, + 19, 20, 21, -1, 167, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 177, -1, -1, 36, -1, -1, + -1, 40, 394, -1, -1, -1, -1, 46, -1, -1, + -1, 194, -1, -1, 53, -1, 199, -1, -1, -1, + -1, 502, -1, -1, 505, 506, 507, -1, 509, 510, + 511, 512, 513, 514, -1, -1, -1, -1, -1, 222, + 223, 80, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 177, -1, -1, 237, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 194, -1, + -1, -1, -1, 199, -1, -1, -1, -1, 8, -1, + -1, 11, -1, -1, -1, 15, 16, 17, 18, 19, + 20, 21, 275, -1, -1, 278, 222, 223, -1, -1, + -1, -1, -1, -1, -1, -1, 36, -1, -1, 292, + 502, 237, 295, 505, 506, 507, 46, 509, 510, 511, + 512, 513, 514, 53, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 177, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 275, + 80, -1, 278, -1, -1, 194, -1, -1, -1, -1, + 199, -1, -1, -1, -1, -1, 292, -1, -1, 295, + -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, + -1, 11, -1, 222, 223, 15, 16, 17, 18, 19, + 20, 21, -1, -1, -1, -1, -1, -1, 237, -1, + -1, -1, -1, -1, -1, -1, 36, -1, -1, -1, + -1, 394, -1, -1, -1, -1, 46, -1, -1, -1, + -1, -1, -1, 53, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 275, -1, -1, 278, + -1, -1, -1, -1, -1, -1, -1, 177, -1, -1, + 80, -1, -1, 292, -1, -1, 295, -1, -1, -1, + -1, -1, -1, -1, 194, -1, -1, 8, 394, 199, + 11, -1, -1, -1, 15, 16, 17, 18, 19, 20, + 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 222, 223, -1, 36, -1, -1, -1, -1, + -1, 427, -1, -1, -1, 46, -1, 237, -1, -1, + -1, -1, 53, -1, -1, -1, -1, -1, -1, 502, + -1, -1, 505, 506, 507, -1, 509, 510, 511, 512, + 513, 514, -1, -1, -1, -1, -1, -1, -1, 80, + -1, -1, -1, -1, -1, 275, -1, 177, 278, -1, + -1, -1, -1, -1, -1, 394, -1, -1, -1, -1, + -1, -1, 292, -1, 194, 295, -1, -1, -1, 199, -1, -1, -1, -1, -1, -1, 502, -1, -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, -1, - -1, 177, -1, -1, -1, -1, -1, -1, -1, -1, - 275, -1, -1, 278, -1, -1, -1, -1, 194, -1, - -1, -1, -1, 199, -1, -1, -1, 292, -1, -1, - 295, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 8, -1, -1, 11, -1, 222, 223, 15, 16, - 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, - -1, 237, -1, 394, -1, -1, -1, -1, -1, 36, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, - -1, -1, -1, -1, -1, 502, 53, -1, 505, 506, - 507, -1, 509, 510, 511, 512, 513, 514, 8, 275, - -1, 11, 278, -1, -1, 15, 16, 17, 18, 19, - 20, 21, -1, 80, -1, -1, 292, -1, -1, 295, - -1, -1, -1, -1, -1, -1, 36, -1, -1, 394, - -1, -1, -1, -1, -1, -1, 46, -1, -1, -1, - -1, -1, -1, 53, -1, -1, -1, -1, -1, -1, + -1, -1, 222, 223, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 237, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 80, 502, -1, -1, 505, 506, 507, -1, 509, 510, - 511, 512, 513, 514, -1, 8, -1, -1, 11, -1, - -1, -1, 15, 16, 17, 18, 19, 20, 21, -1, - 167, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 177, -1, -1, 36, -1, -1, -1, 40, 394, -1, - -1, -1, -1, 46, -1, -1, -1, 194, -1, -1, - 53, -1, 199, -1, -1, -1, -1, 502, -1, -1, - 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, - -1, -1, -1, -1, -1, 222, 223, 80, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 177, -1, -1, - 237, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 194, -1, -1, -1, -1, 199, - -1, -1, -1, -1, 8, -1, -1, 11, -1, -1, - -1, 15, 16, 17, 18, 19, 20, 21, 275, -1, - -1, 278, 222, 223, -1, -1, -1, -1, -1, -1, - -1, -1, 36, -1, -1, 292, 502, 237, 295, 505, - 506, 507, 46, 509, 510, 511, 512, 513, 514, 53, + -1, -1, -1, -1, -1, -1, 177, -1, -1, -1, + -1, -1, -1, -1, -1, 275, -1, -1, 278, -1, + -1, -1, -1, 194, -1, -1, -1, -1, 199, -1, + -1, -1, 292, 502, 394, 295, 505, 506, 507, -1, + 509, 510, 511, 512, 513, 514, -1, -1, -1, -1, + -1, 222, 223, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 237, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 177, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 275, 80, -1, 278, -1, - -1, 194, -1, -1, -1, -1, 199, -1, -1, -1, - -1, -1, 292, -1, -1, 295, -1, -1, -1, -1, - -1, -1, -1, -1, 8, -1, -1, 11, -1, 222, - 223, 15, 16, 17, 18, 19, 20, 21, -1, -1, - -1, -1, -1, -1, 237, -1, -1, -1, -1, -1, - -1, -1, 36, -1, -1, -1, -1, 394, -1, -1, - -1, -1, 46, -1, -1, -1, -1, -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 275, -1, -1, 278, -1, -1, -1, -1, - -1, -1, -1, 177, -1, -1, 80, -1, -1, 292, - -1, -1, 295, -1, -1, -1, -1, -1, -1, -1, - 194, -1, -1, 8, 394, 199, 11, -1, -1, -1, - 15, 16, 17, 18, 19, 20, 21, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 222, 223, - -1, 36, -1, -1, -1, -1, -1, 427, -1, -1, - -1, 46, -1, 237, -1, -1, -1, -1, 53, -1, - -1, -1, -1, -1, -1, 502, -1, -1, 505, 506, - 507, -1, 509, 510, 511, 512, 513, 514, -1, -1, - -1, -1, -1, -1, -1, 80, -1, -1, -1, -1, - -1, 275, -1, 177, 278, -1, -1, -1, -1, -1, - -1, 394, -1, -1, -1, -1, -1, -1, 292, -1, - 194, 295, -1, -1, -1, 199, -1, -1, -1, -1, - -1, -1, 502, -1, -1, 505, 506, 507, -1, 509, - 510, 511, 512, 513, 514, -1, -1, -1, 222, 223, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 237, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 275, -1, -1, 278, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 292, -1, -1, 295, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 394, -1, -1, -1, -1, -1, + -1, -1, 502, -1, -1, 505, 506, 507, -1, 509, + 510, 511, 512, 513, 514, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 177, -1, -1, -1, -1, -1, -1, -1, - -1, 275, -1, -1, 278, -1, -1, -1, -1, 194, - -1, -1, -1, -1, 199, -1, -1, -1, 292, 502, - 394, 295, 505, 506, 507, -1, 509, 510, 511, 512, - 513, 514, -1, -1, -1, -1, -1, 222, 223, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 237, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 275, -1, -1, 278, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 292, -1, -1, - 295, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 394, -1, -1, -1, -1, -1, -1, -1, 502, -1, - -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, - 514, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 394, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 502, -1, -1, 505, 506, 507, -1, 509, + 510, 511, 512, 513, 514, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 394, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 502, -1, - -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, - 514, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -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, 502, -1, -1, 505, 506, 507, -1, 509, 510, + 511, 512, 513, 514, 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, 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, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 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, 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, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 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, 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, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 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, 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, 3, -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, 502, -1, -1, - 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, 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, @@ -16295,422 +16905,422 @@ static const yytype_int16 yycheck[] = 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, - 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 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, 65, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, + 33, -1, -1, -1, 37, -1, -1, -1, -1, 42, + 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, + 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, + 73, -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + -1, 94, 95, 96, 97, 98, 99, -1, 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, + 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, + 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, + -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, + -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, 160, 161, -1, + 163, 164, 165, 166, -1, 168, -1, 170, 171, -1, + 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, + 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, + 203, 204, 205, 206, -1, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, -1, 219, -1, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, -1, + -1, 234, 235, 236, 237, -1, 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, + 273, 274, -1, 276, 277, 278, 279, -1, 281, 282, + 283, 284, 285, 286, -1, 288, 289, 290, -1, 292, + 293, 294, -1, -1, 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, + 313, 314, -1, -1, -1, -1, 319, 320, 321, 322, + 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, + 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, + 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, - 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, + 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, + -1, 394, 395, 396, 397, 398, -1, 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, + 413, 414, -1, -1, 417, 418, -1, 420, 421, 422, + 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 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, + 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, + 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, + 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, + 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 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, 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, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + 34, 35, -1, 37, -1, -1, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 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, + 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, + 274, -1, 276, 277, 278, 279, -1, 281, 282, 283, + 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 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, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 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, + 374, 375, 376, 377, 378, 379, 380, 381, -1, 383, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 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, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 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, - 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, -1, 31, 32, 33, -1, + -1, -1, -1, -1, -1, -1, -1, 42, 43, 44, + -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, + -1, 66, 67, 68, 69, 70, 71, 72, 73, -1, + 75, 76, 77, 78, 79, -1, 81, -1, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, + 95, 96, 97, 98, 99, -1, 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, + 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, + 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, + 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, + 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, + 165, 166, -1, 168, -1, 170, 171, -1, 173, 174, + 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, + 185, -1, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, + 205, 206, -1, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, -1, 219, -1, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, -1, -1, 234, + 235, 236, 237, -1, 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, + -1, 276, 277, 278, 279, -1, 281, 282, 283, 284, + 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, + -1, -1, 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, + -1, -1, -1, -1, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, + 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, -1, 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, + 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, + 385, 386, 387, 388, 389, 390, 391, 392, -1, 394, + 395, 396, 397, 398, -1, 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, + -1, -1, 417, 418, -1, 420, 421, 422, 423, 424, + 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, + 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, + 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, + 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, + 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, + 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, + -1, -1, -1, -1, -1, -1, 42, 43, 44, -1, 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, + 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, + -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, + 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, + 96, 97, 98, 99, -1, 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, + 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, + -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, + 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, + 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, + 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, + 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, + -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, + 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, + 236, 237, -1, 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, + 266, 267, 268, 269, 270, 271, 272, 273, 274, -1, + 276, 277, 278, 279, -1, 281, 282, 283, 284, 285, + 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, + -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, + -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, + 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, + -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, + 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, -1, 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, + 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, + 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, + 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, + 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, + -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, + 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, + 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, + 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, + 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, + -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, + -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 3, -1, 5, -1, + 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, - 37, -1, -1, -1, -1, 42, 43, 44, -1, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, + 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, - 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, - 77, 78, 79, -1, 81, -1, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, - 97, 98, 99, -1, 101, 102, 103, 104, 105, 106, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, -1, -1, 82, 83, 84, 85, 86, + 87, 88, -1, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, -1, 163, 164, 165, 166, - -1, 168, -1, 170, 171, -1, 173, 174, 175, 176, - 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, + -1, 168, 169, 170, -1, -1, -1, 174, 175, 176, + -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, + 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, - -1, 208, 209, 210, 211, 212, 213, 214, 215, 216, - 217, -1, 219, -1, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, -1, -1, 234, 235, 236, - 237, -1, 239, 240, 241, 242, 243, 244, 245, 246, + -1, 208, -1, 210, 211, 212, 213, 214, 215, 216, + 217, -1, 219, -1, 221, -1, -1, 224, -1, 226, + 227, 228, 229, 230, 231, -1, -1, 234, -1, 236, + -1, -1, 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, -1, 276, - 277, 278, 279, -1, 281, 282, 283, 284, 285, 286, - -1, 288, 289, 290, -1, 292, 293, 294, -1, -1, - 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 267, 268, -1, 270, 271, 272, 273, 274, -1, 276, + 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, + -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, + 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, - -1, -1, 319, 320, 321, 322, 323, 324, 325, 326, - 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, + -1, -1, 319, 320, 321, -1, 323, 324, 325, 326, + 327, 328, 329, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, -1, 362, 363, 364, 365, 366, + 357, 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, - 377, 378, 379, 380, 381, -1, 383, 384, 385, 386, - 387, 388, 389, 390, 391, 392, -1, 394, 395, 396, + 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, + 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, - 417, 418, -1, 420, 421, 422, 423, 424, 425, 426, + 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, + 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, + -1, 448, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, - 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, + 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, - 28, 29, -1, 31, 32, 33, 34, 35, -1, 37, - -1, -1, -1, -1, 42, 43, 44, -1, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, + 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, - 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, - 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, - 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, -1, -1, -1, 83, 84, 85, 86, 87, + 88, -1, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, - 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, + 168, 169, 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, - -1, 219, -1, 221, 222, 223, 224, 225, 226, 227, - 228, 229, 230, 231, -1, -1, 234, 235, 236, 237, + 208, -1, 210, 211, 212, 213, 214, 215, 216, 217, + -1, 219, -1, 221, -1, -1, 224, -1, 226, 227, + 228, 229, 230, 231, -1, -1, 234, -1, 236, 237, -1, 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, -1, 276, 277, - 278, 279, -1, 281, 282, 283, 284, 285, 286, -1, + 268, -1, 270, 271, 272, 273, 274, -1, 276, 277, + -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, - 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, + 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, - -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, - 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, + -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, + 328, 329, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, + 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, - 378, 379, 380, 381, -1, 383, 384, 385, 386, 387, - 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, + 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, + 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, - 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, + 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, - -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, + 448, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, - 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, + -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, - 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, + 498, 499, 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, - 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, - -1, -1, -1, 42, 43, 44, -1, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, - 59, 60, 61, 62, 63, 64, -1, 66, 67, 68, + 29, -1, 31, 32, 33, 34, 35, -1, -1, -1, + -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, + -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, + 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, - 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, - 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 79, -1, -1, -1, 83, 84, 85, 86, 87, 88, + -1, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, 168, - -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, - 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, - 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + -1, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, -1, -1, 224, -1, 226, 227, 228, + 229, 230, 231, -1, -1, 234, -1, 236, -1, -1, 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, -1, 276, 277, 278, + -1, 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, - 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, - 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + 319, 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 359, 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, - 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, - -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, - 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, + 459, 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, + 499, 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, - -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, - -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, + 30, 31, 32, 33, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, + 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, - -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, + -1, -1, -1, 83, 84, 85, 86, 87, 88, -1, 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, - -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, + -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, - 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, + 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, - 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, + 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, + 200, 201, 202, 203, 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, - -1, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, -1, -1, 234, 235, 236, 237, -1, 239, + -1, 221, -1, -1, 224, -1, 226, 227, 228, 229, + 230, 231, -1, -1, 234, -1, 236, -1, -1, 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, -1, 276, 277, 278, 279, + 260, 261, 262, 263, 264, 265, 266, 267, 268, -1, + 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, - 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, + -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, - 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, + 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, + 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, - 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, + 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, - 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, + 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, - 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, + 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, + 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, - 71, 72, 73, 74, 75, 76, 77, 78, 79, -1, - -1, 82, 83, 84, 85, 86, 87, 88, -1, 90, - 91, 92, 93, 94, 95, 96, 97, 98, 99, -1, + 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, + -1, -1, 83, 84, 85, 86, 87, 88, -1, 90, + 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, - 161, -1, 163, 164, 165, 166, -1, 168, 169, 170, + 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, @@ -16723,10 +17333,10 @@ static const yytype_int16 yycheck[] = 261, 262, 263, 264, 265, 266, 267, 268, -1, 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, + 291, 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, -1, 323, 324, 325, 326, 327, 328, 329, 330, + 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, @@ -16738,45 +17348,45 @@ static const yytype_int16 yycheck[] = 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, - 441, 442, 443, 444, 445, 446, -1, 448, 449, 450, + 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, + 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, -1, -1, + 72, 73, -1, 75, 76, 77, 78, 79, -1, -1, -1, 83, 84, 85, 86, 87, 88, -1, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, -1, -1, + 92, -1, 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, - -1, 163, 164, 165, 166, -1, 168, 169, 170, -1, + -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, -1, -1, 224, -1, 226, 227, 228, 229, 230, 231, - -1, -1, 234, -1, 236, 237, -1, 239, 240, 241, + -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, - 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, + 282, 283, 284, 285, 286, -1, 288, 289, -1, 291, 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, - -1, 323, 324, 325, 326, 327, 328, 329, 330, 331, + -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, @@ -16788,7 +17398,7 @@ static const yytype_int16 yycheck[] = 412, 413, 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, - 442, 443, 444, 445, 446, -1, 448, 449, 450, 451, + 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, @@ -16796,8 +17406,8 @@ static const yytype_int16 yycheck[] = 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, - 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, - 33, 34, 35, -1, -1, -1, -1, -1, -1, -1, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, @@ -16846,7 +17456,7 @@ static const yytype_int16 yycheck[] = 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, @@ -16872,7 +17482,7 @@ static const yytype_int16 yycheck[] = 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, -1, 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, - 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, + 284, 285, 286, -1, 288, 289, -1, 291, 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, @@ -16922,7 +17532,7 @@ static const yytype_int16 yycheck[] = 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, -1, 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, - 285, 286, -1, 288, 289, -1, 291, 292, 293, 294, + 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, 324, @@ -16935,7 +17545,7 @@ static const yytype_int16 yycheck[] = 385, 386, 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, + -1, -1, 417, 418, 419, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, @@ -16972,7 +17582,7 @@ static const yytype_int16 yycheck[] = 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, -1, 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, - 286, -1, 288, 289, -1, 291, 292, 293, 294, -1, + 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, 324, 325, @@ -16996,7 +17606,7 @@ static const yytype_int16 yycheck[] = 496, 497, 498, 499, 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, -1, -1, -1, + 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, @@ -17043,10 +17653,10 @@ static const yytype_int16 yycheck[] = 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, - 497, 498, 499, 500, 501, 3, -1, 5, -1, -1, + 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, - 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, + 28, 29, 30, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, @@ -17072,7 +17682,7 @@ static const yytype_int16 yycheck[] = 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, -1, 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, - 288, 289, -1, 291, 292, 293, 294, -1, -1, 297, + 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, @@ -17093,8 +17703,8 @@ static const yytype_int16 yycheck[] = -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, - 498, 499, 500, 501, 3, 4, -1, -1, -1, -1, - 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 498, 499, 500, 501, 3, -1, 5, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, @@ -17184,7 +17794,7 @@ static const yytype_int16 yycheck[] = 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, -1, -1, 417, 418, 419, + 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, @@ -17293,9 +17903,9 @@ static const yytype_int16 yycheck[] = 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, @@ -17442,11 +18052,11 @@ static const yytype_int16 yycheck[] = 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, - 495, 496, 497, 498, 499, 500, 501, 3, -1, 5, + 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, + -1, -1, -1, -1, 40, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, @@ -17492,11 +18102,11 @@ static const yytype_int16 yycheck[] = -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 3, -1, 5, -1, + 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, + -1, -1, -1, 40, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, @@ -17542,10 +18152,10 @@ static const yytype_int16 yycheck[] = 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, - 497, 498, 499, 500, 501, 3, -1, 5, -1, -1, + 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, - 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, + 28, 29, 30, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, @@ -17692,10 +18302,258 @@ static const yytype_int16 yycheck[] = 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, + 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, + 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, + 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, + 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, + 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, + -1, -1, 83, 84, 85, 86, 87, 88, -1, 90, + 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, + -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, + 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, + 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, + 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, + 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, + -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, + -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, + 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, + 201, 202, 203, 204, 205, 206, -1, 208, -1, 210, + 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, + 221, -1, -1, 224, -1, 226, 227, 228, 229, 230, + 231, -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, + 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, + 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, + -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, + 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, + 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, + 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, + 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, + 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, + 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, + 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, + -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, + -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, + 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, + 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, + 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, + 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, + 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, + 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, + 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, + 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, + 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, + 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, + 72, 73, -1, 75, 76, 77, 78, 79, -1, -1, + -1, 83, 84, 85, 86, 87, 88, -1, 90, 91, + 92, -1, 94, 95, 96, 97, 98, 99, -1, -1, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, + 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, + -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, + 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, + -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, + -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, + 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, + 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, + 202, 203, 204, 205, 206, -1, 208, -1, 210, 211, + 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, + -1, -1, 224, -1, 226, 227, 228, 229, 230, 231, + -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, + 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, + 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, + 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, + -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, + -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, + 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, + 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, + -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, + 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, + 412, 413, 414, -1, -1, 417, 418, -1, 420, -1, + 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, + -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, + 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, + -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, + 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, + 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, + 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, + 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, + 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, + 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, + 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, + 73, -1, 75, 76, 77, 78, 79, -1, -1, -1, + 83, 84, 85, 86, 87, 88, -1, 90, 91, 92, + -1, 94, 95, 96, 97, 98, 99, -1, -1, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, + 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, + -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, + -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, + 163, 164, 165, 166, -1, 168, -1, 170, -1, -1, + -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, + 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, + 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, + 203, 204, 205, 206, -1, 208, -1, 210, 211, 212, + 213, 214, 215, 216, 217, -1, 219, -1, 221, -1, + -1, 224, -1, 226, 227, 228, 229, 230, 231, -1, + -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, + 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, + 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, + 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, -1, -1, -1, -1, 319, 320, 321, -1, + 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, + 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, + 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, + 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, + -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, + -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, + 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, + 413, 414, -1, -1, 417, 418, -1, 420, -1, 422, + 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, + 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, + 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, + 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, + 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, + 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, + 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, + 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, 37, -1, -1, 40, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, -1, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, -1, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, -1, 153, + 154, 155, 156, 157, 158, -1, -1, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, -1, -1, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, -1, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, -1, -1, 282, 283, + 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, -1, 300, 301, 302, -1, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, -1, 322, 323, + 324, -1, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, 383, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + -1, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, -1, 436, -1, -1, 439, 440, 441, 442, 443, + 444, 445, 446, 447, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, -1, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 3, -1, 5, -1, -1, -1, -1, + -1, -1, -1, -1, 498, 499, 500, 501, -1, -1, + -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, + -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, + 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, + 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, + 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, + -1, -1, -1, 83, 84, 85, 86, 87, 88, -1, + 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, + -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, + 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, + 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, + 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, + 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, + 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, + 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, + 200, 201, 202, 203, 204, 205, 206, -1, 208, -1, + 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, + -1, 221, -1, -1, 224, -1, 226, 227, 228, 229, + 230, 231, -1, -1, 234, -1, 236, -1, -1, 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, -1, + 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, + -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, + -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, + -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, + 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, + 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, + 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, + 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, + 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, + 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, + 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, + 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, + 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, + 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, + 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, + 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, + -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, + 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, -1, 40, + 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, @@ -17745,7 +18603,7 @@ static const yytype_int16 yycheck[] = 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, - 32, 33, -1, -1, -1, -1, -1, -1, 40, -1, + 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, @@ -17794,7 +18652,7 @@ static const yytype_int16 yycheck[] = 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, @@ -17842,7 +18700,7 @@ static const yytype_int16 yycheck[] = 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 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, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, @@ -17851,297 +18709,49 @@ static const yytype_int16 yycheck[] = 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, -1, -1, 83, 84, 85, 86, 87, 88, -1, 90, 91, 92, -1, - 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, - 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, - 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, - 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, - 164, 165, 166, -1, 168, -1, 170, -1, -1, -1, - 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, - 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, - -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, - 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, - 214, 215, 216, 217, -1, 219, -1, 221, -1, -1, - 224, -1, 226, 227, 228, 229, 230, 231, -1, -1, - 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, - 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, - 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, - 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, - 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, - 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, - 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, - -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, - 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, - 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, - -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, - 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, - 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, - 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, - 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, - 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, - 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, - 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, - 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, - 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, - 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, - 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, - -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, - -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, - -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, - 75, 76, 77, 78, 79, -1, -1, -1, 83, 84, - 85, 86, 87, 88, -1, 90, 91, 92, -1, 94, - 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, - 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, - 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, - 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, - 165, 166, -1, 168, -1, 170, -1, -1, -1, 174, - 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, - 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, - 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, - 205, 206, -1, 208, -1, 210, 211, 212, 213, 214, - 215, 216, 217, -1, 219, -1, 221, -1, -1, 224, - -1, 226, 227, 228, 229, 230, 231, -1, -1, 234, - -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, 274, - -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, - 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, - -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - -1, -1, -1, -1, 319, 320, 321, -1, 323, 324, - 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, - 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, -1, 362, 363, -1, - 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, - 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, - 385, 386, 387, 388, 389, 390, 391, 392, -1, -1, - 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, - 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, - 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, - 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, - 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, - 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, - 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, - 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, - 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, - 495, 496, 497, 498, 499, 500, 501, 3, -1, 5, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, - 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, - 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, - -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, -1, -1, 83, 84, 85, - 86, 87, 88, -1, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, -1, -1, -1, 174, 175, - 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, -1, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, -1, -1, 224, -1, - 226, 227, 228, 229, 230, 231, -1, -1, 234, -1, - 236, -1, -1, 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, -1, 270, 271, 272, 273, 274, -1, - 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, - 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, -1, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, -1, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, -1, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 3, -1, 5, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, - 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, - 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, - 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, - 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, - 77, 78, 79, -1, -1, -1, 83, 84, 85, 86, - 87, 88, -1, 90, 91, 92, -1, 94, 95, 96, - 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, - -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, - 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, - -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, - -1, 168, -1, 170, -1, -1, -1, 174, 175, 176, - -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, - 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, - 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, - -1, 208, -1, 210, 211, 212, 213, 214, 215, 216, - 217, -1, 219, -1, 221, -1, -1, 224, -1, 226, - 227, 228, 229, 230, 231, -1, -1, 234, -1, 236, - -1, -1, 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, -1, 270, 271, 272, 273, 274, -1, 276, - 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, - -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, - 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, - -1, -1, 319, 320, 321, -1, 323, 324, 325, 326, - 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, - 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, - -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, -1, 362, 363, -1, 365, 366, - 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, - 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, - 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, - 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, - 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, - 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, - -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, - 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, - -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, - -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, - 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, - -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, - 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, - 497, 498, 499, 500, 501, 3, -1, 5, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, - 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, - 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, - -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, - 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, - 78, 79, -1, -1, -1, 83, 84, 85, 86, 87, - 88, -1, 90, 91, 92, -1, 94, 95, 96, 97, - 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, - 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, - 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, - 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, - 168, -1, 170, -1, -1, -1, 174, 175, 176, -1, - 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, - 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, - 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, - 208, -1, 210, 211, 212, 213, 214, 215, 216, 217, - -1, 219, -1, 221, -1, -1, 224, -1, 226, 227, - 228, 229, 230, 231, -1, -1, 234, -1, 236, -1, - -1, 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, -1, 270, 271, 272, 273, 274, -1, 276, 277, - -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, - 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, - 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, - -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, - 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, - 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, - 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, - 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, - 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, - 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, - 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, - 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, - 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, - 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, - -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, - -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, - 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, - -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, - 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, - 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, - 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, + 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, -1, -1, -1, + 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, -1, -1, + 224, -1, 226, 227, 228, 229, 230, 231, -1, -1, + 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, + 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, + 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, - 29, -1, 31, 32, 33, -1, -1, -1, 37, -1, - -1, 40, -1, 42, 43, 44, -1, 46, 47, 48, - 49, 50, 51, 52, -1, 54, 55, 56, 57, -1, - 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, - 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, - -1, -1, 81, -1, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, - 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, - -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, - 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, - -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, - 149, 150, 151, -1, 153, 154, 155, 156, 157, 158, - -1, -1, 161, -1, 163, 164, 165, 166, -1, 168, - -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, - -1, 180, -1, -1, -1, 184, 185, -1, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, - 209, -1, 211, 212, 213, 214, 215, 216, 217, -1, - 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, - 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, -1, 276, 277, 278, - 279, -1, -1, 282, 283, 284, 285, 286, -1, 288, - 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, - -1, 300, 301, 302, -1, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, - 319, 320, -1, 322, 323, 324, -1, 326, 327, 328, - -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, - 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, - 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, - 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, - 379, 380, 381, -1, 383, 384, 385, 386, 387, 388, - 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, - -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, - 409, 410, 411, 412, 413, -1, -1, -1, 417, 418, - -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, - 429, 430, -1, -1, 433, 434, -1, 436, -1, -1, - 439, 440, 441, 442, 443, 444, 445, 446, 447, -1, - 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, - 459, 460, 461, 462, -1, 464, 465, -1, 467, 468, - 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, - -1, -1, 481, 482, 483, 484, 485, 486, 3, -1, - 5, -1, -1, -1, -1, -1, -1, -1, -1, 498, - 499, 500, 501, -1, -1, -1, -1, 22, 23, 24, + -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, @@ -18243,7 +18853,7 @@ static const yytype_int16 yycheck[] = -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, + -1, -1, -1, 40, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, @@ -18278,7 +18888,7 @@ static const yytype_int16 yycheck[] = 357, 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, - 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, + 387, 388, -1, 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, @@ -18357,7 +18967,252 @@ static const yytype_int16 yycheck[] = 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, -1, -1, 174, 175, 176, -1, 178, - -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + -1, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, -1, -1, 224, -1, 226, 227, 228, + 229, 230, 231, -1, -1, 234, -1, 236, -1, -1, + 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, + -1, 270, 271, 272, 273, 274, -1, 276, 277, -1, + 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, -1, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, -1, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, -1, 467, -1, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, + -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, + 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, + 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, + 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, + -1, -1, -1, 83, 84, 85, 86, 87, 88, -1, + 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, + -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, + 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, + 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, + 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, + 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, + 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, + 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, + 200, 201, 202, 203, 204, 205, 206, -1, 208, -1, + 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, + -1, 221, -1, -1, 224, -1, 226, 227, 228, 229, + 230, 231, -1, -1, 234, -1, 236, -1, -1, 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, -1, + 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, + -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, + -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, + -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, + 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, + 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, + 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, + 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, + 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, + 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, + 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, + 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, + 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, + 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, + 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, + 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, + -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, + 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, + 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, + 31, 32, 33, -1, -1, -1, 37, -1, -1, -1, + -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, + 51, 52, -1, 54, 55, 56, 57, -1, 59, 60, + 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, + 71, 72, 73, -1, 75, 76, 77, 78, -1, -1, + 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, + 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, + 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, + 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, + 151, -1, 153, 154, 155, 156, 157, 158, -1, -1, + 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, + 171, -1, 173, 174, 175, -1, 177, 178, -1, 180, + -1, -1, -1, 184, 185, -1, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, + 201, 202, 203, 204, 205, 206, -1, 208, 209, -1, + 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, -1, + -1, 282, 283, 284, 285, 286, -1, 288, 289, -1, + -1, 292, 293, 294, -1, -1, 297, 298, -1, 300, + 301, 302, -1, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, + -1, 322, 323, 324, -1, 326, 327, 328, -1, 330, + 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, + 381, -1, 383, 384, 385, 386, 387, 388, 389, 390, + 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, + 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, + 411, 412, 413, -1, -1, -1, 417, 418, -1, 420, + 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, + -1, -1, 433, 434, -1, 436, -1, -1, 439, 440, + 441, 442, 443, 444, 445, 446, 447, -1, 449, 450, + 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, + 461, 462, -1, 464, 465, -1, 467, 468, 469, 470, + 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, + 481, 482, 483, 484, 485, 486, 3, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 498, 499, 500, + 501, -1, -1, -1, -1, 22, 23, 24, 25, 26, + 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, + 37, -1, -1, -1, -1, 42, 43, 44, -1, 46, + 47, 48, 49, 50, 51, 52, -1, 54, 55, 56, + 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, + 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, + 77, 78, -1, -1, 81, -1, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, + 97, 98, 99, -1, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, + -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, + 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, + -1, 148, 149, 150, 151, -1, 153, 154, 155, 156, + 157, 158, -1, -1, 161, -1, 163, 164, 165, 166, + -1, 168, -1, 170, 171, -1, 173, 174, 175, -1, + 177, 178, -1, 180, -1, -1, -1, 184, 185, -1, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, + -1, 208, 209, -1, 211, 212, 213, 214, 215, 216, + 217, -1, 219, -1, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, -1, -1, 234, 235, 236, + 237, -1, 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, -1, 276, + 277, 278, 279, -1, -1, 282, 283, 284, 285, 286, + -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, + 297, 298, -1, 300, 301, 302, -1, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, + -1, -1, 319, 320, -1, 322, 323, 324, -1, 326, + 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, + 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, + -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, -1, 362, 363, 364, 365, 366, + 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, -1, 383, 384, 385, 386, + 387, 388, 389, 390, 391, 392, -1, 394, 395, 396, + 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, 412, 413, -1, -1, -1, + 417, 418, -1, 420, 421, 422, 423, 424, 425, 426, + -1, 428, 429, 430, -1, -1, 433, 434, -1, 436, + -1, -1, 439, 440, 441, 442, 443, 444, 445, 446, + 447, -1, 449, 450, 451, -1, 453, 454, 455, 456, + -1, 458, 459, 460, 461, 462, -1, 464, 465, -1, + 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, + -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, + 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 498, 499, 500, 501, -1, -1, -1, -1, 22, + 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, + 33, -1, -1, -1, 37, -1, -1, -1, -1, 42, + 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, + -1, 54, 55, 56, 57, -1, 59, 60, 61, 62, + 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, + 73, -1, 75, 76, 77, 78, -1, -1, 81, -1, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, + 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, + -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, + -1, 144, 145, 146, -1, 148, 149, 150, 151, -1, + 153, 154, 155, 156, 157, 158, -1, -1, 161, -1, + 163, 164, 165, 166, -1, 168, -1, 170, 171, -1, + 173, 174, 175, 176, 177, 178, -1, 180, -1, -1, + -1, 184, 185, -1, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, + 203, 204, 205, 206, -1, 208, 209, -1, 211, 212, + 213, 214, 215, 216, 217, -1, 219, -1, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, -1, + -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, -1, -1, 282, + 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, + 293, 294, -1, -1, 297, 298, -1, 300, 301, 302, + -1, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, -1, -1, -1, -1, 319, 320, -1, 322, + 323, 324, -1, 326, 327, 328, -1, 330, 331, 332, + 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, + 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, + 363, 364, 365, 366, 367, -1, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, + 383, 384, 385, 386, 387, 388, 389, -1, 391, 392, + -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, + 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, + 413, -1, -1, -1, 417, 418, -1, 420, 421, 422, + 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, + 433, 434, -1, 436, -1, -1, 439, 440, 441, 442, + 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, + 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, + -1, 464, 465, -1, 467, 468, 469, 470, 471, 472, + 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, + 483, 484, 485, 486, 3, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 498, 499, 500, 501, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, + -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, + 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, -1, -1, 83, 84, 85, 86, 87, 88, + -1, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, -1, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, -1, -1, -1, 174, 175, 176, -1, 178, + -1, 180, -1, 182, 183, -1, 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, 214, 215, 216, 217, -1, @@ -18370,13 +19225,13 @@ static const yytype_int16 yycheck[] = 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 309, -1, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, - 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 339, -1, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, 368, - 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + -1, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, @@ -18392,597 +19247,103 @@ static const yytype_int16 yycheck[] = 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, - -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, - 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, + -1, 31, 32, 33, -1, -1, -1, 37, -1, -1, + -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, + 50, 51, 52, -1, 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, - 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, - -1, -1, -1, 83, 84, 85, 86, 87, 88, -1, + 70, 71, 72, 73, -1, 75, 76, 77, 78, -1, + -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, - -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, + -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 150, 151, -1, 153, 154, 155, 156, 157, 158, -1, -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, - 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, - 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, - 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, - 200, 201, 202, 203, 204, 205, 206, -1, 208, -1, - 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, - -1, 221, -1, -1, 224, -1, 226, 227, 228, 229, - 230, 231, -1, -1, 234, -1, 236, -1, -1, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 170, 171, -1, 173, 174, 175, -1, 177, 178, -1, + 180, -1, -1, -1, 184, 185, -1, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, + 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, + -1, 211, 212, 213, 214, 215, 216, 217, -1, 219, + -1, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, -1, -1, 234, 235, 236, 237, -1, 239, + 240, 241, 242, 243, 244, 245, 246, -1, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, - 260, 261, 262, 263, 264, 265, 266, 267, 268, -1, - 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, - -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, - -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, - -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, + 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, + 270, 271, 272, 273, -1, -1, 276, 277, 278, 279, + -1, -1, 282, 283, 284, 285, 286, -1, 288, 289, + -1, -1, 292, 293, 294, -1, -1, 297, 298, -1, + 300, 301, 302, -1, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, - 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, + 320, -1, 322, 323, 324, -1, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, + 360, -1, 362, 363, 364, 365, 366, 367, -1, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, - 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, - 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, - 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, - 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, - 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, - 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, - 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, - 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, - 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, - -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, - 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, - 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, - 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - -1, -1, 83, 84, 85, 86, 87, 88, -1, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, -1, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, -1, -1, 224, -1, 226, 227, 228, 229, 230, - 231, -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, - 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, - 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, - 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, - 32, 33, -1, -1, -1, -1, -1, -1, 40, -1, - -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, - 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, - 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, - 72, 73, -1, 75, 76, 77, 78, 79, -1, -1, - -1, 83, 84, 85, 86, 87, 88, -1, 90, 91, - 92, -1, 94, 95, 96, 97, 98, 99, -1, -1, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, - 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, - -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, - 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, - -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, - -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, - 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, - 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, - 202, 203, 204, 205, 206, -1, 208, -1, 210, 211, - 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, - -1, -1, 224, -1, 226, 227, 228, 229, 230, 231, - -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, - 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, - 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, - 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, - -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, - -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, - 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, - 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, - 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - -1, -1, 384, 385, 386, 387, 388, -1, 390, 391, - 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, -1, -1, 417, 418, -1, 420, -1, - 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, - -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, - 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, - -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, - 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, - 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, - 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, - 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, - 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, - 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, - 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, - 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, - 73, -1, 75, 76, 77, 78, 79, -1, -1, -1, - 83, 84, 85, 86, 87, 88, -1, 90, 91, 92, - -1, 94, 95, 96, 97, 98, 99, -1, -1, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, - 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, - -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, - -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, - 163, 164, 165, 166, -1, 168, -1, 170, -1, -1, - -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, - 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, - 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, - 203, 204, 205, 206, -1, 208, -1, 210, 211, 212, - 213, 214, 215, 216, 217, -1, 219, -1, 221, -1, - -1, 224, -1, 226, 227, 228, 229, 230, 231, -1, - -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, - 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, - 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, - 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, -1, -1, -1, -1, 319, 320, 321, -1, - 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, - 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, - 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, - 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, - 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, - -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, - -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, - 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, -1, -1, 417, 418, -1, 420, -1, 422, - 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, - 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, - 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, - 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, - 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, - 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, - 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, - 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, - 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, - 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, - 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, - 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, - -1, 75, 76, 77, 78, 79, -1, -1, -1, 83, - 84, 85, 86, 87, 88, -1, 90, 91, 92, -1, - 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, - 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, - 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, - 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, - 164, 165, 166, -1, 168, -1, 170, -1, -1, -1, - 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, - 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, - -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, - 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, - 214, 215, 216, 217, -1, 219, -1, 221, -1, -1, - 224, -1, 226, 227, 228, 229, 230, 231, -1, -1, - 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, - 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, - 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, - 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, - 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, - 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, - 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, - -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, - 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, - 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, - -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, - 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, - 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, - 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, - 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, - 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, - 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, - 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, - 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, - 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, + 380, 381, -1, 383, 384, 385, 386, 387, 388, 389, + -1, 391, 392, -1, 394, 395, 396, 397, 398, -1, + 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, + 410, 411, -1, 413, -1, -1, -1, 417, 418, -1, + 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, + 430, -1, -1, 433, 434, -1, 436, -1, -1, 439, + 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, + 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, + 460, 461, 462, -1, 464, 465, -1, 467, 468, 469, + 470, 471, 472, 473, 474, 475, -1, 22, 478, -1, + -1, 481, 482, 483, 484, 485, 486, 32, -1, 34, + 35, -1, -1, -1, -1, 22, -1, -1, 498, 499, + 500, 501, -1, -1, -1, 32, -1, 52, -1, -1, + -1, -1, -1, -1, -1, -1, 61, -1, -1, -1, + -1, -1, -1, -1, -1, 52, -1, -1, -1, -1, + 75, -1, -1, -1, 61, -1, -1, -1, -1, -1, + -1, 86, -1, -1, -1, -1, -1, -1, 75, -1, + -1, -1, -1, 98, -1, 100, -1, -1, -1, 86, + -1, -1, -1, -1, -1, -1, 111, -1, -1, -1, + -1, 98, -1, 100, -1, -1, -1, -1, -1, -1, + -1, 126, 127, -1, 111, -1, -1, -1, -1, -1, + -1, -1, 137, -1, -1, -1, -1, -1, 143, 126, + 127, -1, -1, -1, -1, -1, 151, -1, -1, -1, + 137, -1, -1, -1, -1, -1, 143, -1, -1, -1, + -1, -1, -1, 168, 151, -1, -1, 172, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, - 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, - -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, - -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, - -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, - 75, 76, 77, 78, 79, -1, -1, -1, 83, 84, - 85, 86, 87, 88, -1, 90, 91, 92, -1, 94, - 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, - 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, - 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, - 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, - 165, 166, -1, 168, -1, 170, -1, -1, -1, 174, - 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, - 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, - 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, - 205, 206, -1, 208, -1, 210, 211, 212, 213, 214, - 215, 216, 217, -1, 219, -1, 221, -1, -1, 224, - -1, 226, 227, 228, 229, 230, 231, -1, -1, 234, - -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, 274, - -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, - 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, - -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - -1, -1, -1, -1, 319, 320, 321, -1, 323, 324, - 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, - 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, -1, 362, 363, -1, - 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, - 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, - 385, 386, 387, 388, 389, 390, 391, 392, -1, -1, - 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, - 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, - 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, - 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, - 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, - 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, - 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, - 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, - 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, - 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, + -1, 168, -1, -1, -1, 172, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, 37, -1, -1, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, -1, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, - -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, -1, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, -1, 153, 154, 155, - 156, 157, 158, -1, -1, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - -1, 177, 178, -1, 180, -1, -1, -1, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, -1, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, - 276, 277, 278, 279, -1, -1, 282, 283, 284, 285, - 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, -1, 300, 301, 302, -1, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, -1, 322, 323, 324, -1, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, 383, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, -1, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, -1, - 436, -1, -1, 439, 440, 441, 442, 443, 444, 445, - 446, 447, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, -1, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 3, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 498, 499, 500, 501, -1, -1, -1, -1, - 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, - 32, 33, -1, -1, -1, 37, -1, -1, -1, -1, - 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, - 52, -1, 54, 55, 56, 57, -1, 59, 60, 61, - 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, - 72, 73, -1, 75, 76, 77, 78, -1, -1, 81, - -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, - 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, - -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, - 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, - -1, 153, 154, 155, 156, 157, 158, -1, -1, 161, - -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, - -1, 173, 174, 175, -1, 177, 178, -1, 180, -1, - -1, -1, 184, 185, -1, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, - 202, 203, 204, 205, 206, -1, 208, 209, -1, 211, - 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, -1, -1, - 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, - 292, 293, 294, -1, -1, 297, 298, -1, 300, 301, - 302, -1, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, -1, -1, -1, -1, 319, 320, -1, - 322, 323, 324, -1, 326, 327, 328, -1, 330, 331, - 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, - 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, - 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - -1, 383, 384, 385, 386, 387, 388, 389, 390, 391, - 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, -1, -1, -1, 417, 418, -1, 420, 421, - 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, - -1, 433, 434, -1, 436, -1, -1, 439, 440, 441, - 442, 443, 444, 445, 446, 447, -1, 449, 450, 451, - -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, - 462, -1, 464, 465, -1, 467, 468, 469, 470, 471, - 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, - 482, 483, 484, 485, 486, 3, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 498, 499, 500, 501, - -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, - 28, 29, -1, 31, 32, 33, -1, -1, -1, 37, - -1, -1, -1, -1, 42, 43, 44, -1, 46, 47, - 48, 49, 50, 51, 52, -1, 54, 55, 56, 57, - -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, - 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, - 78, -1, -1, 81, -1, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, - 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, - 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, - 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, - 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, - 148, 149, 150, 151, -1, 153, 154, 155, 156, 157, - 158, -1, -1, 161, -1, 163, 164, 165, 166, -1, - 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, - 178, -1, 180, -1, -1, -1, 184, 185, -1, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, - 208, 209, -1, 211, 212, 213, 214, 215, 216, 217, - -1, 219, -1, 221, 222, 223, 224, 225, 226, 227, - 228, 229, 230, 231, -1, -1, 234, 235, 236, 237, - -1, 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, -1, 276, 277, - 278, 279, -1, -1, 282, 283, 284, 285, 286, -1, - 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, - 298, -1, 300, 301, 302, -1, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, - -1, 319, 320, -1, 322, 323, 324, -1, 326, 327, - 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, - 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, - 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, - -1, 369, 370, 371, 372, 373, 374, 375, 376, 377, - 378, 379, 380, 381, -1, 383, 384, 385, 386, 387, - 388, 389, -1, 391, 392, -1, 394, 395, 396, 397, - 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, - 408, 409, 410, 411, 412, 413, -1, -1, -1, 417, - 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, - 428, 429, 430, -1, -1, 433, 434, -1, 436, -1, - -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, - -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, - 458, 459, 460, 461, 462, -1, 464, 465, -1, 467, - 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, - 478, -1, -1, 481, 482, 483, 484, 485, 486, 3, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 214, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 498, 499, 500, 501, -1, -1, -1, -1, 22, 23, - 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, - 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, - 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, - 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, - -1, 75, 76, 77, 78, 79, -1, -1, -1, 83, - 84, 85, 86, 87, 88, -1, 90, 91, 92, -1, - 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, - 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, - 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, - 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, - 164, 165, 166, -1, 168, -1, 170, -1, -1, -1, - 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, - -1, 185, -1, 187, 188, 189, 190, 191, 192, 193, - -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, - 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, - 214, 215, 216, 217, -1, 219, -1, 221, -1, -1, - 224, -1, 226, 227, 228, 229, 230, 231, -1, -1, - 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, - 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, - 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, - 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, - 304, 305, 306, 307, 308, 309, -1, 311, 312, 313, - 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, - 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, - 334, 335, -1, 337, 338, 339, -1, 341, 342, 343, - 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, - -1, 365, 366, 367, 368, -1, 370, 371, 372, 373, - 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, - 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, - -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, - 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, - 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, - 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, - 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, - 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, - 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, - 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, - 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, - 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, + -1, -1, -1, -1, -1, -1, -1, 214, -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, 22, 23, 24, - 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, - -1, -1, 37, -1, -1, -1, -1, 42, 43, 44, - -1, 46, 47, 48, 49, 50, 51, 52, -1, 54, - 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, - -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, - 75, 76, 77, 78, -1, -1, 81, -1, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, - 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, - 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, - 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, - 145, 146, -1, 148, 149, 150, 151, -1, 153, 154, - 155, 156, 157, 158, -1, -1, 161, -1, 163, 164, - 165, 166, -1, 168, -1, 170, 171, -1, 173, 174, - 175, -1, 177, 178, -1, 180, -1, -1, -1, 184, - 185, -1, 187, 188, 189, 190, 191, 192, 193, 194, - 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, - 205, 206, -1, 208, 209, -1, 211, 212, 213, 214, - 215, 216, 217, -1, 219, -1, 221, 222, 223, 224, - 225, 226, 227, 228, 229, 230, 231, -1, -1, 234, - 235, 236, 237, -1, 239, 240, 241, 242, 243, 244, - 245, 246, -1, 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, - -1, 276, 277, 278, 279, -1, -1, 282, 283, 284, - 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, - -1, -1, 297, 298, -1, 300, 301, 302, -1, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - -1, -1, -1, -1, 319, 320, -1, 322, 323, 324, - -1, 326, 327, 328, -1, 330, 331, 332, 333, 334, - 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, - 365, 366, 367, -1, 369, 370, 371, 372, 373, 374, - 375, 376, 377, 378, 379, 380, 381, -1, 383, 384, - 385, 386, 387, 388, 389, -1, 391, 392, -1, 394, - 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, - 405, 406, 407, 408, 409, 410, 411, -1, 413, -1, - -1, -1, 417, 418, -1, 420, 421, 422, 423, 424, - 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, - -1, 436, -1, -1, 439, 440, 441, 442, 443, 444, - 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, - 455, 456, -1, 458, 459, 460, 461, 462, -1, 464, - 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, - 475, -1, 22, 478, -1, -1, 481, 482, 483, 484, - 485, 486, 32, -1, 34, 35, -1, -1, -1, -1, - 22, -1, -1, 498, 499, 500, 501, -1, -1, -1, - 32, -1, 52, -1, -1, -1, -1, -1, -1, -1, - -1, 61, -1, -1, -1, -1, -1, -1, -1, -1, - 52, -1, -1, -1, -1, 75, -1, -1, -1, 61, - -1, -1, -1, -1, -1, -1, 86, -1, -1, -1, - -1, -1, -1, 75, -1, -1, -1, -1, 98, -1, - 100, -1, -1, -1, 86, -1, -1, -1, -1, -1, - -1, 111, -1, -1, -1, -1, 98, -1, 100, -1, - -1, -1, -1, -1, -1, -1, 126, 127, -1, 111, - -1, -1, -1, -1, -1, -1, -1, 137, -1, -1, - -1, -1, -1, 143, 126, 127, -1, -1, -1, -1, - -1, 151, -1, -1, -1, 137, -1, -1, -1, -1, - -1, 143, -1, -1, -1, -1, -1, -1, 168, 151, - -1, -1, 172, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 168, -1, -1, -1, - 172, -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, 214, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 214, -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, 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, + 315, 316, 317, -1, -1, -1, -1, -1, 323, -1, + -1, 326, -1, -1, -1, -1, -1, -1, 315, 316, + 317, -1, -1, -1, -1, -1, 323, -1, -1, 326, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 357, -1, -1, -1, -1, -1, -1, -1, + -1, 366, -1, -1, -1, -1, -1, -1, -1, -1, + 357, -1, -1, -1, -1, -1, -1, 382, -1, 366, + -1, -1, -1, -1, 389, -1, -1, -1, 393, -1, + -1, -1, -1, -1, -1, 382, -1, -1, 403, -1, + -1, -1, 389, -1, -1, -1, 393, -1, -1, -1, + 415, -1, -1, -1, 419, -1, 403, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 415, -1, + -1, -1, 419, -1, 439, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 452, -1, -1, + -1, -1, 439, 458, -1, -1, -1, -1, 463, -1, + -1, -1, -1, 468, -1, 452, -1, -1, -1, -1, + -1, 458, -1, -1, -1, 480, 463, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 315, 316, 317, -1, -1, - -1, -1, -1, 323, -1, -1, 326, -1, -1, -1, - -1, -1, -1, 315, 316, 317, -1, -1, -1, -1, - -1, 323, -1, -1, 326, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 357, -1, -1, - -1, -1, -1, -1, -1, -1, 366, -1, -1, -1, - -1, -1, -1, -1, -1, 357, -1, -1, -1, -1, - -1, -1, 382, -1, 366, -1, -1, -1, -1, 389, - -1, -1, -1, 393, -1, -1, -1, -1, -1, -1, - 382, -1, -1, 403, -1, -1, -1, 389, -1, -1, - -1, 393, -1, -1, -1, 415, -1, -1, -1, 419, - -1, 403, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 415, -1, -1, -1, 419, -1, 439, + -1, -1, -1, 480, -1, -1, -1, -1, -1, 504, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 452, -1, -1, -1, -1, 439, 458, -1, - -1, -1, -1, 463, -1, -1, -1, -1, 468, -1, - 452, -1, -1, -1, -1, -1, 458, -1, -1, -1, - 480, 463, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 480, -1, - -1, -1, -1, -1, 504, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, - -1, -1, 504, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 518 + -1, -1, -1, 518, -1, -1, -1, 504, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 518 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -18996,11 +19357,11 @@ static const yytype_uint16 yystos[] = 452, 455, 458, 463, 480, 504, 518, 530, 531, 532, 533, 544, 553, 555, 560, 576, 579, 580, 582, 586, 587, 591, 598, 600, 603, 604, 652, 658, 667, 668, - 686, 687, 688, 689, 691, 693, 694, 698, 751, 752, - 925, 928, 931, 938, 939, 941, 944, 945, 946, 953, - 957, 963, 964, 967, 972, 976, 977, 978, 981, 984, - 985, 986, 990, 991, 993, 433, 483, 601, 203, 373, - 384, 419, 470, 108, 192, 979, 601, 3, 22, 23, + 686, 687, 688, 689, 691, 693, 694, 698, 752, 753, + 935, 938, 941, 948, 949, 951, 954, 955, 956, 963, + 967, 973, 974, 977, 982, 986, 987, 988, 991, 994, + 995, 996, 999, 1000, 1002, 433, 483, 601, 203, 373, + 384, 419, 470, 108, 192, 989, 601, 3, 22, 23, 24, 25, 26, 27, 28, 29, 31, 32, 33, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 60, 61, 62, 63, 64, @@ -19041,10 +19402,10 @@ static const yytype_uint16 yystos[] = 467, 468, 469, 470, 471, 472, 473, 474, 475, 478, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 546, 831, 914, 918, 996, 997, 998, 3, 176, - 247, 412, 546, 940, 996, 290, 601, 55, 172, 518, + 501, 546, 834, 924, 928, 1005, 1006, 1007, 3, 176, + 247, 412, 546, 950, 1005, 290, 601, 55, 172, 518, 681, 178, 241, 295, 314, 373, 423, 425, 442, 448, - 451, 584, 650, 937, 5, 30, 326, 546, 547, 913, + 451, 584, 650, 947, 5, 30, 326, 546, 547, 923, 3, 30, 34, 35, 36, 37, 38, 39, 40, 41, 42, 45, 49, 53, 54, 55, 56, 57, 58, 65, 66, 71, 72, 74, 79, 80, 81, 82, 83, 89, @@ -19060,293 +19421,297 @@ static const yytype_uint16 yystos[] = 412, 414, 415, 416, 419, 421, 427, 429, 430, 431, 432, 435, 437, 438, 441, 447, 448, 452, 457, 463, 464, 466, 468, 476, 477, 479, 480, 487, 488, 489, - 490, 491, 492, 493, 494, 495, 496, 497, 552, 996, - 1000, 1002, 24, 81, 97, 146, 156, 169, 174, 203, + 490, 491, 492, 493, 494, 495, 496, 497, 552, 1005, + 1009, 1011, 24, 81, 97, 146, 156, 169, 174, 203, 246, 250, 320, 335, 370, 373, 384, 387, 405, 419, 425, 426, 436, 442, 470, 584, 653, 654, 657, 601, - 913, 100, 137, 468, 518, 533, 544, 553, 555, 576, + 923, 100, 137, 468, 518, 533, 544, 553, 555, 576, 579, 580, 586, 587, 591, 600, 604, 652, 658, 667, - 668, 686, 925, 928, 931, 938, 939, 949, 953, 957, - 963, 967, 972, 981, 984, 990, 991, 993, 108, 75, + 668, 686, 935, 938, 941, 948, 949, 959, 963, 967, + 973, 977, 982, 991, 994, 999, 1000, 1002, 108, 75, 66, 79, 81, 159, 232, 281, 291, 303, 321, 369, 414, 435, 437, 441, 463, 518, 545, 546, 547, 687, - 752, 754, 756, 766, 773, 774, 831, 833, 834, 108, - 5, 546, 548, 965, 546, 913, 30, 178, 241, 388, - 429, 433, 465, 546, 982, 983, 988, 601, 30, 132, - 707, 708, 178, 241, 373, 388, 429, 465, 958, 959, - 988, 601, 546, 686, 698, 989, 546, 773, 419, 704, - 545, 173, 518, 969, 518, 345, 699, 700, 913, 699, - 687, 688, 984, 0, 521, 122, 213, 454, 147, 218, - 296, 447, 710, 711, 756, 756, 687, 689, 691, 522, - 468, 947, 214, 30, 429, 433, 686, 989, 192, 545, - 913, 192, 545, 192, 773, 192, 545, 275, 548, 341, - 602, 516, 520, 549, 550, 518, 82, 108, 174, 203, - 246, 373, 384, 419, 442, 470, 943, 108, 686, 545, - 423, 425, 423, 425, 355, 192, 545, 545, 380, 174, - 246, 345, 384, 419, 470, 665, 203, 30, 913, 192, - 552, 252, 436, 107, 419, 419, 470, 377, 380, 192, - 546, 655, 920, 192, 910, 913, 192, 913, 518, 590, - 295, 425, 949, 3, 463, 950, 952, 953, 955, 956, - 996, 1000, 947, 546, 548, 940, 518, 518, 167, 518, - 687, 774, 518, 518, 545, 518, 518, 172, 518, 518, - 518, 518, 687, 752, 756, 766, 511, 549, 40, 546, - 767, 768, 767, 382, 522, 690, 37, 42, 101, 173, - 209, 225, 235, 269, 315, 322, 364, 383, 452, 770, - 768, 40, 546, 767, 769, 504, 778, 548, 507, 518, - 518, 926, 983, 983, 983, 501, 224, 983, 520, 290, - 4, 6, 7, 8, 9, 10, 39, 54, 56, 57, - 65, 71, 72, 83, 112, 115, 117, 136, 152, 160, - 165, 182, 183, 216, 217, 219, 247, 268, 270, 275, - 280, 283, 292, 342, 368, 397, 429, 430, 438, 464, - 502, 509, 510, 511, 516, 518, 523, 524, 525, 526, - 546, 548, 687, 741, 790, 793, 796, 797, 798, 800, - 801, 802, 803, 805, 806, 822, 824, 825, 826, 827, - 828, 829, 830, 831, 832, 834, 836, 851, 852, 863, - 885, 892, 900, 901, 902, 914, 915, 916, 899, 901, - 958, 958, 548, 958, 501, 958, 172, 431, 507, 602, - 520, 549, 773, 973, 3, 171, 173, 468, 953, 968, - 970, 171, 971, 822, 869, 870, 699, 522, 518, 922, - 519, 519, 519, 532, 172, 295, 563, 157, 973, 30, - 132, 705, 705, 59, 705, 162, 167, 238, 287, 716, - 718, 719, 744, 746, 747, 748, 181, 290, 457, 290, - 710, 711, 518, 545, 965, 420, 987, 501, 224, 152, - 26, 32, 137, 294, 353, 357, 389, 460, 538, 541, - 542, 353, 152, 40, 60, 106, 202, 251, 261, 273, - 305, 353, 359, 384, 389, 403, 541, 592, 595, 152, - 353, 389, 541, 152, 353, 389, 541, 152, 40, 980, - 291, 485, 822, 893, 551, 552, 550, 3, 30, 37, - 42, 49, 55, 81, 83, 89, 101, 132, 171, 173, - 176, 177, 194, 209, 222, 223, 225, 235, 237, 247, - 269, 278, 300, 302, 322, 364, 383, 394, 412, 421, - 441, 466, 468, 519, 822, 872, 873, 917, 923, 996, - 1001, 822, 419, 545, 546, 519, 518, 639, 373, 584, - 650, 275, 929, 40, 192, 546, 583, 470, 192, 545, - 192, 545, 995, 192, 545, 192, 545, 89, 934, 152, - 484, 90, 129, 308, 424, 192, 546, 152, 520, 921, - 63, 360, 522, 656, 152, 522, 656, 152, 290, 588, - 589, 822, 923, 355, 519, 522, 4, 160, 290, 438, - 509, 510, 548, 594, 597, 916, 948, 950, 951, 954, - 949, 431, 518, 676, 680, 822, 870, 518, 3, 68, - 69, 109, 110, 113, 114, 189, 190, 253, 254, 255, - 256, 257, 258, 259, 260, 263, 264, 337, 338, 378, - 379, 474, 475, 498, 499, 548, 808, 809, 810, 811, - 812, 813, 814, 815, 816, 817, 818, 819, 820, 875, - 876, 768, 769, 822, 545, 822, 877, 509, 510, 546, - 823, 824, 852, 863, 879, 518, 822, 869, 880, 822, - 58, 172, 233, 432, 822, 870, 883, 822, 519, 547, - 518, 421, 724, 725, 725, 707, 708, 756, 220, 702, - 225, 37, 225, 383, 770, 225, 300, 771, 756, 771, - 225, 770, 518, 225, 771, 225, 148, 200, 758, 225, - 725, 518, 547, 518, 725, 297, 822, 960, 962, 872, - 3, 37, 42, 49, 54, 55, 56, 57, 71, 72, - 81, 83, 89, 101, 112, 115, 165, 171, 173, 177, - 194, 209, 216, 217, 219, 222, 223, 225, 235, 237, - 247, 268, 269, 270, 278, 283, 300, 302, 322, 342, - 364, 368, 383, 390, 394, 397, 412, 421, 429, 430, - 441, 447, 464, 468, 784, 786, 787, 789, 791, 793, - 795, 797, 798, 799, 801, 802, 805, 806, 874, 919, - 996, 999, 40, 236, 546, 518, 516, 687, 467, 804, - 822, 889, 804, 804, 518, 518, 792, 792, 325, 687, - 518, 794, 526, 71, 72, 804, 822, 792, 518, 518, - 482, 504, 518, 807, 518, 807, 822, 822, 822, 83, - 148, 903, 904, 822, 870, 871, 687, 822, 869, 9, - 552, 547, 853, 854, 855, 520, 549, 894, 549, 518, - 548, 518, 518, 548, 916, 3, 8, 11, 15, 16, - 17, 18, 19, 20, 21, 36, 40, 46, 53, 80, - 177, 194, 199, 222, 223, 237, 275, 278, 292, 295, - 394, 502, 505, 506, 507, 509, 510, 511, 512, 513, - 514, 861, 862, 863, 865, 897, 481, 837, 302, 822, - 522, 702, 518, 548, 702, 3, 117, 241, 548, 594, - 806, 961, 104, 962, 962, 546, 40, 546, 519, 522, - 947, 522, 519, 700, 910, 911, 40, 973, 193, 355, - 220, 639, 389, 689, 689, 30, 712, 713, 822, 59, - 689, 706, 164, 272, 732, 227, 273, 341, 392, 454, - 4, 9, 30, 727, 822, 509, 510, 728, 729, 822, - 824, 744, 745, 719, 718, 716, 717, 167, 747, 285, - 749, 59, 695, 696, 697, 759, 823, 901, 901, 716, - 744, 870, 922, 172, 469, 966, 236, 545, 74, 82, - 93, 169, 192, 329, 448, 546, 621, 631, 646, 82, - 93, 554, 93, 554, 518, 431, 518, 619, 245, 451, - 619, 93, 522, 431, 545, 3, 789, 594, 59, 596, - 594, 594, 106, 251, 261, 59, 431, 480, 504, 593, - 266, 373, 593, 595, 773, 93, 431, 554, 373, 545, - 431, 373, 979, 546, 676, 517, 528, 872, 872, 873, - 522, 710, 711, 13, 14, 222, 222, 431, 431, 546, - 638, 643, 480, 679, 545, 380, 345, 384, 419, 470, - 665, 152, 100, 580, 604, 930, 931, 991, 144, 786, - 275, 199, 585, 545, 275, 581, 592, 275, 518, 639, - 40, 275, 639, 275, 518, 659, 660, 661, 662, 663, - 664, 666, 192, 546, 633, 935, 552, 152, 172, 599, - 655, 551, 520, 920, 910, 913, 913, 920, 519, 522, - 13, 949, 955, 4, 916, 4, 916, 548, 552, 678, - 685, 55, 102, 123, 141, 145, 168, 171, 187, 280, - 288, 310, 339, 682, 40, 519, 822, 519, 172, 522, - 519, 318, 878, 519, 823, 823, 11, 15, 16, 19, - 20, 21, 199, 222, 292, 505, 506, 507, 509, 510, - 511, 512, 513, 514, 863, 823, 519, 775, 776, 833, - 167, 172, 881, 882, 522, 519, 40, 883, 870, 883, - 883, 172, 519, 40, 767, 518, 911, 4, 9, 546, - 720, 722, 723, 901, 899, 178, 241, 419, 423, 425, - 451, 545, 703, 477, 779, 756, 756, 225, 756, 290, - 457, 772, 756, 225, 901, 756, 756, 282, 282, 518, - 756, 547, 780, 781, 518, 547, 780, 522, 519, 522, - 520, 518, 789, 518, 518, 520, 39, 788, 518, 808, - 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, - 819, 820, 821, 519, 522, 792, 555, 560, 667, 668, - 686, 927, 972, 984, 870, 871, 518, 476, 886, 887, - 822, 871, 916, 822, 856, 857, 858, 859, 804, 804, - 8, 15, 16, 19, 20, 21, 505, 506, 507, 509, - 510, 511, 512, 513, 514, 546, 861, 866, 519, 870, - 429, 429, 916, 916, 518, 518, 546, 355, 908, 167, - 517, 519, 522, 528, 522, 527, 511, 550, 870, 916, - 822, 821, 821, 786, 822, 822, 822, 822, 822, 822, - 822, 822, 5, 552, 924, 429, 45, 416, 898, 920, - 822, 822, 518, 687, 827, 884, 892, 132, 160, 275, - 280, 285, 438, 449, 822, 280, 518, 822, 431, 53, - 177, 194, 199, 237, 394, 822, 822, 822, 822, 822, - 822, 822, 822, 822, 822, 30, 38, 399, 860, 516, - 520, 896, 181, 163, 838, 368, 518, 852, 902, 172, - 753, 872, 753, 518, 548, 546, 545, 968, 545, 976, - 822, 522, 519, 250, 275, 701, 457, 975, 545, 557, - 518, 546, 562, 572, 573, 575, 41, 126, 714, 522, - 457, 714, 266, 689, 368, 369, 509, 510, 729, 731, - 824, 392, 227, 291, 313, 313, 522, 513, 4, 730, - 916, 730, 368, 369, 731, 545, 909, 279, 396, 750, - 518, 911, 912, 522, 181, 457, 199, 181, 220, 745, - 717, 519, 546, 548, 546, 548, 353, 541, 518, 192, - 631, 913, 227, 275, 227, 457, 518, 624, 785, 786, - 913, 546, 192, 913, 192, 546, 26, 137, 389, 537, - 540, 552, 615, 629, 913, 552, 623, 642, 913, 538, - 913, 353, 389, 541, 592, 594, 920, 913, 594, 920, - 913, 594, 353, 389, 541, 913, 913, 913, 913, 353, - 389, 541, 913, 913, 548, 510, 822, 893, 710, 710, - 710, 466, 873, 193, 358, 709, 822, 822, 280, 548, - 942, 280, 942, 546, 334, 675, 519, 522, 288, 172, - 431, 670, 929, 583, 470, 545, 545, 995, 545, 545, - 545, 295, 650, 518, 687, 152, 3, 518, 518, 152, - 152, 237, 546, 621, 631, 634, 637, 647, 649, 480, - 482, 626, 151, 686, 152, 480, 936, 152, 519, 872, - 522, 522, 40, 275, 290, 546, 3, 656, 551, 656, - 290, 656, 588, 822, 676, 247, 511, 516, 518, 594, - 677, 828, 829, 830, 954, 519, 522, 40, 674, 548, - 674, 275, 280, 339, 674, 59, 674, 786, 519, 822, - 822, 822, 881, 786, 823, 823, 823, 823, 823, 823, - 132, 275, 285, 823, 823, 823, 823, 823, 823, 823, - 823, 823, 823, 519, 522, 40, 777, 822, 822, 882, - 881, 786, 519, 519, 519, 870, 786, 911, 519, 313, - 513, 313, 369, 513, 518, 518, 702, 423, 425, 423, - 425, 545, 704, 704, 704, 822, 181, 733, 772, 772, - 756, 822, 518, 756, 167, 772, 518, 547, 763, 772, - 786, 519, 522, 780, 519, 960, 3, 874, 39, 788, - 546, 783, 783, 3, 516, 516, 916, 431, 431, 431, - 431, 786, 454, 519, 517, 870, 822, 139, 887, 888, - 519, 519, 519, 528, 522, 527, 520, 519, 519, 501, - 501, 519, 519, 822, 911, 518, 822, 905, 546, 835, - 890, 891, 822, 822, 853, 904, 519, 519, 519, 501, - 823, 823, 145, 870, 172, 132, 160, 280, 285, 438, - 449, 518, 145, 866, 822, 416, 898, 822, 884, 822, - 431, 518, 687, 822, 893, 551, 518, 518, 155, 839, - 754, 755, 779, 710, 779, 916, 821, 922, 922, 250, - 518, 755, 477, 974, 40, 59, 558, 568, 575, 894, - 522, 753, 507, 503, 715, 713, 292, 861, 864, 715, - 4, 916, 731, 291, 454, 728, 522, 244, 911, 695, - 59, 901, 518, 547, 59, 266, 966, 966, 431, 822, - 275, 646, 518, 152, 518, 624, 203, 643, 644, 605, - 40, 176, 614, 640, 605, 26, 137, 357, 359, 389, - 534, 535, 536, 542, 543, 152, 656, 152, 656, 615, - 629, 615, 519, 522, 548, 608, 507, 520, 519, 522, - 431, 373, 93, 431, 554, 373, 431, 431, 431, 373, - 980, 528, 517, 528, 709, 709, 709, 873, 282, 282, - 519, 518, 669, 3, 406, 407, 548, 684, 638, 675, - 585, 545, 581, 518, 40, 639, 662, 664, 929, 355, - 419, 548, 577, 578, 583, 685, 643, 545, 545, 995, - 545, 519, 522, 288, 619, 288, 290, 618, 913, 480, - 994, 545, 619, 40, 545, 519, 660, 666, 663, 666, - 419, 822, 152, 545, 599, 920, 672, 683, 954, 678, - 548, 548, 280, 643, 511, 643, 548, 511, 643, 548, - 519, 519, 882, 172, 132, 285, 518, 778, 775, 518, - 519, 519, 519, 546, 720, 779, 704, 704, 704, 704, - 545, 545, 545, 59, 186, 742, 772, 911, 518, 760, - 761, 762, 825, 827, 911, 167, 80, 782, 781, 519, - 519, 516, 786, 519, 522, 519, 916, 517, 916, 519, - 809, 811, 812, 813, 812, 813, 813, 519, 427, 822, - 143, 822, 856, 866, 807, 807, 519, 519, 822, 905, - 906, 907, 40, 199, 522, 519, 908, 821, 822, 36, - 36, 822, 519, 822, 172, 518, 874, 822, 519, 145, - 823, 823, 145, 145, 822, 822, 517, 528, 518, 895, - 711, 477, 822, 301, 843, 522, 733, 709, 733, 519, - 927, 822, 361, 566, 546, 266, 321, 117, 304, 518, - 556, 686, 519, 522, 562, 974, 822, 164, 231, 518, - 715, 291, 545, 519, 912, 181, 687, 688, 901, 912, - 913, 913, 519, 152, 644, 631, 644, 605, 633, 522, - 519, 119, 207, 273, 275, 630, 518, 33, 59, 651, - 640, 74, 80, 93, 117, 119, 207, 275, 280, 329, - 347, 448, 457, 610, 611, 625, 176, 117, 191, 275, - 619, 593, 107, 117, 176, 275, 405, 408, 595, 619, - 389, 536, 442, 913, 546, 540, 3, 37, 42, 49, - 55, 81, 83, 89, 101, 171, 173, 176, 177, 194, - 209, 222, 223, 225, 235, 237, 247, 269, 274, 278, - 292, 300, 302, 322, 364, 383, 390, 394, 412, 421, - 441, 447, 468, 509, 510, 548, 594, 606, 645, 786, - 864, 917, 996, 1002, 552, 642, 913, 913, 913, 913, - 913, 913, 913, 913, 913, 913, 676, 893, 893, 519, - 519, 519, 710, 107, 373, 520, 593, 684, 518, 518, - 637, 686, 936, 650, 192, 545, 519, 522, 585, 519, - 519, 581, 518, 40, 628, 626, 634, 86, 590, 107, - 273, 639, 686, 662, 664, 40, 40, 687, 688, 633, - 457, 933, 656, 519, 522, 643, 823, 172, 518, 874, - 780, 519, 522, 519, 733, 545, 545, 545, 545, 30, - 103, 182, 367, 518, 734, 735, 736, 737, 738, 739, - 740, 822, 822, 479, 840, 519, 824, 867, 868, 199, - 181, 757, 761, 519, 763, 764, 765, 920, 788, 916, - 788, 546, 788, 517, 517, 822, 522, 519, 546, 822, - 824, 891, 822, 822, 822, 874, 519, 822, 36, 36, - 822, 822, 145, 519, 510, 893, 519, 872, 519, 822, - 519, 518, 546, 844, 742, 519, 742, 548, 519, 900, + 753, 755, 757, 758, 768, 775, 776, 834, 836, 837, + 108, 5, 546, 548, 975, 546, 923, 30, 178, 241, + 388, 429, 433, 465, 546, 992, 993, 998, 601, 30, + 132, 707, 708, 178, 241, 373, 388, 429, 465, 968, + 969, 998, 601, 545, 546, 547, 686, 698, 775, 419, + 704, 545, 173, 518, 979, 518, 345, 699, 700, 923, + 699, 687, 688, 994, 0, 521, 122, 213, 454, 147, + 218, 296, 447, 710, 711, 758, 758, 687, 689, 691, + 522, 468, 957, 214, 30, 429, 433, 545, 686, 192, + 545, 923, 192, 545, 192, 775, 192, 545, 275, 548, + 341, 602, 516, 520, 549, 550, 518, 82, 108, 174, + 203, 246, 373, 384, 419, 442, 470, 953, 108, 686, + 545, 423, 425, 423, 425, 355, 192, 545, 545, 380, + 174, 246, 345, 384, 419, 470, 665, 203, 30, 923, + 192, 552, 252, 436, 107, 419, 419, 470, 377, 380, + 192, 546, 655, 930, 192, 920, 923, 192, 923, 518, + 590, 295, 425, 959, 3, 463, 960, 962, 963, 965, + 966, 1005, 1009, 957, 546, 548, 950, 518, 518, 167, + 518, 687, 776, 518, 518, 545, 518, 518, 172, 518, + 518, 518, 518, 687, 753, 758, 768, 511, 549, 523, + 40, 546, 769, 770, 769, 382, 522, 690, 518, 687, + 775, 776, 37, 42, 101, 173, 209, 225, 235, 269, + 315, 322, 364, 383, 452, 772, 770, 40, 546, 769, + 771, 504, 780, 548, 507, 518, 518, 936, 993, 993, + 993, 501, 224, 993, 520, 290, 4, 6, 7, 8, + 9, 10, 39, 54, 56, 57, 65, 71, 72, 83, + 112, 115, 117, 136, 152, 160, 165, 182, 183, 216, + 217, 219, 247, 268, 270, 275, 280, 283, 292, 342, + 368, 397, 429, 430, 438, 464, 502, 509, 510, 511, + 516, 518, 524, 525, 526, 527, 546, 548, 687, 742, + 792, 795, 798, 799, 800, 802, 803, 804, 805, 807, + 808, 824, 826, 827, 828, 829, 830, 831, 832, 833, + 834, 835, 837, 839, 854, 855, 866, 888, 895, 903, + 904, 905, 924, 925, 926, 902, 904, 968, 968, 548, + 968, 501, 968, 172, 431, 507, 602, 549, 775, 983, + 3, 171, 173, 468, 963, 978, 980, 171, 981, 546, + 824, 872, 873, 699, 522, 518, 932, 519, 519, 519, + 532, 172, 295, 563, 157, 983, 30, 132, 705, 705, + 59, 705, 162, 167, 238, 287, 716, 718, 719, 745, + 747, 748, 749, 181, 290, 457, 290, 710, 711, 518, + 545, 975, 420, 997, 501, 224, 152, 26, 32, 137, + 294, 353, 357, 389, 460, 538, 541, 542, 353, 152, + 40, 60, 106, 202, 251, 261, 273, 305, 353, 359, + 384, 389, 403, 541, 592, 595, 152, 353, 389, 541, + 152, 353, 389, 541, 152, 40, 990, 291, 485, 824, + 896, 551, 552, 550, 3, 30, 37, 42, 49, 55, + 81, 83, 89, 101, 132, 171, 173, 176, 177, 194, + 209, 222, 223, 225, 235, 237, 247, 269, 278, 300, + 302, 322, 364, 383, 394, 412, 421, 441, 466, 468, + 519, 824, 875, 876, 927, 933, 1005, 1010, 824, 419, + 545, 546, 519, 518, 639, 373, 584, 650, 275, 939, + 40, 192, 546, 583, 470, 192, 545, 192, 545, 1004, + 192, 545, 192, 545, 89, 944, 152, 484, 90, 129, + 308, 424, 192, 546, 152, 520, 931, 63, 360, 522, + 656, 152, 522, 656, 152, 290, 588, 589, 824, 933, + 355, 519, 522, 4, 160, 290, 438, 509, 510, 548, + 594, 597, 926, 958, 960, 961, 964, 959, 431, 518, + 676, 680, 824, 873, 518, 3, 68, 69, 109, 110, + 113, 114, 189, 190, 253, 254, 255, 256, 257, 258, + 259, 260, 263, 264, 337, 338, 378, 379, 474, 475, + 498, 499, 548, 810, 811, 812, 813, 814, 815, 816, + 817, 818, 819, 820, 821, 822, 878, 879, 770, 771, + 824, 545, 824, 880, 509, 510, 546, 825, 826, 855, + 866, 882, 518, 824, 872, 883, 824, 58, 172, 233, + 432, 824, 873, 886, 824, 519, 547, 518, 421, 725, + 726, 726, 707, 708, 758, 220, 702, 768, 726, 726, + 726, 225, 37, 225, 383, 772, 225, 300, 773, 758, + 773, 225, 772, 518, 225, 773, 225, 148, 200, 760, + 225, 726, 518, 547, 518, 726, 297, 824, 970, 972, + 875, 3, 37, 42, 49, 54, 55, 56, 57, 71, + 72, 81, 83, 89, 101, 112, 115, 165, 171, 173, + 177, 194, 209, 216, 217, 219, 222, 223, 225, 235, + 237, 247, 268, 269, 270, 278, 283, 300, 302, 322, + 342, 364, 368, 383, 390, 394, 397, 412, 421, 429, + 430, 441, 447, 464, 468, 786, 788, 789, 791, 793, + 795, 797, 799, 800, 801, 803, 804, 807, 808, 877, + 929, 1005, 1008, 40, 236, 546, 518, 516, 687, 467, + 806, 824, 892, 806, 806, 518, 518, 794, 794, 325, + 687, 518, 796, 527, 71, 72, 806, 824, 794, 518, + 518, 482, 504, 518, 809, 518, 809, 824, 824, 824, + 83, 148, 906, 910, 824, 873, 874, 687, 824, 872, + 552, 9, 547, 856, 857, 858, 520, 523, 549, 897, + 549, 518, 548, 518, 518, 548, 926, 3, 8, 11, + 15, 16, 17, 18, 19, 20, 21, 36, 40, 46, + 53, 80, 177, 194, 199, 222, 223, 237, 275, 278, + 292, 295, 394, 502, 505, 506, 507, 509, 510, 511, + 512, 513, 514, 864, 865, 866, 868, 900, 481, 840, + 302, 824, 522, 702, 518, 548, 702, 3, 117, 241, + 548, 594, 808, 971, 104, 972, 972, 40, 546, 519, + 522, 957, 522, 519, 700, 920, 921, 40, 983, 193, + 355, 220, 639, 389, 689, 689, 30, 712, 713, 824, + 59, 689, 706, 164, 272, 733, 227, 273, 341, 392, + 454, 4, 9, 30, 728, 824, 509, 510, 729, 730, + 824, 826, 745, 746, 719, 718, 716, 717, 167, 748, + 285, 750, 59, 695, 696, 697, 761, 825, 904, 904, + 716, 745, 873, 932, 172, 469, 976, 236, 545, 74, + 82, 93, 169, 192, 329, 448, 546, 621, 631, 646, + 82, 93, 554, 93, 554, 518, 431, 518, 619, 245, + 451, 619, 93, 522, 431, 545, 3, 791, 594, 59, + 596, 594, 594, 106, 251, 261, 59, 431, 480, 504, + 593, 266, 373, 593, 595, 775, 93, 431, 554, 373, + 545, 431, 373, 989, 546, 676, 517, 523, 875, 875, + 876, 522, 710, 711, 13, 14, 222, 222, 431, 431, + 546, 638, 643, 480, 679, 545, 380, 345, 384, 419, + 470, 665, 152, 100, 580, 604, 940, 941, 1000, 144, + 788, 275, 199, 585, 545, 275, 581, 592, 275, 518, + 639, 40, 275, 639, 275, 518, 659, 660, 661, 662, + 663, 664, 666, 192, 546, 633, 945, 552, 152, 172, + 599, 655, 551, 520, 930, 920, 923, 923, 930, 519, + 522, 13, 959, 965, 4, 926, 4, 926, 548, 552, + 678, 685, 55, 102, 123, 141, 145, 168, 171, 187, + 280, 288, 310, 339, 682, 40, 519, 824, 519, 172, + 522, 519, 318, 881, 519, 825, 825, 11, 15, 16, + 19, 20, 21, 199, 222, 292, 505, 506, 507, 509, + 510, 511, 512, 513, 514, 866, 825, 519, 777, 778, + 836, 167, 172, 884, 885, 522, 519, 40, 886, 873, + 886, 886, 172, 519, 40, 769, 518, 921, 4, 9, + 546, 720, 721, 723, 724, 829, 904, 902, 178, 241, + 419, 423, 425, 451, 545, 703, 477, 781, 519, 758, + 758, 225, 758, 290, 457, 774, 758, 225, 904, 758, + 758, 282, 282, 518, 758, 547, 782, 783, 518, 547, + 782, 522, 519, 522, 520, 518, 791, 518, 518, 520, + 39, 790, 518, 810, 811, 812, 813, 814, 815, 816, + 817, 818, 819, 820, 821, 822, 823, 519, 522, 794, + 555, 560, 667, 668, 686, 937, 982, 994, 873, 874, + 518, 476, 889, 890, 824, 874, 926, 824, 859, 860, + 861, 862, 806, 806, 8, 15, 16, 19, 20, 21, + 505, 506, 507, 509, 510, 511, 512, 513, 514, 546, + 864, 869, 519, 873, 429, 429, 926, 926, 518, 518, + 547, 907, 355, 914, 167, 517, 519, 522, 523, 522, + 528, 511, 824, 550, 873, 926, 824, 823, 823, 788, + 824, 824, 824, 824, 824, 824, 824, 824, 5, 552, + 934, 429, 45, 416, 901, 930, 824, 824, 518, 687, + 830, 887, 895, 132, 160, 275, 280, 285, 438, 449, + 824, 280, 518, 824, 431, 53, 177, 194, 199, 237, + 394, 824, 824, 824, 824, 824, 824, 824, 824, 824, + 824, 30, 38, 399, 863, 516, 520, 899, 181, 163, + 841, 368, 518, 855, 905, 172, 754, 875, 754, 518, + 548, 546, 545, 978, 545, 986, 824, 522, 519, 250, + 275, 701, 457, 985, 545, 557, 518, 546, 562, 572, + 573, 575, 41, 126, 714, 522, 457, 714, 266, 689, + 368, 369, 509, 510, 730, 732, 826, 392, 227, 291, + 313, 313, 522, 513, 4, 731, 926, 731, 368, 369, + 732, 545, 919, 279, 396, 751, 518, 921, 922, 522, + 181, 457, 199, 181, 220, 746, 717, 519, 546, 548, + 546, 548, 353, 541, 518, 192, 631, 923, 227, 275, + 227, 457, 518, 624, 787, 788, 923, 546, 192, 923, + 192, 546, 26, 137, 389, 537, 540, 552, 615, 629, + 923, 552, 623, 642, 923, 538, 923, 353, 389, 541, + 592, 594, 930, 923, 594, 930, 923, 594, 353, 389, + 541, 923, 923, 923, 923, 353, 389, 541, 923, 923, + 548, 510, 824, 896, 710, 710, 710, 466, 876, 193, + 358, 709, 824, 824, 280, 548, 952, 280, 952, 546, + 334, 675, 519, 522, 288, 172, 431, 670, 939, 583, + 470, 545, 545, 1004, 545, 545, 545, 295, 650, 518, + 687, 152, 3, 518, 518, 152, 152, 237, 546, 621, + 631, 634, 637, 647, 649, 480, 482, 626, 151, 686, + 152, 480, 946, 152, 519, 875, 522, 522, 40, 275, + 290, 546, 3, 656, 551, 656, 290, 656, 588, 824, + 676, 247, 511, 516, 518, 594, 677, 831, 832, 833, + 964, 519, 522, 40, 674, 548, 674, 275, 280, 339, + 674, 59, 674, 788, 519, 824, 824, 824, 884, 788, + 825, 825, 825, 825, 825, 825, 132, 275, 285, 825, + 825, 825, 825, 825, 825, 825, 825, 825, 825, 519, + 522, 40, 779, 824, 824, 885, 884, 788, 519, 519, + 519, 873, 788, 921, 519, 313, 369, 513, 518, 518, + 702, 423, 425, 423, 425, 545, 704, 704, 704, 824, + 181, 734, 774, 774, 758, 824, 518, 758, 167, 774, + 518, 547, 765, 774, 788, 519, 522, 782, 519, 970, + 3, 877, 39, 790, 546, 785, 785, 3, 516, 516, + 926, 431, 431, 431, 431, 788, 454, 519, 517, 873, + 824, 139, 890, 891, 519, 519, 519, 523, 522, 528, + 520, 519, 519, 501, 501, 519, 519, 824, 907, 908, + 909, 520, 518, 824, 911, 353, 918, 546, 838, 893, + 894, 824, 824, 856, 910, 519, 519, 519, 501, 825, + 825, 145, 873, 172, 132, 160, 280, 285, 438, 449, + 518, 145, 869, 824, 416, 901, 824, 887, 824, 431, + 518, 687, 824, 896, 551, 518, 518, 155, 842, 755, + 756, 781, 710, 781, 926, 823, 932, 932, 250, 518, + 756, 477, 984, 40, 59, 558, 568, 575, 897, 522, + 754, 507, 503, 715, 713, 292, 864, 867, 715, 4, + 926, 732, 291, 454, 729, 522, 244, 921, 695, 59, + 904, 518, 547, 59, 266, 976, 976, 431, 824, 275, + 646, 518, 152, 518, 624, 203, 643, 644, 605, 40, + 176, 614, 640, 605, 26, 137, 357, 359, 389, 534, + 535, 536, 542, 543, 152, 656, 152, 656, 615, 629, + 615, 519, 522, 548, 608, 507, 520, 519, 522, 431, + 373, 93, 431, 554, 373, 431, 431, 431, 373, 990, + 523, 517, 523, 709, 709, 709, 876, 282, 282, 519, + 518, 669, 3, 406, 407, 548, 684, 638, 675, 585, + 545, 581, 518, 40, 639, 662, 664, 939, 355, 419, + 548, 577, 578, 583, 685, 643, 545, 545, 1004, 545, + 519, 522, 288, 619, 288, 290, 618, 923, 480, 1003, + 545, 619, 40, 545, 519, 660, 666, 663, 666, 419, + 824, 152, 545, 599, 930, 672, 683, 964, 678, 548, + 548, 280, 643, 511, 643, 548, 511, 643, 548, 519, + 519, 885, 172, 132, 285, 518, 780, 777, 518, 519, + 519, 519, 546, 721, 781, 704, 704, 704, 704, 545, + 545, 545, 59, 186, 743, 774, 921, 518, 762, 763, + 764, 827, 830, 921, 167, 80, 784, 783, 519, 519, + 516, 788, 519, 522, 519, 926, 517, 926, 519, 811, + 813, 814, 815, 814, 815, 815, 519, 427, 824, 143, + 824, 859, 869, 809, 809, 519, 522, 519, 547, 824, + 911, 912, 913, 40, 518, 907, 915, 199, 522, 519, + 914, 823, 824, 36, 36, 824, 519, 824, 172, 518, + 877, 824, 519, 145, 825, 825, 145, 145, 824, 824, + 517, 523, 518, 898, 711, 477, 824, 301, 846, 522, + 734, 709, 734, 519, 937, 824, 361, 566, 546, 266, + 321, 117, 304, 518, 556, 686, 519, 522, 562, 984, + 824, 164, 231, 518, 715, 291, 545, 519, 922, 181, + 687, 688, 904, 922, 923, 923, 519, 152, 644, 631, + 644, 605, 633, 522, 519, 119, 207, 273, 275, 630, + 518, 33, 59, 651, 640, 74, 80, 93, 117, 119, + 207, 275, 280, 329, 347, 448, 457, 610, 611, 625, + 176, 117, 191, 275, 619, 593, 107, 117, 176, 275, + 405, 408, 595, 619, 389, 536, 442, 923, 546, 540, + 3, 37, 42, 49, 55, 81, 83, 89, 101, 171, + 173, 176, 177, 194, 209, 222, 223, 225, 235, 237, + 247, 269, 274, 278, 292, 300, 302, 322, 364, 383, + 390, 394, 412, 421, 441, 447, 468, 509, 510, 548, + 594, 606, 645, 788, 867, 927, 1005, 1011, 552, 642, + 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, + 676, 896, 896, 519, 519, 519, 710, 107, 373, 520, + 593, 684, 518, 518, 637, 686, 946, 650, 192, 545, + 519, 522, 585, 519, 519, 581, 518, 40, 628, 626, + 634, 86, 590, 107, 273, 639, 686, 662, 664, 40, + 40, 687, 688, 633, 457, 943, 656, 519, 522, 643, + 825, 172, 518, 877, 782, 519, 522, 519, 734, 545, + 545, 545, 545, 30, 103, 182, 367, 518, 735, 736, + 737, 738, 739, 740, 741, 824, 824, 479, 843, 519, + 826, 870, 871, 199, 181, 759, 763, 519, 765, 766, + 767, 930, 790, 926, 790, 546, 790, 517, 517, 824, + 907, 522, 519, 546, 915, 916, 917, 40, 824, 826, + 894, 918, 824, 824, 824, 877, 519, 824, 36, 36, + 824, 824, 145, 519, 510, 896, 519, 875, 519, 824, + 519, 518, 546, 847, 743, 519, 743, 548, 519, 903, 463, 418, 456, 567, 546, 561, 571, 290, 564, 507, - 575, 566, 866, 59, 519, 519, 462, 463, 692, 605, + 575, 566, 869, 59, 519, 519, 462, 463, 692, 605, 631, 519, 519, 480, 636, 120, 195, 205, 119, 459, - 822, 117, 40, 518, 920, 913, 823, 120, 195, 119, - 280, 227, 545, 636, 88, 651, 192, 280, 594, 822, - 651, 280, 509, 510, 597, 546, 786, 656, 656, 3, - 247, 412, 917, 921, 507, 431, 431, 517, 517, 709, - 519, 519, 546, 676, 457, 671, 673, 685, 643, 519, - 994, 40, 419, 275, 518, 548, 518, 936, 637, 151, - 686, 149, 201, 618, 122, 137, 328, 994, 107, 936, - 480, 992, 419, 290, 546, 932, 518, 683, 823, 874, - 519, 519, 9, 354, 726, 742, 518, 391, 518, 519, - 522, 546, 841, 842, 336, 743, 522, 519, 518, 547, - 59, 519, 199, 519, 764, 517, 786, 905, 517, 192, - 519, 822, 822, 822, 528, 517, 528, 519, 519, 546, - 845, 840, 548, 840, 522, 462, 894, 519, 522, 91, - 566, 822, 519, 912, 912, 347, 636, 518, 627, 605, - 519, 191, 518, 822, 275, 611, 636, 639, 913, 40, - 152, 782, 921, 513, 606, 913, 913, 519, 593, 124, - 519, 519, 626, 686, 545, 152, 685, 40, 519, 913, - 994, 30, 85, 94, 118, 191, 204, 405, 408, 622, - 622, 369, 369, 40, 64, 74, 241, 687, 545, 518, - 546, 565, 574, 833, 519, 519, 518, 840, 870, 518, - 870, 736, 40, 522, 822, 457, 721, 824, 901, 911, - 768, 518, 768, 822, 893, 893, 310, 846, 743, 743, - 686, 304, 686, 561, 290, 518, 559, 545, 605, 552, - 632, 635, 409, 472, 612, 613, 518, 607, 822, 519, - 249, 648, 191, 457, 539, 513, 442, 676, 548, 936, - 618, 992, 518, 545, 519, 686, 626, 590, 686, 74, - 293, 74, 933, 822, 80, 569, 519, 522, 569, 9, - 743, 519, 735, 519, 844, 842, 371, 519, 901, 517, - 517, 517, 59, 710, 721, 721, 567, 93, 574, 133, - 639, 507, 519, 522, 592, 519, 273, 620, 173, 309, - 395, 290, 616, 617, 641, 607, 822, 442, 40, 518, - 992, 618, 994, 992, 293, 293, 518, 519, 920, 570, - 920, 936, 565, 570, 519, 721, 519, 723, 519, 869, - 184, 340, 369, 847, 462, 913, 519, 276, 454, 648, - 606, 635, 519, 613, 205, 122, 454, 290, 641, 290, - 616, 686, 574, 569, 714, 779, 714, 53, 104, 444, - 822, 848, 849, 848, 848, 519, 686, 779, 389, 617, - 63, 273, 360, 389, 609, 609, 992, 519, 570, 715, - 715, 849, 368, 166, 324, 166, 324, 148, 850, 850, - 850, 573, 605, 25, 117, 280, 936, 714, 36, 104, - 181, 273, 428, 779, 779, 715, 849, 368, 298 + 824, 117, 40, 518, 930, 923, 825, 120, 195, 119, + 280, 227, 545, 636, 88, 651, 192, 280, 594, 824, + 651, 280, 509, 510, 597, 546, 787, 788, 656, 656, + 3, 247, 412, 927, 931, 507, 431, 431, 517, 517, + 709, 519, 519, 546, 676, 457, 671, 673, 685, 643, + 519, 1003, 40, 419, 275, 518, 548, 518, 946, 637, + 151, 686, 149, 201, 618, 122, 137, 328, 1003, 107, + 946, 480, 1001, 419, 290, 546, 942, 518, 683, 825, + 877, 519, 519, 9, 354, 727, 743, 518, 391, 518, + 519, 522, 546, 844, 845, 336, 744, 522, 519, 518, + 547, 59, 519, 199, 519, 766, 517, 788, 911, 522, + 519, 546, 517, 192, 519, 824, 824, 824, 523, 517, + 523, 519, 519, 546, 848, 843, 548, 843, 522, 462, + 897, 519, 522, 91, 566, 824, 519, 922, 922, 347, + 636, 518, 627, 605, 519, 191, 518, 824, 275, 611, + 636, 639, 923, 40, 152, 784, 931, 513, 606, 923, + 923, 519, 593, 124, 519, 519, 626, 686, 545, 152, + 685, 40, 519, 923, 1003, 30, 85, 94, 118, 191, + 204, 405, 408, 622, 622, 369, 369, 40, 64, 74, + 241, 687, 545, 518, 546, 565, 574, 836, 519, 519, + 518, 843, 873, 518, 873, 737, 40, 522, 824, 457, + 722, 826, 904, 921, 770, 518, 770, 915, 824, 896, + 896, 310, 849, 744, 744, 686, 304, 686, 561, 290, + 518, 559, 545, 605, 552, 632, 635, 409, 472, 612, + 613, 518, 607, 824, 519, 249, 648, 191, 457, 539, + 513, 442, 676, 548, 946, 618, 1001, 518, 545, 519, + 686, 626, 590, 686, 74, 293, 74, 943, 824, 80, + 569, 519, 522, 569, 9, 744, 519, 736, 519, 847, + 845, 371, 519, 904, 517, 517, 517, 59, 710, 722, + 722, 567, 93, 574, 133, 639, 507, 519, 522, 592, + 519, 273, 620, 173, 309, 395, 290, 616, 617, 641, + 607, 824, 442, 40, 518, 1001, 618, 1003, 1001, 293, + 293, 518, 519, 930, 570, 930, 946, 565, 570, 519, + 722, 519, 724, 519, 872, 184, 340, 369, 850, 462, + 923, 519, 276, 454, 648, 606, 635, 519, 613, 205, + 122, 454, 290, 641, 290, 616, 686, 574, 569, 714, + 781, 714, 53, 104, 444, 824, 851, 852, 851, 851, + 519, 686, 781, 389, 617, 63, 273, 360, 389, 609, + 609, 1001, 519, 570, 715, 715, 852, 368, 166, 324, + 166, 324, 148, 853, 853, 853, 573, 605, 25, 117, + 280, 946, 714, 36, 104, 181, 273, 428, 781, 781, + 715, 852, 368, 298 }; #define yyerrok (yyerrstatus = 0) @@ -20189,14 +20554,14 @@ YYLTYPE yylloc; switch (yyn) { case 2: -#line 509 "third_party/libpg_query/grammar/grammar.y" +#line 510 "third_party/libpg_query/grammar/grammar.y" { pg_yyget_extra(yyscanner)->parsetree = (yyvsp[(1) - (1)].list); ;} break; case 3: -#line 525 "third_party/libpg_query/grammar/grammar.y" +#line 526 "third_party/libpg_query/grammar/grammar.y" { if ((yyvsp[(1) - (3)].list) != NIL) { @@ -20211,7 +20576,7 @@ YYLTYPE yylloc; break; case 4: -#line 537 "third_party/libpg_query/grammar/grammar.y" +#line 538 "third_party/libpg_query/grammar/grammar.y" { if ((yyvsp[(1) - (1)].node) != NULL) (yyval.list) = list_make1(makeRawStmt((yyvsp[(1) - (1)].node), 0)); @@ -20221,7 +20586,7 @@ YYLTYPE yylloc; break; case 46: -#line 587 "third_party/libpg_query/grammar/grammar.y" +#line 588 "third_party/libpg_query/grammar/grammar.y" { (yyval.node) = NULL; ;} break; @@ -24817,357 +25182,357 @@ YYLTYPE yylloc; break; case 634: -#line 692 "third_party/libpg_query/grammar/statements/select.y" +#line 689 "third_party/libpg_query/grammar/statements/select.y" { - (yyval.node) = makeSampleSize(makeFloat((yyvsp[(1) - (2)].str)), true); - ;} + (yyval.node) = makeFloatConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); + ;} break; case 635: -#line 696 "third_party/libpg_query/grammar/statements/select.y" - { - (yyval.node) = makeSampleSize(makeInteger((yyvsp[(1) - (2)].ival)), true); - ;} - break; - - case 636: -#line 700 "third_party/libpg_query/grammar/statements/select.y" +#line 693 "third_party/libpg_query/grammar/statements/select.y" { - (yyval.node) = makeSampleSize(makeFloat((yyvsp[(1) - (2)].str)), true); - ;} + (yyval.node) = makeIntConst((yyvsp[(1) - (1)].ival), (yylsp[(1) - (1)])); + ;} break; case 637: #line 704 "third_party/libpg_query/grammar/statements/select.y" { - (yyval.node) = makeSampleSize(makeInteger((yyvsp[(1) - (2)].ival)), true); + (yyval.node) = makeSampleSize((yyvsp[(1) - (2)].node), true); ;} break; case 638: #line 708 "third_party/libpg_query/grammar/statements/select.y" { - (yyval.node) = makeSampleSize(makeInteger((yyvsp[(1) - (1)].ival)), false); + (yyval.node) = makeSampleSize((yyvsp[(1) - (2)].node), true); ;} break; case 639: #line 712 "third_party/libpg_query/grammar/statements/select.y" { - (yyval.node) = makeSampleSize(makeInteger((yyvsp[(1) - (2)].ival)), false); + (yyval.node) = makeSampleSize((yyvsp[(1) - (1)].node), false); ;} break; case 640: -#line 719 "third_party/libpg_query/grammar/statements/select.y" +#line 716 "third_party/libpg_query/grammar/statements/select.y" { - (yyval.node) = (yyvsp[(3) - (3)].node); - ;} + (yyval.node) = makeSampleSize((yyvsp[(1) - (2)].node), false); + ;} break; case 641: #line 723 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = NULL; ;} + { + (yyval.node) = (yyvsp[(3) - (3)].node); + ;} break; case 642: -#line 730 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.str) = (yyvsp[(1) - (1)].str); ;} +#line 727 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = NULL; ;} break; case 643: -#line 731 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.str) = NULL; ;} +#line 734 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 644: -#line 736 "third_party/libpg_query/grammar/statements/select.y" +#line 735 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.str) = NULL; ;} + break; + + case 645: +#line 740 "third_party/libpg_query/grammar/statements/select.y" { int seed = (yyvsp[(5) - (5)].ival); (yyval.node) = makeSampleOptions((yyvsp[(3) - (5)].node), (yyvsp[(1) - (5)].str), &seed, (yylsp[(1) - (5)])); ;} break; - case 645: -#line 741 "third_party/libpg_query/grammar/statements/select.y" + case 646: +#line 745 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeSampleOptions((yyvsp[(1) - (1)].node), NULL, NULL, (yylsp[(1) - (1)])); ;} break; - case 646: -#line 745 "third_party/libpg_query/grammar/statements/select.y" + case 647: +#line 749 "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 647: -#line 749 "third_party/libpg_query/grammar/statements/select.y" + case 648: +#line 753 "third_party/libpg_query/grammar/statements/select.y" { int seed = (yyvsp[(5) - (6)].ival); (yyval.node) = makeSampleOptions((yyvsp[(1) - (6)].node), (yyvsp[(3) - (6)].str), &seed, (yylsp[(1) - (6)])); ;} break; - case 648: -#line 757 "third_party/libpg_query/grammar/statements/select.y" + case 649: +#line 761 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 649: -#line 763 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = (yyvsp[(1) - (1)].node); ;} - break; - case 650: -#line 764 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = NULL; ;} +#line 767 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 651: -#line 769 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.ival) = (yyvsp[(3) - (4)].ival); ;} +#line 768 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = NULL; ;} break; case 652: -#line 770 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.ival) = -1; ;} +#line 773 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.ival) = (yyvsp[(3) - (4)].ival); ;} break; case 653: #line 774 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = (yyvsp[(1) - (1)].node); ;} + { (yyval.ival) = -1; ;} break; case 654: -#line 776 "third_party/libpg_query/grammar/statements/select.y" +#line 778 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); ;} + break; + + case 655: +#line 780 "third_party/libpg_query/grammar/statements/select.y" { /* LIMIT ALL is represented as a NULL constant */ (yyval.node) = makeNullAConst((yylsp[(1) - (1)])); ;} break; - case 655: -#line 781 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = makeLimitPercent((yyvsp[(1) - (2)].node)); ;} - break; - case 656: -#line 783 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = makeLimitPercent(makeFloatConst((yyvsp[(1) - (2)].str),(yylsp[(1) - (2)]))); ;} +#line 785 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = makeLimitPercent((yyvsp[(1) - (2)].node)); ;} break; case 657: -#line 785 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = makeLimitPercent(makeIntConst((yyvsp[(1) - (2)].ival),(yylsp[(1) - (2)]))); ;} +#line 787 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = makeLimitPercent(makeFloatConst((yyvsp[(1) - (2)].str),(yylsp[(1) - (2)]))); ;} break; case 658: #line 789 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = (yyvsp[(1) - (1)].node); ;} + { (yyval.node) = makeLimitPercent(makeIntConst((yyvsp[(1) - (2)].ival),(yylsp[(1) - (2)]))); ;} break; case 659: -#line 809 "third_party/libpg_query/grammar/statements/select.y" +#line 793 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 660: -#line 811 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "+", NULL, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} +#line 813 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 661: -#line 813 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = doNegate((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} +#line 815 "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 662: #line 817 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = makeIntConst((yyvsp[(1) - (1)].ival),(yylsp[(1) - (1)])); ;} + { (yyval.node) = doNegate((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; case 663: -#line 818 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = makeFloatConst((yyvsp[(1) - (1)].str),(yylsp[(1) - (1)])); ;} +#line 821 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = makeIntConst((yyvsp[(1) - (1)].ival),(yylsp[(1) - (1)])); ;} break; case 664: #line 822 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.ival) = 0; ;} + { (yyval.node) = makeFloatConst((yyvsp[(1) - (1)].str),(yylsp[(1) - (1)])); ;} break; case 665: -#line 823 "third_party/libpg_query/grammar/statements/select.y" +#line 826 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = 0; ;} break; case 666: -#line 826 "third_party/libpg_query/grammar/statements/select.y" +#line 827 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = 0; ;} break; case 667: -#line 827 "third_party/libpg_query/grammar/statements/select.y" +#line 830 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = 0; ;} break; case 668: -#line 852 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(3) - (3)].list); ;} +#line 831 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.ival) = 0; ;} break; case 669: -#line 854 "third_party/libpg_query/grammar/statements/select.y" - { - PGNode *node = (PGNode *) makeGroupingSet(GROUPING_SET_ALL, NIL, (yylsp[(3) - (3)])); - (yyval.list) = list_make1(node); - ;} +#line 856 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = (yyvsp[(3) - (3)].list); ;} break; case 670: #line 858 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = NIL; ;} + { + PGNode *node = (PGNode *) makeGroupingSet(GROUPING_SET_ALL, NIL, (yylsp[(3) - (3)])); + (yyval.list) = list_make1(node); + ;} break; case 671: #line 862 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} + { (yyval.list) = NIL; ;} break; case 672: -#line 863 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = lappend((yyvsp[(1) - (3)].list),(yyvsp[(3) - (3)].node)); ;} +#line 866 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; case 673: #line 867 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(1) - (1)].list); ;} + { (yyval.list) = lappend((yyvsp[(1) - (3)].list),(yyvsp[(3) - (3)].node)); ;} break; case 674: -#line 868 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(1) - (2)].list); ;} +#line 871 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; case 675: #line 872 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = (yyvsp[(1) - (1)].node); ;} + { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; case 676: -#line 873 "third_party/libpg_query/grammar/statements/select.y" +#line 876 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 677: -#line 874 "third_party/libpg_query/grammar/statements/select.y" +#line 877 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 678: -#line 875 "third_party/libpg_query/grammar/statements/select.y" +#line 878 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 679: -#line 876 "third_party/libpg_query/grammar/statements/select.y" +#line 879 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 680: -#line 881 "third_party/libpg_query/grammar/statements/select.y" - { - (yyval.node) = (PGNode *) makeGroupingSet(GROUPING_SET_EMPTY, NIL, (yylsp[(1) - (2)])); - ;} +#line 880 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 681: -#line 894 "third_party/libpg_query/grammar/statements/select.y" +#line 885 "third_party/libpg_query/grammar/statements/select.y" { - (yyval.node) = (PGNode *) makeGroupingSet(GROUPING_SET_ROLLUP, (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); + (yyval.node) = (PGNode *) makeGroupingSet(GROUPING_SET_EMPTY, NIL, (yylsp[(1) - (2)])); ;} break; case 682: -#line 901 "third_party/libpg_query/grammar/statements/select.y" +#line 898 "third_party/libpg_query/grammar/statements/select.y" { - (yyval.node) = (PGNode *) makeGroupingSet(GROUPING_SET_CUBE, (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); + (yyval.node) = (PGNode *) makeGroupingSet(GROUPING_SET_ROLLUP, (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); ;} break; case 683: -#line 908 "third_party/libpg_query/grammar/statements/select.y" +#line 905 "third_party/libpg_query/grammar/statements/select.y" { - (yyval.node) = (PGNode *) makeGroupingSet(GROUPING_SET_SETS, (yyvsp[(4) - (5)].list), (yylsp[(1) - (5)])); + (yyval.node) = (PGNode *) makeGroupingSet(GROUPING_SET_CUBE, (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); ;} break; case 684: -#line 914 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = NULL; ;} +#line 912 "third_party/libpg_query/grammar/statements/select.y" + { + (yyval.node) = (PGNode *) makeGroupingSet(GROUPING_SET_SETS, (yyvsp[(4) - (5)].list), (yylsp[(1) - (5)])); + ;} break; case 685: -#line 915 "third_party/libpg_query/grammar/statements/select.y" +#line 918 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; case 686: #line 919 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = (yyvsp[(2) - (2)].node); ;} + { (yyval.node) = NULL; ;} break; case 687: -#line 920 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = NULL; ;} +#line 923 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; case 688: #line 924 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = (yyvsp[(2) - (2)].node); ;} + { (yyval.node) = NULL; ;} break; case 689: -#line 925 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = NULL; ;} +#line 928 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; case 690: #line 929 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(1) - (1)].list); ;} + { (yyval.node) = NULL; ;} break; case 691: -#line 930 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = NIL; ;} +#line 933 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; case 692: #line 934 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(1) - (1)].list); ;} + { (yyval.list) = NIL; ;} break; case 693: -#line 935 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = NIL; ;} +#line 938 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; case 694: #line 939 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} + { (yyval.list) = NIL; ;} break; case 695: -#line 940 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} +#line 943 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; case 696: -#line 945 "third_party/libpg_query/grammar/statements/select.y" +#line 944 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} + break; + + case 697: +#line 949 "third_party/libpg_query/grammar/statements/select.y" { PGLockingClause *n = makeNode(PGLockingClause); n->lockedRels = (yyvsp[(2) - (3)].list); @@ -25177,53 +25542,53 @@ YYLTYPE yylloc; ;} break; - case 697: -#line 955 "third_party/libpg_query/grammar/statements/select.y" + case 698: +#line 959 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockstrength) = LCS_FORUPDATE; ;} break; - case 698: -#line 956 "third_party/libpg_query/grammar/statements/select.y" + case 699: +#line 960 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockstrength) = PG_LCS_FORNOKEYUPDATE; ;} break; - case 699: -#line 957 "third_party/libpg_query/grammar/statements/select.y" + case 700: +#line 961 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockstrength) = PG_LCS_FORSHARE; ;} break; - case 700: -#line 958 "third_party/libpg_query/grammar/statements/select.y" + case 701: +#line 962 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockstrength) = PG_LCS_FORKEYSHARE; ;} break; - case 701: -#line 962 "third_party/libpg_query/grammar/statements/select.y" + case 702: +#line 966 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 702: -#line 963 "third_party/libpg_query/grammar/statements/select.y" + case 703: +#line 967 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 703: -#line 968 "third_party/libpg_query/grammar/statements/select.y" + case 704: +#line 972 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockwaitpolicy) = LockWaitError; ;} break; - case 704: -#line 969 "third_party/libpg_query/grammar/statements/select.y" + case 705: +#line 973 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockwaitpolicy) = PGLockWaitSkip; ;} break; - case 705: -#line 970 "third_party/libpg_query/grammar/statements/select.y" + case 706: +#line 974 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockwaitpolicy) = PGLockWaitBlock; ;} break; - case 706: -#line 980 "third_party/libpg_query/grammar/statements/select.y" + case 707: +#line 984 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *n = makeNode(PGSelectStmt); n->valuesLists = list_make1((yyvsp[(3) - (4)].list)); @@ -25231,8 +25596,8 @@ YYLTYPE yylloc; ;} break; - case 707: -#line 986 "third_party/libpg_query/grammar/statements/select.y" + case 708: +#line 990 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *n = (PGSelectStmt *) (yyvsp[(1) - (5)].node); n->valuesLists = lappend(n->valuesLists, (yyvsp[(4) - (5)].list)); @@ -25240,48 +25605,56 @@ YYLTYPE yylloc; ;} break; - case 708: -#line 994 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = (yyvsp[(1) - (1)].node); ;} - break; - case 709: -#line 995 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = (yyvsp[(1) - (2)].node); ;} +#line 998 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 710: -#line 1008 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(2) - (2)].list); ;} +#line 999 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = (yyvsp[(1) - (2)].node); ;} break; case 711: -#line 1009 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = NIL; ;} +#line 1012 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; case 712: #line 1013 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} + { (yyval.list) = NIL; ;} break; case 713: -#line 1014 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} +#line 1017 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; case 714: #line 1018 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(1) - (1)].list); ;} + { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; case 715: -#line 1019 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(1) - (2)].list); ;} +#line 1022 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; case 716: -#line 1026 "third_party/libpg_query/grammar/statements/select.y" +#line 1023 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = (yyvsp[(1) - (2)].list); ;} + break; + + case 717: +#line 1028 "third_party/libpg_query/grammar/statements/select.y" + { + (yyval.alias) = makeNode(PGAlias); + (yyval.alias)->aliasname = (yyvsp[(1) - (2)].str); + ;} + break; + + case 718: +#line 1039 "third_party/libpg_query/grammar/statements/select.y" { (yyvsp[(1) - (3)].range)->alias = (yyvsp[(2) - (3)].alias); (yyvsp[(1) - (3)].range)->sample = (yyvsp[(3) - (3)].node); @@ -25289,8 +25662,17 @@ YYLTYPE yylloc; ;} break; - case 717: -#line 1032 "third_party/libpg_query/grammar/statements/select.y" + case 719: +#line 1045 "third_party/libpg_query/grammar/statements/select.y" + { + (yyvsp[(2) - (3)].range)->alias = (yyvsp[(1) - (3)].alias); + (yyvsp[(2) - (3)].range)->sample = (yyvsp[(3) - (3)].node); + (yyval.node) = (PGNode *) (yyvsp[(2) - (3)].range); + ;} + break; + + case 720: +#line 1051 "third_party/libpg_query/grammar/statements/select.y" { PGRangeFunction *n = (PGRangeFunction *) (yyvsp[(1) - (3)].node); n->alias = (PGAlias*) linitial((yyvsp[(2) - (3)].list)); @@ -25300,20 +25682,30 @@ YYLTYPE yylloc; ;} break; - case 718: -#line 1040 "third_party/libpg_query/grammar/statements/select.y" + case 721: +#line 1059 "third_party/libpg_query/grammar/statements/select.y" { - PGRangeSubselect *n = makeNode(PGRangeSubselect); - n->lateral = false; - n->subquery = (yyvsp[(1) - (3)].node); - n->alias = (yyvsp[(2) - (3)].alias); - n->sample = (yyvsp[(3) - (3)].node); - (yyval.node) = (PGNode *) n; - ;} + PGRangeFunction *n = (PGRangeFunction *) (yyvsp[(2) - (3)].node); + n->alias = (yyvsp[(1) - (3)].alias); + n->sample = (yyvsp[(3) - (3)].node); + (yyval.node) = (PGNode *) n; + ;} break; - case 719: -#line 1049 "third_party/libpg_query/grammar/statements/select.y" + case 722: +#line 1067 "third_party/libpg_query/grammar/statements/select.y" + { + PGRangeSubselect *n = makeNode(PGRangeSubselect); + n->lateral = false; + n->subquery = (yyvsp[(1) - (3)].node); + n->alias = (yyvsp[(2) - (3)].alias); + n->sample = (yyvsp[(3) - (3)].node); + (yyval.node) = (PGNode *) n; + ;} + break; + + case 723: +#line 1077 "third_party/libpg_query/grammar/statements/select.y" { PGRangeFunction *n = (PGRangeFunction *) (yyvsp[(2) - (3)].node); n->lateral = true; @@ -25323,8 +25715,8 @@ YYLTYPE yylloc; ;} break; - case 720: -#line 1057 "third_party/libpg_query/grammar/statements/select.y" + case 724: +#line 1085 "third_party/libpg_query/grammar/statements/select.y" { PGRangeSubselect *n = makeNode(PGRangeSubselect); n->lateral = false; @@ -25335,8 +25727,20 @@ YYLTYPE yylloc; ;} break; - case 721: -#line 1066 "third_party/libpg_query/grammar/statements/select.y" + case 725: +#line 1094 "third_party/libpg_query/grammar/statements/select.y" + { + PGRangeSubselect *n = makeNode(PGRangeSubselect); + n->lateral = false; + n->subquery = (yyvsp[(2) - (3)].node); + n->alias = (yyvsp[(1) - (3)].alias); + n->sample = (yyvsp[(3) - (3)].node); + (yyval.node) = (PGNode *) n; + ;} + break; + + case 726: +#line 1103 "third_party/libpg_query/grammar/statements/select.y" { PGRangeSubselect *n = makeNode(PGRangeSubselect); n->lateral = true; @@ -25347,23 +25751,31 @@ YYLTYPE yylloc; ;} break; - case 722: -#line 1075 "third_party/libpg_query/grammar/statements/select.y" + case 727: +#line 1112 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) (yyvsp[(1) - (1)].jexpr); ;} break; - case 723: -#line 1079 "third_party/libpg_query/grammar/statements/select.y" + case 728: +#line 1116 "third_party/libpg_query/grammar/statements/select.y" { (yyvsp[(2) - (4)].jexpr)->alias = (yyvsp[(4) - (4)].alias); (yyval.node) = (PGNode *) (yyvsp[(2) - (4)].jexpr); ;} break; - case 724: -#line 1084 "third_party/libpg_query/grammar/statements/select.y" + case 729: +#line 1121 "third_party/libpg_query/grammar/statements/select.y" + { + (yyvsp[(3) - (4)].jexpr)->alias = (yyvsp[(1) - (4)].alias); + (yyval.node) = (PGNode *) (yyvsp[(3) - (4)].jexpr); + ;} + break; + + case 730: +#line 1126 "third_party/libpg_query/grammar/statements/select.y" { PGPivotExpr *n = makeNode(PGPivotExpr); n->source = (yyvsp[(1) - (9)].node); @@ -25376,8 +25788,8 @@ YYLTYPE yylloc; ;} break; - case 725: -#line 1095 "third_party/libpg_query/grammar/statements/select.y" + case 731: +#line 1137 "third_party/libpg_query/grammar/statements/select.y" { PGPivotExpr *n = makeNode(PGPivotExpr); n->source = (yyvsp[(1) - (9)].node); @@ -25390,33 +25802,33 @@ YYLTYPE yylloc; ;} break; - case 726: -#line 1108 "third_party/libpg_query/grammar/statements/select.y" + case 732: +#line 1150 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (3)].list); ;} break; - case 727: -#line 1109 "third_party/libpg_query/grammar/statements/select.y" + case 733: +#line 1151 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 728: -#line 1112 "third_party/libpg_query/grammar/statements/select.y" + case 734: +#line 1154 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = true; ;} break; - case 729: -#line 1113 "third_party/libpg_query/grammar/statements/select.y" + case 735: +#line 1155 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 730: -#line 1114 "third_party/libpg_query/grammar/statements/select.y" + case 736: +#line 1156 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 731: -#line 1118 "third_party/libpg_query/grammar/statements/select.y" + case 737: +#line 1160 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); n->pivot_columns = list_make1((yyvsp[(1) - (5)].node)); @@ -25425,8 +25837,8 @@ YYLTYPE yylloc; ;} break; - case 732: -#line 1126 "third_party/libpg_query/grammar/statements/select.y" + case 738: +#line 1168 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); n->pivot_columns = list_make1((yyvsp[(1) - (3)].node)); @@ -25435,23 +25847,23 @@ YYLTYPE yylloc; ;} break; - case 733: -#line 1135 "third_party/libpg_query/grammar/statements/select.y" + case 739: +#line 1177 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 734: -#line 1136 "third_party/libpg_query/grammar/statements/select.y" + case 740: +#line 1178 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 735: -#line 1137 "third_party/libpg_query/grammar/statements/select.y" + case 741: +#line 1179 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 736: -#line 1141 "third_party/libpg_query/grammar/statements/select.y" + case 742: +#line 1183 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); n->pivot_columns = (yyvsp[(1) - (5)].list); @@ -25460,8 +25872,8 @@ YYLTYPE yylloc; ;} break; - case 737: -#line 1149 "third_party/libpg_query/grammar/statements/select.y" + case 743: +#line 1191 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); n->pivot_columns = (yyvsp[(1) - (3)].list); @@ -25470,32 +25882,32 @@ YYLTYPE yylloc; ;} break; - case 738: -#line 1158 "third_party/libpg_query/grammar/statements/select.y" + case 744: +#line 1200 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 739: -#line 1162 "third_party/libpg_query/grammar/statements/select.y" + case 745: +#line 1204 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 740: -#line 1168 "third_party/libpg_query/grammar/statements/select.y" + case 746: +#line 1210 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 741: -#line 1169 "third_party/libpg_query/grammar/statements/select.y" + case 747: +#line 1211 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 742: -#line 1174 "third_party/libpg_query/grammar/statements/select.y" + case 748: +#line 1216 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); n->unpivot_columns = (yyvsp[(1) - (5)].list); @@ -25504,29 +25916,29 @@ YYLTYPE yylloc; ;} break; - case 743: -#line 1183 "third_party/libpg_query/grammar/statements/select.y" + case 749: +#line 1225 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 744: -#line 1187 "third_party/libpg_query/grammar/statements/select.y" + case 750: +#line 1229 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 745: -#line 1212 "third_party/libpg_query/grammar/statements/select.y" + case 751: +#line 1254 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jexpr) = (yyvsp[(2) - (3)].jexpr); ;} break; - case 746: -#line 1216 "third_party/libpg_query/grammar/statements/select.y" + case 752: +#line 1258 "third_party/libpg_query/grammar/statements/select.y" { /* CROSS JOIN is same as unqualified inner join */ PGJoinExpr *n = makeNode(PGJoinExpr); @@ -25541,8 +25953,8 @@ YYLTYPE yylloc; ;} break; - case 747: -#line 1229 "third_party/libpg_query/grammar/statements/select.y" + case 753: +#line 1271 "third_party/libpg_query/grammar/statements/select.y" { PGJoinExpr *n = makeNode(PGJoinExpr); n->jointype = (yyvsp[(2) - (5)].jtype); @@ -25558,8 +25970,8 @@ YYLTYPE yylloc; ;} break; - case 748: -#line 1243 "third_party/libpg_query/grammar/statements/select.y" + case 754: +#line 1285 "third_party/libpg_query/grammar/statements/select.y" { /* letting join_type reduce to empty doesn't work */ PGJoinExpr *n = makeNode(PGJoinExpr); @@ -25576,8 +25988,8 @@ YYLTYPE yylloc; ;} break; - case 749: -#line 1258 "third_party/libpg_query/grammar/statements/select.y" + case 755: +#line 1300 "third_party/libpg_query/grammar/statements/select.y" { PGJoinExpr *n = makeNode(PGJoinExpr); n->jointype = (yyvsp[(3) - (5)].jtype); @@ -25591,8 +26003,8 @@ YYLTYPE yylloc; ;} break; - case 750: -#line 1270 "third_party/libpg_query/grammar/statements/select.y" + case 756: +#line 1312 "third_party/libpg_query/grammar/statements/select.y" { /* letting join_type reduce to empty doesn't work */ PGJoinExpr *n = makeNode(PGJoinExpr); @@ -25607,8 +26019,8 @@ YYLTYPE yylloc; ;} break; - case 751: -#line 1283 "third_party/libpg_query/grammar/statements/select.y" + case 757: +#line 1325 "third_party/libpg_query/grammar/statements/select.y" { PGJoinExpr *n = makeNode(PGJoinExpr); n->jointype = (yyvsp[(3) - (6)].jtype); @@ -25624,8 +26036,8 @@ YYLTYPE yylloc; ;} break; - case 752: -#line 1297 "third_party/libpg_query/grammar/statements/select.y" + case 758: +#line 1339 "third_party/libpg_query/grammar/statements/select.y" { PGJoinExpr *n = makeNode(PGJoinExpr); n->jointype = PG_JOIN_INNER; @@ -25641,8 +26053,8 @@ YYLTYPE yylloc; ;} break; - case 753: -#line 1311 "third_party/libpg_query/grammar/statements/select.y" + case 759: +#line 1353 "third_party/libpg_query/grammar/statements/select.y" { /* POSITIONAL JOIN is a coordinated scan */ PGJoinExpr *n = makeNode(PGJoinExpr); @@ -25657,8 +26069,8 @@ YYLTYPE yylloc; ;} break; - case 754: -#line 1324 "third_party/libpg_query/grammar/statements/select.y" + case 760: +#line 1366 "third_party/libpg_query/grammar/statements/select.y" { /* ANTI JOIN is a filter */ PGJoinExpr *n = makeNode(PGJoinExpr); @@ -25675,8 +26087,8 @@ YYLTYPE yylloc; ;} break; - case 755: -#line 1339 "third_party/libpg_query/grammar/statements/select.y" + case 761: +#line 1381 "third_party/libpg_query/grammar/statements/select.y" { /* SEMI JOIN is also a filter */ PGJoinExpr *n = makeNode(PGJoinExpr); @@ -25694,8 +26106,8 @@ YYLTYPE yylloc; ;} break; - case 756: -#line 1358 "third_party/libpg_query/grammar/statements/select.y" + case 762: +#line 1400 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = makeNode(PGAlias); (yyval.alias)->aliasname = (yyvsp[(2) - (5)].str); @@ -25703,16 +26115,16 @@ YYLTYPE yylloc; ;} break; - case 757: -#line 1364 "third_party/libpg_query/grammar/statements/select.y" + case 763: +#line 1406 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = makeNode(PGAlias); (yyval.alias)->aliasname = (yyvsp[(2) - (2)].str); ;} break; - case 758: -#line 1369 "third_party/libpg_query/grammar/statements/select.y" + case 764: +#line 1411 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = makeNode(PGAlias); (yyval.alias)->aliasname = (yyvsp[(1) - (4)].str); @@ -25720,40 +26132,40 @@ YYLTYPE yylloc; ;} break; - case 759: -#line 1375 "third_party/libpg_query/grammar/statements/select.y" + case 765: +#line 1417 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = makeNode(PGAlias); (yyval.alias)->aliasname = (yyvsp[(1) - (1)].str); ;} break; - case 760: -#line 1381 "third_party/libpg_query/grammar/statements/select.y" + case 766: +#line 1423 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = (yyvsp[(1) - (1)].alias); ;} break; - case 761: -#line 1382 "third_party/libpg_query/grammar/statements/select.y" + case 767: +#line 1424 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = NULL; ;} break; - case 762: -#line 1391 "third_party/libpg_query/grammar/statements/select.y" + case 768: +#line 1433 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (1)].alias), NIL); ;} break; - case 763: -#line 1395 "third_party/libpg_query/grammar/statements/select.y" + case 769: +#line 1437 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2(NULL, (yyvsp[(3) - (4)].list)); ;} break; - case 764: -#line 1399 "third_party/libpg_query/grammar/statements/select.y" + case 770: +#line 1441 "third_party/libpg_query/grammar/statements/select.y" { PGAlias *a = makeNode(PGAlias); a->aliasname = (yyvsp[(2) - (5)].str); @@ -25761,8 +26173,8 @@ YYLTYPE yylloc; ;} break; - case 765: -#line 1405 "third_party/libpg_query/grammar/statements/select.y" + case 771: +#line 1447 "third_party/libpg_query/grammar/statements/select.y" { PGAlias *a = makeNode(PGAlias); a->aliasname = (yyvsp[(1) - (4)].str); @@ -25770,65 +26182,65 @@ YYLTYPE yylloc; ;} break; - case 766: -#line 1411 "third_party/libpg_query/grammar/statements/select.y" + case 772: +#line 1453 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2(NULL, NIL); ;} break; - case 767: -#line 1416 "third_party/libpg_query/grammar/statements/select.y" + case 773: +#line 1458 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_FULL; ;} break; - case 768: -#line 1417 "third_party/libpg_query/grammar/statements/select.y" + case 774: +#line 1459 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_LEFT; ;} break; - case 769: -#line 1418 "third_party/libpg_query/grammar/statements/select.y" + case 775: +#line 1460 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_RIGHT; ;} break; - case 770: -#line 1419 "third_party/libpg_query/grammar/statements/select.y" + case 776: +#line 1461 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_SEMI; ;} break; - case 771: -#line 1420 "third_party/libpg_query/grammar/statements/select.y" + case 777: +#line 1462 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_ANTI; ;} break; - case 772: -#line 1421 "third_party/libpg_query/grammar/statements/select.y" + case 778: +#line 1463 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_INNER; ;} break; - case 773: -#line 1425 "third_party/libpg_query/grammar/statements/select.y" + case 779: +#line 1467 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 774: -#line 1426 "third_party/libpg_query/grammar/statements/select.y" + case 780: +#line 1468 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 775: -#line 1438 "third_party/libpg_query/grammar/statements/select.y" + case 781: +#line 1480 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) (yyvsp[(3) - (4)].list); ;} break; - case 776: -#line 1439 "third_party/libpg_query/grammar/statements/select.y" + case 782: +#line 1481 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 777: -#line 1445 "third_party/libpg_query/grammar/statements/select.y" + case 783: +#line 1487 "third_party/libpg_query/grammar/statements/select.y" { /* inheritance query, implicitly */ (yyval.range) = (yyvsp[(1) - (1)].range); @@ -25837,8 +26249,8 @@ YYLTYPE yylloc; ;} break; - case 778: -#line 1452 "third_party/libpg_query/grammar/statements/select.y" + case 784: +#line 1494 "third_party/libpg_query/grammar/statements/select.y" { /* inheritance query, explicitly */ (yyval.range) = (yyvsp[(1) - (2)].range); @@ -25847,8 +26259,8 @@ YYLTYPE yylloc; ;} break; - case 779: -#line 1459 "third_party/libpg_query/grammar/statements/select.y" + case 785: +#line 1501 "third_party/libpg_query/grammar/statements/select.y" { /* no inheritance */ (yyval.range) = (yyvsp[(2) - (2)].range); @@ -25857,8 +26269,8 @@ YYLTYPE yylloc; ;} break; - case 780: -#line 1466 "third_party/libpg_query/grammar/statements/select.y" + case 786: +#line 1508 "third_party/libpg_query/grammar/statements/select.y" { /* no inheritance, SQL99-style syntax */ (yyval.range) = (yyvsp[(3) - (4)].range); @@ -25867,8 +26279,8 @@ YYLTYPE yylloc; ;} break; - case 781: -#line 1498 "third_party/libpg_query/grammar/statements/select.y" + case 787: +#line 1540 "third_party/libpg_query/grammar/statements/select.y" { PGRangeFunction *n = makeNode(PGRangeFunction); n->lateral = false; @@ -25881,8 +26293,8 @@ YYLTYPE yylloc; ;} break; - case 782: -#line 1509 "third_party/libpg_query/grammar/statements/select.y" + case 788: +#line 1551 "third_party/libpg_query/grammar/statements/select.y" { PGRangeFunction *n = makeNode(PGRangeFunction); n->lateral = false; @@ -25895,67 +26307,67 @@ YYLTYPE yylloc; ;} break; - case 783: -#line 1522 "third_party/libpg_query/grammar/statements/select.y" + case 789: +#line 1564 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].list)); ;} break; - case 784: -#line 1526 "third_party/libpg_query/grammar/statements/select.y" + case 790: +#line 1568 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].list)); ;} break; - case 785: -#line 1527 "third_party/libpg_query/grammar/statements/select.y" + case 791: +#line 1569 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); ;} break; - case 786: -#line 1530 "third_party/libpg_query/grammar/statements/select.y" + case 792: +#line 1572 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 787: -#line 1531 "third_party/libpg_query/grammar/statements/select.y" + case 793: +#line 1573 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 788: -#line 1534 "third_party/libpg_query/grammar/statements/select.y" + case 794: +#line 1576 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = true; ;} break; - case 789: -#line 1535 "third_party/libpg_query/grammar/statements/select.y" + case 795: +#line 1577 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 790: -#line 1540 "third_party/libpg_query/grammar/statements/select.y" + case 796: +#line 1582 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 791: -#line 1541 "third_party/libpg_query/grammar/statements/select.y" + case 797: +#line 1583 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 792: -#line 1547 "third_party/libpg_query/grammar/statements/select.y" + case 798: +#line 1589 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 793: -#line 1551 "third_party/libpg_query/grammar/statements/select.y" + case 799: +#line 1593 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 794: -#line 1557 "third_party/libpg_query/grammar/statements/select.y" + case 800: +#line 1599 "third_party/libpg_query/grammar/statements/select.y" { PGColumnDef *n = makeNode(PGColumnDef); n->colname = (yyvsp[(1) - (3)].str); @@ -25975,8 +26387,8 @@ YYLTYPE yylloc; ;} break; - case 795: -#line 1578 "third_party/libpg_query/grammar/statements/select.y" + case 801: +#line 1620 "third_party/libpg_query/grammar/statements/select.y" { PGCollateClause *n = makeNode(PGCollateClause); n->arg = NULL; @@ -25986,45 +26398,45 @@ YYLTYPE yylloc; ;} break; - case 796: -#line 1585 "third_party/libpg_query/grammar/statements/select.y" + case 802: +#line 1627 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 797: -#line 1598 "third_party/libpg_query/grammar/statements/select.y" + case 803: +#line 1641 "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 798: -#line 1601 "third_party/libpg_query/grammar/statements/select.y" + case 804: +#line 1644 "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 801: -#line 1608 "third_party/libpg_query/grammar/statements/select.y" + case 807: +#line 1651 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 802: -#line 1609 "third_party/libpg_query/grammar/statements/select.y" + case 808: +#line 1652 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = NULL; ;} break; - case 803: -#line 1612 "third_party/libpg_query/grammar/statements/select.y" + case 809: +#line 1655 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (2)].typnam); (yyval.typnam)->arrayBounds = (yyvsp[(2) - (2)].list); ;} break; - case 804: -#line 1617 "third_party/libpg_query/grammar/statements/select.y" + case 810: +#line 1660 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(2) - (3)].typnam); (yyval.typnam)->arrayBounds = (yyvsp[(3) - (3)].list); @@ -26032,16 +26444,16 @@ YYLTYPE yylloc; ;} break; - case 805: -#line 1624 "third_party/libpg_query/grammar/statements/select.y" + case 811: +#line 1667 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (5)].typnam); (yyval.typnam)->arrayBounds = list_make1(makeInteger((yyvsp[(4) - (5)].ival))); ;} break; - case 806: -#line 1629 "third_party/libpg_query/grammar/statements/select.y" + case 812: +#line 1672 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(2) - (6)].typnam); (yyval.typnam)->arrayBounds = list_make1(makeInteger((yyvsp[(5) - (6)].ival))); @@ -26049,16 +26461,16 @@ YYLTYPE yylloc; ;} break; - case 807: -#line 1635 "third_party/libpg_query/grammar/statements/select.y" + case 813: +#line 1678 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (2)].typnam); (yyval.typnam)->arrayBounds = list_make1(makeInteger(-1)); ;} break; - case 808: -#line 1640 "third_party/libpg_query/grammar/statements/select.y" + case 814: +#line 1683 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(2) - (3)].typnam); (yyval.typnam)->arrayBounds = list_make1(makeInteger(-1)); @@ -26066,15 +26478,15 @@ YYLTYPE yylloc; ;} break; - case 809: -#line 1646 "third_party/libpg_query/grammar/statements/select.y" + case 815: +#line 1689 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = makeTypeNameFromNameList((yyvsp[(1) - (1)].list)); ;} break; - case 810: -#line 1650 "third_party/libpg_query/grammar/statements/select.y" + case 816: +#line 1693 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("struct"); (yyval.typnam)->arrayBounds = (yyvsp[(5) - (5)].list); @@ -26083,8 +26495,8 @@ YYLTYPE yylloc; ;} break; - case 811: -#line 1657 "third_party/libpg_query/grammar/statements/select.y" + case 817: +#line 1700 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("map"); (yyval.typnam)->arrayBounds = (yyvsp[(5) - (5)].list); @@ -26093,8 +26505,8 @@ YYLTYPE yylloc; ;} break; - case 812: -#line 1664 "third_party/libpg_query/grammar/statements/select.y" + case 818: +#line 1707 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("union"); (yyval.typnam)->arrayBounds = (yyvsp[(5) - (5)].list); @@ -26103,66 +26515,66 @@ YYLTYPE yylloc; ;} break; - case 813: -#line 1673 "third_party/libpg_query/grammar/statements/select.y" + case 819: +#line 1716 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2(makeString((yyvsp[(1) - (3)].str)), makeString((yyvsp[(3) - (3)].str))); ;} break; - case 814: -#line 1674 "third_party/libpg_query/grammar/statements/select.y" + case 820: +#line 1717 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), makeString((yyvsp[(3) - (3)].str))); ;} break; - case 815: -#line 1679 "third_party/libpg_query/grammar/statements/select.y" + case 821: +#line 1722 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), makeInteger(-1)); ;} break; - case 816: -#line 1681 "third_party/libpg_query/grammar/statements/select.y" + case 822: +#line 1724 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (4)].list), makeInteger((yyvsp[(3) - (4)].ival))); ;} break; - case 817: -#line 1683 "third_party/libpg_query/grammar/statements/select.y" + case 823: +#line 1726 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 818: -#line 1687 "third_party/libpg_query/grammar/statements/select.y" + case 824: +#line 1730 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 819: -#line 1688 "third_party/libpg_query/grammar/statements/select.y" + case 825: +#line 1731 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 820: -#line 1689 "third_party/libpg_query/grammar/statements/select.y" + case 826: +#line 1732 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 821: -#line 1690 "third_party/libpg_query/grammar/statements/select.y" + case 827: +#line 1733 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 822: -#line 1691 "third_party/libpg_query/grammar/statements/select.y" + case 828: +#line 1734 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 823: -#line 1693 "third_party/libpg_query/grammar/statements/select.y" + case 829: +#line 1736 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (2)].typnam); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); ;} break; - case 824: -#line 1698 "third_party/libpg_query/grammar/statements/select.y" + case 830: +#line 1741 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (4)].typnam); (yyval.typnam)->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1), @@ -26170,28 +26582,28 @@ YYLTYPE yylloc; ;} break; - case 825: -#line 1717 "third_party/libpg_query/grammar/statements/select.y" + case 831: +#line 1760 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 826: -#line 1718 "third_party/libpg_query/grammar/statements/select.y" + case 832: +#line 1761 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 827: -#line 1719 "third_party/libpg_query/grammar/statements/select.y" + case 833: +#line 1762 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 828: -#line 1720 "third_party/libpg_query/grammar/statements/select.y" + case 834: +#line 1763 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 829: -#line 1732 "third_party/libpg_query/grammar/statements/select.y" + case 835: +#line 1775 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = makeTypeName((yyvsp[(1) - (2)].str)); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -26199,74 +26611,74 @@ YYLTYPE yylloc; ;} break; - case 830: -#line 1745 "third_party/libpg_query/grammar/statements/select.y" + case 836: +#line 1788 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 831: -#line 1746 "third_party/libpg_query/grammar/statements/select.y" + case 837: +#line 1789 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 832: -#line 1753 "third_party/libpg_query/grammar/statements/select.y" + case 838: +#line 1796 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("int4"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 833: -#line 1758 "third_party/libpg_query/grammar/statements/select.y" + case 839: +#line 1801 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("int4"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 834: -#line 1763 "third_party/libpg_query/grammar/statements/select.y" + case 840: +#line 1806 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("int2"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 835: -#line 1768 "third_party/libpg_query/grammar/statements/select.y" + case 841: +#line 1811 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("int8"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 836: -#line 1773 "third_party/libpg_query/grammar/statements/select.y" + case 842: +#line 1816 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("float4"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 837: -#line 1778 "third_party/libpg_query/grammar/statements/select.y" + case 843: +#line 1821 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(2) - (2)].typnam); (yyval.typnam)->location = (yylsp[(1) - (2)]); ;} break; - case 838: -#line 1783 "third_party/libpg_query/grammar/statements/select.y" + case 844: +#line 1826 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("float8"); (yyval.typnam)->location = (yylsp[(1) - (2)]); ;} break; - case 839: -#line 1788 "third_party/libpg_query/grammar/statements/select.y" + case 845: +#line 1831 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("numeric"); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -26274,8 +26686,8 @@ YYLTYPE yylloc; ;} break; - case 840: -#line 1794 "third_party/libpg_query/grammar/statements/select.y" + case 846: +#line 1837 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("numeric"); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -26283,8 +26695,8 @@ YYLTYPE yylloc; ;} break; - case 841: -#line 1800 "third_party/libpg_query/grammar/statements/select.y" + case 847: +#line 1843 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("numeric"); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -26292,16 +26704,16 @@ YYLTYPE yylloc; ;} break; - case 842: -#line 1806 "third_party/libpg_query/grammar/statements/select.y" + case 848: +#line 1849 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("bool"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 843: -#line 1813 "third_party/libpg_query/grammar/statements/select.y" + case 849: +#line 1856 "third_party/libpg_query/grammar/statements/select.y" { /* * Check FLOAT() precision limits assuming IEEE floating @@ -26324,44 +26736,44 @@ YYLTYPE yylloc; ;} break; - case 844: -#line 1834 "third_party/libpg_query/grammar/statements/select.y" + case 850: +#line 1877 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("float4"); ;} break; - case 845: -#line 1844 "third_party/libpg_query/grammar/statements/select.y" + case 851: +#line 1887 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 846: -#line 1848 "third_party/libpg_query/grammar/statements/select.y" + case 852: +#line 1891 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 847: -#line 1856 "third_party/libpg_query/grammar/statements/select.y" + case 853: +#line 1899 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 848: -#line 1860 "third_party/libpg_query/grammar/statements/select.y" + case 854: +#line 1903 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); (yyval.typnam)->typmods = NIL; ;} break; - case 849: -#line 1868 "third_party/libpg_query/grammar/statements/select.y" + case 855: +#line 1911 "third_party/libpg_query/grammar/statements/select.y" { const char *typname; @@ -26372,8 +26784,8 @@ YYLTYPE yylloc; ;} break; - case 850: -#line 1880 "third_party/libpg_query/grammar/statements/select.y" + case 856: +#line 1923 "third_party/libpg_query/grammar/statements/select.y" { /* bit defaults to bit(1), varbit to no limit */ if ((yyvsp[(2) - (2)].boolean)) @@ -26389,29 +26801,29 @@ YYLTYPE yylloc; ;} break; - case 851: -#line 1901 "third_party/libpg_query/grammar/statements/select.y" + case 857: +#line 1944 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 852: -#line 1905 "third_party/libpg_query/grammar/statements/select.y" + case 858: +#line 1948 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 853: -#line 1911 "third_party/libpg_query/grammar/statements/select.y" + case 859: +#line 1954 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 854: -#line 1915 "third_party/libpg_query/grammar/statements/select.y" + case 860: +#line 1958 "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 @@ -26424,8 +26836,8 @@ YYLTYPE yylloc; ;} break; - case 855: -#line 1928 "third_party/libpg_query/grammar/statements/select.y" + case 861: +#line 1971 "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)]))); @@ -26433,8 +26845,8 @@ YYLTYPE yylloc; ;} break; - case 856: -#line 1936 "third_party/libpg_query/grammar/statements/select.y" + case 862: +#line 1979 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName((yyvsp[(1) - (1)].conststr)); /* char defaults to char(1), varchar to no limit */ @@ -26444,48 +26856,48 @@ YYLTYPE yylloc; ;} break; - case 857: -#line 1946 "third_party/libpg_query/grammar/statements/select.y" + case 863: +#line 1989 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = (yyvsp[(2) - (2)].boolean) ? "varchar": "bpchar"; ;} break; - case 858: -#line 1948 "third_party/libpg_query/grammar/statements/select.y" + case 864: +#line 1991 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = (yyvsp[(2) - (2)].boolean) ? "varchar": "bpchar"; ;} break; - case 859: -#line 1950 "third_party/libpg_query/grammar/statements/select.y" + case 865: +#line 1993 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "varchar"; ;} break; - case 860: -#line 1952 "third_party/libpg_query/grammar/statements/select.y" + case 866: +#line 1995 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = (yyvsp[(3) - (3)].boolean) ? "varchar": "bpchar"; ;} break; - case 861: -#line 1954 "third_party/libpg_query/grammar/statements/select.y" + case 867: +#line 1997 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = (yyvsp[(3) - (3)].boolean) ? "varchar": "bpchar"; ;} break; - case 862: -#line 1956 "third_party/libpg_query/grammar/statements/select.y" + case 868: +#line 1999 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = (yyvsp[(2) - (2)].boolean) ? "varchar": "bpchar"; ;} break; - case 863: -#line 1960 "third_party/libpg_query/grammar/statements/select.y" + case 869: +#line 2003 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = true; ;} break; - case 864: -#line 1961 "third_party/libpg_query/grammar/statements/select.y" + case 870: +#line 2004 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 865: -#line 1969 "third_party/libpg_query/grammar/statements/select.y" + case 871: +#line 2012 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(5) - (5)].boolean)) (yyval.typnam) = SystemTypeName("timestamptz"); @@ -26496,8 +26908,8 @@ YYLTYPE yylloc; ;} break; - case 866: -#line 1978 "third_party/libpg_query/grammar/statements/select.y" + case 872: +#line 2021 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(2) - (2)].boolean)) (yyval.typnam) = SystemTypeName("timestamptz"); @@ -26507,8 +26919,8 @@ YYLTYPE yylloc; ;} break; - case 867: -#line 1986 "third_party/libpg_query/grammar/statements/select.y" + case 873: +#line 2029 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(5) - (5)].boolean)) (yyval.typnam) = SystemTypeName("timetz"); @@ -26519,8 +26931,8 @@ YYLTYPE yylloc; ;} break; - case 868: -#line 1995 "third_party/libpg_query/grammar/statements/select.y" + case 874: +#line 2038 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(2) - (2)].boolean)) (yyval.typnam) = SystemTypeName("timetz"); @@ -26530,112 +26942,112 @@ YYLTYPE yylloc; ;} break; - case 869: -#line 2006 "third_party/libpg_query/grammar/statements/select.y" + case 875: +#line 2049 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("interval"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 870: -#line 2013 "third_party/libpg_query/grammar/statements/select.y" + case 876: +#line 2056 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = true; ;} break; - case 871: -#line 2014 "third_party/libpg_query/grammar/statements/select.y" + case 877: +#line 2057 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 872: -#line 2015 "third_party/libpg_query/grammar/statements/select.y" + case 878: +#line 2058 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 899: -#line 2059 "third_party/libpg_query/grammar/statements/select.y" + case 905: +#line 2102 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(YEAR), (yylsp[(1) - (1)]))); ;} break; - case 900: -#line 2061 "third_party/libpg_query/grammar/statements/select.y" + case 906: +#line 2104 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MONTH), (yylsp[(1) - (1)]))); ;} break; - case 901: -#line 2063 "third_party/libpg_query/grammar/statements/select.y" + case 907: +#line 2106 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DAY), (yylsp[(1) - (1)]))); ;} break; - case 902: -#line 2065 "third_party/libpg_query/grammar/statements/select.y" + case 908: +#line 2108 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(HOUR), (yylsp[(1) - (1)]))); ;} break; - case 903: -#line 2067 "third_party/libpg_query/grammar/statements/select.y" + case 909: +#line 2110 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MINUTE), (yylsp[(1) - (1)]))); ;} break; - case 904: -#line 2069 "third_party/libpg_query/grammar/statements/select.y" + case 910: +#line 2112 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(SECOND), (yylsp[(1) - (1)]))); ;} break; - case 905: -#line 2071 "third_party/libpg_query/grammar/statements/select.y" + case 911: +#line 2114 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MILLISECOND), (yylsp[(1) - (1)]))); ;} break; - case 906: -#line 2073 "third_party/libpg_query/grammar/statements/select.y" + case 912: +#line 2116 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MICROSECOND), (yylsp[(1) - (1)]))); ;} break; - case 907: -#line 2075 "third_party/libpg_query/grammar/statements/select.y" + case 913: +#line 2118 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(WEEK), (yylsp[(1) - (1)]))); ;} break; - case 908: -#line 2077 "third_party/libpg_query/grammar/statements/select.y" + case 914: +#line 2120 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(QUARTER), (yylsp[(1) - (1)]))); ;} break; - case 909: -#line 2079 "third_party/libpg_query/grammar/statements/select.y" + case 915: +#line 2122 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DECADE), (yylsp[(1) - (1)]))); ;} break; - case 910: -#line 2081 "third_party/libpg_query/grammar/statements/select.y" + case 916: +#line 2124 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(CENTURY), (yylsp[(1) - (1)]))); ;} break; - case 911: -#line 2083 "third_party/libpg_query/grammar/statements/select.y" + case 917: +#line 2126 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MILLENNIUM), (yylsp[(1) - (1)]))); ;} break; - case 912: -#line 2085 "third_party/libpg_query/grammar/statements/select.y" + case 918: +#line 2128 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH), (yylsp[(1) - (3)]))); ;} break; - case 913: -#line 2090 "third_party/libpg_query/grammar/statements/select.y" + case 919: +#line 2133 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR), (yylsp[(1) - (3)]))); ;} break; - case 914: -#line 2095 "third_party/libpg_query/grammar/statements/select.y" + case 920: +#line 2138 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | @@ -26643,8 +27055,8 @@ YYLTYPE yylloc; ;} break; - case 915: -#line 2101 "third_party/libpg_query/grammar/statements/select.y" + case 921: +#line 2144 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | @@ -26653,16 +27065,16 @@ YYLTYPE yylloc; ;} break; - case 916: -#line 2108 "third_party/libpg_query/grammar/statements/select.y" + case 922: +#line 2151 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE), (yylsp[(1) - (3)]))); ;} break; - case 917: -#line 2113 "third_party/libpg_query/grammar/statements/select.y" + case 923: +#line 2156 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | @@ -26670,31 +27082,31 @@ YYLTYPE yylloc; ;} break; - case 918: -#line 2119 "third_party/libpg_query/grammar/statements/select.y" + case 924: +#line 2162 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND), (yylsp[(1) - (3)]))); ;} break; - case 919: -#line 2124 "third_party/libpg_query/grammar/statements/select.y" + case 925: +#line 2167 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 920: -#line 2155 "third_party/libpg_query/grammar/statements/select.y" + case 926: +#line 2198 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 921: -#line 2158 "third_party/libpg_query/grammar/statements/select.y" + case 927: +#line 2201 "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 922: -#line 2160 "third_party/libpg_query/grammar/statements/select.y" + case 928: +#line 2203 "third_party/libpg_query/grammar/statements/select.y" { PGCollateClause *n = makeNode(PGCollateClause); n->arg = (yyvsp[(1) - (3)].node); @@ -26704,8 +27116,8 @@ YYLTYPE yylloc; ;} break; - case 923: -#line 2168 "third_party/libpg_query/grammar/statements/select.y" + case 929: +#line 2211 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("timezone"), list_make2((yyvsp[(5) - (5)].node), (yyvsp[(1) - (5)].node)), @@ -26713,139 +27125,139 @@ YYLTYPE yylloc; ;} break; - case 924: -#line 2183 "third_party/libpg_query/grammar/statements/select.y" + case 930: +#line 2226 "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 925: -#line 2185 "third_party/libpg_query/grammar/statements/select.y" + case 931: +#line 2228 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = doNegate((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 926: -#line 2187 "third_party/libpg_query/grammar/statements/select.y" + case 932: +#line 2230 "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 927: -#line 2189 "third_party/libpg_query/grammar/statements/select.y" + case 933: +#line 2232 "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 928: -#line 2191 "third_party/libpg_query/grammar/statements/select.y" + case 934: +#line 2234 "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 929: -#line 2193 "third_party/libpg_query/grammar/statements/select.y" + case 935: +#line 2236 "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 930: -#line 2195 "third_party/libpg_query/grammar/statements/select.y" + case 936: +#line 2238 "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 931: -#line 2197 "third_party/libpg_query/grammar/statements/select.y" + case 937: +#line 2240 "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 932: -#line 2199 "third_party/libpg_query/grammar/statements/select.y" + case 938: +#line 2242 "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 933: -#line 2201 "third_party/libpg_query/grammar/statements/select.y" + case 939: +#line 2244 "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 934: -#line 2203 "third_party/libpg_query/grammar/statements/select.y" + case 940: +#line 2246 "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 935: -#line 2205 "third_party/libpg_query/grammar/statements/select.y" + case 941: +#line 2248 "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 936: -#line 2207 "third_party/libpg_query/grammar/statements/select.y" + case 942: +#line 2250 "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 937: -#line 2209 "third_party/libpg_query/grammar/statements/select.y" + case 943: +#line 2252 "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 938: -#line 2211 "third_party/libpg_query/grammar/statements/select.y" + case 944: +#line 2254 "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 939: -#line 2213 "third_party/libpg_query/grammar/statements/select.y" + case 945: +#line 2256 "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 940: -#line 2216 "third_party/libpg_query/grammar/statements/select.y" + case 946: +#line 2259 "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 941: -#line 2218 "third_party/libpg_query/grammar/statements/select.y" + case 947: +#line 2261 "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 942: -#line 2220 "third_party/libpg_query/grammar/statements/select.y" + case 948: +#line 2263 "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 943: -#line 2223 "third_party/libpg_query/grammar/statements/select.y" + case 949: +#line 2266 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeAndExpr((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 944: -#line 2225 "third_party/libpg_query/grammar/statements/select.y" + case 950: +#line 2268 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeOrExpr((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 945: -#line 2227 "third_party/libpg_query/grammar/statements/select.y" + case 951: +#line 2270 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeNotExpr((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 946: -#line 2229 "third_party/libpg_query/grammar/statements/select.y" + case 952: +#line 2272 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeNotExpr((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 947: -#line 2231 "third_party/libpg_query/grammar/statements/select.y" + case 953: +#line 2274 "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 948: -#line 2236 "third_party/libpg_query/grammar/statements/select.y" + case 954: +#line 2279 "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 949: -#line 2241 "third_party/libpg_query/grammar/statements/select.y" + case 955: +#line 2284 "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)), @@ -26854,16 +27266,16 @@ YYLTYPE yylloc; ;} break; - case 950: -#line 2248 "third_party/libpg_query/grammar/statements/select.y" + case 956: +#line 2291 "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 951: -#line 2253 "third_party/libpg_query/grammar/statements/select.y" + case 957: +#line 2296 "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)), @@ -26872,16 +27284,16 @@ YYLTYPE yylloc; ;} break; - case 952: -#line 2260 "third_party/libpg_query/grammar/statements/select.y" + case 958: +#line 2303 "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 953: -#line 2265 "third_party/libpg_query/grammar/statements/select.y" + case 959: +#line 2308 "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)), @@ -26890,16 +27302,16 @@ YYLTYPE yylloc; ;} break; - case 954: -#line 2272 "third_party/libpg_query/grammar/statements/select.y" + case 960: +#line 2315 "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 955: -#line 2277 "third_party/libpg_query/grammar/statements/select.y" + case 961: +#line 2320 "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)), @@ -26908,8 +27320,8 @@ YYLTYPE yylloc; ;} break; - case 956: -#line 2285 "third_party/libpg_query/grammar/statements/select.y" + case 962: +#line 2328 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("similar_escape"), list_make2((yyvsp[(4) - (4)].node), makeNullAConst(-1)), @@ -26919,8 +27331,8 @@ YYLTYPE yylloc; ;} break; - case 957: -#line 2293 "third_party/libpg_query/grammar/statements/select.y" + case 963: +#line 2336 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("similar_escape"), list_make2((yyvsp[(4) - (6)].node), (yyvsp[(6) - (6)].node)), @@ -26930,8 +27342,8 @@ YYLTYPE yylloc; ;} break; - case 958: -#line 2301 "third_party/libpg_query/grammar/statements/select.y" + case 964: +#line 2344 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("similar_escape"), list_make2((yyvsp[(5) - (5)].node), makeNullAConst(-1)), @@ -26941,8 +27353,8 @@ YYLTYPE yylloc; ;} break; - case 959: -#line 2309 "third_party/libpg_query/grammar/statements/select.y" + case 965: +#line 2352 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("similar_escape"), list_make2((yyvsp[(5) - (7)].node), (yyvsp[(7) - (7)].node)), @@ -26952,8 +27364,8 @@ YYLTYPE yylloc; ;} break; - case 960: -#line 2327 "third_party/libpg_query/grammar/statements/select.y" + case 966: +#line 2370 "third_party/libpg_query/grammar/statements/select.y" { PGNullTest *n = makeNode(PGNullTest); n->arg = (PGExpr *) (yyvsp[(1) - (3)].node); @@ -26963,8 +27375,8 @@ YYLTYPE yylloc; ;} break; - case 961: -#line 2335 "third_party/libpg_query/grammar/statements/select.y" + case 967: +#line 2378 "third_party/libpg_query/grammar/statements/select.y" { PGNullTest *n = makeNode(PGNullTest); n->arg = (PGExpr *) (yyvsp[(1) - (2)].node); @@ -26974,8 +27386,8 @@ YYLTYPE yylloc; ;} break; - case 962: -#line 2343 "third_party/libpg_query/grammar/statements/select.y" + case 968: +#line 2386 "third_party/libpg_query/grammar/statements/select.y" { PGNullTest *n = makeNode(PGNullTest); n->arg = (PGExpr *) (yyvsp[(1) - (4)].node); @@ -26985,8 +27397,8 @@ YYLTYPE yylloc; ;} break; - case 963: -#line 2351 "third_party/libpg_query/grammar/statements/select.y" + case 969: +#line 2394 "third_party/libpg_query/grammar/statements/select.y" { PGNullTest *n = makeNode(PGNullTest); n->arg = (PGExpr *) (yyvsp[(1) - (3)].node); @@ -26996,8 +27408,8 @@ YYLTYPE yylloc; ;} break; - case 964: -#line 2359 "third_party/libpg_query/grammar/statements/select.y" + case 970: +#line 2402 "third_party/libpg_query/grammar/statements/select.y" { PGNullTest *n = makeNode(PGNullTest); n->arg = (PGExpr *) (yyvsp[(1) - (2)].node); @@ -27007,8 +27419,8 @@ YYLTYPE yylloc; ;} break; - case 965: -#line 2367 "third_party/libpg_query/grammar/statements/select.y" + case 971: +#line 2410 "third_party/libpg_query/grammar/statements/select.y" { PGLambdaFunction *n = makeNode(PGLambdaFunction); n->lhs = (yyvsp[(1) - (3)].node); @@ -27018,15 +27430,15 @@ YYLTYPE yylloc; ;} break; - case 966: -#line 2375 "third_party/libpg_query/grammar/statements/select.y" + case 972: +#line 2418 "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 967: -#line 2379 "third_party/libpg_query/grammar/statements/select.y" + case 973: +#line 2422 "third_party/libpg_query/grammar/statements/select.y" { if (list_length((yyvsp[(1) - (3)].list)) != 2) ereport(ERROR, @@ -27044,8 +27456,8 @@ YYLTYPE yylloc; ;} break; - case 968: -#line 2395 "third_party/libpg_query/grammar/statements/select.y" + case 974: +#line 2438 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (3)].node); @@ -27055,8 +27467,8 @@ YYLTYPE yylloc; ;} break; - case 969: -#line 2403 "third_party/libpg_query/grammar/statements/select.y" + case 975: +#line 2446 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (4)].node); @@ -27066,8 +27478,8 @@ YYLTYPE yylloc; ;} break; - case 970: -#line 2411 "third_party/libpg_query/grammar/statements/select.y" + case 976: +#line 2454 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (3)].node); @@ -27077,8 +27489,8 @@ YYLTYPE yylloc; ;} break; - case 971: -#line 2419 "third_party/libpg_query/grammar/statements/select.y" + case 977: +#line 2462 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (4)].node); @@ -27088,8 +27500,8 @@ YYLTYPE yylloc; ;} break; - case 972: -#line 2427 "third_party/libpg_query/grammar/statements/select.y" + case 978: +#line 2470 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (3)].node); @@ -27099,8 +27511,8 @@ YYLTYPE yylloc; ;} break; - case 973: -#line 2435 "third_party/libpg_query/grammar/statements/select.y" + case 979: +#line 2478 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (4)].node); @@ -27110,36 +27522,36 @@ YYLTYPE yylloc; ;} break; - case 974: -#line 2443 "third_party/libpg_query/grammar/statements/select.y" + case 980: +#line 2486 "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 975: -#line 2447 "third_party/libpg_query/grammar/statements/select.y" + case 981: +#line 2490 "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 976: -#line 2451 "third_party/libpg_query/grammar/statements/select.y" + case 982: +#line 2494 "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 977: -#line 2455 "third_party/libpg_query/grammar/statements/select.y" + case 983: +#line 2498 "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 978: -#line 2459 "third_party/libpg_query/grammar/statements/select.y" + case 984: +#line 2502 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_BETWEEN, "BETWEEN", @@ -27149,8 +27561,8 @@ YYLTYPE yylloc; ;} break; - case 979: -#line 2467 "third_party/libpg_query/grammar/statements/select.y" + case 985: +#line 2510 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_NOT_BETWEEN, "NOT BETWEEN", @@ -27160,8 +27572,8 @@ YYLTYPE yylloc; ;} break; - case 980: -#line 2475 "third_party/libpg_query/grammar/statements/select.y" + case 986: +#line 2518 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_BETWEEN_SYM, "BETWEEN SYMMETRIC", @@ -27171,8 +27583,8 @@ YYLTYPE yylloc; ;} break; - case 981: -#line 2483 "third_party/libpg_query/grammar/statements/select.y" + case 987: +#line 2526 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_NOT_BETWEEN_SYM, "NOT BETWEEN SYMMETRIC", @@ -27182,8 +27594,8 @@ YYLTYPE yylloc; ;} break; - case 982: -#line 2491 "third_party/libpg_query/grammar/statements/select.y" + case 988: +#line 2534 "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)) @@ -27205,8 +27617,8 @@ YYLTYPE yylloc; ;} break; - case 983: -#line 2511 "third_party/libpg_query/grammar/statements/select.y" + case 989: +#line 2554 "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)) @@ -27230,8 +27642,8 @@ YYLTYPE yylloc; ;} break; - case 984: -#line 2533 "third_party/libpg_query/grammar/statements/select.y" + case 990: +#line 2576 "third_party/libpg_query/grammar/statements/select.y" { PGSubLink *n = makeNode(PGSubLink); n->subLinkType = (yyvsp[(3) - (4)].subquerytype); @@ -27244,8 +27656,8 @@ YYLTYPE yylloc; ;} break; - case 985: -#line 2544 "third_party/libpg_query/grammar/statements/select.y" + case 991: +#line 2587 "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)])); @@ -27254,8 +27666,8 @@ YYLTYPE yylloc; ;} break; - case 986: -#line 2551 "third_party/libpg_query/grammar/statements/select.y" + case 992: +#line 2594 "third_party/libpg_query/grammar/statements/select.y" { /* * The SQL spec only allows DEFAULT in "contextually typed @@ -27271,8 +27683,8 @@ YYLTYPE yylloc; ;} break; - case 987: -#line 2565 "third_party/libpg_query/grammar/statements/select.y" + case 993: +#line 2608 "third_party/libpg_query/grammar/statements/select.y" { PGAStar *star = makeNode(PGAStar); star->expr = (yyvsp[(4) - (5)].node); @@ -27283,8 +27695,8 @@ YYLTYPE yylloc; ;} break; - case 988: -#line 2574 "third_party/libpg_query/grammar/statements/select.y" + case 994: +#line 2617 "third_party/libpg_query/grammar/statements/select.y" { PGAStar *star = makeNode(PGAStar); star->expr = (yyvsp[(3) - (4)].node); @@ -27294,164 +27706,166 @@ YYLTYPE yylloc; ;} break; - case 989: -#line 2582 "third_party/libpg_query/grammar/statements/select.y" + case 995: +#line 2625 "third_party/libpg_query/grammar/statements/select.y" { PGAStar *star = makeNode(PGAStar); - star->except_list = (yyvsp[(2) - (3)].list); - star->replace_list = (yyvsp[(3) - (3)].list); - star->location = (yylsp[(1) - (3)]); + star->except_list = (yyvsp[(2) - (4)].list); + star->replace_list = (yyvsp[(3) - (4)].list); + star->rename_list = (yyvsp[(4) - (4)].list); + star->location = (yylsp[(1) - (4)]); (yyval.node) = (PGNode *) star; ;} break; - case 990: -#line 2590 "third_party/libpg_query/grammar/statements/select.y" + case 996: +#line 2634 "third_party/libpg_query/grammar/statements/select.y" { PGAStar *star = makeNode(PGAStar); - star->relation = (yyvsp[(1) - (5)].str); - star->except_list = (yyvsp[(4) - (5)].list); - star->replace_list = (yyvsp[(5) - (5)].list); - star->location = (yylsp[(1) - (5)]); + star->relation = (yyvsp[(1) - (6)].str); + star->except_list = (yyvsp[(4) - (6)].list); + star->replace_list = (yyvsp[(5) - (6)].list); + star->rename_list = (yyvsp[(6) - (6)].list); + star->location = (yylsp[(1) - (6)]); (yyval.node) = (PGNode *) star; ;} break; - case 991: -#line 2610 "third_party/libpg_query/grammar/statements/select.y" + case 997: +#line 2655 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 992: -#line 2612 "third_party/libpg_query/grammar/statements/select.y" + case 998: +#line 2657 "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 993: -#line 2614 "third_party/libpg_query/grammar/statements/select.y" + case 999: +#line 2659 "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 994: -#line 2616 "third_party/libpg_query/grammar/statements/select.y" + case 1000: +#line 2661 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = doNegate((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 995: -#line 2618 "third_party/libpg_query/grammar/statements/select.y" + case 1001: +#line 2663 "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 2620 "third_party/libpg_query/grammar/statements/select.y" + case 1002: +#line 2665 "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 2622 "third_party/libpg_query/grammar/statements/select.y" + case 1003: +#line 2667 "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 2624 "third_party/libpg_query/grammar/statements/select.y" + case 1004: +#line 2669 "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 2626 "third_party/libpg_query/grammar/statements/select.y" + case 1005: +#line 2671 "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 2628 "third_party/libpg_query/grammar/statements/select.y" + case 1006: +#line 2673 "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 2630 "third_party/libpg_query/grammar/statements/select.y" + case 1007: +#line 2675 "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 2632 "third_party/libpg_query/grammar/statements/select.y" + case 1008: +#line 2677 "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 1003: -#line 2634 "third_party/libpg_query/grammar/statements/select.y" + case 1009: +#line 2679 "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 1004: -#line 2636 "third_party/libpg_query/grammar/statements/select.y" + case 1010: +#line 2681 "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 1005: -#line 2638 "third_party/libpg_query/grammar/statements/select.y" + case 1011: +#line 2683 "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 1006: -#line 2640 "third_party/libpg_query/grammar/statements/select.y" + case 1012: +#line 2685 "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 1007: -#line 2642 "third_party/libpg_query/grammar/statements/select.y" + case 1013: +#line 2687 "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 1008: -#line 2644 "third_party/libpg_query/grammar/statements/select.y" + case 1014: +#line 2689 "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 1009: -#line 2646 "third_party/libpg_query/grammar/statements/select.y" + case 1015: +#line 2691 "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 1010: -#line 2648 "third_party/libpg_query/grammar/statements/select.y" + case 1016: +#line 2693 "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 1011: -#line 2650 "third_party/libpg_query/grammar/statements/select.y" + case 1017: +#line 2695 "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 1012: -#line 2652 "third_party/libpg_query/grammar/statements/select.y" + case 1018: +#line 2697 "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 1013: -#line 2656 "third_party/libpg_query/grammar/statements/select.y" + case 1019: +#line 2701 "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 1014: -#line 2660 "third_party/libpg_query/grammar/statements/select.y" + case 1020: +#line 2705 "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 1015: -#line 2664 "third_party/libpg_query/grammar/statements/select.y" + case 1021: +#line 2709 "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 1017: -#line 2679 "third_party/libpg_query/grammar/statements/select.y" + case 1023: +#line 2724 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(2) - (2)].list)) { @@ -27465,18 +27879,18 @@ YYLTYPE yylloc; ;} break; - case 1018: -#line 2692 "third_party/libpg_query/grammar/statements/select.y" + case 1024: +#line 2737 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1019: -#line 2693 "third_party/libpg_query/grammar/statements/select.y" + case 1025: +#line 2738 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1020: -#line 2695 "third_party/libpg_query/grammar/statements/select.y" + case 1026: +#line 2740 "third_party/libpg_query/grammar/statements/select.y" { PGSubLink *n = makeNode(PGSubLink); n->subLinkType = PG_EXPR_SUBLINK; @@ -27489,8 +27903,8 @@ YYLTYPE yylloc; ;} break; - case 1021: -#line 2706 "third_party/libpg_query/grammar/statements/select.y" + case 1027: +#line 2751 "third_party/libpg_query/grammar/statements/select.y" { /* * Because the select_with_parens nonterminal is designed @@ -27516,8 +27930,8 @@ YYLTYPE yylloc; ;} break; - case 1022: -#line 2730 "third_party/libpg_query/grammar/statements/select.y" + case 1028: +#line 2775 "third_party/libpg_query/grammar/statements/select.y" { PGSubLink *n = makeNode(PGSubLink); n->subLinkType = PG_EXISTS_SUBLINK; @@ -27530,8 +27944,8 @@ YYLTYPE yylloc; ;} break; - case 1023: -#line 2741 "third_party/libpg_query/grammar/statements/select.y" + case 1029: +#line 2786 "third_party/libpg_query/grammar/statements/select.y" { PGGroupingFunc *g = makeNode(PGGroupingFunc); g->args = (yyvsp[(3) - (4)].list); @@ -27540,37 +27954,37 @@ YYLTYPE yylloc; ;} break; - case 1024: -#line 2751 "third_party/libpg_query/grammar/statements/select.y" + case 1030: +#line 2796 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (3)].node); ;} break; - case 1025: -#line 2755 "third_party/libpg_query/grammar/statements/select.y" + case 1031: +#line 2800 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1026: -#line 2758 "third_party/libpg_query/grammar/statements/select.y" + case 1032: +#line 2803 "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 1027: -#line 2766 "third_party/libpg_query/grammar/statements/select.y" + case 1033: +#line 2811 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeParamRef(0, (yylsp[(1) - (1)])); ;} break; - case 1028: -#line 2770 "third_party/libpg_query/grammar/statements/select.y" + case 1034: +#line 2815 "third_party/libpg_query/grammar/statements/select.y" { PGParamRef *p = makeNode(PGParamRef); p->number = (yyvsp[(1) - (1)].ival); @@ -27579,48 +27993,15 @@ YYLTYPE yylloc; ;} break; - case 1029: -#line 2777 "third_party/libpg_query/grammar/statements/select.y" - { - (yyval.node) = (yyvsp[(1) - (1)].node); - ;} - break; - - case 1030: -#line 2781 "third_party/libpg_query/grammar/statements/select.y" - { - (yyval.node) = (yyvsp[(1) - (1)].node); - ;} - break; - - case 1031: -#line 2785 "third_party/libpg_query/grammar/statements/select.y" + case 1035: +#line 2822 "third_party/libpg_query/grammar/statements/select.y" { - (yyval.node) = (yyvsp[(1) - (1)].node); + (yyval.node) = makeNamedParamRef((yyvsp[(2) - (2)].str), (yylsp[(1) - (2)])); ;} break; - case 1032: -#line 2789 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = (yyvsp[(1) - (1)].node); ;} - break; - - case 1033: -#line 2790 "third_party/libpg_query/grammar/statements/select.y" - { - (yyval.node) = (yyvsp[(1) - (1)].node); - ;} - break; - - case 1034: -#line 2793 "third_party/libpg_query/grammar/statements/select.y" - { - (yyval.node) = (yyvsp[(1) - (1)].node); - ;} - break; - - case 1035: -#line 2797 "third_party/libpg_query/grammar/statements/select.y" + case 1043: +#line 2836 "third_party/libpg_query/grammar/statements/select.y" { PGSubLink *n = makeNode(PGSubLink); n->subLinkType = PG_ARRAY_SUBLINK; @@ -27633,8 +28014,8 @@ YYLTYPE yylloc; ;} break; - case 1036: -#line 2807 "third_party/libpg_query/grammar/statements/select.y" + case 1044: +#line 2846 "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)])); @@ -27642,8 +28023,8 @@ YYLTYPE yylloc; ;} break; - case 1037: -#line 2813 "third_party/libpg_query/grammar/statements/select.y" + case 1045: +#line 2852 "third_party/libpg_query/grammar/statements/select.y" { PGPositionalReference *n = makeNode(PGPositionalReference); n->position = (yyvsp[(2) - (2)].ival); @@ -27652,31 +28033,24 @@ YYLTYPE yylloc; ;} break; - case 1038: -#line 2820 "third_party/libpg_query/grammar/statements/select.y" - { - (yyval.node) = makeNamedParamRef((yyvsp[(2) - (2)].str), (yylsp[(1) - (2)])); - ;} - break; - - case 1039: -#line 2825 "third_party/libpg_query/grammar/statements/select.y" + case 1046: +#line 2860 "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 1040: -#line 2832 "third_party/libpg_query/grammar/statements/select.y" + case 1047: +#line 2867 "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 1041: -#line 2839 "third_party/libpg_query/grammar/statements/select.y" + case 1048: +#line 2874 "third_party/libpg_query/grammar/statements/select.y" { PGList *key_list = NULL; PGList *value_list = NULL; @@ -27695,15 +28069,15 @@ YYLTYPE yylloc; ;} break; - case 1042: -#line 2859 "third_party/libpg_query/grammar/statements/select.y" + case 1049: +#line 2894 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall((yyvsp[(1) - (3)].list), NIL, (yylsp[(1) - (3)])); ;} break; - case 1043: -#line 2863 "third_party/libpg_query/grammar/statements/select.y" + case 1050: +#line 2898 "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); @@ -27712,8 +28086,8 @@ YYLTYPE yylloc; ;} break; - case 1044: -#line 2870 "third_party/libpg_query/grammar/statements/select.y" + case 1051: +#line 2905 "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; @@ -27723,8 +28097,8 @@ YYLTYPE yylloc; ;} break; - case 1045: -#line 2878 "third_party/libpg_query/grammar/statements/select.y" + case 1052: +#line 2913 "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; @@ -27734,8 +28108,8 @@ YYLTYPE yylloc; ;} break; - case 1046: -#line 2886 "third_party/libpg_query/grammar/statements/select.y" + case 1053: +#line 2921 "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); @@ -27748,8 +28122,8 @@ YYLTYPE yylloc; ;} break; - case 1047: -#line 2897 "third_party/libpg_query/grammar/statements/select.y" + case 1054: +#line 2932 "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); @@ -27759,8 +28133,8 @@ YYLTYPE yylloc; ;} break; - case 1048: -#line 2917 "third_party/libpg_query/grammar/statements/select.y" + case 1055: +#line 2952 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = (PGFuncCall *) (yyvsp[(1) - (5)].node); /* @@ -27798,23 +28172,23 @@ YYLTYPE yylloc; ;} break; - case 1049: -#line 2953 "third_party/libpg_query/grammar/statements/select.y" + case 1056: +#line 2988 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1050: -#line 2963 "third_party/libpg_query/grammar/statements/select.y" + case 1057: +#line 2998 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1051: -#line 2964 "third_party/libpg_query/grammar/statements/select.y" + case 1058: +#line 2999 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1052: -#line 2972 "third_party/libpg_query/grammar/statements/select.y" + case 1059: +#line 3007 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("pg_collation_for"), list_make1((yyvsp[(4) - (5)].node)), @@ -27822,25 +28196,25 @@ YYLTYPE yylloc; ;} break; - case 1053: -#line 2978 "third_party/libpg_query/grammar/statements/select.y" + case 1060: +#line 3013 "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 1054: -#line 2980 "third_party/libpg_query/grammar/statements/select.y" + case 1061: +#line 3015 "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 1055: -#line 2982 "third_party/libpg_query/grammar/statements/select.y" + case 1062: +#line 3017 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("date_part"), (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); ;} break; - case 1056: -#line 2986 "third_party/libpg_query/grammar/statements/select.y" + case 1063: +#line 3021 "third_party/libpg_query/grammar/statements/select.y" { /* overlay(A PLACING B FROM C FOR D) is converted to * overlay(A, B, C, D) @@ -27851,16 +28225,16 @@ YYLTYPE yylloc; ;} break; - case 1057: -#line 2995 "third_party/libpg_query/grammar/statements/select.y" + case 1064: +#line 3030 "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 1058: -#line 3000 "third_party/libpg_query/grammar/statements/select.y" + case 1065: +#line 3035 "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 @@ -27869,8 +28243,8 @@ YYLTYPE yylloc; ;} break; - case 1059: -#line 3007 "third_party/libpg_query/grammar/statements/select.y" + case 1066: +#line 3042 "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. @@ -27887,8 +28261,8 @@ YYLTYPE yylloc; ;} break; - case 1060: -#line 3022 "third_party/libpg_query/grammar/statements/select.y" + case 1067: +#line 3057 "third_party/libpg_query/grammar/statements/select.y" { /* various trim expressions are defined in SQL * - thomas 1997-07-19 @@ -27897,36 +28271,36 @@ YYLTYPE yylloc; ;} break; - case 1061: -#line 3029 "third_party/libpg_query/grammar/statements/select.y" + case 1068: +#line 3064 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("ltrim"), (yyvsp[(4) - (5)].list), (yylsp[(1) - (5)])); ;} break; - case 1062: -#line 3033 "third_party/libpg_query/grammar/statements/select.y" + case 1069: +#line 3068 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("rtrim"), (yyvsp[(4) - (5)].list), (yylsp[(1) - (5)])); ;} break; - case 1063: -#line 3037 "third_party/libpg_query/grammar/statements/select.y" + case 1070: +#line 3072 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("trim"), (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); ;} break; - case 1064: -#line 3041 "third_party/libpg_query/grammar/statements/select.y" + case 1071: +#line 3076 "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 1065: -#line 3045 "third_party/libpg_query/grammar/statements/select.y" + case 1072: +#line 3080 "third_party/libpg_query/grammar/statements/select.y" { PGCoalesceExpr *c = makeNode(PGCoalesceExpr); c->args = (yyvsp[(3) - (4)].list); @@ -27935,16 +28309,16 @@ YYLTYPE yylloc; ;} break; - case 1066: -#line 3055 "third_party/libpg_query/grammar/statements/select.y" + case 1073: +#line 3090 "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 1067: -#line 3063 "third_party/libpg_query/grammar/statements/select.y" + case 1074: +#line 3098 "third_party/libpg_query/grammar/statements/select.y" { PGLambdaFunction *lambda = makeNode(PGLambdaFunction); lambda->lhs = (yyvsp[(4) - (7)].node); @@ -27955,8 +28329,8 @@ YYLTYPE yylloc; ;} break; - case 1068: -#line 3072 "third_party/libpg_query/grammar/statements/select.y" + case 1075: +#line 3107 "third_party/libpg_query/grammar/statements/select.y" { PGLambdaFunction *lambda = makeNode(PGLambdaFunction); lambda->lhs = (yyvsp[(4) - (9)].node); @@ -27973,63 +28347,63 @@ YYLTYPE yylloc; ;} break; - case 1069: -#line 3093 "third_party/libpg_query/grammar/statements/select.y" + case 1076: +#line 3128 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(4) - (5)].list); ;} break; - case 1070: -#line 3094 "third_party/libpg_query/grammar/statements/select.y" + case 1077: +#line 3129 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1071: -#line 3098 "third_party/libpg_query/grammar/statements/select.y" + case 1078: +#line 3133 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(4) - (5)].node); ;} break; - case 1072: -#line 3099 "third_party/libpg_query/grammar/statements/select.y" + case 1079: +#line 3134 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(3) - (4)].node); ;} break; - case 1073: -#line 3100 "third_party/libpg_query/grammar/statements/select.y" + case 1080: +#line 3135 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 1074: -#line 3104 "third_party/libpg_query/grammar/statements/select.y" + case 1081: +#line 3139 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = true; ;} break; - case 1075: -#line 3105 "third_party/libpg_query/grammar/statements/select.y" + case 1082: +#line 3140 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 1076: -#line 3112 "third_party/libpg_query/grammar/statements/select.y" + case 1083: +#line 3147 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 1077: -#line 3113 "third_party/libpg_query/grammar/statements/select.y" + case 1084: +#line 3148 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1078: -#line 3117 "third_party/libpg_query/grammar/statements/select.y" + case 1085: +#line 3152 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].windef)); ;} break; - case 1079: -#line 3119 "third_party/libpg_query/grammar/statements/select.y" + case 1086: +#line 3154 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].windef)); ;} break; - case 1080: -#line 3124 "third_party/libpg_query/grammar/statements/select.y" + case 1087: +#line 3159 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = (yyvsp[(3) - (3)].windef); n->name = (yyvsp[(1) - (3)].str); @@ -28037,13 +28411,13 @@ YYLTYPE yylloc; ;} break; - case 1081: -#line 3132 "third_party/libpg_query/grammar/statements/select.y" + case 1088: +#line 3167 "third_party/libpg_query/grammar/statements/select.y" { (yyval.windef) = (yyvsp[(2) - (2)].windef); ;} break; - case 1082: -#line 3134 "third_party/libpg_query/grammar/statements/select.y" + case 1089: +#line 3169 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); n->name = (yyvsp[(2) - (2)].str); @@ -28058,13 +28432,13 @@ YYLTYPE yylloc; ;} break; - case 1083: -#line 3147 "third_party/libpg_query/grammar/statements/select.y" + case 1090: +#line 3182 "third_party/libpg_query/grammar/statements/select.y" { (yyval.windef) = NULL; ;} break; - case 1084: -#line 3152 "third_party/libpg_query/grammar/statements/select.y" + case 1091: +#line 3187 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); n->name = NULL; @@ -28080,28 +28454,28 @@ YYLTYPE yylloc; ;} break; - case 1085: -#line 3177 "third_party/libpg_query/grammar/statements/select.y" + case 1092: +#line 3212 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1086: -#line 3178 "third_party/libpg_query/grammar/statements/select.y" + case 1093: +#line 3213 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = NULL; ;} break; - case 1087: -#line 3181 "third_party/libpg_query/grammar/statements/select.y" + case 1094: +#line 3216 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (3)].list); ;} break; - case 1088: -#line 3182 "third_party/libpg_query/grammar/statements/select.y" + case 1095: +#line 3217 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1089: -#line 3191 "third_party/libpg_query/grammar/statements/select.y" + case 1096: +#line 3226 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = (yyvsp[(2) - (3)].windef); @@ -28111,8 +28485,8 @@ YYLTYPE yylloc; ;} break; - case 1090: -#line 3199 "third_party/libpg_query/grammar/statements/select.y" + case 1097: +#line 3234 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = (yyvsp[(2) - (3)].windef); @@ -28122,8 +28496,8 @@ YYLTYPE yylloc; ;} break; - case 1091: -#line 3207 "third_party/libpg_query/grammar/statements/select.y" + case 1098: +#line 3242 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = (yyvsp[(2) - (3)].windef); @@ -28133,8 +28507,8 @@ YYLTYPE yylloc; ;} break; - case 1092: -#line 3215 "third_party/libpg_query/grammar/statements/select.y" + case 1099: +#line 3250 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -28145,8 +28519,8 @@ YYLTYPE yylloc; ;} break; - case 1093: -#line 3226 "third_party/libpg_query/grammar/statements/select.y" + case 1100: +#line 3261 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = (yyvsp[(1) - (1)].windef); @@ -28166,8 +28540,8 @@ YYLTYPE yylloc; ;} break; - case 1094: -#line 3244 "third_party/libpg_query/grammar/statements/select.y" + case 1101: +#line 3279 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n1 = (yyvsp[(2) - (4)].windef); PGWindowDef *n2 = (yyvsp[(4) - (4)].windef); @@ -28207,8 +28581,8 @@ YYLTYPE yylloc; ;} break; - case 1095: -#line 3290 "third_party/libpg_query/grammar/statements/select.y" + case 1102: +#line 3325 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -28219,8 +28593,8 @@ YYLTYPE yylloc; ;} break; - case 1096: -#line 3299 "third_party/libpg_query/grammar/statements/select.y" + case 1103: +#line 3334 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -28231,8 +28605,8 @@ YYLTYPE yylloc; ;} break; - case 1097: -#line 3308 "third_party/libpg_query/grammar/statements/select.y" + case 1104: +#line 3343 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -28243,8 +28617,8 @@ YYLTYPE yylloc; ;} break; - case 1098: -#line 3317 "third_party/libpg_query/grammar/statements/select.y" + case 1105: +#line 3352 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -28255,8 +28629,8 @@ YYLTYPE yylloc; ;} break; - case 1099: -#line 3326 "third_party/libpg_query/grammar/statements/select.y" + case 1106: +#line 3361 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -28267,53 +28641,53 @@ YYLTYPE yylloc; ;} break; - case 1100: -#line 3337 "third_party/libpg_query/grammar/statements/select.y" + case 1107: +#line 3372 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = FRAMEOPTION_EXCLUDE_CURRENT_ROW; ;} break; - case 1101: -#line 3338 "third_party/libpg_query/grammar/statements/select.y" + case 1108: +#line 3373 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = FRAMEOPTION_EXCLUDE_GROUP; ;} break; - case 1102: -#line 3339 "third_party/libpg_query/grammar/statements/select.y" + case 1109: +#line 3374 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = FRAMEOPTION_EXCLUDE_TIES; ;} break; - case 1103: -#line 3340 "third_party/libpg_query/grammar/statements/select.y" + case 1110: +#line 3375 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = 0; ;} break; - case 1104: -#line 3341 "third_party/libpg_query/grammar/statements/select.y" + case 1111: +#line 3376 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = 0; ;} break; - case 1105: -#line 3355 "third_party/libpg_query/grammar/statements/select.y" + case 1112: +#line 3390 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1106: -#line 3356 "third_party/libpg_query/grammar/statements/select.y" + case 1113: +#line 3391 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1107: -#line 3359 "third_party/libpg_query/grammar/statements/select.y" + case 1114: +#line 3394 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list);;} break; - case 1108: -#line 3360 "third_party/libpg_query/grammar/statements/select.y" + case 1115: +#line 3395 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(2) - (5)].list), (yyvsp[(4) - (5)].node)); ;} break; - case 1109: -#line 3364 "third_party/libpg_query/grammar/statements/select.y" + case 1116: +#line 3399 "third_party/libpg_query/grammar/statements/select.y" { PGNamedArgExpr *na = makeNode(PGNamedArgExpr); na->name = (yyvsp[(1) - (3)].str); @@ -28324,321 +28698,321 @@ YYLTYPE yylloc; ;} break; - case 1110: -#line 3374 "third_party/libpg_query/grammar/statements/select.y" + case 1117: +#line 3409 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1111: -#line 3375 "third_party/libpg_query/grammar/statements/select.y" + case 1118: +#line 3410 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1112: -#line 3379 "third_party/libpg_query/grammar/statements/select.y" + case 1119: +#line 3414 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1113: -#line 3380 "third_party/libpg_query/grammar/statements/select.y" + case 1120: +#line 3415 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1114: -#line 3385 "third_party/libpg_query/grammar/statements/select.y" + case 1121: +#line 3420 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); ;} break; - case 1115: -#line 3391 "third_party/libpg_query/grammar/statements/select.y" + case 1122: +#line 3426 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].list)); ;} break; - case 1116: -#line 3392 "third_party/libpg_query/grammar/statements/select.y" + case 1123: +#line 3427 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); ;} break; - case 1117: -#line 3397 "third_party/libpg_query/grammar/statements/select.y" + case 1124: +#line 3432 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1118: -#line 3398 "third_party/libpg_query/grammar/statements/select.y" + case 1125: +#line 3433 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1119: -#line 3403 "third_party/libpg_query/grammar/statements/select.y" + case 1126: +#line 3438 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1120: -#line 3404 "third_party/libpg_query/grammar/statements/select.y" + case 1127: +#line 3439 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 1121: -#line 3407 "third_party/libpg_query/grammar/statements/select.y" + case 1128: +#line 3442 "third_party/libpg_query/grammar/statements/select.y" { (yyval.subquerytype) = PG_ANY_SUBLINK; ;} break; - case 1122: -#line 3408 "third_party/libpg_query/grammar/statements/select.y" + case 1129: +#line 3443 "third_party/libpg_query/grammar/statements/select.y" { (yyval.subquerytype) = PG_ANY_SUBLINK; ;} break; - case 1123: -#line 3409 "third_party/libpg_query/grammar/statements/select.y" + case 1130: +#line 3444 "third_party/libpg_query/grammar/statements/select.y" { (yyval.subquerytype) = PG_ALL_SUBLINK; ;} break; - case 1124: -#line 3412 "third_party/libpg_query/grammar/statements/select.y" + case 1131: +#line 3447 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1125: -#line 3413 "third_party/libpg_query/grammar/statements/select.y" + case 1132: +#line 3448 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) (yyvsp[(1) - (1)].conststr); ;} break; - case 1126: -#line 3416 "third_party/libpg_query/grammar/statements/select.y" + case 1133: +#line 3451 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "+"; ;} break; - case 1127: -#line 3417 "third_party/libpg_query/grammar/statements/select.y" + case 1134: +#line 3452 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "-"; ;} break; - case 1128: -#line 3418 "third_party/libpg_query/grammar/statements/select.y" + case 1135: +#line 3453 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "*"; ;} break; - case 1129: -#line 3419 "third_party/libpg_query/grammar/statements/select.y" + case 1136: +#line 3454 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "/"; ;} break; - case 1130: -#line 3420 "third_party/libpg_query/grammar/statements/select.y" + case 1137: +#line 3455 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "//"; ;} break; - case 1131: -#line 3421 "third_party/libpg_query/grammar/statements/select.y" + case 1138: +#line 3456 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "%"; ;} break; - case 1132: -#line 3422 "third_party/libpg_query/grammar/statements/select.y" + case 1139: +#line 3457 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "^"; ;} break; - case 1133: -#line 3423 "third_party/libpg_query/grammar/statements/select.y" + case 1140: +#line 3458 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "**"; ;} break; - case 1134: -#line 3424 "third_party/libpg_query/grammar/statements/select.y" + case 1141: +#line 3459 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "<"; ;} break; - case 1135: -#line 3425 "third_party/libpg_query/grammar/statements/select.y" + case 1142: +#line 3460 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = ">"; ;} break; - case 1136: -#line 3426 "third_party/libpg_query/grammar/statements/select.y" + case 1143: +#line 3461 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "="; ;} break; - case 1137: -#line 3427 "third_party/libpg_query/grammar/statements/select.y" + case 1144: +#line 3462 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "<="; ;} break; - case 1138: -#line 3428 "third_party/libpg_query/grammar/statements/select.y" + case 1145: +#line 3463 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = ">="; ;} break; - case 1139: -#line 3429 "third_party/libpg_query/grammar/statements/select.y" + case 1146: +#line 3464 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "<>"; ;} break; - case 1140: -#line 3433 "third_party/libpg_query/grammar/statements/select.y" + case 1147: +#line 3468 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1141: -#line 3435 "third_party/libpg_query/grammar/statements/select.y" + case 1148: +#line 3470 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1142: -#line 3440 "third_party/libpg_query/grammar/statements/select.y" + case 1149: +#line 3475 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1143: -#line 3442 "third_party/libpg_query/grammar/statements/select.y" + case 1150: +#line 3477 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1144: -#line 3447 "third_party/libpg_query/grammar/statements/select.y" + case 1151: +#line 3482 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1145: -#line 3449 "third_party/libpg_query/grammar/statements/select.y" + case 1152: +#line 3484 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1146: -#line 3451 "third_party/libpg_query/grammar/statements/select.y" + case 1153: +#line 3486 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("~~")); ;} break; - case 1147: -#line 3453 "third_party/libpg_query/grammar/statements/select.y" + case 1154: +#line 3488 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("!~~")); ;} break; - case 1148: -#line 3455 "third_party/libpg_query/grammar/statements/select.y" + case 1155: +#line 3490 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("~~~")); ;} break; - case 1149: -#line 3457 "third_party/libpg_query/grammar/statements/select.y" + case 1156: +#line 3492 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("!~~~")); ;} break; - case 1150: -#line 3459 "third_party/libpg_query/grammar/statements/select.y" + case 1157: +#line 3494 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("~~*")); ;} break; - case 1151: -#line 3461 "third_party/libpg_query/grammar/statements/select.y" + case 1158: +#line 3496 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("!~~*")); ;} break; - case 1152: -#line 3475 "third_party/libpg_query/grammar/statements/select.y" + case 1159: +#line 3510 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1153: -#line 3477 "third_party/libpg_query/grammar/statements/select.y" + case 1160: +#line 3512 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lcons(makeString((yyvsp[(1) - (3)].str)), (yyvsp[(3) - (3)].list)); ;} break; - case 1154: -#line 3482 "third_party/libpg_query/grammar/statements/select.y" + case 1161: +#line 3517 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1155: -#line 3486 "third_party/libpg_query/grammar/statements/select.y" + case 1162: +#line 3521 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1156: -#line 3493 "third_party/libpg_query/grammar/statements/select.y" + case 1163: +#line 3528 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1157: -#line 3498 "third_party/libpg_query/grammar/statements/select.y" + case 1164: +#line 3533 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1158: -#line 3504 "third_party/libpg_query/grammar/statements/select.y" + case 1165: +#line 3539 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1159: -#line 3508 "third_party/libpg_query/grammar/statements/select.y" + case 1166: +#line 3543 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1160: -#line 3515 "third_party/libpg_query/grammar/statements/select.y" + case 1167: +#line 3550 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1161: -#line 3520 "third_party/libpg_query/grammar/statements/select.y" + case 1168: +#line 3555 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1162: -#line 3527 "third_party/libpg_query/grammar/statements/select.y" + case 1169: +#line 3562 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1163: -#line 3531 "third_party/libpg_query/grammar/statements/select.y" + case 1170: +#line 3566 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 1164: -#line 3540 "third_party/libpg_query/grammar/statements/select.y" + case 1171: +#line 3575 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1165: -#line 3544 "third_party/libpg_query/grammar/statements/select.y" + case 1172: +#line 3579 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1166: -#line 3550 "third_party/libpg_query/grammar/statements/select.y" + case 1173: +#line 3585 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1167: -#line 3554 "third_party/libpg_query/grammar/statements/select.y" + case 1174: +#line 3589 "third_party/libpg_query/grammar/statements/select.y" { PGNamedArgExpr *na = makeNode(PGNamedArgExpr); na->name = (yyvsp[(1) - (3)].str); @@ -28649,8 +29023,8 @@ YYLTYPE yylloc; ;} break; - case 1168: -#line 3563 "third_party/libpg_query/grammar/statements/select.y" + case 1175: +#line 3598 "third_party/libpg_query/grammar/statements/select.y" { PGNamedArgExpr *na = makeNode(PGNamedArgExpr); na->name = (yyvsp[(1) - (3)].str); @@ -28661,156 +29035,156 @@ YYLTYPE yylloc; ;} break; - case 1169: -#line 3573 "third_party/libpg_query/grammar/statements/select.y" + case 1176: +#line 3608 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].typnam)); ;} break; - case 1170: -#line 3574 "third_party/libpg_query/grammar/statements/select.y" + case 1177: +#line 3609 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].typnam)); ;} break; - case 1171: -#line 3579 "third_party/libpg_query/grammar/statements/select.y" + case 1178: +#line 3614 "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 1172: -#line 3582 "third_party/libpg_query/grammar/statements/select.y" + case 1179: +#line 3617 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1173: -#line 3589 "third_party/libpg_query/grammar/statements/select.y" + case 1180: +#line 3624 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1174: -#line 3590 "third_party/libpg_query/grammar/statements/select.y" + case 1181: +#line 3625 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "year"; ;} break; - case 1175: -#line 3591 "third_party/libpg_query/grammar/statements/select.y" + case 1182: +#line 3626 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "month"; ;} break; - case 1176: -#line 3592 "third_party/libpg_query/grammar/statements/select.y" + case 1183: +#line 3627 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "day"; ;} break; - case 1177: -#line 3593 "third_party/libpg_query/grammar/statements/select.y" + case 1184: +#line 3628 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "hour"; ;} break; - case 1178: -#line 3594 "third_party/libpg_query/grammar/statements/select.y" + case 1185: +#line 3629 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "minute"; ;} break; - case 1179: -#line 3595 "third_party/libpg_query/grammar/statements/select.y" + case 1186: +#line 3630 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "second"; ;} break; - case 1180: -#line 3596 "third_party/libpg_query/grammar/statements/select.y" + case 1187: +#line 3631 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "millisecond"; ;} break; - case 1181: -#line 3597 "third_party/libpg_query/grammar/statements/select.y" + case 1188: +#line 3632 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "microsecond"; ;} break; - case 1182: -#line 3598 "third_party/libpg_query/grammar/statements/select.y" + case 1189: +#line 3633 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "week"; ;} break; - case 1183: -#line 3599 "third_party/libpg_query/grammar/statements/select.y" + case 1190: +#line 3634 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "quarter"; ;} break; - case 1184: -#line 3600 "third_party/libpg_query/grammar/statements/select.y" + case 1191: +#line 3635 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "decade"; ;} break; - case 1185: -#line 3601 "third_party/libpg_query/grammar/statements/select.y" + case 1192: +#line 3636 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "century"; ;} break; - case 1186: -#line 3602 "third_party/libpg_query/grammar/statements/select.y" + case 1193: +#line 3637 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "millennium"; ;} break; - case 1187: -#line 3603 "third_party/libpg_query/grammar/statements/select.y" + case 1194: +#line 3638 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1188: -#line 3614 "third_party/libpg_query/grammar/statements/select.y" + case 1195: +#line 3649 "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 1189: -#line 3618 "third_party/libpg_query/grammar/statements/select.y" + case 1196: +#line 3653 "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 1190: -#line 3625 "third_party/libpg_query/grammar/statements/select.y" + case 1197: +#line 3660 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 1191: -#line 3631 "third_party/libpg_query/grammar/statements/select.y" + case 1198: +#line 3666 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); ;} break; - case 1192: -#line 3632 "third_party/libpg_query/grammar/statements/select.y" + case 1199: +#line 3667 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1193: -#line 3649 "third_party/libpg_query/grammar/statements/select.y" + case 1200: +#line 3684 "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 1194: -#line 3653 "third_party/libpg_query/grammar/statements/select.y" + case 1201: +#line 3688 "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 1195: -#line 3658 "third_party/libpg_query/grammar/statements/select.y" + case 1202: +#line 3693 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); ;} break; - case 1196: -#line 3662 "third_party/libpg_query/grammar/statements/select.y" + case 1203: +#line 3697 "third_party/libpg_query/grammar/statements/select.y" { /* * Since there are no cases where this syntax allows @@ -28827,45 +29201,45 @@ YYLTYPE yylloc; ;} break; - case 1197: -#line 3677 "third_party/libpg_query/grammar/statements/select.y" + case 1204: +#line 3712 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1198: -#line 3681 "third_party/libpg_query/grammar/statements/select.y" + case 1205: +#line 3716 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1199: -#line 3685 "third_party/libpg_query/grammar/statements/select.y" + case 1206: +#line 3720 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 1200: -#line 3688 "third_party/libpg_query/grammar/statements/select.y" + case 1207: +#line 3723 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 1201: -#line 3691 "third_party/libpg_query/grammar/statements/select.y" + case 1208: +#line 3726 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(3) - (3)].list), (yyvsp[(1) - (3)].node)); ;} break; - case 1202: -#line 3692 "third_party/libpg_query/grammar/statements/select.y" + case 1209: +#line 3727 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 1203: -#line 3693 "third_party/libpg_query/grammar/statements/select.y" + case 1210: +#line 3728 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1204: -#line 3697 "third_party/libpg_query/grammar/statements/select.y" + case 1211: +#line 3732 "third_party/libpg_query/grammar/statements/select.y" { PGSubLink *n = makeNode(PGSubLink); n->subselect = (yyvsp[(1) - (1)].node); @@ -28874,18 +29248,18 @@ YYLTYPE yylloc; ;} break; - case 1205: -#line 3703 "third_party/libpg_query/grammar/statements/select.y" + case 1212: +#line 3738 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *)(yyvsp[(2) - (3)].list); ;} break; - case 1207: -#line 3705 "third_party/libpg_query/grammar/statements/select.y" + case 1214: +#line 3740 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *)(yyvsp[(1) - (1)].node); ;} break; - case 1208: -#line 3716 "third_party/libpg_query/grammar/statements/select.y" + case 1215: +#line 3751 "third_party/libpg_query/grammar/statements/select.y" { PGCaseExpr *c = makeNode(PGCaseExpr); c->casetype = InvalidOid; /* not analyzed yet */ @@ -28897,18 +29271,18 @@ YYLTYPE yylloc; ;} break; - case 1209: -#line 3729 "third_party/libpg_query/grammar/statements/select.y" + case 1216: +#line 3764 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1210: -#line 3730 "third_party/libpg_query/grammar/statements/select.y" + case 1217: +#line 3765 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 1211: -#line 3735 "third_party/libpg_query/grammar/statements/select.y" + case 1218: +#line 3770 "third_party/libpg_query/grammar/statements/select.y" { PGCaseWhen *w = makeNode(PGCaseWhen); w->expr = (PGExpr *) (yyvsp[(2) - (4)].node); @@ -28918,59 +29292,59 @@ YYLTYPE yylloc; ;} break; - case 1212: -#line 3745 "third_party/libpg_query/grammar/statements/select.y" + case 1219: +#line 3780 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 1213: -#line 3746 "third_party/libpg_query/grammar/statements/select.y" + case 1220: +#line 3781 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 1214: -#line 3749 "third_party/libpg_query/grammar/statements/select.y" + case 1221: +#line 3784 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1215: -#line 3750 "third_party/libpg_query/grammar/statements/select.y" + case 1222: +#line 3785 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 1216: -#line 3754 "third_party/libpg_query/grammar/statements/select.y" + case 1223: +#line 3789 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1217: -#line 3755 "third_party/libpg_query/grammar/statements/select.y" + case 1224: +#line 3790 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1218: -#line 3759 "third_party/libpg_query/grammar/statements/select.y" + case 1225: +#line 3794 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeColumnRef((yyvsp[(1) - (1)].str), NIL, (yylsp[(1) - (1)]), yyscanner); ;} break; - case 1219: -#line 3765 "third_party/libpg_query/grammar/statements/select.y" + case 1226: +#line 3800 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeColumnRef((yyvsp[(1) - (1)].str), NIL, (yylsp[(1) - (1)]), yyscanner); ;} break; - case 1220: -#line 3769 "third_party/libpg_query/grammar/statements/select.y" + case 1227: +#line 3804 "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 1221: -#line 3776 "third_party/libpg_query/grammar/statements/select.y" + case 1228: +#line 3811 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = false; @@ -28980,8 +29354,8 @@ YYLTYPE yylloc; ;} break; - case 1222: -#line 3784 "third_party/libpg_query/grammar/statements/select.y" + case 1229: +#line 3819 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -28991,8 +29365,8 @@ YYLTYPE yylloc; ;} break; - case 1223: -#line 3791 "third_party/libpg_query/grammar/statements/select.y" + case 1230: +#line 3826 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -29003,8 +29377,8 @@ YYLTYPE yylloc; ;} break; - case 1224: -#line 3799 "third_party/libpg_query/grammar/statements/select.y" + case 1231: +#line 3834 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -29014,43 +29388,43 @@ YYLTYPE yylloc; ;} break; - case 1225: -#line 3809 "third_party/libpg_query/grammar/statements/select.y" + case 1232: +#line 3844 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1226: -#line 3810 "third_party/libpg_query/grammar/statements/select.y" + case 1233: +#line 3845 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 1227: -#line 3815 "third_party/libpg_query/grammar/statements/select.y" + case 1234: +#line 3850 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1228: -#line 3816 "third_party/libpg_query/grammar/statements/select.y" + case 1235: +#line 3851 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 1229: -#line 3820 "third_party/libpg_query/grammar/statements/select.y" + case 1236: +#line 3855 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 1230: -#line 3821 "third_party/libpg_query/grammar/statements/select.y" + case 1237: +#line 3856 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(NULL); ;} break; - case 1231: -#line 3822 "third_party/libpg_query/grammar/statements/select.y" + case 1238: +#line 3857 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 1232: -#line 3827 "third_party/libpg_query/grammar/statements/select.y" + case 1239: +#line 3862 "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)])); @@ -29061,8 +29435,8 @@ YYLTYPE yylloc; ;} break; - case 1233: -#line 3836 "third_party/libpg_query/grammar/statements/select.y" + case 1240: +#line 3871 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = false; @@ -29072,8 +29446,8 @@ YYLTYPE yylloc; ;} break; - case 1234: -#line 3844 "third_party/libpg_query/grammar/statements/select.y" + case 1241: +#line 3879 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -29083,8 +29457,8 @@ YYLTYPE yylloc; ;} break; - case 1235: -#line 3851 "third_party/libpg_query/grammar/statements/select.y" + case 1242: +#line 3886 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -29095,8 +29469,8 @@ YYLTYPE yylloc; ;} break; - case 1236: -#line 3860 "third_party/libpg_query/grammar/statements/select.y" + case 1243: +#line 3895 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -29106,48 +29480,48 @@ YYLTYPE yylloc; ;} break; - case 1237: -#line 3875 "third_party/libpg_query/grammar/statements/select.y" + case 1244: +#line 3910 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1238: -#line 3876 "third_party/libpg_query/grammar/statements/select.y" + case 1245: +#line 3911 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 1241: -#line 3892 "third_party/libpg_query/grammar/statements/select.y" + case 1248: +#line 3927 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1242: -#line 3893 "third_party/libpg_query/grammar/statements/select.y" + case 1249: +#line 3928 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1243: -#line 3897 "third_party/libpg_query/grammar/statements/select.y" + case 1250: +#line 3932 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].target)); ;} break; - case 1244: -#line 3898 "third_party/libpg_query/grammar/statements/select.y" + case 1251: +#line 3933 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].target)); ;} break; - case 1245: -#line 3902 "third_party/libpg_query/grammar/statements/select.y" + case 1252: +#line 3937 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1246: -#line 3903 "third_party/libpg_query/grammar/statements/select.y" + case 1253: +#line 3938 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1247: -#line 3907 "third_party/libpg_query/grammar/statements/select.y" + case 1254: +#line 3942 "third_party/libpg_query/grammar/statements/select.y" { (yyval.target) = makeNode(PGResTarget); (yyval.target)->name = (yyvsp[(3) - (3)].str); @@ -29157,8 +29531,8 @@ YYLTYPE yylloc; ;} break; - case 1248: -#line 3923 "third_party/libpg_query/grammar/statements/select.y" + case 1255: +#line 3958 "third_party/libpg_query/grammar/statements/select.y" { (yyval.target) = makeNode(PGResTarget); (yyval.target)->name = (yyvsp[(2) - (2)].str); @@ -29168,8 +29542,8 @@ YYLTYPE yylloc; ;} break; - case 1249: -#line 3931 "third_party/libpg_query/grammar/statements/select.y" + case 1256: +#line 3966 "third_party/libpg_query/grammar/statements/select.y" { (yyval.target) = makeNode(PGResTarget); (yyval.target)->name = NULL; @@ -29179,140 +29553,225 @@ YYLTYPE yylloc; ;} break; - case 1250: -#line 3940 "third_party/libpg_query/grammar/statements/select.y" + case 1257: +#line 3974 "third_party/libpg_query/grammar/statements/select.y" + { + (yyval.target) = makeNode(PGResTarget); + (yyval.target)->name = (yyvsp[(1) - (3)].str); + (yyval.target)->indirection = NIL; + (yyval.target)->val = (PGNode *)(yyvsp[(3) - (3)].node); + (yyval.target)->location = (yylsp[(1) - (3)]); + ;} + break; + + case 1258: +#line 3983 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1251: -#line 3941 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = list_make1(makeString((yyvsp[(2) - (2)].str))); ;} + case 1259: +#line 3984 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = list_make1((yyvsp[(2) - (2)].list)); ;} break; - case 1252: -#line 3944 "third_party/libpg_query/grammar/statements/select.y" + case 1260: +#line 3989 "third_party/libpg_query/grammar/statements/select.y" + { + (yyval.list) = list_make1((yyvsp[(1) - (1)].str)); + ;} + break; + + case 1261: +#line 3993 "third_party/libpg_query/grammar/statements/select.y" + { + (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].str)); + ;} + break; + + case 1262: +#line 3999 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = list_make1((yyvsp[(1) - (1)].list)); ;} + break; + + case 1263: +#line 4001 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); ;} + break; + + case 1264: +#line 4005 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1253: -#line 3945 "third_party/libpg_query/grammar/statements/select.y" + case 1265: +#line 4006 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = (yyvsp[(1) - (2)].list); ;} + break; + + case 1266: +#line 4010 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = (yyvsp[(1) - (1)].list); ;} + break; + + case 1267: +#line 4011 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 1254: -#line 3948 "third_party/libpg_query/grammar/statements/select.y" + case 1268: +#line 4014 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (3)].node), makeString((yyvsp[(3) - (3)].str))); ;} break; - case 1255: -#line 3952 "third_party/libpg_query/grammar/statements/select.y" + case 1269: +#line 4018 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].list)); ;} break; - case 1256: -#line 3953 "third_party/libpg_query/grammar/statements/select.y" + case 1270: +#line 4019 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); ;} break; - case 1257: -#line 3957 "third_party/libpg_query/grammar/statements/select.y" + case 1271: +#line 4023 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1258: -#line 3958 "third_party/libpg_query/grammar/statements/select.y" + case 1272: +#line 4024 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1259: -#line 3961 "third_party/libpg_query/grammar/statements/select.y" + case 1273: +#line 4027 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1260: -#line 3962 "third_party/libpg_query/grammar/statements/select.y" + case 1274: +#line 4028 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(2) - (2)].list)); ;} break; - case 1261: -#line 3963 "third_party/libpg_query/grammar/statements/select.y" + case 1275: +#line 4029 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 1262: -#line 3973 "third_party/libpg_query/grammar/statements/select.y" + case 1276: +#line 4032 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = list_make2((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].str)); ;} + break; + + case 1277: +#line 4036 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = list_make1((yyvsp[(1) - (1)].list)); ;} + break; + + case 1278: +#line 4037 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); ;} + break; + + case 1279: +#line 4041 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = (yyvsp[(1) - (1)].list); ;} + break; + + case 1280: +#line 4042 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = (yyvsp[(1) - (2)].list); ;} + break; + + case 1281: +#line 4044 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = (yyvsp[(3) - (4)].list); ;} + break; + + case 1282: +#line 4045 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = list_make1((yyvsp[(2) - (2)].list)); ;} + break; + + case 1283: +#line 4046 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = NULL; ;} + break; + + case 1284: +#line 4056 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].range)); ;} break; - case 1263: -#line 3974 "third_party/libpg_query/grammar/statements/select.y" + case 1285: +#line 4057 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].range)); ;} break; - case 1264: -#line 3979 "third_party/libpg_query/grammar/statements/select.y" + case 1286: +#line 4062 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1265: -#line 3981 "third_party/libpg_query/grammar/statements/select.y" + case 1287: +#line 4064 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), makeString((yyvsp[(3) - (3)].str))); ;} break; - case 1266: -#line 3986 "third_party/libpg_query/grammar/statements/select.y" + case 1288: +#line 4069 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1267: -#line 3987 "third_party/libpg_query/grammar/statements/select.y" + case 1289: +#line 4070 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1268: -#line 3991 "third_party/libpg_query/grammar/statements/select.y" + case 1290: +#line 4074 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1269: -#line 3992 "third_party/libpg_query/grammar/statements/select.y" + case 1291: +#line 4075 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 1270: -#line 3995 "third_party/libpg_query/grammar/statements/select.y" + case 1292: +#line 4078 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1271: -#line 4007 "third_party/libpg_query/grammar/statements/select.y" + case 1293: +#line 4090 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1272: -#line 4010 "third_party/libpg_query/grammar/statements/select.y" + case 1294: +#line 4093 "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 1273: -#line 4021 "third_party/libpg_query/grammar/statements/select.y" + case 1295: +#line 4104 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeIntConst((yyvsp[(1) - (1)].ival), (yylsp[(1) - (1)])); ;} break; - case 1274: -#line 4025 "third_party/libpg_query/grammar/statements/select.y" + case 1296: +#line 4108 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeFloatConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 1275: -#line 4029 "third_party/libpg_query/grammar/statements/select.y" + case 1297: +#line 4112 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(2) - (2)].list)) { @@ -29326,15 +29785,15 @@ YYLTYPE yylloc; ;} break; - case 1276: -#line 4041 "third_party/libpg_query/grammar/statements/select.y" + case 1298: +#line 4124 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeBitStringConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 1277: -#line 4045 "third_party/libpg_query/grammar/statements/select.y" + case 1299: +#line 4128 "third_party/libpg_query/grammar/statements/select.y" { /* This is a bit constant per SQL99: * Without Feature F511, "BIT data type", @@ -29345,8 +29804,8 @@ YYLTYPE yylloc; ;} break; - case 1278: -#line 4054 "third_party/libpg_query/grammar/statements/select.y" + case 1300: +#line 4137 "third_party/libpg_query/grammar/statements/select.y" { /* generic type 'literal' syntax */ PGTypeName *t = makeTypeNameFromNameList((yyvsp[(1) - (2)].list)); @@ -29355,8 +29814,8 @@ YYLTYPE yylloc; ;} break; - case 1279: -#line 4061 "third_party/libpg_query/grammar/statements/select.y" + case 1301: +#line 4144 "third_party/libpg_query/grammar/statements/select.y" { /* generic syntax with a type modifier */ PGTypeName *t = makeTypeNameFromNameList((yyvsp[(1) - (7)].list)); @@ -29396,146 +29855,146 @@ YYLTYPE yylloc; ;} break; - case 1280: -#line 4099 "third_party/libpg_query/grammar/statements/select.y" + case 1302: +#line 4182 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeStringConstCast((yyvsp[(2) - (2)].str), (yylsp[(2) - (2)]), (yyvsp[(1) - (2)].typnam)); ;} break; - case 1281: -#line 4103 "third_party/libpg_query/grammar/statements/select.y" + case 1303: +#line 4186 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeIntervalNode((yyvsp[(3) - (5)].node), (yylsp[(3) - (5)]), (yyvsp[(5) - (5)].list)); ;} break; - case 1282: -#line 4107 "third_party/libpg_query/grammar/statements/select.y" + case 1304: +#line 4190 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeIntervalNode((yyvsp[(2) - (3)].ival), (yylsp[(2) - (3)]), (yyvsp[(3) - (3)].list)); ;} break; - case 1283: -#line 4111 "third_party/libpg_query/grammar/statements/select.y" + case 1305: +#line 4194 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeIntervalNode((yyvsp[(2) - (3)].str), (yylsp[(2) - (3)]), (yyvsp[(3) - (3)].list)); ;} break; - case 1284: -#line 4115 "third_party/libpg_query/grammar/statements/select.y" + case 1306: +#line 4198 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeBoolAConst(true, (yylsp[(1) - (1)])); ;} break; - case 1285: -#line 4119 "third_party/libpg_query/grammar/statements/select.y" + case 1307: +#line 4202 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeBoolAConst(false, (yylsp[(1) - (1)])); ;} break; - case 1286: -#line 4123 "third_party/libpg_query/grammar/statements/select.y" + case 1308: +#line 4206 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeNullAConst((yylsp[(1) - (1)])); ;} break; - case 1287: -#line 4128 "third_party/libpg_query/grammar/statements/select.y" + case 1309: +#line 4211 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = (yyvsp[(1) - (1)].ival); ;} break; - case 1288: -#line 4145 "third_party/libpg_query/grammar/statements/select.y" + case 1310: +#line 4228 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1289: -#line 4146 "third_party/libpg_query/grammar/statements/select.y" + case 1311: +#line 4229 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1290: -#line 4147 "third_party/libpg_query/grammar/statements/select.y" + case 1312: +#line 4230 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1291: -#line 4150 "third_party/libpg_query/grammar/statements/select.y" + case 1313: +#line 4233 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1292: -#line 4151 "third_party/libpg_query/grammar/statements/select.y" + case 1314: +#line 4234 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1293: -#line 4152 "third_party/libpg_query/grammar/statements/select.y" + case 1315: +#line 4235 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1294: -#line 4155 "third_party/libpg_query/grammar/statements/select.y" + case 1316: +#line 4238 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1295: -#line 4156 "third_party/libpg_query/grammar/statements/select.y" + case 1317: +#line 4239 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1296: -#line 4157 "third_party/libpg_query/grammar/statements/select.y" + case 1318: +#line 4240 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1297: -#line 4160 "third_party/libpg_query/grammar/statements/select.y" + case 1319: +#line 4243 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1298: -#line 4161 "third_party/libpg_query/grammar/statements/select.y" + case 1320: +#line 4244 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lcons(makeString((yyvsp[(1) - (2)].str)), (yyvsp[(2) - (2)].list)); ;} break; - case 1299: -#line 4165 "third_party/libpg_query/grammar/statements/select.y" + case 1321: +#line 4248 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(2) - (2)].str))); ;} break; - case 1300: -#line 4167 "third_party/libpg_query/grammar/statements/select.y" + case 1322: +#line 4250 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), makeString((yyvsp[(3) - (3)].str))); ;} break; - case 1301: -#line 4171 "third_party/libpg_query/grammar/statements/select.y" + case 1323: +#line 4254 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 1302: -#line 4172 "third_party/libpg_query/grammar/statements/select.y" + case 1324: +#line 4255 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1304: -#line 4179 "third_party/libpg_query/grammar/statements/select.y" + case 1326: +#line 4262 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1305: -#line 4180 "third_party/libpg_query/grammar/statements/select.y" + case 1327: +#line 4263 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1306: + case 1328: #line 8 "third_party/libpg_query/grammar/statements/prepare.y" { PGPrepareStmt *n = makeNode(PGPrepareStmt); @@ -29546,17 +30005,17 @@ YYLTYPE yylloc; ;} break; - case 1307: + case 1329: #line 18 "third_party/libpg_query/grammar/statements/prepare.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 1308: + case 1330: #line 19 "third_party/libpg_query/grammar/statements/prepare.y" { (yyval.list) = NIL; ;} break; - case 1315: + case 1337: #line 8 "third_party/libpg_query/grammar/statements/create_schema.y" { PGCreateSchemaStmt *n = makeNode(PGCreateSchemaStmt); @@ -29578,7 +30037,7 @@ YYLTYPE yylloc; ;} break; - case 1316: + case 1338: #line 27 "third_party/libpg_query/grammar/statements/create_schema.y" { PGCreateSchemaStmt *n = makeNode(PGCreateSchemaStmt); @@ -29605,7 +30064,7 @@ YYLTYPE yylloc; ;} break; - case 1317: + case 1339: #line 51 "third_party/libpg_query/grammar/statements/create_schema.y" { PGCreateSchemaStmt *n = makeNode(PGCreateSchemaStmt); @@ -29627,7 +30086,7 @@ YYLTYPE yylloc; ;} break; - case 1318: + case 1340: #line 74 "third_party/libpg_query/grammar/statements/create_schema.y" { if ((yyloc) < 0) /* see comments for YYLLOC_DEFAULT */ @@ -29636,12 +30095,12 @@ YYLTYPE yylloc; ;} break; - case 1319: + case 1341: #line 80 "third_party/libpg_query/grammar/statements/create_schema.y" { (yyval.list) = NIL; ;} break; - case 1324: + case 1346: #line 11 "third_party/libpg_query/grammar/statements/index.y" { PGIndexStmt *n = makeNode(PGIndexStmt); @@ -29667,7 +30126,7 @@ YYLTYPE yylloc; ;} break; - case 1325: + case 1347: #line 36 "third_party/libpg_query/grammar/statements/index.y" { PGIndexStmt *n = makeNode(PGIndexStmt); @@ -29693,62 +30152,62 @@ YYLTYPE yylloc; ;} break; - case 1326: + case 1348: #line 62 "third_party/libpg_query/grammar/statements/index.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1327: + case 1349: #line 66 "third_party/libpg_query/grammar/statements/index.y" { (yyval.str) = (yyvsp[(2) - (2)].str); ;} break; - case 1328: + case 1350: #line 67 "third_party/libpg_query/grammar/statements/index.y" { (yyval.str) = (char*) DEFAULT_INDEX_TYPE; ;} break; - case 1329: + case 1351: #line 72 "third_party/libpg_query/grammar/statements/index.y" { (yyval.boolean) = true; ;} break; - case 1330: + case 1352: #line 73 "third_party/libpg_query/grammar/statements/index.y" { (yyval.boolean) = false; ;} break; - case 1331: + case 1353: #line 78 "third_party/libpg_query/grammar/statements/index.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1332: + case 1354: #line 79 "third_party/libpg_query/grammar/statements/index.y" { (yyval.str) = NULL; ;} break; - case 1333: + case 1355: #line 83 "third_party/libpg_query/grammar/statements/index.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 1334: + case 1356: #line 84 "third_party/libpg_query/grammar/statements/index.y" { (yyval.list) = NIL; ;} break; - case 1335: + case 1357: #line 89 "third_party/libpg_query/grammar/statements/index.y" { (yyval.boolean) = true; ;} break; - case 1336: + case 1358: #line 90 "third_party/libpg_query/grammar/statements/index.y" { (yyval.boolean) = false; ;} break; - case 1337: + case 1359: #line 8 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -29760,7 +30219,7 @@ YYLTYPE yylloc; ;} break; - case 1338: + case 1360: #line 17 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -29772,7 +30231,7 @@ YYLTYPE yylloc; ;} break; - case 1339: + case 1361: #line 26 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -29784,7 +30243,7 @@ YYLTYPE yylloc; ;} break; - case 1340: + case 1362: #line 35 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -29796,7 +30255,7 @@ YYLTYPE yylloc; ;} break; - case 1341: + case 1363: #line 44 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -29808,7 +30267,7 @@ YYLTYPE yylloc; ;} break; - case 1342: + case 1364: #line 53 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -29820,7 +30279,7 @@ YYLTYPE yylloc; ;} break; - case 1343: + case 1365: #line 6 "third_party/libpg_query/grammar/statements/checkpoint.y" { PGCheckPointStmt *n = makeNode(PGCheckPointStmt); @@ -29830,7 +30289,7 @@ YYLTYPE yylloc; ;} break; - case 1344: + case 1366: #line 13 "third_party/libpg_query/grammar/statements/checkpoint.y" { PGCheckPointStmt *n = makeNode(PGCheckPointStmt); @@ -29840,17 +30299,17 @@ YYLTYPE yylloc; ;} break; - case 1345: + case 1367: #line 22 "third_party/libpg_query/grammar/statements/checkpoint.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1346: + case 1368: #line 23 "third_party/libpg_query/grammar/statements/checkpoint.y" { (yyval.str) = NULL; ;} break; - case 1347: + case 1369: #line 8 "third_party/libpg_query/grammar/statements/comment_on.y" { PGCommentOnStmt *n = makeNode(PGCommentOnStmt); @@ -29861,7 +30320,7 @@ YYLTYPE yylloc; ;} break; - case 1348: + case 1370: #line 16 "third_party/libpg_query/grammar/statements/comment_on.y" { PGCommentOnStmt *n = makeNode(PGCommentOnStmt); @@ -29872,67 +30331,67 @@ YYLTYPE yylloc; ;} break; - case 1349: + case 1371: #line 26 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.node) = makeStringConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 1350: + case 1372: #line 27 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.node) = makeNullAConst((yylsp[(1) - (1)])); ;} break; - case 1351: + case 1373: #line 30 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_TABLE; ;} break; - case 1352: + case 1374: #line 31 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_SEQUENCE; ;} break; - case 1353: + case 1375: #line 32 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_FUNCTION; ;} break; - case 1354: + case 1376: #line 33 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_FUNCTION; ;} break; - case 1355: + case 1377: #line 34 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_TABLE_MACRO; ;} break; - case 1356: + case 1378: #line 35 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_VIEW; ;} break; - case 1357: + case 1379: #line 36 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_DATABASE; ;} break; - case 1358: + case 1380: #line 37 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_INDEX; ;} break; - case 1359: + case 1381: #line 38 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_SCHEMA; ;} break; - case 1360: + case 1382: #line 39 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_TYPE; ;} break; - case 1361: + case 1383: #line 8 "third_party/libpg_query/grammar/statements/export.y" { PGExportStmt *n = makeNode(PGExportStmt); @@ -29946,7 +30405,7 @@ YYLTYPE yylloc; ;} break; - case 1362: + case 1384: #line 20 "third_party/libpg_query/grammar/statements/export.y" { PGExportStmt *n = makeNode(PGExportStmt); @@ -29960,7 +30419,7 @@ YYLTYPE yylloc; ;} break; - case 1363: + case 1385: #line 34 "third_party/libpg_query/grammar/statements/export.y" { PGImportStmt *n = makeNode(PGImportStmt); @@ -29969,7 +30428,7 @@ YYLTYPE yylloc; ;} break; - case 1364: + case 1386: #line 10 "third_party/libpg_query/grammar/statements/explain.y" { PGExplainStmt *n = makeNode(PGExplainStmt); @@ -29979,7 +30438,7 @@ YYLTYPE yylloc; ;} break; - case 1365: + case 1387: #line 17 "third_party/libpg_query/grammar/statements/explain.y" { PGExplainStmt *n = makeNode(PGExplainStmt); @@ -29992,7 +30451,7 @@ YYLTYPE yylloc; ;} break; - case 1366: + case 1388: #line 27 "third_party/libpg_query/grammar/statements/explain.y" { PGExplainStmt *n = makeNode(PGExplainStmt); @@ -30002,7 +30461,7 @@ YYLTYPE yylloc; ;} break; - case 1367: + case 1389: #line 34 "third_party/libpg_query/grammar/statements/explain.y" { PGExplainStmt *n = makeNode(PGExplainStmt); @@ -30012,118 +30471,118 @@ YYLTYPE yylloc; ;} break; - case 1368: + case 1390: #line 44 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.boolean) = true; ;} break; - case 1369: + case 1391: #line 45 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.boolean) = false; ;} break; - case 1370: + case 1392: #line 50 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.node) = (PGNode *) makeString((yyvsp[(1) - (1)].str)); ;} break; - case 1371: + case 1393: #line 51 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.node) = (PGNode *) (yyvsp[(1) - (1)].value); ;} break; - case 1372: + case 1394: #line 52 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.node) = NULL; ;} break; - case 1404: + case 1426: #line 91 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1405: + case 1427: #line 92 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1406: + case 1428: #line 93 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1407: + case 1429: #line 98 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1408: + case 1430: #line 99 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1409: + case 1431: #line 105 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].defelt)); ;} break; - case 1410: + case 1432: #line 109 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].defelt)); ;} break; - case 1411: + case 1433: #line 116 "third_party/libpg_query/grammar/statements/explain.y" {;} break; - case 1412: + case 1434: #line 117 "third_party/libpg_query/grammar/statements/explain.y" {;} break; - case 1413: + case 1435: #line 122 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (char*) "true"; ;} break; - case 1414: + case 1436: #line 123 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (char*) "false"; ;} break; - case 1415: + case 1437: #line 124 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (char*) "on"; ;} break; - case 1416: + case 1438: #line 130 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1417: + case 1439: #line 136 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.defelt) = makeDefElem((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 1418: + case 1440: #line 143 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1419: + case 1441: #line 144 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (char*) "analyze"; ;} break; - case 1420: + case 1442: #line 11 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = (yyvsp[(2) - (2)].vsetstmt); @@ -30132,7 +30591,7 @@ YYLTYPE yylloc; ;} break; - case 1421: + case 1443: #line 17 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = (yyvsp[(3) - (3)].vsetstmt); @@ -30141,7 +30600,7 @@ YYLTYPE yylloc; ;} break; - case 1422: + case 1444: #line 23 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = (yyvsp[(3) - (3)].vsetstmt); @@ -30150,7 +30609,7 @@ YYLTYPE yylloc; ;} break; - case 1423: + case 1445: #line 29 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = (yyvsp[(3) - (3)].vsetstmt); @@ -30159,7 +30618,7 @@ YYLTYPE yylloc; ;} break; - case 1424: + case 1446: #line 35 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = (yyvsp[(3) - (3)].vsetstmt); @@ -30168,12 +30627,12 @@ YYLTYPE yylloc; ;} break; - case 1425: + case 1447: #line 44 "third_party/libpg_query/grammar/statements/variable_set.y" {(yyval.vsetstmt) = (yyvsp[(1) - (1)].vsetstmt);;} break; - case 1426: + case 1448: #line 46 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -30183,7 +30642,7 @@ YYLTYPE yylloc; ;} break; - case 1427: + case 1449: #line 54 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -30197,7 +30656,7 @@ YYLTYPE yylloc; ;} break; - case 1428: + case 1450: #line 65 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -30208,7 +30667,7 @@ YYLTYPE yylloc; ;} break; - case 1429: + case 1451: #line 77 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -30219,7 +30678,7 @@ YYLTYPE yylloc; ;} break; - case 1430: + case 1452: #line 85 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -30230,26 +30689,26 @@ YYLTYPE yylloc; ;} break; - case 1431: + case 1453: #line 96 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1432: + case 1454: #line 102 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = makeStringConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 1433: + case 1455: #line 106 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = makeStringConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 1434: + case 1456: #line 110 "third_party/libpg_query/grammar/statements/variable_set.y" { PGTypeName *t = (yyvsp[(1) - (3)].typnam); @@ -30267,7 +30726,7 @@ YYLTYPE yylloc; ;} break; - case 1435: + case 1457: #line 125 "third_party/libpg_query/grammar/statements/variable_set.y" { PGTypeName *t = (yyvsp[(1) - (5)].typnam); @@ -30277,32 +30736,32 @@ YYLTYPE yylloc; ;} break; - case 1436: + case 1458: #line 131 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = makeAConst((yyvsp[(1) - (1)].value), (yylsp[(1) - (1)])); ;} break; - case 1437: + case 1459: #line 132 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = NULL; ;} break; - case 1438: + case 1460: #line 133 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = NULL; ;} break; - case 1439: + case 1461: #line 137 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1440: + case 1462: #line 138 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1441: + case 1463: #line 8 "third_party/libpg_query/grammar/statements/load.y" { PGLoadStmt *n = makeNode(PGLoadStmt); @@ -30315,7 +30774,7 @@ YYLTYPE yylloc; ;} break; - case 1442: + case 1464: #line 17 "third_party/libpg_query/grammar/statements/load.y" { PGLoadStmt *n = makeNode(PGLoadStmt); @@ -30328,7 +30787,7 @@ YYLTYPE yylloc; ;} break; - case 1443: + case 1465: #line 26 "third_party/libpg_query/grammar/statements/load.y" { PGLoadStmt *n = makeNode(PGLoadStmt); @@ -30341,7 +30800,7 @@ YYLTYPE yylloc; ;} break; - case 1444: + case 1466: #line 35 "third_party/libpg_query/grammar/statements/load.y" { PGLoadStmt *n = makeNode(PGLoadStmt); @@ -30354,42 +30813,42 @@ YYLTYPE yylloc; ;} break; - case 1445: + case 1467: #line 46 "third_party/libpg_query/grammar/statements/load.y" { (yyval.loadinstalltype) = PG_LOAD_TYPE_INSTALL; ;} break; - case 1446: + case 1468: #line 47 "third_party/libpg_query/grammar/statements/load.y" { (yyval.loadinstalltype) = PG_LOAD_TYPE_FORCE_INSTALL; ;} break; - case 1447: + case 1469: #line 49 "third_party/libpg_query/grammar/statements/load.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1448: + case 1470: #line 50 "third_party/libpg_query/grammar/statements/load.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1449: + case 1471: #line 53 "third_party/libpg_query/grammar/statements/load.y" { (yyval.str) = NULL; ;} break; - case 1450: + case 1472: #line 54 "third_party/libpg_query/grammar/statements/load.y" { (yyval.str) = (yyvsp[(2) - (2)].str); ;} break; - case 1451: + case 1473: #line 55 "third_party/libpg_query/grammar/statements/load.y" { (yyval.str) = (yyvsp[(2) - (2)].str); ;} break; - case 1452: + case 1474: #line 9 "third_party/libpg_query/grammar/statements/vacuum.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -30406,7 +30865,7 @@ YYLTYPE yylloc; ;} break; - case 1453: + case 1475: #line 23 "third_party/libpg_query/grammar/statements/vacuum.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -30423,7 +30882,7 @@ YYLTYPE yylloc; ;} break; - case 1454: + case 1476: #line 37 "third_party/libpg_query/grammar/statements/vacuum.y" { PGVacuumStmt *n = (PGVacuumStmt *) (yyvsp[(5) - (5)].node); @@ -30438,7 +30897,7 @@ YYLTYPE yylloc; ;} break; - case 1455: + case 1477: #line 49 "third_party/libpg_query/grammar/statements/vacuum.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -30449,7 +30908,7 @@ YYLTYPE yylloc; ;} break; - case 1456: + case 1478: #line 57 "third_party/libpg_query/grammar/statements/vacuum.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -30462,27 +30921,27 @@ YYLTYPE yylloc; ;} break; - case 1457: + case 1479: #line 70 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = PG_VACOPT_ANALYZE; ;} break; - case 1458: + case 1480: #line 71 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = PG_VACOPT_VERBOSE; ;} break; - case 1459: + case 1481: #line 72 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = PG_VACOPT_FREEZE; ;} break; - case 1460: + case 1482: #line 73 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = PG_VACOPT_FULL; ;} break; - case 1461: + case 1483: #line 75 "third_party/libpg_query/grammar/statements/vacuum.y" { if (strcmp((yyvsp[(1) - (1)].str), "disable_page_skipping") == 0) @@ -30495,37 +30954,37 @@ YYLTYPE yylloc; ;} break; - case 1462: + case 1484: #line 87 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.boolean) = true; ;} break; - case 1463: + case 1485: #line 88 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.boolean) = false; ;} break; - case 1464: + case 1486: #line 93 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = (yyvsp[(1) - (1)].ival); ;} break; - case 1465: + case 1487: #line 94 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = (yyvsp[(1) - (3)].ival) | (yyvsp[(3) - (3)].ival); ;} break; - case 1466: + case 1488: #line 98 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.boolean) = true; ;} break; - case 1467: + case 1489: #line 99 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.boolean) = false; ;} break; - case 1468: + case 1490: #line 9 "third_party/libpg_query/grammar/statements/delete.y" { PGDeleteStmt *n = makeNode(PGDeleteStmt); @@ -30538,7 +30997,7 @@ YYLTYPE yylloc; ;} break; - case 1469: + case 1491: #line 19 "third_party/libpg_query/grammar/statements/delete.y" { PGDeleteStmt *n = makeNode(PGDeleteStmt); @@ -30551,14 +31010,14 @@ YYLTYPE yylloc; ;} break; - case 1470: + case 1492: #line 32 "third_party/libpg_query/grammar/statements/delete.y" { (yyval.range) = (yyvsp[(1) - (1)].range); ;} break; - case 1471: + case 1493: #line 36 "third_party/libpg_query/grammar/statements/delete.y" { PGAlias *alias = makeNode(PGAlias); @@ -30568,7 +31027,7 @@ YYLTYPE yylloc; ;} break; - case 1472: + case 1494: #line 43 "third_party/libpg_query/grammar/statements/delete.y" { PGAlias *alias = makeNode(PGAlias); @@ -30578,27 +31037,27 @@ YYLTYPE yylloc; ;} break; - case 1473: + case 1495: #line 53 "third_party/libpg_query/grammar/statements/delete.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 1474: + case 1496: #line 54 "third_party/libpg_query/grammar/statements/delete.y" { (yyval.node) = NULL; ;} break; - case 1475: + case 1497: #line 60 "third_party/libpg_query/grammar/statements/delete.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 1476: + case 1498: #line 61 "third_party/libpg_query/grammar/statements/delete.y" { (yyval.list) = NIL; ;} break; - case 1477: + case 1499: #line 10 "third_party/libpg_query/grammar/statements/analyze.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -30611,7 +31070,7 @@ YYLTYPE yylloc; ;} break; - case 1478: + case 1500: #line 20 "third_party/libpg_query/grammar/statements/analyze.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -30624,7 +31083,7 @@ YYLTYPE yylloc; ;} break; - case 1479: + case 1501: #line 8 "third_party/libpg_query/grammar/statements/attach.y" { PGAttachStmt *n = makeNode(PGAttachStmt); @@ -30636,7 +31095,7 @@ YYLTYPE yylloc; ;} break; - case 1480: + case 1502: #line 17 "third_party/libpg_query/grammar/statements/attach.y" { PGAttachStmt *n = makeNode(PGAttachStmt); @@ -30648,7 +31107,7 @@ YYLTYPE yylloc; ;} break; - case 1481: + case 1503: #line 29 "third_party/libpg_query/grammar/statements/attach.y" { PGDetachStmt *n = makeNode(PGDetachStmt); @@ -30658,7 +31117,7 @@ YYLTYPE yylloc; ;} break; - case 1482: + case 1504: #line 36 "third_party/libpg_query/grammar/statements/attach.y" { PGDetachStmt *n = makeNode(PGDetachStmt); @@ -30668,7 +31127,7 @@ YYLTYPE yylloc; ;} break; - case 1483: + case 1505: #line 43 "third_party/libpg_query/grammar/statements/attach.y" { PGDetachStmt *n = makeNode(PGDetachStmt); @@ -30678,27 +31137,27 @@ YYLTYPE yylloc; ;} break; - case 1484: + case 1506: #line 51 "third_party/libpg_query/grammar/statements/attach.y" {;} break; - case 1485: + case 1507: #line 52 "third_party/libpg_query/grammar/statements/attach.y" {;} break; - case 1486: + case 1508: #line 56 "third_party/libpg_query/grammar/statements/attach.y" { (yyval.str) = (yyvsp[(2) - (2)].str); ;} break; - case 1487: + case 1509: #line 57 "third_party/libpg_query/grammar/statements/attach.y" { (yyval.str) = NULL; ;} break; - case 1488: + case 1510: #line 3 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyvsp[(2) - (2)].vsetstmt)->scope = VAR_SET_SCOPE_DEFAULT; @@ -30706,7 +31165,7 @@ YYLTYPE yylloc; ;} break; - case 1489: + case 1511: #line 8 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyvsp[(3) - (3)].vsetstmt)->scope = VAR_SET_SCOPE_LOCAL; @@ -30714,7 +31173,7 @@ YYLTYPE yylloc; ;} break; - case 1490: + case 1512: #line 13 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyvsp[(3) - (3)].vsetstmt)->scope = VAR_SET_SCOPE_SESSION; @@ -30722,7 +31181,7 @@ YYLTYPE yylloc; ;} break; - case 1491: + case 1513: #line 18 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyvsp[(3) - (3)].vsetstmt)->scope = VAR_SET_SCOPE_GLOBAL; @@ -30730,7 +31189,7 @@ YYLTYPE yylloc; ;} break; - case 1492: + case 1514: #line 23 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyvsp[(3) - (3)].vsetstmt)->scope = VAR_SET_SCOPE_VARIABLE; @@ -30738,7 +31197,7 @@ YYLTYPE yylloc; ;} break; - case 1493: + case 1515: #line 32 "third_party/libpg_query/grammar/statements/variable_reset.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -30748,7 +31207,7 @@ YYLTYPE yylloc; ;} break; - case 1494: + case 1516: #line 39 "third_party/libpg_query/grammar/statements/variable_reset.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -30757,12 +31216,12 @@ YYLTYPE yylloc; ;} break; - case 1495: + case 1517: #line 48 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyval.vsetstmt) = (yyvsp[(1) - (1)].vsetstmt); ;} break; - case 1496: + case 1518: #line 50 "third_party/libpg_query/grammar/statements/variable_reset.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -30772,7 +31231,7 @@ YYLTYPE yylloc; ;} break; - case 1497: + case 1519: #line 57 "third_party/libpg_query/grammar/statements/variable_reset.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -30782,7 +31241,7 @@ YYLTYPE yylloc; ;} break; - case 1498: + case 1520: #line 3 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowSelectStmt *n = makeNode(PGVariableShowSelectStmt); @@ -30793,7 +31252,7 @@ YYLTYPE yylloc; ;} break; - case 1499: + case 1521: #line 10 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowSelectStmt *n = makeNode(PGVariableShowSelectStmt); @@ -30804,87 +31263,77 @@ YYLTYPE yylloc; ;} break; - case 1500: + case 1522: #line 18 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); - n->name = (yyvsp[(2) - (2)].str); + n->relation = (yyvsp[(2) - (2)].range); n->is_summary = 1; (yyval.node) = (PGNode *) n; ;} break; - case 1501: + case 1523: #line 25 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); - n->name = (yyvsp[(2) - (2)].str); + n->relation = (yyvsp[(2) - (2)].range); n->is_summary = 0; (yyval.node) = (PGNode *) n; ;} break; - case 1502: + case 1524: #line 32 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); - n->name = (char*) "timezone"; + n->set = (char*) "timezone"; n->is_summary = 0; (yyval.node) = (PGNode *) n; ;} break; - case 1503: + case 1525: #line 39 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); - n->name = (char*) "transaction_isolation"; + n->set = (char*) "transaction_isolation"; n->is_summary = 0; (yyval.node) = (PGNode *) n; ;} break; - case 1504: + case 1526: #line 46 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); - n->name = (char*) "__show_tables_expanded"; + n->set = (char*) "__show_tables_expanded"; n->is_summary = 0; (yyval.node) = (PGNode *) n; ;} break; - case 1505: + case 1527: #line 53 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); - n->name = (char*) "__show_tables_expanded"; + n->set = (char*) "__show_tables_expanded"; n->is_summary = 0; (yyval.node) = (PGNode *) n; ;} break; - case 1512: + case 1534: #line 67 "third_party/libpg_query/grammar/statements/variable_show.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1513: + case 1535: #line 69 "third_party/libpg_query/grammar/statements/variable_show.y" { (yyval.str) = psprintf("%s.%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ;} break; - case 1514: -#line 72 "third_party/libpg_query/grammar/statements/variable_show.y" - { (yyval.str) = psprintf("\"%s\"", (yyvsp[(1) - (1)].str)); ;} - break; - - case 1515: -#line 74 "third_party/libpg_query/grammar/statements/variable_show.y" - { (yyval.str) = psprintf("%s.\"%s\"", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ;} - break; - - case 1516: + case 1536: #line 7 "third_party/libpg_query/grammar/statements/call.y" { PGCallStmt *n = makeNode(PGCallStmt); @@ -30893,7 +31342,7 @@ YYLTYPE yylloc; ;} break; - case 1517: + case 1537: #line 10 "third_party/libpg_query/grammar/statements/view.y" { PGViewStmt *n = makeNode(PGViewStmt); @@ -30908,7 +31357,7 @@ YYLTYPE yylloc; ;} break; - case 1518: + case 1538: #line 23 "third_party/libpg_query/grammar/statements/view.y" { PGViewStmt *n = makeNode(PGViewStmt); @@ -30923,7 +31372,7 @@ YYLTYPE yylloc; ;} break; - case 1519: + case 1539: #line 36 "third_party/libpg_query/grammar/statements/view.y" { PGViewStmt *n = makeNode(PGViewStmt); @@ -30938,7 +31387,7 @@ YYLTYPE yylloc; ;} break; - case 1520: + case 1540: #line 49 "third_party/libpg_query/grammar/statements/view.y" { PGViewStmt *n = makeNode(PGViewStmt); @@ -30958,7 +31407,7 @@ YYLTYPE yylloc; ;} break; - case 1521: + case 1541: #line 67 "third_party/libpg_query/grammar/statements/view.y" { PGViewStmt *n = makeNode(PGViewStmt); @@ -30978,27 +31427,27 @@ YYLTYPE yylloc; ;} break; - case 1522: + case 1542: #line 87 "third_party/libpg_query/grammar/statements/view.y" { (yyval.viewcheckoption) = CASCADED_CHECK_OPTION; ;} break; - case 1523: + case 1543: #line 88 "third_party/libpg_query/grammar/statements/view.y" { (yyval.viewcheckoption) = CASCADED_CHECK_OPTION; ;} break; - case 1524: + case 1544: #line 89 "third_party/libpg_query/grammar/statements/view.y" { (yyval.viewcheckoption) = PG_LOCAL_CHECK_OPTION; ;} break; - case 1525: + case 1545: #line 90 "third_party/libpg_query/grammar/statements/view.y" { (yyval.viewcheckoption) = PG_NO_CHECK_OPTION; ;} break; - case 1526: + case 1546: #line 12 "third_party/libpg_query/grammar/statements/create_as.y" { PGCreateTableAsStmt *ctas = makeNode(PGCreateTableAsStmt); @@ -31014,7 +31463,7 @@ YYLTYPE yylloc; ;} break; - case 1527: + case 1547: #line 25 "third_party/libpg_query/grammar/statements/create_as.y" { PGCreateTableAsStmt *ctas = makeNode(PGCreateTableAsStmt); @@ -31030,7 +31479,7 @@ YYLTYPE yylloc; ;} break; - case 1528: + case 1548: #line 38 "third_party/libpg_query/grammar/statements/create_as.y" { PGCreateTableAsStmt *ctas = makeNode(PGCreateTableAsStmt); @@ -31046,22 +31495,22 @@ YYLTYPE yylloc; ;} break; - case 1529: + case 1549: #line 54 "third_party/libpg_query/grammar/statements/create_as.y" { (yyval.boolean) = true; ;} break; - case 1530: + case 1550: #line 55 "third_party/libpg_query/grammar/statements/create_as.y" { (yyval.boolean) = false; ;} break; - case 1531: + case 1551: #line 56 "third_party/libpg_query/grammar/statements/create_as.y" { (yyval.boolean) = true; ;} break; - case 1532: + case 1552: #line 62 "third_party/libpg_query/grammar/statements/create_as.y" { (yyval.into) = makeNode(PGIntoClause); @@ -31076,7 +31525,7 @@ YYLTYPE yylloc; /* Line 1267 of yacc.c. */ -#line 31080 "third_party/libpg_query/grammar/grammar_out.cpp" +#line 31529 "third_party/libpg_query/grammar/grammar_out.cpp" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -31459,10 +31908,10 @@ makeIntervalNode(PGNode *arg, int location, PGList *typmods) { } static PGNode * -makeSampleSize(PGValue *sample_size, bool is_percentage) { +makeSampleSize(PGNode *sample_size, bool is_percentage) { PGSampleSize *n = makeNode(PGSampleSize); - n->sample_size = *sample_size; + n->sample_size = sample_size; n->is_percentage = is_percentage; return (PGNode *)n; diff --git a/src/duckdb/third_party/parquet/parquet_constants.cpp b/src/duckdb/third_party/parquet/parquet_constants.cpp deleted file mode 100644 index de4420ba0..000000000 --- a/src/duckdb/third_party/parquet/parquet_constants.cpp +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Autogenerated by Thrift Compiler (0.11.0) - * - * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - * @generated - */ -#include "parquet_constants.h" - -namespace duckdb_parquet { namespace format { - -const parquetConstants g_parquet_constants; - -parquetConstants::parquetConstants() { -} - -}} // namespace - diff --git a/src/duckdb/third_party/parquet/parquet_constants.h b/src/duckdb/third_party/parquet/parquet_constants.h deleted file mode 100644 index 468309ce8..000000000 --- a/src/duckdb/third_party/parquet/parquet_constants.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Autogenerated by Thrift Compiler (0.11.0) - * - * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - * @generated - */ -#ifndef parquet_CONSTANTS_H -#define parquet_CONSTANTS_H - -#include "parquet_types.h" - -namespace duckdb_parquet { namespace format { - -class parquetConstants { - public: - parquetConstants(); - -}; - -extern const parquetConstants g_parquet_constants; - -}} // namespace - -#endif diff --git a/src/duckdb/third_party/parquet/parquet_types.cpp b/src/duckdb/third_party/parquet/parquet_types.cpp index 746965f83..cd989782f 100644 --- a/src/duckdb/third_party/parquet/parquet_types.cpp +++ b/src/duckdb/third_party/parquet/parquet_types.cpp @@ -1,5 +1,5 @@ /** - * Autogenerated by Thrift Compiler (0.11.0) + * Autogenerated by Thrift Compiler (0.21.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -9,244 +9,812 @@ #include #include -#include "thrift/TToString.h" - -namespace duckdb_parquet { namespace format { - -std::ostream &operator<<(std::ostream &out, const Type::type &val) { - switch (val) { - case Type::BOOLEAN: - out << "BOOLEAN"; - return out; - case Type::INT32: - out << "INT32"; - return out; - case Type::INT64: - out << "INT64"; - return out; - case Type::INT96: - out << "INT96"; - return out; - case Type::FLOAT: - out << "FLOAT"; - return out; - case Type::DOUBLE: - out << "DOUBLE"; - return out; - case Type::BYTE_ARRAY: - out << "BYTE_ARRAY"; - return out; - case Type::FIXED_LEN_BYTE_ARRAY: - out << "FIXED_LEN_BYTE_ARRAY"; - return out; - // no default for compiler error on missing enum - } - out << static_cast(val); - return out; -} - -std::ostream &operator<<(std::ostream &out, const ConvertedType::type &val) { - switch (val) { - case ConvertedType::UTF8: - out << "UTF8"; - return out; - case ConvertedType::MAP: - out << "MAP"; - return out; - case ConvertedType::MAP_KEY_VALUE: - out << "MAP_KEY_VALUE"; - return out; - case ConvertedType::LIST: - out << "LIST"; - return out; - case ConvertedType::ENUM: - out << "ENUM"; - return out; - case ConvertedType::DECIMAL: - out << "DECIMAL"; - return out; - case ConvertedType::DATE: - out << "DATE"; - return out; - case ConvertedType::TIME_MILLIS: - out << "TIME_MILLIS"; - return out; - case ConvertedType::TIME_MICROS: - out << "TIME_MICROS"; - return out; - case ConvertedType::TIMESTAMP_MILLIS: - out << "TIMESTAMP_MILLIS"; - return out; - case ConvertedType::TIMESTAMP_MICROS: - out << "TIMESTAMP_MICROS"; - return out; - case ConvertedType::UINT_8: - out << "UINT_8"; - return out; - case ConvertedType::UINT_16: - out << "UINT_16"; - return out; - case ConvertedType::UINT_32: - out << "UINT_32"; - return out; - case ConvertedType::UINT_64: - out << "UINT_64"; - return out; - case ConvertedType::INT_8: - out << "INT_8"; - return out; - case ConvertedType::INT_16: - out << "INT_16"; - return out; - case ConvertedType::INT_32: - out << "INT_32"; - return out; - case ConvertedType::INT_64: - out << "INT_64"; - return out; - case ConvertedType::JSON: - out << "JSON"; - return out; - case ConvertedType::BSON: - out << "BSON"; - return out; - case ConvertedType::INTERVAL: - out << "INTERVAL"; - return out; - case ConvertedType::NULL_TYPE: - out << "NULL"; - return out; - // no default for compiler error on missing enum - } - out << static_cast(val); - return out; -} - -std::ostream &operator<<(std::ostream &out, const FieldRepetitionType::type &val) { - switch (val) { - case FieldRepetitionType::REQUIRED: - out << "REQUIRED"; - return out; - case FieldRepetitionType::OPTIONAL: - out << "OPTIONAL"; - return out; - case FieldRepetitionType::REPEATED: - out << "REPEATED"; - return out; - // no default for compiler error on missing enum - } - out << static_cast(val); - return out; -} - -std::ostream &operator<<(std::ostream &out, const Encoding::type &val) { - switch (val) { - case Encoding::PLAIN: - out << "PLAIN"; - return out; - case Encoding::PLAIN_DICTIONARY: - out << "PLAIN_DICTIONARY"; - return out; - case Encoding::RLE: - out << "RLE"; - return out; - case Encoding::BIT_PACKED: - out << "BIT_PACKED"; - return out; - case Encoding::DELTA_BINARY_PACKED: - out << "DELTA_BINARY_PACKED"; - return out; - case Encoding::DELTA_LENGTH_BYTE_ARRAY: - out << "DELTA_LENGTH_BYTE_ARRAY"; - return out; - case Encoding::DELTA_BYTE_ARRAY: - out << "DELTA_BYTE_ARRAY"; - return out; - case Encoding::RLE_DICTIONARY: - out << "RLE_DICTIONARY"; - return out; - case Encoding::BYTE_STREAM_SPLIT: - out << "BYTE_STREAM_SPLIT"; - return out; - // no default for compiler error on missing enum - } - out << static_cast(val); - return out; -} - -std::ostream &operator<<(std::ostream &out, const CompressionCodec::type &val) { - switch (val) { - case CompressionCodec::UNCOMPRESSED: - out << "UNCOMPRESSED"; - return out; - case CompressionCodec::SNAPPY: - out << "SNAPPY"; - return out; - case CompressionCodec::GZIP: - out << "GZIP"; - return out; - case CompressionCodec::LZO: - out << "LZO"; - return out; - case CompressionCodec::BROTLI: - out << "BROTLI"; - return out; - case CompressionCodec::LZ4: - out << "LZ4"; - return out; - case CompressionCodec::ZSTD: - out << "ZSTD"; - return out; - case CompressionCodec::LZ4_RAW: - out << "LZ4_RAW"; - return out; - // no default for compiler error on missing enum - } - out << static_cast(val); - return out; -} - -std::ostream &operator<<(std::ostream &out, const PageType::type &val) { - switch (val) { - case PageType::DATA_PAGE: - out << "DATA_PAGE"; - return out; - case PageType::INDEX_PAGE: - out << "INDEX_PAGE"; - return out; - case PageType::DICTIONARY_PAGE: - out << "DICTIONARY_PAGE"; - return out; - case PageType::DATA_PAGE_V2: - out << "DATA_PAGE_V2"; - return out; - // no default for compiler error on missing enum - } - out << static_cast(val); - return out; -} - -std::ostream &operator<<(std::ostream &out, const BoundaryOrder::type &val) { - switch (val) { - case BoundaryOrder::UNORDERED: - out << "UNORDERED"; - return out; - case BoundaryOrder::ASCENDING: - out << "ASCENDING"; - return out; - case BoundaryOrder::DESCENDING: - out << "DESCENDING"; - return out; - // no default for compiler error on missing enum - } - out << static_cast(val); - return out; -} - - -Statistics::~Statistics() throw() { +#include + +namespace duckdb_parquet { + +int _kTypeValues[] = { + Type::BOOLEAN, + Type::INT32, + Type::INT64, + Type::INT96, + Type::FLOAT, + Type::DOUBLE, + Type::BYTE_ARRAY, + Type::FIXED_LEN_BYTE_ARRAY +}; +const char* _kTypeNames[] = { + "BOOLEAN", + "INT32", + "INT64", + "INT96", + "FLOAT", + "DOUBLE", + "BYTE_ARRAY", + "FIXED_LEN_BYTE_ARRAY" +}; +const std::map _Type_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(8, _kTypeValues, _kTypeNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); + +std::ostream& operator<<(std::ostream& out, const Type::type& val) { + std::map::const_iterator it = _Type_VALUES_TO_NAMES.find(val); + if (it != _Type_VALUES_TO_NAMES.end()) { + out << it->second; + } else { + out << static_cast(val); + } + return out; +} + +std::string to_string(const Type::type& val) { + std::map::const_iterator it = _Type_VALUES_TO_NAMES.find(val); + if (it != _Type_VALUES_TO_NAMES.end()) { + return std::string(it->second); + } else { + return std::to_string(static_cast(val)); + } +} + +int _kConvertedTypeValues[] = { + /** + * a BYTE_ARRAY actually contains UTF8 encoded chars + */ + ConvertedType::UTF8, + /** + * a map is converted as an optional field containing a repeated key/value pair + */ + ConvertedType::MAP, + /** + * a key/value pair is converted into a group of two fields + */ + ConvertedType::MAP_KEY_VALUE, + /** + * a list is converted into an optional field containing a repeated field for its + * values + */ + ConvertedType::LIST, + /** + * an enum is converted into a BYTE_ARRAY field + */ + ConvertedType::ENUM, + /** + * A decimal value. + * + * This may be used to annotate BYTE_ARRAY or FIXED_LEN_BYTE_ARRAY primitive + * types. The underlying byte array stores the unscaled value encoded as two's + * complement using big-endian byte order (the most significant byte is the + * zeroth element). The value of the decimal is the value * 10^{-scale}. + * + * This must be accompanied by a (maximum) precision and a scale in the + * SchemaElement. The precision specifies the number of digits in the decimal + * and the scale stores the location of the decimal point. For example 1.23 + * would have precision 3 (3 total digits) and scale 2 (the decimal point is + * 2 digits over). + */ + ConvertedType::DECIMAL, + /** + * A Date + * + * Stored as days since Unix epoch, encoded as the INT32 physical type. + * + */ + ConvertedType::DATE, + /** + * A time + * + * The total number of milliseconds since midnight. The value is stored + * as an INT32 physical type. + */ + ConvertedType::TIME_MILLIS, + /** + * A time. + * + * The total number of microseconds since midnight. The value is stored as + * an INT64 physical type. + */ + ConvertedType::TIME_MICROS, + /** + * A date/time combination + * + * Date and time recorded as milliseconds since the Unix epoch. Recorded as + * a physical type of INT64. + */ + ConvertedType::TIMESTAMP_MILLIS, + /** + * A date/time combination + * + * Date and time recorded as microseconds since the Unix epoch. The value is + * stored as an INT64 physical type. + */ + ConvertedType::TIMESTAMP_MICROS, + /** + * An unsigned integer value. + * + * The number describes the maximum number of meaningful data bits in + * the stored value. 8, 16 and 32 bit values are stored using the + * INT32 physical type. 64 bit values are stored using the INT64 + * physical type. + * + */ + ConvertedType::UINT_8, + ConvertedType::UINT_16, + ConvertedType::UINT_32, + ConvertedType::UINT_64, + /** + * A signed integer value. + * + * The number describes the maximum number of meaningful data bits in + * the stored value. 8, 16 and 32 bit values are stored using the + * INT32 physical type. 64 bit values are stored using the INT64 + * physical type. + * + */ + ConvertedType::INT_8, + ConvertedType::INT_16, + ConvertedType::INT_32, + ConvertedType::INT_64, + /** + * An embedded JSON document + * + * A JSON document embedded within a single UTF8 column. + */ + ConvertedType::JSON, + /** + * An embedded BSON document + * + * A BSON document embedded within a single BYTE_ARRAY column. + */ + ConvertedType::BSON, + /** + * An interval of time + * + * This type annotates data stored as a FIXED_LEN_BYTE_ARRAY of length 12 + * This data is composed of three separate little endian unsigned + * integers. Each stores a component of a duration of time. The first + * integer identifies the number of months associated with the duration, + * the second identifies the number of days associated with the duration + * and the third identifies the number of milliseconds associated with + * the provided duration. This duration of time is independent of any + * particular timezone or date. + */ + ConvertedType::INTERVAL +}; +const char* _kConvertedTypeNames[] = { + /** + * a BYTE_ARRAY actually contains UTF8 encoded chars + */ + "UTF8", + /** + * a map is converted as an optional field containing a repeated key/value pair + */ + "MAP", + /** + * a key/value pair is converted into a group of two fields + */ + "MAP_KEY_VALUE", + /** + * a list is converted into an optional field containing a repeated field for its + * values + */ + "LIST", + /** + * an enum is converted into a BYTE_ARRAY field + */ + "ENUM", + /** + * A decimal value. + * + * This may be used to annotate BYTE_ARRAY or FIXED_LEN_BYTE_ARRAY primitive + * types. The underlying byte array stores the unscaled value encoded as two's + * complement using big-endian byte order (the most significant byte is the + * zeroth element). The value of the decimal is the value * 10^{-scale}. + * + * This must be accompanied by a (maximum) precision and a scale in the + * SchemaElement. The precision specifies the number of digits in the decimal + * and the scale stores the location of the decimal point. For example 1.23 + * would have precision 3 (3 total digits) and scale 2 (the decimal point is + * 2 digits over). + */ + "DECIMAL", + /** + * A Date + * + * Stored as days since Unix epoch, encoded as the INT32 physical type. + * + */ + "DATE", + /** + * A time + * + * The total number of milliseconds since midnight. The value is stored + * as an INT32 physical type. + */ + "TIME_MILLIS", + /** + * A time. + * + * The total number of microseconds since midnight. The value is stored as + * an INT64 physical type. + */ + "TIME_MICROS", + /** + * A date/time combination + * + * Date and time recorded as milliseconds since the Unix epoch. Recorded as + * a physical type of INT64. + */ + "TIMESTAMP_MILLIS", + /** + * A date/time combination + * + * Date and time recorded as microseconds since the Unix epoch. The value is + * stored as an INT64 physical type. + */ + "TIMESTAMP_MICROS", + /** + * An unsigned integer value. + * + * The number describes the maximum number of meaningful data bits in + * the stored value. 8, 16 and 32 bit values are stored using the + * INT32 physical type. 64 bit values are stored using the INT64 + * physical type. + * + */ + "UINT_8", + "UINT_16", + "UINT_32", + "UINT_64", + /** + * A signed integer value. + * + * The number describes the maximum number of meaningful data bits in + * the stored value. 8, 16 and 32 bit values are stored using the + * INT32 physical type. 64 bit values are stored using the INT64 + * physical type. + * + */ + "INT_8", + "INT_16", + "INT_32", + "INT_64", + /** + * An embedded JSON document + * + * A JSON document embedded within a single UTF8 column. + */ + "JSON", + /** + * An embedded BSON document + * + * A BSON document embedded within a single BYTE_ARRAY column. + */ + "BSON", + /** + * An interval of time + * + * This type annotates data stored as a FIXED_LEN_BYTE_ARRAY of length 12 + * This data is composed of three separate little endian unsigned + * integers. Each stores a component of a duration of time. The first + * integer identifies the number of months associated with the duration, + * the second identifies the number of days associated with the duration + * and the third identifies the number of milliseconds associated with + * the provided duration. This duration of time is independent of any + * particular timezone or date. + */ + "INTERVAL" +}; +const std::map _ConvertedType_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(22, _kConvertedTypeValues, _kConvertedTypeNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); + +std::ostream& operator<<(std::ostream& out, const ConvertedType::type& val) { + std::map::const_iterator it = _ConvertedType_VALUES_TO_NAMES.find(val); + if (it != _ConvertedType_VALUES_TO_NAMES.end()) { + out << it->second; + } else { + out << static_cast(val); + } + return out; +} + +std::string to_string(const ConvertedType::type& val) { + std::map::const_iterator it = _ConvertedType_VALUES_TO_NAMES.find(val); + if (it != _ConvertedType_VALUES_TO_NAMES.end()) { + return std::string(it->second); + } else { + return std::to_string(static_cast(val)); + } +} + +int _kFieldRepetitionTypeValues[] = { + /** + * This field is required (can not be null) and each row has exactly 1 value. + */ + FieldRepetitionType::REQUIRED, + /** + * The field is optional (can be null) and each row has 0 or 1 values. + */ + FieldRepetitionType::OPTIONAL, + /** + * The field is repeated and can contain 0 or more values + */ + FieldRepetitionType::REPEATED +}; +const char* _kFieldRepetitionTypeNames[] = { + /** + * This field is required (can not be null) and each row has exactly 1 value. + */ + "REQUIRED", + /** + * The field is optional (can be null) and each row has 0 or 1 values. + */ + "OPTIONAL", + /** + * The field is repeated and can contain 0 or more values + */ + "REPEATED" +}; +const std::map _FieldRepetitionType_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(3, _kFieldRepetitionTypeValues, _kFieldRepetitionTypeNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); + +std::ostream& operator<<(std::ostream& out, const FieldRepetitionType::type& val) { + std::map::const_iterator it = _FieldRepetitionType_VALUES_TO_NAMES.find(val); + if (it != _FieldRepetitionType_VALUES_TO_NAMES.end()) { + out << it->second; + } else { + out << static_cast(val); + } + return out; +} + +std::string to_string(const FieldRepetitionType::type& val) { + std::map::const_iterator it = _FieldRepetitionType_VALUES_TO_NAMES.find(val); + if (it != _FieldRepetitionType_VALUES_TO_NAMES.end()) { + return std::string(it->second); + } else { + return std::to_string(static_cast(val)); + } +} + +int _kEncodingValues[] = { + /** + * Default encoding. + * BOOLEAN - 1 bit per value. 0 is false; 1 is true. + * INT32 - 4 bytes per value. Stored as little-endian. + * INT64 - 8 bytes per value. Stored as little-endian. + * FLOAT - 4 bytes per value. IEEE. Stored as little-endian. + * DOUBLE - 8 bytes per value. IEEE. Stored as little-endian. + * BYTE_ARRAY - 4 byte length stored as little endian, followed by bytes. + * FIXED_LEN_BYTE_ARRAY - Just the bytes. + */ + Encoding::PLAIN, + /** + * Deprecated: Dictionary encoding. The values in the dictionary are encoded in the + * plain type. + * in a data page use RLE_DICTIONARY instead. + * in a Dictionary page use PLAIN instead + */ + Encoding::PLAIN_DICTIONARY, + /** + * Group packed run length encoding. Usable for definition/repetition levels + * encoding and Booleans (on one bit: 0 is false; 1 is true.) + */ + Encoding::RLE, + /** + * Bit packed encoding. This can only be used if the data has a known max + * width. Usable for definition/repetition levels encoding. + */ + Encoding::BIT_PACKED, + /** + * Delta encoding for integers. This can be used for int columns and works best + * on sorted data + */ + Encoding::DELTA_BINARY_PACKED, + /** + * Encoding for byte arrays to separate the length values and the data. The lengths + * are encoded using DELTA_BINARY_PACKED + */ + Encoding::DELTA_LENGTH_BYTE_ARRAY, + /** + * Incremental-encoded byte array. Prefix lengths are encoded using DELTA_BINARY_PACKED. + * Suffixes are stored as delta length byte arrays. + */ + Encoding::DELTA_BYTE_ARRAY, + /** + * Dictionary encoding: the ids are encoded using the RLE encoding + */ + Encoding::RLE_DICTIONARY, + /** + * Encoding for fixed-width data (FLOAT, DOUBLE, INT32, INT64, FIXED_LEN_BYTE_ARRAY). + * K byte-streams are created where K is the size in bytes of the data type. + * The individual bytes of a value are scattered to the corresponding stream and + * the streams are concatenated. + * This itself does not reduce the size of the data but can lead to better compression + * afterwards. + * + * Added in 2.8 for FLOAT and DOUBLE. + * Support for INT32, INT64 and FIXED_LEN_BYTE_ARRAY added in 2.11. + */ + Encoding::BYTE_STREAM_SPLIT +}; +const char* _kEncodingNames[] = { + /** + * Default encoding. + * BOOLEAN - 1 bit per value. 0 is false; 1 is true. + * INT32 - 4 bytes per value. Stored as little-endian. + * INT64 - 8 bytes per value. Stored as little-endian. + * FLOAT - 4 bytes per value. IEEE. Stored as little-endian. + * DOUBLE - 8 bytes per value. IEEE. Stored as little-endian. + * BYTE_ARRAY - 4 byte length stored as little endian, followed by bytes. + * FIXED_LEN_BYTE_ARRAY - Just the bytes. + */ + "PLAIN", + /** + * Deprecated: Dictionary encoding. The values in the dictionary are encoded in the + * plain type. + * in a data page use RLE_DICTIONARY instead. + * in a Dictionary page use PLAIN instead + */ + "PLAIN_DICTIONARY", + /** + * Group packed run length encoding. Usable for definition/repetition levels + * encoding and Booleans (on one bit: 0 is false; 1 is true.) + */ + "RLE", + /** + * Bit packed encoding. This can only be used if the data has a known max + * width. Usable for definition/repetition levels encoding. + */ + "BIT_PACKED", + /** + * Delta encoding for integers. This can be used for int columns and works best + * on sorted data + */ + "DELTA_BINARY_PACKED", + /** + * Encoding for byte arrays to separate the length values and the data. The lengths + * are encoded using DELTA_BINARY_PACKED + */ + "DELTA_LENGTH_BYTE_ARRAY", + /** + * Incremental-encoded byte array. Prefix lengths are encoded using DELTA_BINARY_PACKED. + * Suffixes are stored as delta length byte arrays. + */ + "DELTA_BYTE_ARRAY", + /** + * Dictionary encoding: the ids are encoded using the RLE encoding + */ + "RLE_DICTIONARY", + /** + * Encoding for fixed-width data (FLOAT, DOUBLE, INT32, INT64, FIXED_LEN_BYTE_ARRAY). + * K byte-streams are created where K is the size in bytes of the data type. + * The individual bytes of a value are scattered to the corresponding stream and + * the streams are concatenated. + * This itself does not reduce the size of the data but can lead to better compression + * afterwards. + * + * Added in 2.8 for FLOAT and DOUBLE. + * Support for INT32, INT64 and FIXED_LEN_BYTE_ARRAY added in 2.11. + */ + "BYTE_STREAM_SPLIT" +}; +const std::map _Encoding_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(9, _kEncodingValues, _kEncodingNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); + +std::ostream& operator<<(std::ostream& out, const Encoding::type& val) { + std::map::const_iterator it = _Encoding_VALUES_TO_NAMES.find(val); + if (it != _Encoding_VALUES_TO_NAMES.end()) { + out << it->second; + } else { + out << static_cast(val); + } + return out; +} + +std::string to_string(const Encoding::type& val) { + std::map::const_iterator it = _Encoding_VALUES_TO_NAMES.find(val); + if (it != _Encoding_VALUES_TO_NAMES.end()) { + return std::string(it->second); + } else { + return std::to_string(static_cast(val)); + } +} + +int _kCompressionCodecValues[] = { + CompressionCodec::UNCOMPRESSED, + CompressionCodec::SNAPPY, + CompressionCodec::GZIP, + CompressionCodec::LZO, + CompressionCodec::BROTLI, + CompressionCodec::LZ4, + CompressionCodec::ZSTD, + CompressionCodec::LZ4_RAW +}; +const char* _kCompressionCodecNames[] = { + "UNCOMPRESSED", + "SNAPPY", + "GZIP", + "LZO", + "BROTLI", + "LZ4", + "ZSTD", + "LZ4_RAW" +}; +const std::map _CompressionCodec_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(8, _kCompressionCodecValues, _kCompressionCodecNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); + +std::ostream& operator<<(std::ostream& out, const CompressionCodec::type& val) { + std::map::const_iterator it = _CompressionCodec_VALUES_TO_NAMES.find(val); + if (it != _CompressionCodec_VALUES_TO_NAMES.end()) { + out << it->second; + } else { + out << static_cast(val); + } + return out; +} + +std::string to_string(const CompressionCodec::type& val) { + std::map::const_iterator it = _CompressionCodec_VALUES_TO_NAMES.find(val); + if (it != _CompressionCodec_VALUES_TO_NAMES.end()) { + return std::string(it->second); + } else { + return std::to_string(static_cast(val)); + } +} + +int _kPageTypeValues[] = { + PageType::DATA_PAGE, + PageType::INDEX_PAGE, + PageType::DICTIONARY_PAGE, + PageType::DATA_PAGE_V2 +}; +const char* _kPageTypeNames[] = { + "DATA_PAGE", + "INDEX_PAGE", + "DICTIONARY_PAGE", + "DATA_PAGE_V2" +}; +const std::map _PageType_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(4, _kPageTypeValues, _kPageTypeNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); + +std::ostream& operator<<(std::ostream& out, const PageType::type& val) { + std::map::const_iterator it = _PageType_VALUES_TO_NAMES.find(val); + if (it != _PageType_VALUES_TO_NAMES.end()) { + out << it->second; + } else { + out << static_cast(val); + } + return out; +} + +std::string to_string(const PageType::type& val) { + std::map::const_iterator it = _PageType_VALUES_TO_NAMES.find(val); + if (it != _PageType_VALUES_TO_NAMES.end()) { + return std::string(it->second); + } else { + return std::to_string(static_cast(val)); + } +} + +int _kBoundaryOrderValues[] = { + BoundaryOrder::UNORDERED, + BoundaryOrder::ASCENDING, + BoundaryOrder::DESCENDING +}; +const char* _kBoundaryOrderNames[] = { + "UNORDERED", + "ASCENDING", + "DESCENDING" +}; +const std::map _BoundaryOrder_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(3, _kBoundaryOrderValues, _kBoundaryOrderNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); + +std::ostream& operator<<(std::ostream& out, const BoundaryOrder::type& val) { + std::map::const_iterator it = _BoundaryOrder_VALUES_TO_NAMES.find(val); + if (it != _BoundaryOrder_VALUES_TO_NAMES.end()) { + out << it->second; + } else { + out << static_cast(val); + } + return out; +} + +std::string to_string(const BoundaryOrder::type& val) { + std::map::const_iterator it = _BoundaryOrder_VALUES_TO_NAMES.find(val); + if (it != _BoundaryOrder_VALUES_TO_NAMES.end()) { + return std::string(it->second); + } else { + return std::to_string(static_cast(val)); + } +} + + +SizeStatistics::~SizeStatistics() noexcept { +} + +SizeStatistics::SizeStatistics() noexcept + : unencoded_byte_array_data_bytes(0) { +} + +void SizeStatistics::__set_unencoded_byte_array_data_bytes(const int64_t val) { + this->unencoded_byte_array_data_bytes = val; +__isset.unencoded_byte_array_data_bytes = true; +} + +void SizeStatistics::__set_repetition_level_histogram(const duckdb::vector & val) { + this->repetition_level_histogram = val; +__isset.repetition_level_histogram = true; +} + +void SizeStatistics::__set_definition_level_histogram(const duckdb::vector & val) { + this->definition_level_histogram = val; +__isset.definition_level_histogram = true; +} +std::ostream& operator<<(std::ostream& out, const SizeStatistics& obj) +{ + obj.printTo(out); + return out; +} + + +uint32_t SizeStatistics::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == ::apache::thrift::protocol::T_I64) { + xfer += iprot->readI64(this->unencoded_byte_array_data_bytes); + this->__isset.unencoded_byte_array_data_bytes = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 2: + if (ftype == ::apache::thrift::protocol::T_LIST) { + { + this->repetition_level_histogram.clear(); + uint32_t _size0; + ::apache::thrift::protocol::TType _etype3; + xfer += iprot->readListBegin(_etype3, _size0); + this->repetition_level_histogram.resize(_size0); + uint32_t _i4; + for (_i4 = 0; _i4 < _size0; ++_i4) + { + xfer += iprot->readI64(this->repetition_level_histogram[_i4]); + } + xfer += iprot->readListEnd(); + } + this->__isset.repetition_level_histogram = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 3: + if (ftype == ::apache::thrift::protocol::T_LIST) { + { + this->definition_level_histogram.clear(); + uint32_t _size5; + ::apache::thrift::protocol::TType _etype8; + xfer += iprot->readListBegin(_etype8, _size5); + this->definition_level_histogram.resize(_size5); + uint32_t _i9; + for (_i9 = 0; _i9 < _size5; ++_i9) + { + xfer += iprot->readI64(this->definition_level_histogram[_i9]); + } + xfer += iprot->readListEnd(); + } + this->__isset.definition_level_histogram = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t SizeStatistics::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("SizeStatistics"); + + if (this->__isset.unencoded_byte_array_data_bytes) { + xfer += oprot->writeFieldBegin("unencoded_byte_array_data_bytes", ::apache::thrift::protocol::T_I64, 1); + xfer += oprot->writeI64(this->unencoded_byte_array_data_bytes); + xfer += oprot->writeFieldEnd(); + } + if (this->__isset.repetition_level_histogram) { + xfer += oprot->writeFieldBegin("repetition_level_histogram", ::apache::thrift::protocol::T_LIST, 2); + { + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64, static_cast(this->repetition_level_histogram.size())); + duckdb::vector ::const_iterator _iter10; + for (_iter10 = this->repetition_level_histogram.begin(); _iter10 != this->repetition_level_histogram.end(); ++_iter10) + { + xfer += oprot->writeI64((*_iter10)); + } + xfer += oprot->writeListEnd(); + } + xfer += oprot->writeFieldEnd(); + } + if (this->__isset.definition_level_histogram) { + xfer += oprot->writeFieldBegin("definition_level_histogram", ::apache::thrift::protocol::T_LIST, 3); + { + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64, static_cast(this->definition_level_histogram.size())); + duckdb::vector ::const_iterator _iter11; + for (_iter11 = this->definition_level_histogram.begin(); _iter11 != this->definition_level_histogram.end(); ++_iter11) + { + xfer += oprot->writeI64((*_iter11)); + } + xfer += oprot->writeListEnd(); + } + xfer += oprot->writeFieldEnd(); + } + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +void swap(SizeStatistics &a, SizeStatistics &b) { + using ::std::swap; + swap(a.unencoded_byte_array_data_bytes, b.unencoded_byte_array_data_bytes); + swap(a.repetition_level_histogram, b.repetition_level_histogram); + swap(a.definition_level_histogram, b.definition_level_histogram); + swap(a.__isset, b.__isset); +} + +SizeStatistics::SizeStatistics(const SizeStatistics& other12) { + unencoded_byte_array_data_bytes = other12.unencoded_byte_array_data_bytes; + repetition_level_histogram = other12.repetition_level_histogram; + definition_level_histogram = other12.definition_level_histogram; + __isset = other12.__isset; +} +SizeStatistics& SizeStatistics::operator=(const SizeStatistics& other13) { + unencoded_byte_array_data_bytes = other13.unencoded_byte_array_data_bytes; + repetition_level_histogram = other13.repetition_level_histogram; + definition_level_histogram = other13.definition_level_histogram; + __isset = other13.__isset; + return *this; +} +void SizeStatistics::printTo(std::ostream& out) const { + using ::apache::thrift::to_string; + out << "SizeStatistics("; + out << "unencoded_byte_array_data_bytes="; (__isset.unencoded_byte_array_data_bytes ? (out << to_string(unencoded_byte_array_data_bytes)) : (out << "")); + out << ", " << "repetition_level_histogram="; (__isset.repetition_level_histogram ? (out << to_string(repetition_level_histogram)) : (out << "")); + out << ", " << "definition_level_histogram="; (__isset.definition_level_histogram ? (out << to_string(definition_level_histogram)) : (out << "")); + out << ")"; +} + + +Statistics::~Statistics() noexcept { } +Statistics::Statistics() noexcept + : max(), + min(), + null_count(0), + distinct_count(0), + max_value(), + min_value(), + is_max_value_exact(0), + is_min_value_exact(0) { +} void Statistics::__set_max(const std::string& val) { this->max = val; @@ -277,6 +845,16 @@ void Statistics::__set_min_value(const std::string& val) { this->min_value = val; __isset.min_value = true; } + +void Statistics::__set_is_max_value_exact(const bool val) { + this->is_max_value_exact = val; +__isset.is_max_value_exact = true; +} + +void Statistics::__set_is_min_value_exact(const bool val) { + this->is_min_value_exact = val; +__isset.is_min_value_exact = true; +} std::ostream& operator<<(std::ostream& out, const Statistics& obj) { obj.printTo(out); @@ -284,29 +862,29 @@ std::ostream& operator<<(std::ostream& out, const Statistics& obj) } -uint32_t Statistics::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t Statistics::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->max); this->__isset.max = true; } else { @@ -314,7 +892,7 @@ uint32_t Statistics::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->min); this->__isset.min = true; } else { @@ -322,7 +900,7 @@ uint32_t Statistics::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->null_count); this->__isset.null_count = true; } else { @@ -330,7 +908,7 @@ uint32_t Statistics::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 4: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->distinct_count); this->__isset.distinct_count = true; } else { @@ -338,7 +916,7 @@ uint32_t Statistics::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 5: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->max_value); this->__isset.max_value = true; } else { @@ -346,13 +924,29 @@ uint32_t Statistics::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 6: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->min_value); this->__isset.min_value = true; } else { xfer += iprot->skip(ftype); } break; + case 7: + if (ftype == ::apache::thrift::protocol::T_BOOL) { + xfer += iprot->readBool(this->is_max_value_exact); + this->__isset.is_max_value_exact = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 8: + if (ftype == ::apache::thrift::protocol::T_BOOL) { + xfer += iprot->readBool(this->is_min_value_exact); + this->__isset.is_min_value_exact = true; + } else { + xfer += iprot->skip(ftype); + } + break; default: xfer += iprot->skip(ftype); break; @@ -365,41 +959,51 @@ uint32_t Statistics::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t Statistics::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t Statistics::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("Statistics"); if (this->__isset.max) { - xfer += oprot->writeFieldBegin("max", ::duckdb_apache::thrift::protocol::T_STRING, 1); + xfer += oprot->writeFieldBegin("max", ::apache::thrift::protocol::T_STRING, 1); xfer += oprot->writeBinary(this->max); xfer += oprot->writeFieldEnd(); } if (this->__isset.min) { - xfer += oprot->writeFieldBegin("min", ::duckdb_apache::thrift::protocol::T_STRING, 2); + xfer += oprot->writeFieldBegin("min", ::apache::thrift::protocol::T_STRING, 2); xfer += oprot->writeBinary(this->min); xfer += oprot->writeFieldEnd(); } if (this->__isset.null_count) { - xfer += oprot->writeFieldBegin("null_count", ::duckdb_apache::thrift::protocol::T_I64, 3); + xfer += oprot->writeFieldBegin("null_count", ::apache::thrift::protocol::T_I64, 3); xfer += oprot->writeI64(this->null_count); xfer += oprot->writeFieldEnd(); } if (this->__isset.distinct_count) { - xfer += oprot->writeFieldBegin("distinct_count", ::duckdb_apache::thrift::protocol::T_I64, 4); + xfer += oprot->writeFieldBegin("distinct_count", ::apache::thrift::protocol::T_I64, 4); xfer += oprot->writeI64(this->distinct_count); xfer += oprot->writeFieldEnd(); } if (this->__isset.max_value) { - xfer += oprot->writeFieldBegin("max_value", ::duckdb_apache::thrift::protocol::T_STRING, 5); + xfer += oprot->writeFieldBegin("max_value", ::apache::thrift::protocol::T_STRING, 5); xfer += oprot->writeBinary(this->max_value); xfer += oprot->writeFieldEnd(); } if (this->__isset.min_value) { - xfer += oprot->writeFieldBegin("min_value", ::duckdb_apache::thrift::protocol::T_STRING, 6); + xfer += oprot->writeFieldBegin("min_value", ::apache::thrift::protocol::T_STRING, 6); xfer += oprot->writeBinary(this->min_value); xfer += oprot->writeFieldEnd(); } + if (this->__isset.is_max_value_exact) { + xfer += oprot->writeFieldBegin("is_max_value_exact", ::apache::thrift::protocol::T_BOOL, 7); + xfer += oprot->writeBool(this->is_max_value_exact); + xfer += oprot->writeFieldEnd(); + } + if (this->__isset.is_min_value_exact) { + xfer += oprot->writeFieldBegin("is_min_value_exact", ::apache::thrift::protocol::T_BOOL, 8); + xfer += oprot->writeBool(this->is_min_value_exact); + xfer += oprot->writeFieldEnd(); + } xfer += oprot->writeFieldStop(); xfer += oprot->writeStructEnd(); return xfer; @@ -413,30 +1017,36 @@ void swap(Statistics &a, Statistics &b) { swap(a.distinct_count, b.distinct_count); swap(a.max_value, b.max_value); swap(a.min_value, b.min_value); + swap(a.is_max_value_exact, b.is_max_value_exact); + swap(a.is_min_value_exact, b.is_min_value_exact); swap(a.__isset, b.__isset); } -Statistics::Statistics(const Statistics& other0) { - max = other0.max; - min = other0.min; - null_count = other0.null_count; - distinct_count = other0.distinct_count; - max_value = other0.max_value; - min_value = other0.min_value; - __isset = other0.__isset; -} -Statistics& Statistics::operator=(const Statistics& other1) { - max = other1.max; - min = other1.min; - null_count = other1.null_count; - distinct_count = other1.distinct_count; - max_value = other1.max_value; - min_value = other1.min_value; - __isset = other1.__isset; +Statistics::Statistics(const Statistics& other14) { + max = other14.max; + min = other14.min; + null_count = other14.null_count; + distinct_count = other14.distinct_count; + max_value = other14.max_value; + min_value = other14.min_value; + is_max_value_exact = other14.is_max_value_exact; + is_min_value_exact = other14.is_min_value_exact; + __isset = other14.__isset; +} +Statistics& Statistics::operator=(const Statistics& other15) { + max = other15.max; + min = other15.min; + null_count = other15.null_count; + distinct_count = other15.distinct_count; + max_value = other15.max_value; + min_value = other15.min_value; + is_max_value_exact = other15.is_max_value_exact; + is_min_value_exact = other15.is_min_value_exact; + __isset = other15.__isset; return *this; } void Statistics::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "Statistics("; out << "max="; (__isset.max ? (out << to_string(max)) : (out << "")); out << ", " << "min="; (__isset.min ? (out << to_string(min)) : (out << "")); @@ -444,13 +1054,17 @@ void Statistics::printTo(std::ostream& out) const { out << ", " << "distinct_count="; (__isset.distinct_count ? (out << to_string(distinct_count)) : (out << "")); out << ", " << "max_value="; (__isset.max_value ? (out << to_string(max_value)) : (out << "")); out << ", " << "min_value="; (__isset.min_value ? (out << to_string(min_value)) : (out << "")); + out << ", " << "is_max_value_exact="; (__isset.is_max_value_exact ? (out << to_string(is_max_value_exact)) : (out << "")); + out << ", " << "is_min_value_exact="; (__isset.is_min_value_exact ? (out << to_string(is_min_value_exact)) : (out << "")); out << ")"; } -StringType::~StringType() throw() { +StringType::~StringType() noexcept { } +StringType::StringType() noexcept { +} std::ostream& operator<<(std::ostream& out, const StringType& obj) { obj.printTo(out); @@ -458,23 +1072,23 @@ std::ostream& operator<<(std::ostream& out, const StringType& obj) } -uint32_t StringType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t StringType::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -486,9 +1100,9 @@ uint32_t StringType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t StringType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t StringType::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("StringType"); xfer += oprot->writeFieldStop(); @@ -502,23 +1116,25 @@ void swap(StringType &a, StringType &b) { (void) b; } -StringType::StringType(const StringType& other2) { - (void) other2; +StringType::StringType(const StringType& other16) noexcept { + (void) other16; } -StringType& StringType::operator=(const StringType& other3) { - (void) other3; +StringType& StringType::operator=(const StringType& other17) noexcept { + (void) other17; return *this; } void StringType::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "StringType("; out << ")"; } -UUIDType::~UUIDType() throw() { +UUIDType::~UUIDType() noexcept { } +UUIDType::UUIDType() noexcept { +} std::ostream& operator<<(std::ostream& out, const UUIDType& obj) { obj.printTo(out); @@ -526,23 +1142,23 @@ std::ostream& operator<<(std::ostream& out, const UUIDType& obj) } -uint32_t UUIDType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t UUIDType::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -554,9 +1170,9 @@ uint32_t UUIDType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t UUIDType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t UUIDType::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("UUIDType"); xfer += oprot->writeFieldStop(); @@ -570,23 +1186,25 @@ void swap(UUIDType &a, UUIDType &b) { (void) b; } -UUIDType::UUIDType(const UUIDType& other4) { - (void) other4; +UUIDType::UUIDType(const UUIDType& other18) noexcept { + (void) other18; } -UUIDType& UUIDType::operator=(const UUIDType& other5) { - (void) other5; +UUIDType& UUIDType::operator=(const UUIDType& other19) noexcept { + (void) other19; return *this; } void UUIDType::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "UUIDType("; out << ")"; } -MapType::~MapType() throw() { +MapType::~MapType() noexcept { } +MapType::MapType() noexcept { +} std::ostream& operator<<(std::ostream& out, const MapType& obj) { obj.printTo(out); @@ -594,23 +1212,23 @@ std::ostream& operator<<(std::ostream& out, const MapType& obj) } -uint32_t MapType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t MapType::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -622,9 +1240,9 @@ uint32_t MapType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t MapType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t MapType::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("MapType"); xfer += oprot->writeFieldStop(); @@ -638,23 +1256,25 @@ void swap(MapType &a, MapType &b) { (void) b; } -MapType::MapType(const MapType& other6) { - (void) other6; +MapType::MapType(const MapType& other20) noexcept { + (void) other20; } -MapType& MapType::operator=(const MapType& other7) { - (void) other7; +MapType& MapType::operator=(const MapType& other21) noexcept { + (void) other21; return *this; } void MapType::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "MapType("; out << ")"; } -ListType::~ListType() throw() { +ListType::~ListType() noexcept { } +ListType::ListType() noexcept { +} std::ostream& operator<<(std::ostream& out, const ListType& obj) { obj.printTo(out); @@ -662,23 +1282,23 @@ std::ostream& operator<<(std::ostream& out, const ListType& obj) } -uint32_t ListType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t ListType::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -690,9 +1310,9 @@ uint32_t ListType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t ListType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t ListType::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("ListType"); xfer += oprot->writeFieldStop(); @@ -706,23 +1326,25 @@ void swap(ListType &a, ListType &b) { (void) b; } -ListType::ListType(const ListType& other8) { - (void) other8; +ListType::ListType(const ListType& other22) noexcept { + (void) other22; } -ListType& ListType::operator=(const ListType& other9) { - (void) other9; +ListType& ListType::operator=(const ListType& other23) noexcept { + (void) other23; return *this; } void ListType::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "ListType("; out << ")"; } -EnumType::~EnumType() throw() { +EnumType::~EnumType() noexcept { } +EnumType::EnumType() noexcept { +} std::ostream& operator<<(std::ostream& out, const EnumType& obj) { obj.printTo(out); @@ -730,23 +1352,23 @@ std::ostream& operator<<(std::ostream& out, const EnumType& obj) } -uint32_t EnumType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t EnumType::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -758,9 +1380,9 @@ uint32_t EnumType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t EnumType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t EnumType::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("EnumType"); xfer += oprot->writeFieldStop(); @@ -774,23 +1396,25 @@ void swap(EnumType &a, EnumType &b) { (void) b; } -EnumType::EnumType(const EnumType& other10) { - (void) other10; +EnumType::EnumType(const EnumType& other24) noexcept { + (void) other24; } -EnumType& EnumType::operator=(const EnumType& other11) { - (void) other11; +EnumType& EnumType::operator=(const EnumType& other25) noexcept { + (void) other25; return *this; } void EnumType::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "EnumType("; out << ")"; } -DateType::~DateType() throw() { +DateType::~DateType() noexcept { } +DateType::DateType() noexcept { +} std::ostream& operator<<(std::ostream& out, const DateType& obj) { obj.printTo(out); @@ -798,23 +1422,23 @@ std::ostream& operator<<(std::ostream& out, const DateType& obj) } -uint32_t DateType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t DateType::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -826,9 +1450,9 @@ uint32_t DateType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t DateType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t DateType::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("DateType"); xfer += oprot->writeFieldStop(); @@ -842,23 +1466,95 @@ void swap(DateType &a, DateType &b) { (void) b; } -DateType::DateType(const DateType& other12) { - (void) other12; +DateType::DateType(const DateType& other26) noexcept { + (void) other26; } -DateType& DateType::operator=(const DateType& other13) { - (void) other13; +DateType& DateType::operator=(const DateType& other27) noexcept { + (void) other27; return *this; } void DateType::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "DateType("; out << ")"; } -NullType::~NullType() throw() { +Float16Type::~Float16Type() noexcept { +} + +Float16Type::Float16Type() noexcept { +} +std::ostream& operator<<(std::ostream& out, const Float16Type& obj) +{ + obj.printTo(out); + return out; +} + + +uint32_t Float16Type::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t Float16Type::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("Float16Type"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +void swap(Float16Type &a, Float16Type &b) { + using ::std::swap; + (void) a; + (void) b; +} + +Float16Type::Float16Type(const Float16Type& other28) noexcept { + (void) other28; +} +Float16Type& Float16Type::operator=(const Float16Type& other29) noexcept { + (void) other29; + return *this; +} +void Float16Type::printTo(std::ostream& out) const { + using ::apache::thrift::to_string; + out << "Float16Type("; + out << ")"; +} + + +NullType::~NullType() noexcept { } +NullType::NullType() noexcept { +} std::ostream& operator<<(std::ostream& out, const NullType& obj) { obj.printTo(out); @@ -866,23 +1562,23 @@ std::ostream& operator<<(std::ostream& out, const NullType& obj) } -uint32_t NullType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t NullType::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -894,9 +1590,9 @@ uint32_t NullType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t NullType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t NullType::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("NullType"); xfer += oprot->writeFieldStop(); @@ -910,23 +1606,27 @@ void swap(NullType &a, NullType &b) { (void) b; } -NullType::NullType(const NullType& other14) { - (void) other14; +NullType::NullType(const NullType& other30) noexcept { + (void) other30; } -NullType& NullType::operator=(const NullType& other15) { - (void) other15; +NullType& NullType::operator=(const NullType& other31) noexcept { + (void) other31; return *this; } void NullType::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "NullType("; out << ")"; } -DecimalType::~DecimalType() throw() { +DecimalType::~DecimalType() noexcept { } +DecimalType::DecimalType() noexcept + : scale(0), + precision(0) { +} void DecimalType::__set_scale(const int32_t val) { this->scale = val; @@ -942,17 +1642,17 @@ std::ostream& operator<<(std::ostream& out, const DecimalType& obj) } -uint32_t DecimalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t DecimalType::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_scale = false; bool isset_precision = false; @@ -960,13 +1660,13 @@ uint32_t DecimalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->scale); isset_scale = true; } else { @@ -974,7 +1674,7 @@ uint32_t DecimalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->precision); isset_precision = true; } else { @@ -997,16 +1697,16 @@ uint32_t DecimalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) return xfer; } -uint32_t DecimalType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t DecimalType::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("DecimalType"); - xfer += oprot->writeFieldBegin("scale", ::duckdb_apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeFieldBegin("scale", ::apache::thrift::protocol::T_I32, 1); xfer += oprot->writeI32(this->scale); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("precision", ::duckdb_apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeFieldBegin("precision", ::apache::thrift::protocol::T_I32, 2); xfer += oprot->writeI32(this->precision); xfer += oprot->writeFieldEnd(); @@ -1021,17 +1721,17 @@ void swap(DecimalType &a, DecimalType &b) { swap(a.precision, b.precision); } -DecimalType::DecimalType(const DecimalType& other16) { - scale = other16.scale; - precision = other16.precision; +DecimalType::DecimalType(const DecimalType& other32) noexcept { + scale = other32.scale; + precision = other32.precision; } -DecimalType& DecimalType::operator=(const DecimalType& other17) { - scale = other17.scale; - precision = other17.precision; +DecimalType& DecimalType::operator=(const DecimalType& other33) noexcept { + scale = other33.scale; + precision = other33.precision; return *this; } void DecimalType::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "DecimalType("; out << "scale=" << to_string(scale); out << ", " << "precision=" << to_string(precision); @@ -1039,9 +1739,11 @@ void DecimalType::printTo(std::ostream& out) const { } -MilliSeconds::~MilliSeconds() throw() { +MilliSeconds::~MilliSeconds() noexcept { } +MilliSeconds::MilliSeconds() noexcept { +} std::ostream& operator<<(std::ostream& out, const MilliSeconds& obj) { obj.printTo(out); @@ -1049,23 +1751,23 @@ std::ostream& operator<<(std::ostream& out, const MilliSeconds& obj) } -uint32_t MilliSeconds::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t MilliSeconds::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -1077,9 +1779,9 @@ uint32_t MilliSeconds::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) return xfer; } -uint32_t MilliSeconds::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t MilliSeconds::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("MilliSeconds"); xfer += oprot->writeFieldStop(); @@ -1093,23 +1795,25 @@ void swap(MilliSeconds &a, MilliSeconds &b) { (void) b; } -MilliSeconds::MilliSeconds(const MilliSeconds& other18) { - (void) other18; +MilliSeconds::MilliSeconds(const MilliSeconds& other34) noexcept { + (void) other34; } -MilliSeconds& MilliSeconds::operator=(const MilliSeconds& other19) { - (void) other19; +MilliSeconds& MilliSeconds::operator=(const MilliSeconds& other35) noexcept { + (void) other35; return *this; } void MilliSeconds::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "MilliSeconds("; out << ")"; } -MicroSeconds::~MicroSeconds() throw() { +MicroSeconds::~MicroSeconds() noexcept { } +MicroSeconds::MicroSeconds() noexcept { +} std::ostream& operator<<(std::ostream& out, const MicroSeconds& obj) { obj.printTo(out); @@ -1117,23 +1821,23 @@ std::ostream& operator<<(std::ostream& out, const MicroSeconds& obj) } -uint32_t MicroSeconds::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t MicroSeconds::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -1145,9 +1849,9 @@ uint32_t MicroSeconds::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) return xfer; } -uint32_t MicroSeconds::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t MicroSeconds::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("MicroSeconds"); xfer += oprot->writeFieldStop(); @@ -1161,23 +1865,25 @@ void swap(MicroSeconds &a, MicroSeconds &b) { (void) b; } -MicroSeconds::MicroSeconds(const MicroSeconds& other20) { - (void) other20; +MicroSeconds::MicroSeconds(const MicroSeconds& other36) noexcept { + (void) other36; } -MicroSeconds& MicroSeconds::operator=(const MicroSeconds& other21) { - (void) other21; +MicroSeconds& MicroSeconds::operator=(const MicroSeconds& other37) noexcept { + (void) other37; return *this; } void MicroSeconds::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "MicroSeconds("; out << ")"; } -NanoSeconds::~NanoSeconds() throw() { +NanoSeconds::~NanoSeconds() noexcept { } +NanoSeconds::NanoSeconds() noexcept { +} std::ostream& operator<<(std::ostream& out, const NanoSeconds& obj) { obj.printTo(out); @@ -1185,23 +1891,23 @@ std::ostream& operator<<(std::ostream& out, const NanoSeconds& obj) } -uint32_t NanoSeconds::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t NanoSeconds::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -1213,9 +1919,9 @@ uint32_t NanoSeconds::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) return xfer; } -uint32_t NanoSeconds::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t NanoSeconds::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("NanoSeconds"); xfer += oprot->writeFieldStop(); @@ -1229,23 +1935,25 @@ void swap(NanoSeconds &a, NanoSeconds &b) { (void) b; } -NanoSeconds::NanoSeconds(const NanoSeconds& other22) { - (void) other22; +NanoSeconds::NanoSeconds(const NanoSeconds& other38) noexcept { + (void) other38; } -NanoSeconds& NanoSeconds::operator=(const NanoSeconds& other23) { - (void) other23; +NanoSeconds& NanoSeconds::operator=(const NanoSeconds& other39) noexcept { + (void) other39; return *this; } void NanoSeconds::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "NanoSeconds("; out << ")"; } -TimeUnit::~TimeUnit() throw() { +TimeUnit::~TimeUnit() noexcept { } +TimeUnit::TimeUnit() noexcept { +} void TimeUnit::__set_MILLIS(const MilliSeconds& val) { this->MILLIS = val; @@ -1268,29 +1976,29 @@ std::ostream& operator<<(std::ostream& out, const TimeUnit& obj) } -uint32_t TimeUnit::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t TimeUnit::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->MILLIS.read(iprot); this->__isset.MILLIS = true; } else { @@ -1298,7 +2006,7 @@ uint32_t TimeUnit::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->MICROS.read(iprot); this->__isset.MICROS = true; } else { @@ -1306,7 +2014,7 @@ uint32_t TimeUnit::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->NANOS.read(iprot); this->__isset.NANOS = true; } else { @@ -1325,23 +2033,23 @@ uint32_t TimeUnit::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t TimeUnit::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t TimeUnit::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("TimeUnit"); if (this->__isset.MILLIS) { - xfer += oprot->writeFieldBegin("MILLIS", ::duckdb_apache::thrift::protocol::T_STRUCT, 1); + xfer += oprot->writeFieldBegin("MILLIS", ::apache::thrift::protocol::T_STRUCT, 1); xfer += this->MILLIS.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.MICROS) { - xfer += oprot->writeFieldBegin("MICROS", ::duckdb_apache::thrift::protocol::T_STRUCT, 2); + xfer += oprot->writeFieldBegin("MICROS", ::apache::thrift::protocol::T_STRUCT, 2); xfer += this->MICROS.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.NANOS) { - xfer += oprot->writeFieldBegin("NANOS", ::duckdb_apache::thrift::protocol::T_STRUCT, 3); + xfer += oprot->writeFieldBegin("NANOS", ::apache::thrift::protocol::T_STRUCT, 3); xfer += this->NANOS.write(oprot); xfer += oprot->writeFieldEnd(); } @@ -1358,21 +2066,21 @@ void swap(TimeUnit &a, TimeUnit &b) { swap(a.__isset, b.__isset); } -TimeUnit::TimeUnit(const TimeUnit& other24) { - MILLIS = other24.MILLIS; - MICROS = other24.MICROS; - NANOS = other24.NANOS; - __isset = other24.__isset; +TimeUnit::TimeUnit(const TimeUnit& other40) noexcept { + MILLIS = other40.MILLIS; + MICROS = other40.MICROS; + NANOS = other40.NANOS; + __isset = other40.__isset; } -TimeUnit& TimeUnit::operator=(const TimeUnit& other25) { - MILLIS = other25.MILLIS; - MICROS = other25.MICROS; - NANOS = other25.NANOS; - __isset = other25.__isset; +TimeUnit& TimeUnit::operator=(const TimeUnit& other41) noexcept { + MILLIS = other41.MILLIS; + MICROS = other41.MICROS; + NANOS = other41.NANOS; + __isset = other41.__isset; return *this; } void TimeUnit::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "TimeUnit("; out << "MILLIS="; (__isset.MILLIS ? (out << to_string(MILLIS)) : (out << "")); out << ", " << "MICROS="; (__isset.MICROS ? (out << to_string(MICROS)) : (out << "")); @@ -1381,9 +2089,12 @@ void TimeUnit::printTo(std::ostream& out) const { } -TimestampType::~TimestampType() throw() { +TimestampType::~TimestampType() noexcept { } +TimestampType::TimestampType() noexcept + : isAdjustedToUTC(0) { +} void TimestampType::__set_isAdjustedToUTC(const bool val) { this->isAdjustedToUTC = val; @@ -1399,17 +2110,17 @@ std::ostream& operator<<(std::ostream& out, const TimestampType& obj) } -uint32_t TimestampType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t TimestampType::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_isAdjustedToUTC = false; bool isset_unit = false; @@ -1417,13 +2128,13 @@ uint32_t TimestampType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { + if (ftype == ::apache::thrift::protocol::T_BOOL) { xfer += iprot->readBool(this->isAdjustedToUTC); isset_isAdjustedToUTC = true; } else { @@ -1431,7 +2142,7 @@ uint32_t TimestampType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->unit.read(iprot); isset_unit = true; } else { @@ -1454,16 +2165,16 @@ uint32_t TimestampType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot return xfer; } -uint32_t TimestampType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t TimestampType::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("TimestampType"); - xfer += oprot->writeFieldBegin("isAdjustedToUTC", ::duckdb_apache::thrift::protocol::T_BOOL, 1); + xfer += oprot->writeFieldBegin("isAdjustedToUTC", ::apache::thrift::protocol::T_BOOL, 1); xfer += oprot->writeBool(this->isAdjustedToUTC); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("unit", ::duckdb_apache::thrift::protocol::T_STRUCT, 2); + xfer += oprot->writeFieldBegin("unit", ::apache::thrift::protocol::T_STRUCT, 2); xfer += this->unit.write(oprot); xfer += oprot->writeFieldEnd(); @@ -1478,17 +2189,17 @@ void swap(TimestampType &a, TimestampType &b) { swap(a.unit, b.unit); } -TimestampType::TimestampType(const TimestampType& other26) { - isAdjustedToUTC = other26.isAdjustedToUTC; - unit = other26.unit; +TimestampType::TimestampType(const TimestampType& other42) noexcept { + isAdjustedToUTC = other42.isAdjustedToUTC; + unit = other42.unit; } -TimestampType& TimestampType::operator=(const TimestampType& other27) { - isAdjustedToUTC = other27.isAdjustedToUTC; - unit = other27.unit; +TimestampType& TimestampType::operator=(const TimestampType& other43) noexcept { + isAdjustedToUTC = other43.isAdjustedToUTC; + unit = other43.unit; return *this; } void TimestampType::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "TimestampType("; out << "isAdjustedToUTC=" << to_string(isAdjustedToUTC); out << ", " << "unit=" << to_string(unit); @@ -1496,9 +2207,12 @@ void TimestampType::printTo(std::ostream& out) const { } -TimeType::~TimeType() throw() { +TimeType::~TimeType() noexcept { } +TimeType::TimeType() noexcept + : isAdjustedToUTC(0) { +} void TimeType::__set_isAdjustedToUTC(const bool val) { this->isAdjustedToUTC = val; @@ -1514,17 +2228,17 @@ std::ostream& operator<<(std::ostream& out, const TimeType& obj) } -uint32_t TimeType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t TimeType::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_isAdjustedToUTC = false; bool isset_unit = false; @@ -1532,13 +2246,13 @@ uint32_t TimeType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { + if (ftype == ::apache::thrift::protocol::T_BOOL) { xfer += iprot->readBool(this->isAdjustedToUTC); isset_isAdjustedToUTC = true; } else { @@ -1546,7 +2260,7 @@ uint32_t TimeType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->unit.read(iprot); isset_unit = true; } else { @@ -1569,16 +2283,16 @@ uint32_t TimeType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t TimeType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t TimeType::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("TimeType"); - xfer += oprot->writeFieldBegin("isAdjustedToUTC", ::duckdb_apache::thrift::protocol::T_BOOL, 1); + xfer += oprot->writeFieldBegin("isAdjustedToUTC", ::apache::thrift::protocol::T_BOOL, 1); xfer += oprot->writeBool(this->isAdjustedToUTC); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("unit", ::duckdb_apache::thrift::protocol::T_STRUCT, 2); + xfer += oprot->writeFieldBegin("unit", ::apache::thrift::protocol::T_STRUCT, 2); xfer += this->unit.write(oprot); xfer += oprot->writeFieldEnd(); @@ -1593,17 +2307,17 @@ void swap(TimeType &a, TimeType &b) { swap(a.unit, b.unit); } -TimeType::TimeType(const TimeType& other28) { - isAdjustedToUTC = other28.isAdjustedToUTC; - unit = other28.unit; +TimeType::TimeType(const TimeType& other44) noexcept { + isAdjustedToUTC = other44.isAdjustedToUTC; + unit = other44.unit; } -TimeType& TimeType::operator=(const TimeType& other29) { - isAdjustedToUTC = other29.isAdjustedToUTC; - unit = other29.unit; +TimeType& TimeType::operator=(const TimeType& other45) noexcept { + isAdjustedToUTC = other45.isAdjustedToUTC; + unit = other45.unit; return *this; } void TimeType::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "TimeType("; out << "isAdjustedToUTC=" << to_string(isAdjustedToUTC); out << ", " << "unit=" << to_string(unit); @@ -1611,9 +2325,13 @@ void TimeType::printTo(std::ostream& out) const { } -IntType::~IntType() throw() { +IntType::~IntType() noexcept { } +IntType::IntType() noexcept + : bitWidth(0), + isSigned(0) { +} void IntType::__set_bitWidth(const int8_t val) { this->bitWidth = val; @@ -1629,17 +2347,17 @@ std::ostream& operator<<(std::ostream& out, const IntType& obj) } -uint32_t IntType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t IntType::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_bitWidth = false; bool isset_isSigned = false; @@ -1647,13 +2365,13 @@ uint32_t IntType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_BYTE) { + if (ftype == ::apache::thrift::protocol::T_BYTE) { xfer += iprot->readByte(this->bitWidth); isset_bitWidth = true; } else { @@ -1661,7 +2379,7 @@ uint32_t IntType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { + if (ftype == ::apache::thrift::protocol::T_BOOL) { xfer += iprot->readBool(this->isSigned); isset_isSigned = true; } else { @@ -1684,16 +2402,16 @@ uint32_t IntType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t IntType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t IntType::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("IntType"); - xfer += oprot->writeFieldBegin("bitWidth", ::duckdb_apache::thrift::protocol::T_BYTE, 1); + xfer += oprot->writeFieldBegin("bitWidth", ::apache::thrift::protocol::T_BYTE, 1); xfer += oprot->writeByte(this->bitWidth); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("isSigned", ::duckdb_apache::thrift::protocol::T_BOOL, 2); + xfer += oprot->writeFieldBegin("isSigned", ::apache::thrift::protocol::T_BOOL, 2); xfer += oprot->writeBool(this->isSigned); xfer += oprot->writeFieldEnd(); @@ -1708,17 +2426,17 @@ void swap(IntType &a, IntType &b) { swap(a.isSigned, b.isSigned); } -IntType::IntType(const IntType& other30) { - bitWidth = other30.bitWidth; - isSigned = other30.isSigned; +IntType::IntType(const IntType& other46) noexcept { + bitWidth = other46.bitWidth; + isSigned = other46.isSigned; } -IntType& IntType::operator=(const IntType& other31) { - bitWidth = other31.bitWidth; - isSigned = other31.isSigned; +IntType& IntType::operator=(const IntType& other47) noexcept { + bitWidth = other47.bitWidth; + isSigned = other47.isSigned; return *this; } void IntType::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "IntType("; out << "bitWidth=" << to_string(bitWidth); out << ", " << "isSigned=" << to_string(isSigned); @@ -1726,9 +2444,11 @@ void IntType::printTo(std::ostream& out) const { } -JsonType::~JsonType() throw() { +JsonType::~JsonType() noexcept { } +JsonType::JsonType() noexcept { +} std::ostream& operator<<(std::ostream& out, const JsonType& obj) { obj.printTo(out); @@ -1736,23 +2456,23 @@ std::ostream& operator<<(std::ostream& out, const JsonType& obj) } -uint32_t JsonType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t JsonType::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -1764,9 +2484,9 @@ uint32_t JsonType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t JsonType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t JsonType::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("JsonType"); xfer += oprot->writeFieldStop(); @@ -1780,23 +2500,25 @@ void swap(JsonType &a, JsonType &b) { (void) b; } -JsonType::JsonType(const JsonType& other32) { - (void) other32; +JsonType::JsonType(const JsonType& other48) noexcept { + (void) other48; } -JsonType& JsonType::operator=(const JsonType& other33) { - (void) other33; +JsonType& JsonType::operator=(const JsonType& other49) noexcept { + (void) other49; return *this; } void JsonType::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "JsonType("; out << ")"; } -BsonType::~BsonType() throw() { +BsonType::~BsonType() noexcept { } +BsonType::BsonType() noexcept { +} std::ostream& operator<<(std::ostream& out, const BsonType& obj) { obj.printTo(out); @@ -1804,23 +2526,23 @@ std::ostream& operator<<(std::ostream& out, const BsonType& obj) } -uint32_t BsonType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t BsonType::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -1832,9 +2554,9 @@ uint32_t BsonType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t BsonType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t BsonType::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("BsonType"); xfer += oprot->writeFieldStop(); @@ -1848,23 +2570,25 @@ void swap(BsonType &a, BsonType &b) { (void) b; } -BsonType::BsonType(const BsonType& other34) { - (void) other34; +BsonType::BsonType(const BsonType& other50) noexcept { + (void) other50; } -BsonType& BsonType::operator=(const BsonType& other35) { - (void) other35; +BsonType& BsonType::operator=(const BsonType& other51) noexcept { + (void) other51; return *this; } void BsonType::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "BsonType("; out << ")"; } -LogicalType::~LogicalType() throw() { +LogicalType::~LogicalType() noexcept { } +LogicalType::LogicalType() noexcept { +} void LogicalType::__set_STRING(const StringType& val) { this->STRING = val; @@ -1930,6 +2654,11 @@ void LogicalType::__set_UUID(const UUIDType& val) { this->UUID = val; __isset.UUID = true; } + +void LogicalType::__set_FLOAT16(const Float16Type& val) { + this->FLOAT16 = val; +__isset.FLOAT16 = true; +} std::ostream& operator<<(std::ostream& out, const LogicalType& obj) { obj.printTo(out); @@ -1937,29 +2666,29 @@ std::ostream& operator<<(std::ostream& out, const LogicalType& obj) } -uint32_t LogicalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t LogicalType::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->STRING.read(iprot); this->__isset.STRING = true; } else { @@ -1967,7 +2696,7 @@ uint32_t LogicalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->MAP.read(iprot); this->__isset.MAP = true; } else { @@ -1975,7 +2704,7 @@ uint32_t LogicalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->LIST.read(iprot); this->__isset.LIST = true; } else { @@ -1983,7 +2712,7 @@ uint32_t LogicalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 4: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->ENUM.read(iprot); this->__isset.ENUM = true; } else { @@ -1991,7 +2720,7 @@ uint32_t LogicalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 5: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->DECIMAL.read(iprot); this->__isset.DECIMAL = true; } else { @@ -1999,7 +2728,7 @@ uint32_t LogicalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 6: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->DATE.read(iprot); this->__isset.DATE = true; } else { @@ -2007,7 +2736,7 @@ uint32_t LogicalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 7: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->TIME.read(iprot); this->__isset.TIME = true; } else { @@ -2015,7 +2744,7 @@ uint32_t LogicalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 8: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->TIMESTAMP.read(iprot); this->__isset.TIMESTAMP = true; } else { @@ -2023,7 +2752,7 @@ uint32_t LogicalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 10: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->INTEGER.read(iprot); this->__isset.INTEGER = true; } else { @@ -2031,7 +2760,7 @@ uint32_t LogicalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 11: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->UNKNOWN.read(iprot); this->__isset.UNKNOWN = true; } else { @@ -2039,7 +2768,7 @@ uint32_t LogicalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 12: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->JSON.read(iprot); this->__isset.JSON = true; } else { @@ -2047,7 +2776,7 @@ uint32_t LogicalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 13: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->BSON.read(iprot); this->__isset.BSON = true; } else { @@ -2055,13 +2784,21 @@ uint32_t LogicalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 14: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->UUID.read(iprot); this->__isset.UUID = true; } else { xfer += iprot->skip(ftype); } break; + case 15: + if (ftype == ::apache::thrift::protocol::T_STRUCT) { + xfer += this->FLOAT16.read(iprot); + this->__isset.FLOAT16 = true; + } else { + xfer += iprot->skip(ftype); + } + break; default: xfer += iprot->skip(ftype); break; @@ -2074,76 +2811,81 @@ uint32_t LogicalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) return xfer; } -uint32_t LogicalType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t LogicalType::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("LogicalType"); if (this->__isset.STRING) { - xfer += oprot->writeFieldBegin("STRING", ::duckdb_apache::thrift::protocol::T_STRUCT, 1); + xfer += oprot->writeFieldBegin("STRING", ::apache::thrift::protocol::T_STRUCT, 1); xfer += this->STRING.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.MAP) { - xfer += oprot->writeFieldBegin("MAP", ::duckdb_apache::thrift::protocol::T_STRUCT, 2); + xfer += oprot->writeFieldBegin("MAP", ::apache::thrift::protocol::T_STRUCT, 2); xfer += this->MAP.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.LIST) { - xfer += oprot->writeFieldBegin("LIST", ::duckdb_apache::thrift::protocol::T_STRUCT, 3); + xfer += oprot->writeFieldBegin("LIST", ::apache::thrift::protocol::T_STRUCT, 3); xfer += this->LIST.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.ENUM) { - xfer += oprot->writeFieldBegin("ENUM", ::duckdb_apache::thrift::protocol::T_STRUCT, 4); + xfer += oprot->writeFieldBegin("ENUM", ::apache::thrift::protocol::T_STRUCT, 4); xfer += this->ENUM.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.DECIMAL) { - xfer += oprot->writeFieldBegin("DECIMAL", ::duckdb_apache::thrift::protocol::T_STRUCT, 5); + xfer += oprot->writeFieldBegin("DECIMAL", ::apache::thrift::protocol::T_STRUCT, 5); xfer += this->DECIMAL.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.DATE) { - xfer += oprot->writeFieldBegin("DATE", ::duckdb_apache::thrift::protocol::T_STRUCT, 6); + xfer += oprot->writeFieldBegin("DATE", ::apache::thrift::protocol::T_STRUCT, 6); xfer += this->DATE.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.TIME) { - xfer += oprot->writeFieldBegin("TIME", ::duckdb_apache::thrift::protocol::T_STRUCT, 7); + xfer += oprot->writeFieldBegin("TIME", ::apache::thrift::protocol::T_STRUCT, 7); xfer += this->TIME.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.TIMESTAMP) { - xfer += oprot->writeFieldBegin("TIMESTAMP", ::duckdb_apache::thrift::protocol::T_STRUCT, 8); + xfer += oprot->writeFieldBegin("TIMESTAMP", ::apache::thrift::protocol::T_STRUCT, 8); xfer += this->TIMESTAMP.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.INTEGER) { - xfer += oprot->writeFieldBegin("INTEGER", ::duckdb_apache::thrift::protocol::T_STRUCT, 10); + xfer += oprot->writeFieldBegin("INTEGER", ::apache::thrift::protocol::T_STRUCT, 10); xfer += this->INTEGER.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.UNKNOWN) { - xfer += oprot->writeFieldBegin("UNKNOWN", ::duckdb_apache::thrift::protocol::T_STRUCT, 11); + xfer += oprot->writeFieldBegin("UNKNOWN", ::apache::thrift::protocol::T_STRUCT, 11); xfer += this->UNKNOWN.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.JSON) { - xfer += oprot->writeFieldBegin("JSON", ::duckdb_apache::thrift::protocol::T_STRUCT, 12); + xfer += oprot->writeFieldBegin("JSON", ::apache::thrift::protocol::T_STRUCT, 12); xfer += this->JSON.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.BSON) { - xfer += oprot->writeFieldBegin("BSON", ::duckdb_apache::thrift::protocol::T_STRUCT, 13); + xfer += oprot->writeFieldBegin("BSON", ::apache::thrift::protocol::T_STRUCT, 13); xfer += this->BSON.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.UUID) { - xfer += oprot->writeFieldBegin("UUID", ::duckdb_apache::thrift::protocol::T_STRUCT, 14); + xfer += oprot->writeFieldBegin("UUID", ::apache::thrift::protocol::T_STRUCT, 14); xfer += this->UUID.write(oprot); xfer += oprot->writeFieldEnd(); } + if (this->__isset.FLOAT16) { + xfer += oprot->writeFieldBegin("FLOAT16", ::apache::thrift::protocol::T_STRUCT, 15); + xfer += this->FLOAT16.write(oprot); + xfer += oprot->writeFieldEnd(); + } xfer += oprot->writeFieldStop(); xfer += oprot->writeStructEnd(); return xfer; @@ -2164,44 +2906,47 @@ void swap(LogicalType &a, LogicalType &b) { swap(a.JSON, b.JSON); swap(a.BSON, b.BSON); swap(a.UUID, b.UUID); + swap(a.FLOAT16, b.FLOAT16); swap(a.__isset, b.__isset); } -LogicalType::LogicalType(const LogicalType& other36) { - STRING = other36.STRING; - MAP = other36.MAP; - LIST = other36.LIST; - ENUM = other36.ENUM; - DECIMAL = other36.DECIMAL; - DATE = other36.DATE; - TIME = other36.TIME; - TIMESTAMP = other36.TIMESTAMP; - INTEGER = other36.INTEGER; - UNKNOWN = other36.UNKNOWN; - JSON = other36.JSON; - BSON = other36.BSON; - UUID = other36.UUID; - __isset = other36.__isset; -} -LogicalType& LogicalType::operator=(const LogicalType& other37) { - STRING = other37.STRING; - MAP = other37.MAP; - LIST = other37.LIST; - ENUM = other37.ENUM; - DECIMAL = other37.DECIMAL; - DATE = other37.DATE; - TIME = other37.TIME; - TIMESTAMP = other37.TIMESTAMP; - INTEGER = other37.INTEGER; - UNKNOWN = other37.UNKNOWN; - JSON = other37.JSON; - BSON = other37.BSON; - UUID = other37.UUID; - __isset = other37.__isset; +LogicalType::LogicalType(const LogicalType& other52) noexcept { + STRING = other52.STRING; + MAP = other52.MAP; + LIST = other52.LIST; + ENUM = other52.ENUM; + DECIMAL = other52.DECIMAL; + DATE = other52.DATE; + TIME = other52.TIME; + TIMESTAMP = other52.TIMESTAMP; + INTEGER = other52.INTEGER; + UNKNOWN = other52.UNKNOWN; + JSON = other52.JSON; + BSON = other52.BSON; + UUID = other52.UUID; + FLOAT16 = other52.FLOAT16; + __isset = other52.__isset; +} +LogicalType& LogicalType::operator=(const LogicalType& other53) noexcept { + STRING = other53.STRING; + MAP = other53.MAP; + LIST = other53.LIST; + ENUM = other53.ENUM; + DECIMAL = other53.DECIMAL; + DATE = other53.DATE; + TIME = other53.TIME; + TIMESTAMP = other53.TIMESTAMP; + INTEGER = other53.INTEGER; + UNKNOWN = other53.UNKNOWN; + JSON = other53.JSON; + BSON = other53.BSON; + UUID = other53.UUID; + FLOAT16 = other53.FLOAT16; + __isset = other53.__isset; return *this; } void LogicalType::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "LogicalType("; out << "STRING="; (__isset.STRING ? (out << to_string(STRING)) : (out << "")); out << ", " << "MAP="; (__isset.MAP ? (out << to_string(MAP)) : (out << "")); @@ -2216,13 +2961,25 @@ void LogicalType::printTo(std::ostream& out) const { out << ", " << "JSON="; (__isset.JSON ? (out << to_string(JSON)) : (out << "")); out << ", " << "BSON="; (__isset.BSON ? (out << to_string(BSON)) : (out << "")); out << ", " << "UUID="; (__isset.UUID ? (out << to_string(UUID)) : (out << "")); + out << ", " << "FLOAT16="; (__isset.FLOAT16 ? (out << to_string(FLOAT16)) : (out << "")); out << ")"; } -SchemaElement::~SchemaElement() throw() { +SchemaElement::~SchemaElement() noexcept { } +SchemaElement::SchemaElement() noexcept + : type(static_cast(0)), + type_length(0), + repetition_type(static_cast(0)), + name(), + num_children(0), + converted_type(static_cast(0)), + scale(0), + precision(0), + field_id(0) { +} void SchemaElement::__set_type(const Type::type val) { this->type = val; @@ -2279,40 +3036,40 @@ std::ostream& operator<<(std::ostream& out, const SchemaElement& obj) } -uint32_t SchemaElement::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t SchemaElement::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_name = false; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - int32_t ecast38; - xfer += iprot->readI32(ecast38); - this->type = (Type::type)ecast38; + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast54; + xfer += iprot->readI32(ecast54); + this->type = static_cast(ecast54); this->__isset.type = true; } else { xfer += iprot->skip(ftype); } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->type_length); this->__isset.type_length = true; } else { @@ -2320,17 +3077,17 @@ uint32_t SchemaElement::read(::duckdb_apache::thrift::protocol::TProtocol* iprot } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - int32_t ecast39; - xfer += iprot->readI32(ecast39); - this->repetition_type = (FieldRepetitionType::type)ecast39; + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast55; + xfer += iprot->readI32(ecast55); + this->repetition_type = static_cast(ecast55); this->__isset.repetition_type = true; } else { xfer += iprot->skip(ftype); } break; case 4: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readString(this->name); isset_name = true; } else { @@ -2338,7 +3095,7 @@ uint32_t SchemaElement::read(::duckdb_apache::thrift::protocol::TProtocol* iprot } break; case 5: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->num_children); this->__isset.num_children = true; } else { @@ -2346,17 +3103,17 @@ uint32_t SchemaElement::read(::duckdb_apache::thrift::protocol::TProtocol* iprot } break; case 6: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - int32_t ecast40; - xfer += iprot->readI32(ecast40); - this->converted_type = (ConvertedType::type)ecast40; + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast56; + xfer += iprot->readI32(ecast56); + this->converted_type = static_cast(ecast56); this->__isset.converted_type = true; } else { xfer += iprot->skip(ftype); } break; case 7: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->scale); this->__isset.scale = true; } else { @@ -2364,7 +3121,7 @@ uint32_t SchemaElement::read(::duckdb_apache::thrift::protocol::TProtocol* iprot } break; case 8: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->precision); this->__isset.precision = true; } else { @@ -2372,7 +3129,7 @@ uint32_t SchemaElement::read(::duckdb_apache::thrift::protocol::TProtocol* iprot } break; case 9: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->field_id); this->__isset.field_id = true; } else { @@ -2380,7 +3137,7 @@ uint32_t SchemaElement::read(::duckdb_apache::thrift::protocol::TProtocol* iprot } break; case 10: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->logicalType.read(iprot); this->__isset.logicalType = true; } else { @@ -2401,57 +3158,57 @@ uint32_t SchemaElement::read(::duckdb_apache::thrift::protocol::TProtocol* iprot return xfer; } -uint32_t SchemaElement::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t SchemaElement::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("SchemaElement"); if (this->__isset.type) { - xfer += oprot->writeFieldBegin("type", ::duckdb_apache::thrift::protocol::T_I32, 1); - xfer += oprot->writeI32((int32_t)this->type); + xfer += oprot->writeFieldBegin("type", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32(static_cast(this->type)); xfer += oprot->writeFieldEnd(); } if (this->__isset.type_length) { - xfer += oprot->writeFieldBegin("type_length", ::duckdb_apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeFieldBegin("type_length", ::apache::thrift::protocol::T_I32, 2); xfer += oprot->writeI32(this->type_length); xfer += oprot->writeFieldEnd(); } if (this->__isset.repetition_type) { - xfer += oprot->writeFieldBegin("repetition_type", ::duckdb_apache::thrift::protocol::T_I32, 3); - xfer += oprot->writeI32((int32_t)this->repetition_type); + xfer += oprot->writeFieldBegin("repetition_type", ::apache::thrift::protocol::T_I32, 3); + xfer += oprot->writeI32(static_cast(this->repetition_type)); xfer += oprot->writeFieldEnd(); } - xfer += oprot->writeFieldBegin("name", ::duckdb_apache::thrift::protocol::T_STRING, 4); + xfer += oprot->writeFieldBegin("name", ::apache::thrift::protocol::T_STRING, 4); xfer += oprot->writeString(this->name); xfer += oprot->writeFieldEnd(); if (this->__isset.num_children) { - xfer += oprot->writeFieldBegin("num_children", ::duckdb_apache::thrift::protocol::T_I32, 5); + xfer += oprot->writeFieldBegin("num_children", ::apache::thrift::protocol::T_I32, 5); xfer += oprot->writeI32(this->num_children); xfer += oprot->writeFieldEnd(); } if (this->__isset.converted_type) { - xfer += oprot->writeFieldBegin("converted_type", ::duckdb_apache::thrift::protocol::T_I32, 6); - xfer += oprot->writeI32((int32_t)this->converted_type); + xfer += oprot->writeFieldBegin("converted_type", ::apache::thrift::protocol::T_I32, 6); + xfer += oprot->writeI32(static_cast(this->converted_type)); xfer += oprot->writeFieldEnd(); } if (this->__isset.scale) { - xfer += oprot->writeFieldBegin("scale", ::duckdb_apache::thrift::protocol::T_I32, 7); + xfer += oprot->writeFieldBegin("scale", ::apache::thrift::protocol::T_I32, 7); xfer += oprot->writeI32(this->scale); xfer += oprot->writeFieldEnd(); } if (this->__isset.precision) { - xfer += oprot->writeFieldBegin("precision", ::duckdb_apache::thrift::protocol::T_I32, 8); + xfer += oprot->writeFieldBegin("precision", ::apache::thrift::protocol::T_I32, 8); xfer += oprot->writeI32(this->precision); xfer += oprot->writeFieldEnd(); } if (this->__isset.field_id) { - xfer += oprot->writeFieldBegin("field_id", ::duckdb_apache::thrift::protocol::T_I32, 9); + xfer += oprot->writeFieldBegin("field_id", ::apache::thrift::protocol::T_I32, 9); xfer += oprot->writeI32(this->field_id); xfer += oprot->writeFieldEnd(); } if (this->__isset.logicalType) { - xfer += oprot->writeFieldBegin("logicalType", ::duckdb_apache::thrift::protocol::T_STRUCT, 10); + xfer += oprot->writeFieldBegin("logicalType", ::apache::thrift::protocol::T_STRUCT, 10); xfer += this->logicalType.write(oprot); xfer += oprot->writeFieldEnd(); } @@ -2475,35 +3232,35 @@ void swap(SchemaElement &a, SchemaElement &b) { swap(a.__isset, b.__isset); } -SchemaElement::SchemaElement(const SchemaElement& other41) { - type = other41.type; - type_length = other41.type_length; - repetition_type = other41.repetition_type; - name = other41.name; - num_children = other41.num_children; - converted_type = other41.converted_type; - scale = other41.scale; - precision = other41.precision; - field_id = other41.field_id; - logicalType = other41.logicalType; - __isset = other41.__isset; +SchemaElement::SchemaElement(const SchemaElement& other57) { + type = other57.type; + type_length = other57.type_length; + repetition_type = other57.repetition_type; + name = other57.name; + num_children = other57.num_children; + converted_type = other57.converted_type; + scale = other57.scale; + precision = other57.precision; + field_id = other57.field_id; + logicalType = other57.logicalType; + __isset = other57.__isset; } -SchemaElement& SchemaElement::operator=(const SchemaElement& other42) { - type = other42.type; - type_length = other42.type_length; - repetition_type = other42.repetition_type; - name = other42.name; - num_children = other42.num_children; - converted_type = other42.converted_type; - scale = other42.scale; - precision = other42.precision; - field_id = other42.field_id; - logicalType = other42.logicalType; - __isset = other42.__isset; +SchemaElement& SchemaElement::operator=(const SchemaElement& other58) { + type = other58.type; + type_length = other58.type_length; + repetition_type = other58.repetition_type; + name = other58.name; + num_children = other58.num_children; + converted_type = other58.converted_type; + scale = other58.scale; + precision = other58.precision; + field_id = other58.field_id; + logicalType = other58.logicalType; + __isset = other58.__isset; return *this; } void SchemaElement::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "SchemaElement("; out << "type="; (__isset.type ? (out << to_string(type)) : (out << "")); out << ", " << "type_length="; (__isset.type_length ? (out << to_string(type_length)) : (out << "")); @@ -2519,9 +3276,15 @@ void SchemaElement::printTo(std::ostream& out) const { } -DataPageHeader::~DataPageHeader() throw() { +DataPageHeader::~DataPageHeader() noexcept { } +DataPageHeader::DataPageHeader() noexcept + : num_values(0), + encoding(static_cast(0)), + definition_level_encoding(static_cast(0)), + repetition_level_encoding(static_cast(0)) { +} void DataPageHeader::__set_num_values(const int32_t val) { this->num_values = val; @@ -2550,17 +3313,17 @@ std::ostream& operator<<(std::ostream& out, const DataPageHeader& obj) } -uint32_t DataPageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t DataPageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_num_values = false; bool isset_encoding = false; @@ -2570,13 +3333,13 @@ uint32_t DataPageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* ipro while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->num_values); isset_num_values = true; } else { @@ -2584,37 +3347,37 @@ uint32_t DataPageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* ipro } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - int32_t ecast43; - xfer += iprot->readI32(ecast43); - this->encoding = (Encoding::type)ecast43; + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast59; + xfer += iprot->readI32(ecast59); + this->encoding = static_cast(ecast59); isset_encoding = true; } else { xfer += iprot->skip(ftype); } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - int32_t ecast44; - xfer += iprot->readI32(ecast44); - this->definition_level_encoding = (Encoding::type)ecast44; + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast60; + xfer += iprot->readI32(ecast60); + this->definition_level_encoding = static_cast(ecast60); isset_definition_level_encoding = true; } else { xfer += iprot->skip(ftype); } break; case 4: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - int32_t ecast45; - xfer += iprot->readI32(ecast45); - this->repetition_level_encoding = (Encoding::type)ecast45; + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast61; + xfer += iprot->readI32(ecast61); + this->repetition_level_encoding = static_cast(ecast61); isset_repetition_level_encoding = true; } else { xfer += iprot->skip(ftype); } break; case 5: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->statistics.read(iprot); this->__isset.statistics = true; } else { @@ -2641,29 +3404,29 @@ uint32_t DataPageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* ipro return xfer; } -uint32_t DataPageHeader::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t DataPageHeader::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("DataPageHeader"); - xfer += oprot->writeFieldBegin("num_values", ::duckdb_apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeFieldBegin("num_values", ::apache::thrift::protocol::T_I32, 1); xfer += oprot->writeI32(this->num_values); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("encoding", ::duckdb_apache::thrift::protocol::T_I32, 2); - xfer += oprot->writeI32((int32_t)this->encoding); + xfer += oprot->writeFieldBegin("encoding", ::apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeI32(static_cast(this->encoding)); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("definition_level_encoding", ::duckdb_apache::thrift::protocol::T_I32, 3); - xfer += oprot->writeI32((int32_t)this->definition_level_encoding); + xfer += oprot->writeFieldBegin("definition_level_encoding", ::apache::thrift::protocol::T_I32, 3); + xfer += oprot->writeI32(static_cast(this->definition_level_encoding)); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("repetition_level_encoding", ::duckdb_apache::thrift::protocol::T_I32, 4); - xfer += oprot->writeI32((int32_t)this->repetition_level_encoding); + xfer += oprot->writeFieldBegin("repetition_level_encoding", ::apache::thrift::protocol::T_I32, 4); + xfer += oprot->writeI32(static_cast(this->repetition_level_encoding)); xfer += oprot->writeFieldEnd(); if (this->__isset.statistics) { - xfer += oprot->writeFieldBegin("statistics", ::duckdb_apache::thrift::protocol::T_STRUCT, 5); + xfer += oprot->writeFieldBegin("statistics", ::apache::thrift::protocol::T_STRUCT, 5); xfer += this->statistics.write(oprot); xfer += oprot->writeFieldEnd(); } @@ -2682,25 +3445,25 @@ void swap(DataPageHeader &a, DataPageHeader &b) { swap(a.__isset, b.__isset); } -DataPageHeader::DataPageHeader(const DataPageHeader& other46) { - num_values = other46.num_values; - encoding = other46.encoding; - definition_level_encoding = other46.definition_level_encoding; - repetition_level_encoding = other46.repetition_level_encoding; - statistics = other46.statistics; - __isset = other46.__isset; -} -DataPageHeader& DataPageHeader::operator=(const DataPageHeader& other47) { - num_values = other47.num_values; - encoding = other47.encoding; - definition_level_encoding = other47.definition_level_encoding; - repetition_level_encoding = other47.repetition_level_encoding; - statistics = other47.statistics; - __isset = other47.__isset; +DataPageHeader::DataPageHeader(const DataPageHeader& other62) { + num_values = other62.num_values; + encoding = other62.encoding; + definition_level_encoding = other62.definition_level_encoding; + repetition_level_encoding = other62.repetition_level_encoding; + statistics = other62.statistics; + __isset = other62.__isset; +} +DataPageHeader& DataPageHeader::operator=(const DataPageHeader& other63) { + num_values = other63.num_values; + encoding = other63.encoding; + definition_level_encoding = other63.definition_level_encoding; + repetition_level_encoding = other63.repetition_level_encoding; + statistics = other63.statistics; + __isset = other63.__isset; return *this; } void DataPageHeader::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "DataPageHeader("; out << "num_values=" << to_string(num_values); out << ", " << "encoding=" << to_string(encoding); @@ -2711,9 +3474,11 @@ void DataPageHeader::printTo(std::ostream& out) const { } -IndexPageHeader::~IndexPageHeader() throw() { +IndexPageHeader::~IndexPageHeader() noexcept { } +IndexPageHeader::IndexPageHeader() noexcept { +} std::ostream& operator<<(std::ostream& out, const IndexPageHeader& obj) { obj.printTo(out); @@ -2721,23 +3486,23 @@ std::ostream& operator<<(std::ostream& out, const IndexPageHeader& obj) } -uint32_t IndexPageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t IndexPageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -2749,9 +3514,9 @@ uint32_t IndexPageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* ipr return xfer; } -uint32_t IndexPageHeader::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t IndexPageHeader::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("IndexPageHeader"); xfer += oprot->writeFieldStop(); @@ -2765,23 +3530,28 @@ void swap(IndexPageHeader &a, IndexPageHeader &b) { (void) b; } -IndexPageHeader::IndexPageHeader(const IndexPageHeader& other48) { - (void) other48; +IndexPageHeader::IndexPageHeader(const IndexPageHeader& other64) noexcept { + (void) other64; } -IndexPageHeader& IndexPageHeader::operator=(const IndexPageHeader& other49) { - (void) other49; +IndexPageHeader& IndexPageHeader::operator=(const IndexPageHeader& other65) noexcept { + (void) other65; return *this; } void IndexPageHeader::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "IndexPageHeader("; out << ")"; } -DictionaryPageHeader::~DictionaryPageHeader() throw() { +DictionaryPageHeader::~DictionaryPageHeader() noexcept { } +DictionaryPageHeader::DictionaryPageHeader() noexcept + : num_values(0), + encoding(static_cast(0)), + is_sorted(0) { +} void DictionaryPageHeader::__set_num_values(const int32_t val) { this->num_values = val; @@ -2802,17 +3572,17 @@ std::ostream& operator<<(std::ostream& out, const DictionaryPageHeader& obj) } -uint32_t DictionaryPageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t DictionaryPageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_num_values = false; bool isset_encoding = false; @@ -2820,13 +3590,13 @@ uint32_t DictionaryPageHeader::read(::duckdb_apache::thrift::protocol::TProtocol while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->num_values); isset_num_values = true; } else { @@ -2834,17 +3604,17 @@ uint32_t DictionaryPageHeader::read(::duckdb_apache::thrift::protocol::TProtocol } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - int32_t ecast50; - xfer += iprot->readI32(ecast50); - this->encoding = (Encoding::type)ecast50; + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast66; + xfer += iprot->readI32(ecast66); + this->encoding = static_cast(ecast66); isset_encoding = true; } else { xfer += iprot->skip(ftype); } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { + if (ftype == ::apache::thrift::protocol::T_BOOL) { xfer += iprot->readBool(this->is_sorted); this->__isset.is_sorted = true; } else { @@ -2867,21 +3637,21 @@ uint32_t DictionaryPageHeader::read(::duckdb_apache::thrift::protocol::TProtocol return xfer; } -uint32_t DictionaryPageHeader::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t DictionaryPageHeader::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("DictionaryPageHeader"); - xfer += oprot->writeFieldBegin("num_values", ::duckdb_apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeFieldBegin("num_values", ::apache::thrift::protocol::T_I32, 1); xfer += oprot->writeI32(this->num_values); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("encoding", ::duckdb_apache::thrift::protocol::T_I32, 2); - xfer += oprot->writeI32((int32_t)this->encoding); + xfer += oprot->writeFieldBegin("encoding", ::apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeI32(static_cast(this->encoding)); xfer += oprot->writeFieldEnd(); if (this->__isset.is_sorted) { - xfer += oprot->writeFieldBegin("is_sorted", ::duckdb_apache::thrift::protocol::T_BOOL, 3); + xfer += oprot->writeFieldBegin("is_sorted", ::apache::thrift::protocol::T_BOOL, 3); xfer += oprot->writeBool(this->is_sorted); xfer += oprot->writeFieldEnd(); } @@ -2898,21 +3668,21 @@ void swap(DictionaryPageHeader &a, DictionaryPageHeader &b) { swap(a.__isset, b.__isset); } -DictionaryPageHeader::DictionaryPageHeader(const DictionaryPageHeader& other51) { - num_values = other51.num_values; - encoding = other51.encoding; - is_sorted = other51.is_sorted; - __isset = other51.__isset; +DictionaryPageHeader::DictionaryPageHeader(const DictionaryPageHeader& other67) noexcept { + num_values = other67.num_values; + encoding = other67.encoding; + is_sorted = other67.is_sorted; + __isset = other67.__isset; } -DictionaryPageHeader& DictionaryPageHeader::operator=(const DictionaryPageHeader& other52) { - num_values = other52.num_values; - encoding = other52.encoding; - is_sorted = other52.is_sorted; - __isset = other52.__isset; +DictionaryPageHeader& DictionaryPageHeader::operator=(const DictionaryPageHeader& other68) noexcept { + num_values = other68.num_values; + encoding = other68.encoding; + is_sorted = other68.is_sorted; + __isset = other68.__isset; return *this; } void DictionaryPageHeader::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "DictionaryPageHeader("; out << "num_values=" << to_string(num_values); out << ", " << "encoding=" << to_string(encoding); @@ -2920,140 +3690,852 @@ void DictionaryPageHeader::printTo(std::ostream& out) const { out << ")"; } - -DataPageHeaderV2::~DataPageHeaderV2() throw() { + +DataPageHeaderV2::~DataPageHeaderV2() noexcept { +} + +DataPageHeaderV2::DataPageHeaderV2() noexcept + : num_values(0), + num_nulls(0), + num_rows(0), + encoding(static_cast(0)), + definition_levels_byte_length(0), + repetition_levels_byte_length(0), + is_compressed(true) { +} + +void DataPageHeaderV2::__set_num_values(const int32_t val) { + this->num_values = val; +} + +void DataPageHeaderV2::__set_num_nulls(const int32_t val) { + this->num_nulls = val; +} + +void DataPageHeaderV2::__set_num_rows(const int32_t val) { + this->num_rows = val; +} + +void DataPageHeaderV2::__set_encoding(const Encoding::type val) { + this->encoding = val; +} + +void DataPageHeaderV2::__set_definition_levels_byte_length(const int32_t val) { + this->definition_levels_byte_length = val; +} + +void DataPageHeaderV2::__set_repetition_levels_byte_length(const int32_t val) { + this->repetition_levels_byte_length = val; +} + +void DataPageHeaderV2::__set_is_compressed(const bool val) { + this->is_compressed = val; +__isset.is_compressed = true; +} + +void DataPageHeaderV2::__set_statistics(const Statistics& val) { + this->statistics = val; +__isset.statistics = true; +} +std::ostream& operator<<(std::ostream& out, const DataPageHeaderV2& obj) +{ + obj.printTo(out); + return out; +} + + +uint32_t DataPageHeaderV2::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + bool isset_num_values = false; + bool isset_num_nulls = false; + bool isset_num_rows = false; + bool isset_encoding = false; + bool isset_definition_levels_byte_length = false; + bool isset_repetition_levels_byte_length = false; + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->num_values); + isset_num_values = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 2: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->num_nulls); + isset_num_nulls = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 3: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->num_rows); + isset_num_rows = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 4: + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast69; + xfer += iprot->readI32(ecast69); + this->encoding = static_cast(ecast69); + isset_encoding = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 5: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->definition_levels_byte_length); + isset_definition_levels_byte_length = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 6: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->repetition_levels_byte_length); + isset_repetition_levels_byte_length = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 7: + if (ftype == ::apache::thrift::protocol::T_BOOL) { + xfer += iprot->readBool(this->is_compressed); + this->__isset.is_compressed = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 8: + if (ftype == ::apache::thrift::protocol::T_STRUCT) { + xfer += this->statistics.read(iprot); + this->__isset.statistics = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + if (!isset_num_values) + throw TProtocolException(TProtocolException::INVALID_DATA); + if (!isset_num_nulls) + throw TProtocolException(TProtocolException::INVALID_DATA); + if (!isset_num_rows) + throw TProtocolException(TProtocolException::INVALID_DATA); + if (!isset_encoding) + throw TProtocolException(TProtocolException::INVALID_DATA); + if (!isset_definition_levels_byte_length) + throw TProtocolException(TProtocolException::INVALID_DATA); + if (!isset_repetition_levels_byte_length) + throw TProtocolException(TProtocolException::INVALID_DATA); + return xfer; +} + +uint32_t DataPageHeaderV2::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("DataPageHeaderV2"); + + xfer += oprot->writeFieldBegin("num_values", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32(this->num_values); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("num_nulls", ::apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeI32(this->num_nulls); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("num_rows", ::apache::thrift::protocol::T_I32, 3); + xfer += oprot->writeI32(this->num_rows); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("encoding", ::apache::thrift::protocol::T_I32, 4); + xfer += oprot->writeI32(static_cast(this->encoding)); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("definition_levels_byte_length", ::apache::thrift::protocol::T_I32, 5); + xfer += oprot->writeI32(this->definition_levels_byte_length); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("repetition_levels_byte_length", ::apache::thrift::protocol::T_I32, 6); + xfer += oprot->writeI32(this->repetition_levels_byte_length); + xfer += oprot->writeFieldEnd(); + + if (this->__isset.is_compressed) { + xfer += oprot->writeFieldBegin("is_compressed", ::apache::thrift::protocol::T_BOOL, 7); + xfer += oprot->writeBool(this->is_compressed); + xfer += oprot->writeFieldEnd(); + } + if (this->__isset.statistics) { + xfer += oprot->writeFieldBegin("statistics", ::apache::thrift::protocol::T_STRUCT, 8); + xfer += this->statistics.write(oprot); + xfer += oprot->writeFieldEnd(); + } + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +void swap(DataPageHeaderV2 &a, DataPageHeaderV2 &b) { + using ::std::swap; + swap(a.num_values, b.num_values); + swap(a.num_nulls, b.num_nulls); + swap(a.num_rows, b.num_rows); + swap(a.encoding, b.encoding); + swap(a.definition_levels_byte_length, b.definition_levels_byte_length); + swap(a.repetition_levels_byte_length, b.repetition_levels_byte_length); + swap(a.is_compressed, b.is_compressed); + swap(a.statistics, b.statistics); + swap(a.__isset, b.__isset); +} + +DataPageHeaderV2::DataPageHeaderV2(const DataPageHeaderV2& other70) { + num_values = other70.num_values; + num_nulls = other70.num_nulls; + num_rows = other70.num_rows; + encoding = other70.encoding; + definition_levels_byte_length = other70.definition_levels_byte_length; + repetition_levels_byte_length = other70.repetition_levels_byte_length; + is_compressed = other70.is_compressed; + statistics = other70.statistics; + __isset = other70.__isset; +} +DataPageHeaderV2& DataPageHeaderV2::operator=(const DataPageHeaderV2& other71) { + num_values = other71.num_values; + num_nulls = other71.num_nulls; + num_rows = other71.num_rows; + encoding = other71.encoding; + definition_levels_byte_length = other71.definition_levels_byte_length; + repetition_levels_byte_length = other71.repetition_levels_byte_length; + is_compressed = other71.is_compressed; + statistics = other71.statistics; + __isset = other71.__isset; + return *this; +} +void DataPageHeaderV2::printTo(std::ostream& out) const { + using ::apache::thrift::to_string; + out << "DataPageHeaderV2("; + out << "num_values=" << to_string(num_values); + out << ", " << "num_nulls=" << to_string(num_nulls); + out << ", " << "num_rows=" << to_string(num_rows); + out << ", " << "encoding=" << to_string(encoding); + out << ", " << "definition_levels_byte_length=" << to_string(definition_levels_byte_length); + out << ", " << "repetition_levels_byte_length=" << to_string(repetition_levels_byte_length); + out << ", " << "is_compressed="; (__isset.is_compressed ? (out << to_string(is_compressed)) : (out << "")); + out << ", " << "statistics="; (__isset.statistics ? (out << to_string(statistics)) : (out << "")); + out << ")"; +} + + +SplitBlockAlgorithm::~SplitBlockAlgorithm() noexcept { +} + +SplitBlockAlgorithm::SplitBlockAlgorithm() noexcept { +} +std::ostream& operator<<(std::ostream& out, const SplitBlockAlgorithm& obj) +{ + obj.printTo(out); + return out; +} + + +uint32_t SplitBlockAlgorithm::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t SplitBlockAlgorithm::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("SplitBlockAlgorithm"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +void swap(SplitBlockAlgorithm &a, SplitBlockAlgorithm &b) { + using ::std::swap; + (void) a; + (void) b; +} + +SplitBlockAlgorithm::SplitBlockAlgorithm(const SplitBlockAlgorithm& other72) noexcept { + (void) other72; +} +SplitBlockAlgorithm& SplitBlockAlgorithm::operator=(const SplitBlockAlgorithm& other73) noexcept { + (void) other73; + return *this; +} +void SplitBlockAlgorithm::printTo(std::ostream& out) const { + using ::apache::thrift::to_string; + out << "SplitBlockAlgorithm("; + out << ")"; +} + + +BloomFilterAlgorithm::~BloomFilterAlgorithm() noexcept { +} + +BloomFilterAlgorithm::BloomFilterAlgorithm() noexcept { +} + +void BloomFilterAlgorithm::__set_BLOCK(const SplitBlockAlgorithm& val) { + this->BLOCK = val; +__isset.BLOCK = true; +} +std::ostream& operator<<(std::ostream& out, const BloomFilterAlgorithm& obj) +{ + obj.printTo(out); + return out; +} + + +uint32_t BloomFilterAlgorithm::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == ::apache::thrift::protocol::T_STRUCT) { + xfer += this->BLOCK.read(iprot); + this->__isset.BLOCK = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BloomFilterAlgorithm::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BloomFilterAlgorithm"); + + if (this->__isset.BLOCK) { + xfer += oprot->writeFieldBegin("BLOCK", ::apache::thrift::protocol::T_STRUCT, 1); + xfer += this->BLOCK.write(oprot); + xfer += oprot->writeFieldEnd(); + } + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +void swap(BloomFilterAlgorithm &a, BloomFilterAlgorithm &b) { + using ::std::swap; + swap(a.BLOCK, b.BLOCK); + swap(a.__isset, b.__isset); +} + +BloomFilterAlgorithm::BloomFilterAlgorithm(const BloomFilterAlgorithm& other74) noexcept { + BLOCK = other74.BLOCK; + __isset = other74.__isset; +} +BloomFilterAlgorithm& BloomFilterAlgorithm::operator=(const BloomFilterAlgorithm& other75) noexcept { + BLOCK = other75.BLOCK; + __isset = other75.__isset; + return *this; +} +void BloomFilterAlgorithm::printTo(std::ostream& out) const { + using ::apache::thrift::to_string; + out << "BloomFilterAlgorithm("; + out << "BLOCK="; (__isset.BLOCK ? (out << to_string(BLOCK)) : (out << "")); + out << ")"; +} + + +XxHash::~XxHash() noexcept { +} + +XxHash::XxHash() noexcept { +} +std::ostream& operator<<(std::ostream& out, const XxHash& obj) +{ + obj.printTo(out); + return out; +} + + +uint32_t XxHash::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t XxHash::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("XxHash"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +void swap(XxHash &a, XxHash &b) { + using ::std::swap; + (void) a; + (void) b; +} + +XxHash::XxHash(const XxHash& other76) noexcept { + (void) other76; +} +XxHash& XxHash::operator=(const XxHash& other77) noexcept { + (void) other77; + return *this; +} +void XxHash::printTo(std::ostream& out) const { + using ::apache::thrift::to_string; + out << "XxHash("; + out << ")"; +} + + +BloomFilterHash::~BloomFilterHash() noexcept { +} + +BloomFilterHash::BloomFilterHash() noexcept { +} + +void BloomFilterHash::__set_XXHASH(const XxHash& val) { + this->XXHASH = val; +__isset.XXHASH = true; +} +std::ostream& operator<<(std::ostream& out, const BloomFilterHash& obj) +{ + obj.printTo(out); + return out; +} + + +uint32_t BloomFilterHash::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == ::apache::thrift::protocol::T_STRUCT) { + xfer += this->XXHASH.read(iprot); + this->__isset.XXHASH = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BloomFilterHash::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BloomFilterHash"); + + if (this->__isset.XXHASH) { + xfer += oprot->writeFieldBegin("XXHASH", ::apache::thrift::protocol::T_STRUCT, 1); + xfer += this->XXHASH.write(oprot); + xfer += oprot->writeFieldEnd(); + } + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +void swap(BloomFilterHash &a, BloomFilterHash &b) { + using ::std::swap; + swap(a.XXHASH, b.XXHASH); + swap(a.__isset, b.__isset); +} + +BloomFilterHash::BloomFilterHash(const BloomFilterHash& other78) noexcept { + XXHASH = other78.XXHASH; + __isset = other78.__isset; +} +BloomFilterHash& BloomFilterHash::operator=(const BloomFilterHash& other79) noexcept { + XXHASH = other79.XXHASH; + __isset = other79.__isset; + return *this; +} +void BloomFilterHash::printTo(std::ostream& out) const { + using ::apache::thrift::to_string; + out << "BloomFilterHash("; + out << "XXHASH="; (__isset.XXHASH ? (out << to_string(XXHASH)) : (out << "")); + out << ")"; +} + + +Uncompressed::~Uncompressed() noexcept { +} + +Uncompressed::Uncompressed() noexcept { +} +std::ostream& operator<<(std::ostream& out, const Uncompressed& obj) +{ + obj.printTo(out); + return out; +} + + +uint32_t Uncompressed::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t Uncompressed::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("Uncompressed"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +void swap(Uncompressed &a, Uncompressed &b) { + using ::std::swap; + (void) a; + (void) b; +} + +Uncompressed::Uncompressed(const Uncompressed& other80) noexcept { + (void) other80; +} +Uncompressed& Uncompressed::operator=(const Uncompressed& other81) noexcept { + (void) other81; + return *this; +} +void Uncompressed::printTo(std::ostream& out) const { + using ::apache::thrift::to_string; + out << "Uncompressed("; + out << ")"; +} + + +BloomFilterCompression::~BloomFilterCompression() noexcept { +} + +BloomFilterCompression::BloomFilterCompression() noexcept { +} + +void BloomFilterCompression::__set_UNCOMPRESSED(const Uncompressed& val) { + this->UNCOMPRESSED = val; +__isset.UNCOMPRESSED = true; +} +std::ostream& operator<<(std::ostream& out, const BloomFilterCompression& obj) +{ + obj.printTo(out); + return out; +} + + +uint32_t BloomFilterCompression::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == ::apache::thrift::protocol::T_STRUCT) { + xfer += this->UNCOMPRESSED.read(iprot); + this->__isset.UNCOMPRESSED = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BloomFilterCompression::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BloomFilterCompression"); + + if (this->__isset.UNCOMPRESSED) { + xfer += oprot->writeFieldBegin("UNCOMPRESSED", ::apache::thrift::protocol::T_STRUCT, 1); + xfer += this->UNCOMPRESSED.write(oprot); + xfer += oprot->writeFieldEnd(); + } + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +void swap(BloomFilterCompression &a, BloomFilterCompression &b) { + using ::std::swap; + swap(a.UNCOMPRESSED, b.UNCOMPRESSED); + swap(a.__isset, b.__isset); } - -void DataPageHeaderV2::__set_num_values(const int32_t val) { - this->num_values = val; +BloomFilterCompression::BloomFilterCompression(const BloomFilterCompression& other82) noexcept { + UNCOMPRESSED = other82.UNCOMPRESSED; + __isset = other82.__isset; } - -void DataPageHeaderV2::__set_num_nulls(const int32_t val) { - this->num_nulls = val; +BloomFilterCompression& BloomFilterCompression::operator=(const BloomFilterCompression& other83) noexcept { + UNCOMPRESSED = other83.UNCOMPRESSED; + __isset = other83.__isset; + return *this; +} +void BloomFilterCompression::printTo(std::ostream& out) const { + using ::apache::thrift::to_string; + out << "BloomFilterCompression("; + out << "UNCOMPRESSED="; (__isset.UNCOMPRESSED ? (out << to_string(UNCOMPRESSED)) : (out << "")); + out << ")"; } -void DataPageHeaderV2::__set_num_rows(const int32_t val) { - this->num_rows = val; + +BloomFilterHeader::~BloomFilterHeader() noexcept { } -void DataPageHeaderV2::__set_encoding(const Encoding::type val) { - this->encoding = val; +BloomFilterHeader::BloomFilterHeader() noexcept + : numBytes(0) { } -void DataPageHeaderV2::__set_definition_levels_byte_length(const int32_t val) { - this->definition_levels_byte_length = val; +void BloomFilterHeader::__set_numBytes(const int32_t val) { + this->numBytes = val; } -void DataPageHeaderV2::__set_repetition_levels_byte_length(const int32_t val) { - this->repetition_levels_byte_length = val; +void BloomFilterHeader::__set_algorithm(const BloomFilterAlgorithm& val) { + this->algorithm = val; } -void DataPageHeaderV2::__set_is_compressed(const bool val) { - this->is_compressed = val; -__isset.is_compressed = true; +void BloomFilterHeader::__set_hash(const BloomFilterHash& val) { + this->hash = val; } -void DataPageHeaderV2::__set_statistics(const Statistics& val) { - this->statistics = val; -__isset.statistics = true; +void BloomFilterHeader::__set_compression(const BloomFilterCompression& val) { + this->compression = val; } -std::ostream& operator<<(std::ostream& out, const DataPageHeaderV2& obj) +std::ostream& operator<<(std::ostream& out, const BloomFilterHeader& obj) { obj.printTo(out); return out; } -uint32_t DataPageHeaderV2::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t BloomFilterHeader::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; - bool isset_num_values = false; - bool isset_num_nulls = false; - bool isset_num_rows = false; - bool isset_encoding = false; - bool isset_definition_levels_byte_length = false; - bool isset_repetition_levels_byte_length = false; + bool isset_numBytes = false; + bool isset_algorithm = false; + bool isset_hash = false; + bool isset_compression = false; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - xfer += iprot->readI32(this->num_values); - isset_num_values = true; + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->numBytes); + isset_numBytes = true; } else { xfer += iprot->skip(ftype); } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - xfer += iprot->readI32(this->num_nulls); - isset_num_nulls = true; + if (ftype == ::apache::thrift::protocol::T_STRUCT) { + xfer += this->algorithm.read(iprot); + isset_algorithm = true; } else { xfer += iprot->skip(ftype); } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - xfer += iprot->readI32(this->num_rows); - isset_num_rows = true; + if (ftype == ::apache::thrift::protocol::T_STRUCT) { + xfer += this->hash.read(iprot); + isset_hash = true; } else { xfer += iprot->skip(ftype); } break; case 4: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - int32_t ecast53; - xfer += iprot->readI32(ecast53); - this->encoding = (Encoding::type)ecast53; - isset_encoding = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 5: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - xfer += iprot->readI32(this->definition_levels_byte_length); - isset_definition_levels_byte_length = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 6: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - xfer += iprot->readI32(this->repetition_levels_byte_length); - isset_repetition_levels_byte_length = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 7: - if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { - xfer += iprot->readBool(this->is_compressed); - this->__isset.is_compressed = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 8: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { - xfer += this->statistics.read(iprot); - this->__isset.statistics = true; + if (ftype == ::apache::thrift::protocol::T_STRUCT) { + xfer += this->compression.read(iprot); + isset_compression = true; } else { xfer += iprot->skip(ftype); } @@ -3067,119 +4549,84 @@ uint32_t DataPageHeaderV2::read(::duckdb_apache::thrift::protocol::TProtocol* ip xfer += iprot->readStructEnd(); - if (!isset_num_values) - throw TProtocolException(TProtocolException::INVALID_DATA); - if (!isset_num_nulls) - throw TProtocolException(TProtocolException::INVALID_DATA); - if (!isset_num_rows) + if (!isset_numBytes) throw TProtocolException(TProtocolException::INVALID_DATA); - if (!isset_encoding) + if (!isset_algorithm) throw TProtocolException(TProtocolException::INVALID_DATA); - if (!isset_definition_levels_byte_length) + if (!isset_hash) throw TProtocolException(TProtocolException::INVALID_DATA); - if (!isset_repetition_levels_byte_length) + if (!isset_compression) throw TProtocolException(TProtocolException::INVALID_DATA); return xfer; } -uint32_t DataPageHeaderV2::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t BloomFilterHeader::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); - xfer += oprot->writeStructBegin("DataPageHeaderV2"); - - xfer += oprot->writeFieldBegin("num_values", ::duckdb_apache::thrift::protocol::T_I32, 1); - xfer += oprot->writeI32(this->num_values); - xfer += oprot->writeFieldEnd(); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BloomFilterHeader"); - xfer += oprot->writeFieldBegin("num_nulls", ::duckdb_apache::thrift::protocol::T_I32, 2); - xfer += oprot->writeI32(this->num_nulls); - xfer += oprot->writeFieldEnd(); - - xfer += oprot->writeFieldBegin("num_rows", ::duckdb_apache::thrift::protocol::T_I32, 3); - xfer += oprot->writeI32(this->num_rows); + xfer += oprot->writeFieldBegin("numBytes", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32(this->numBytes); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("encoding", ::duckdb_apache::thrift::protocol::T_I32, 4); - xfer += oprot->writeI32((int32_t)this->encoding); + xfer += oprot->writeFieldBegin("algorithm", ::apache::thrift::protocol::T_STRUCT, 2); + xfer += this->algorithm.write(oprot); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("definition_levels_byte_length", ::duckdb_apache::thrift::protocol::T_I32, 5); - xfer += oprot->writeI32(this->definition_levels_byte_length); + xfer += oprot->writeFieldBegin("hash", ::apache::thrift::protocol::T_STRUCT, 3); + xfer += this->hash.write(oprot); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("repetition_levels_byte_length", ::duckdb_apache::thrift::protocol::T_I32, 6); - xfer += oprot->writeI32(this->repetition_levels_byte_length); + xfer += oprot->writeFieldBegin("compression", ::apache::thrift::protocol::T_STRUCT, 4); + xfer += this->compression.write(oprot); xfer += oprot->writeFieldEnd(); - if (this->__isset.is_compressed) { - xfer += oprot->writeFieldBegin("is_compressed", ::duckdb_apache::thrift::protocol::T_BOOL, 7); - xfer += oprot->writeBool(this->is_compressed); - xfer += oprot->writeFieldEnd(); - } - if (this->__isset.statistics) { - xfer += oprot->writeFieldBegin("statistics", ::duckdb_apache::thrift::protocol::T_STRUCT, 8); - xfer += this->statistics.write(oprot); - xfer += oprot->writeFieldEnd(); - } xfer += oprot->writeFieldStop(); xfer += oprot->writeStructEnd(); return xfer; } -void swap(DataPageHeaderV2 &a, DataPageHeaderV2 &b) { +void swap(BloomFilterHeader &a, BloomFilterHeader &b) { using ::std::swap; - swap(a.num_values, b.num_values); - swap(a.num_nulls, b.num_nulls); - swap(a.num_rows, b.num_rows); - swap(a.encoding, b.encoding); - swap(a.definition_levels_byte_length, b.definition_levels_byte_length); - swap(a.repetition_levels_byte_length, b.repetition_levels_byte_length); - swap(a.is_compressed, b.is_compressed); - swap(a.statistics, b.statistics); - swap(a.__isset, b.__isset); -} - -DataPageHeaderV2::DataPageHeaderV2(const DataPageHeaderV2& other54) { - num_values = other54.num_values; - num_nulls = other54.num_nulls; - num_rows = other54.num_rows; - encoding = other54.encoding; - definition_levels_byte_length = other54.definition_levels_byte_length; - repetition_levels_byte_length = other54.repetition_levels_byte_length; - is_compressed = other54.is_compressed; - statistics = other54.statistics; - __isset = other54.__isset; -} -DataPageHeaderV2& DataPageHeaderV2::operator=(const DataPageHeaderV2& other55) { - num_values = other55.num_values; - num_nulls = other55.num_nulls; - num_rows = other55.num_rows; - encoding = other55.encoding; - definition_levels_byte_length = other55.definition_levels_byte_length; - repetition_levels_byte_length = other55.repetition_levels_byte_length; - is_compressed = other55.is_compressed; - statistics = other55.statistics; - __isset = other55.__isset; + swap(a.numBytes, b.numBytes); + swap(a.algorithm, b.algorithm); + swap(a.hash, b.hash); + swap(a.compression, b.compression); +} + +BloomFilterHeader::BloomFilterHeader(const BloomFilterHeader& other84) noexcept { + numBytes = other84.numBytes; + algorithm = other84.algorithm; + hash = other84.hash; + compression = other84.compression; +} +BloomFilterHeader& BloomFilterHeader::operator=(const BloomFilterHeader& other85) noexcept { + numBytes = other85.numBytes; + algorithm = other85.algorithm; + hash = other85.hash; + compression = other85.compression; return *this; } -void DataPageHeaderV2::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; - out << "DataPageHeaderV2("; - out << "num_values=" << to_string(num_values); - out << ", " << "num_nulls=" << to_string(num_nulls); - out << ", " << "num_rows=" << to_string(num_rows); - out << ", " << "encoding=" << to_string(encoding); - out << ", " << "definition_levels_byte_length=" << to_string(definition_levels_byte_length); - out << ", " << "repetition_levels_byte_length=" << to_string(repetition_levels_byte_length); - out << ", " << "is_compressed="; (__isset.is_compressed ? (out << to_string(is_compressed)) : (out << "")); - out << ", " << "statistics="; (__isset.statistics ? (out << to_string(statistics)) : (out << "")); +void BloomFilterHeader::printTo(std::ostream& out) const { + using ::apache::thrift::to_string; + out << "BloomFilterHeader("; + out << "numBytes=" << to_string(numBytes); + out << ", " << "algorithm=" << to_string(algorithm); + out << ", " << "hash=" << to_string(hash); + out << ", " << "compression=" << to_string(compression); out << ")"; } -PageHeader::~PageHeader() throw() { +PageHeader::~PageHeader() noexcept { } +PageHeader::PageHeader() noexcept + : type(static_cast(0)), + uncompressed_page_size(0), + compressed_page_size(0), + crc(0) { +} void PageHeader::__set_type(const PageType::type val) { this->type = val; @@ -3224,17 +4671,17 @@ std::ostream& operator<<(std::ostream& out, const PageHeader& obj) } -uint32_t PageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t PageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_type = false; bool isset_uncompressed_page_size = false; @@ -3243,23 +4690,23 @@ uint32_t PageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - int32_t ecast56; - xfer += iprot->readI32(ecast56); - this->type = (PageType::type)ecast56; + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast86; + xfer += iprot->readI32(ecast86); + this->type = static_cast(ecast86); isset_type = true; } else { xfer += iprot->skip(ftype); } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->uncompressed_page_size); isset_uncompressed_page_size = true; } else { @@ -3267,7 +4714,7 @@ uint32_t PageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->compressed_page_size); isset_compressed_page_size = true; } else { @@ -3275,7 +4722,7 @@ uint32_t PageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 4: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->crc); this->__isset.crc = true; } else { @@ -3283,7 +4730,7 @@ uint32_t PageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 5: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->data_page_header.read(iprot); this->__isset.data_page_header = true; } else { @@ -3291,7 +4738,7 @@ uint32_t PageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 6: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->index_page_header.read(iprot); this->__isset.index_page_header = true; } else { @@ -3299,7 +4746,7 @@ uint32_t PageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 7: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->dictionary_page_header.read(iprot); this->__isset.dictionary_page_header = true; } else { @@ -3307,7 +4754,7 @@ uint32_t PageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 8: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->data_page_header_v2.read(iprot); this->__isset.data_page_header_v2 = true; } else { @@ -3332,45 +4779,45 @@ uint32_t PageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t PageHeader::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t PageHeader::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("PageHeader"); - xfer += oprot->writeFieldBegin("type", ::duckdb_apache::thrift::protocol::T_I32, 1); - xfer += oprot->writeI32((int32_t)this->type); + xfer += oprot->writeFieldBegin("type", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32(static_cast(this->type)); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("uncompressed_page_size", ::duckdb_apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeFieldBegin("uncompressed_page_size", ::apache::thrift::protocol::T_I32, 2); xfer += oprot->writeI32(this->uncompressed_page_size); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("compressed_page_size", ::duckdb_apache::thrift::protocol::T_I32, 3); + xfer += oprot->writeFieldBegin("compressed_page_size", ::apache::thrift::protocol::T_I32, 3); xfer += oprot->writeI32(this->compressed_page_size); xfer += oprot->writeFieldEnd(); if (this->__isset.crc) { - xfer += oprot->writeFieldBegin("crc", ::duckdb_apache::thrift::protocol::T_I32, 4); + xfer += oprot->writeFieldBegin("crc", ::apache::thrift::protocol::T_I32, 4); xfer += oprot->writeI32(this->crc); xfer += oprot->writeFieldEnd(); } if (this->__isset.data_page_header) { - xfer += oprot->writeFieldBegin("data_page_header", ::duckdb_apache::thrift::protocol::T_STRUCT, 5); + xfer += oprot->writeFieldBegin("data_page_header", ::apache::thrift::protocol::T_STRUCT, 5); xfer += this->data_page_header.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.index_page_header) { - xfer += oprot->writeFieldBegin("index_page_header", ::duckdb_apache::thrift::protocol::T_STRUCT, 6); + xfer += oprot->writeFieldBegin("index_page_header", ::apache::thrift::protocol::T_STRUCT, 6); xfer += this->index_page_header.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.dictionary_page_header) { - xfer += oprot->writeFieldBegin("dictionary_page_header", ::duckdb_apache::thrift::protocol::T_STRUCT, 7); + xfer += oprot->writeFieldBegin("dictionary_page_header", ::apache::thrift::protocol::T_STRUCT, 7); xfer += this->dictionary_page_header.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.data_page_header_v2) { - xfer += oprot->writeFieldBegin("data_page_header_v2", ::duckdb_apache::thrift::protocol::T_STRUCT, 8); + xfer += oprot->writeFieldBegin("data_page_header_v2", ::apache::thrift::protocol::T_STRUCT, 8); xfer += this->data_page_header_v2.write(oprot); xfer += oprot->writeFieldEnd(); } @@ -3392,31 +4839,31 @@ void swap(PageHeader &a, PageHeader &b) { swap(a.__isset, b.__isset); } -PageHeader::PageHeader(const PageHeader& other57) { - type = other57.type; - uncompressed_page_size = other57.uncompressed_page_size; - compressed_page_size = other57.compressed_page_size; - crc = other57.crc; - data_page_header = other57.data_page_header; - index_page_header = other57.index_page_header; - dictionary_page_header = other57.dictionary_page_header; - data_page_header_v2 = other57.data_page_header_v2; - __isset = other57.__isset; -} -PageHeader& PageHeader::operator=(const PageHeader& other58) { - type = other58.type; - uncompressed_page_size = other58.uncompressed_page_size; - compressed_page_size = other58.compressed_page_size; - crc = other58.crc; - data_page_header = other58.data_page_header; - index_page_header = other58.index_page_header; - dictionary_page_header = other58.dictionary_page_header; - data_page_header_v2 = other58.data_page_header_v2; - __isset = other58.__isset; +PageHeader::PageHeader(const PageHeader& other87) { + type = other87.type; + uncompressed_page_size = other87.uncompressed_page_size; + compressed_page_size = other87.compressed_page_size; + crc = other87.crc; + data_page_header = other87.data_page_header; + index_page_header = other87.index_page_header; + dictionary_page_header = other87.dictionary_page_header; + data_page_header_v2 = other87.data_page_header_v2; + __isset = other87.__isset; +} +PageHeader& PageHeader::operator=(const PageHeader& other88) { + type = other88.type; + uncompressed_page_size = other88.uncompressed_page_size; + compressed_page_size = other88.compressed_page_size; + crc = other88.crc; + data_page_header = other88.data_page_header; + index_page_header = other88.index_page_header; + dictionary_page_header = other88.dictionary_page_header; + data_page_header_v2 = other88.data_page_header_v2; + __isset = other88.__isset; return *this; } void PageHeader::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "PageHeader("; out << "type=" << to_string(type); out << ", " << "uncompressed_page_size=" << to_string(uncompressed_page_size); @@ -3430,9 +4877,13 @@ void PageHeader::printTo(std::ostream& out) const { } -KeyValue::~KeyValue() throw() { +KeyValue::~KeyValue() noexcept { } +KeyValue::KeyValue() noexcept + : key(), + value() { +} void KeyValue::__set_key(const std::string& val) { this->key = val; @@ -3449,30 +4900,30 @@ std::ostream& operator<<(std::ostream& out, const KeyValue& obj) } -uint32_t KeyValue::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t KeyValue::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_key = false; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readString(this->key); isset_key = true; } else { @@ -3480,7 +4931,7 @@ uint32_t KeyValue::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readString(this->value); this->__isset.value = true; } else { @@ -3501,17 +4952,17 @@ uint32_t KeyValue::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t KeyValue::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t KeyValue::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("KeyValue"); - xfer += oprot->writeFieldBegin("key", ::duckdb_apache::thrift::protocol::T_STRING, 1); + xfer += oprot->writeFieldBegin("key", ::apache::thrift::protocol::T_STRING, 1); xfer += oprot->writeString(this->key); xfer += oprot->writeFieldEnd(); if (this->__isset.value) { - xfer += oprot->writeFieldBegin("value", ::duckdb_apache::thrift::protocol::T_STRING, 2); + xfer += oprot->writeFieldBegin("value", ::apache::thrift::protocol::T_STRING, 2); xfer += oprot->writeString(this->value); xfer += oprot->writeFieldEnd(); } @@ -3527,19 +4978,19 @@ void swap(KeyValue &a, KeyValue &b) { swap(a.__isset, b.__isset); } -KeyValue::KeyValue(const KeyValue& other59) { - key = other59.key; - value = other59.value; - __isset = other59.__isset; +KeyValue::KeyValue(const KeyValue& other89) { + key = other89.key; + value = other89.value; + __isset = other89.__isset; } -KeyValue& KeyValue::operator=(const KeyValue& other60) { - key = other60.key; - value = other60.value; - __isset = other60.__isset; +KeyValue& KeyValue::operator=(const KeyValue& other90) { + key = other90.key; + value = other90.value; + __isset = other90.__isset; return *this; } void KeyValue::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "KeyValue("; out << "key=" << to_string(key); out << ", " << "value="; (__isset.value ? (out << to_string(value)) : (out << "")); @@ -3547,9 +4998,14 @@ void KeyValue::printTo(std::ostream& out) const { } -SortingColumn::~SortingColumn() throw() { +SortingColumn::~SortingColumn() noexcept { } +SortingColumn::SortingColumn() noexcept + : column_idx(0), + descending(0), + nulls_first(0) { +} void SortingColumn::__set_column_idx(const int32_t val) { this->column_idx = val; @@ -3569,17 +5025,17 @@ std::ostream& operator<<(std::ostream& out, const SortingColumn& obj) } -uint32_t SortingColumn::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t SortingColumn::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_column_idx = false; bool isset_descending = false; @@ -3588,13 +5044,13 @@ uint32_t SortingColumn::read(::duckdb_apache::thrift::protocol::TProtocol* iprot while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->column_idx); isset_column_idx = true; } else { @@ -3602,7 +5058,7 @@ uint32_t SortingColumn::read(::duckdb_apache::thrift::protocol::TProtocol* iprot } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { + if (ftype == ::apache::thrift::protocol::T_BOOL) { xfer += iprot->readBool(this->descending); isset_descending = true; } else { @@ -3610,7 +5066,7 @@ uint32_t SortingColumn::read(::duckdb_apache::thrift::protocol::TProtocol* iprot } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { + if (ftype == ::apache::thrift::protocol::T_BOOL) { xfer += iprot->readBool(this->nulls_first); isset_nulls_first = true; } else { @@ -3635,20 +5091,20 @@ uint32_t SortingColumn::read(::duckdb_apache::thrift::protocol::TProtocol* iprot return xfer; } -uint32_t SortingColumn::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t SortingColumn::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("SortingColumn"); - xfer += oprot->writeFieldBegin("column_idx", ::duckdb_apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeFieldBegin("column_idx", ::apache::thrift::protocol::T_I32, 1); xfer += oprot->writeI32(this->column_idx); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("descending", ::duckdb_apache::thrift::protocol::T_BOOL, 2); + xfer += oprot->writeFieldBegin("descending", ::apache::thrift::protocol::T_BOOL, 2); xfer += oprot->writeBool(this->descending); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("nulls_first", ::duckdb_apache::thrift::protocol::T_BOOL, 3); + xfer += oprot->writeFieldBegin("nulls_first", ::apache::thrift::protocol::T_BOOL, 3); xfer += oprot->writeBool(this->nulls_first); xfer += oprot->writeFieldEnd(); @@ -3664,19 +5120,19 @@ void swap(SortingColumn &a, SortingColumn &b) { swap(a.nulls_first, b.nulls_first); } -SortingColumn::SortingColumn(const SortingColumn& other61) { - column_idx = other61.column_idx; - descending = other61.descending; - nulls_first = other61.nulls_first; +SortingColumn::SortingColumn(const SortingColumn& other91) noexcept { + column_idx = other91.column_idx; + descending = other91.descending; + nulls_first = other91.nulls_first; } -SortingColumn& SortingColumn::operator=(const SortingColumn& other62) { - column_idx = other62.column_idx; - descending = other62.descending; - nulls_first = other62.nulls_first; +SortingColumn& SortingColumn::operator=(const SortingColumn& other92) noexcept { + column_idx = other92.column_idx; + descending = other92.descending; + nulls_first = other92.nulls_first; return *this; } void SortingColumn::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "SortingColumn("; out << "column_idx=" << to_string(column_idx); out << ", " << "descending=" << to_string(descending); @@ -3685,9 +5141,14 @@ void SortingColumn::printTo(std::ostream& out) const { } -PageEncodingStats::~PageEncodingStats() throw() { +PageEncodingStats::~PageEncodingStats() noexcept { } +PageEncodingStats::PageEncodingStats() noexcept + : page_type(static_cast(0)), + encoding(static_cast(0)), + count(0) { +} void PageEncodingStats::__set_page_type(const PageType::type val) { this->page_type = val; @@ -3707,17 +5168,17 @@ std::ostream& operator<<(std::ostream& out, const PageEncodingStats& obj) } -uint32_t PageEncodingStats::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t PageEncodingStats::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_page_type = false; bool isset_encoding = false; @@ -3726,33 +5187,33 @@ uint32_t PageEncodingStats::read(::duckdb_apache::thrift::protocol::TProtocol* i while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - int32_t ecast63; - xfer += iprot->readI32(ecast63); - this->page_type = (PageType::type)ecast63; + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast93; + xfer += iprot->readI32(ecast93); + this->page_type = static_cast(ecast93); isset_page_type = true; } else { xfer += iprot->skip(ftype); } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - int32_t ecast64; - xfer += iprot->readI32(ecast64); - this->encoding = (Encoding::type)ecast64; + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast94; + xfer += iprot->readI32(ecast94); + this->encoding = static_cast(ecast94); isset_encoding = true; } else { xfer += iprot->skip(ftype); } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->count); isset_count = true; } else { @@ -3777,20 +5238,20 @@ uint32_t PageEncodingStats::read(::duckdb_apache::thrift::protocol::TProtocol* i return xfer; } -uint32_t PageEncodingStats::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t PageEncodingStats::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("PageEncodingStats"); - xfer += oprot->writeFieldBegin("page_type", ::duckdb_apache::thrift::protocol::T_I32, 1); - xfer += oprot->writeI32((int32_t)this->page_type); + xfer += oprot->writeFieldBegin("page_type", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32(static_cast(this->page_type)); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("encoding", ::duckdb_apache::thrift::protocol::T_I32, 2); - xfer += oprot->writeI32((int32_t)this->encoding); + xfer += oprot->writeFieldBegin("encoding", ::apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeI32(static_cast(this->encoding)); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("count", ::duckdb_apache::thrift::protocol::T_I32, 3); + xfer += oprot->writeFieldBegin("count", ::apache::thrift::protocol::T_I32, 3); xfer += oprot->writeI32(this->count); xfer += oprot->writeFieldEnd(); @@ -3806,19 +5267,19 @@ void swap(PageEncodingStats &a, PageEncodingStats &b) { swap(a.count, b.count); } -PageEncodingStats::PageEncodingStats(const PageEncodingStats& other65) { - page_type = other65.page_type; - encoding = other65.encoding; - count = other65.count; +PageEncodingStats::PageEncodingStats(const PageEncodingStats& other95) noexcept { + page_type = other95.page_type; + encoding = other95.encoding; + count = other95.count; } -PageEncodingStats& PageEncodingStats::operator=(const PageEncodingStats& other66) { - page_type = other66.page_type; - encoding = other66.encoding; - count = other66.count; +PageEncodingStats& PageEncodingStats::operator=(const PageEncodingStats& other96) noexcept { + page_type = other96.page_type; + encoding = other96.encoding; + count = other96.count; return *this; } void PageEncodingStats::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "PageEncodingStats("; out << "page_type=" << to_string(page_type); out << ", " << "encoding=" << to_string(encoding); @@ -3827,9 +5288,21 @@ void PageEncodingStats::printTo(std::ostream& out) const { } -ColumnMetaData::~ColumnMetaData() throw() { +ColumnMetaData::~ColumnMetaData() noexcept { } +ColumnMetaData::ColumnMetaData() noexcept + : type(static_cast(0)), + codec(static_cast(0)), + num_values(0), + total_uncompressed_size(0), + total_compressed_size(0), + data_page_offset(0), + index_page_offset(0), + dictionary_page_offset(0), + bloom_filter_offset(0), + bloom_filter_length(0) { +} void ColumnMetaData::__set_type(const Type::type val) { this->type = val; @@ -3887,6 +5360,21 @@ void ColumnMetaData::__set_encoding_stats(const duckdb::vectorencoding_stats = val; __isset.encoding_stats = true; } + +void ColumnMetaData::__set_bloom_filter_offset(const int64_t val) { + this->bloom_filter_offset = val; +__isset.bloom_filter_offset = true; +} + +void ColumnMetaData::__set_bloom_filter_length(const int32_t val) { + this->bloom_filter_length = val; +__isset.bloom_filter_length = true; +} + +void ColumnMetaData::__set_size_statistics(const SizeStatistics& val) { + this->size_statistics = val; +__isset.size_statistics = true; +} std::ostream& operator<<(std::ostream& out, const ColumnMetaData& obj) { obj.printTo(out); @@ -3894,17 +5382,17 @@ std::ostream& operator<<(std::ostream& out, const ColumnMetaData& obj) } -uint32_t ColumnMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t ColumnMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_type = false; bool isset_encodings = false; @@ -3918,35 +5406,35 @@ uint32_t ColumnMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* ipro while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - int32_t ecast67; - xfer += iprot->readI32(ecast67); - this->type = (Type::type)ecast67; + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast97; + xfer += iprot->readI32(ecast97); + this->type = static_cast(ecast97); isset_type = true; } else { xfer += iprot->skip(ftype); } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { + if (ftype == ::apache::thrift::protocol::T_LIST) { { this->encodings.clear(); - uint32_t _size68; - ::duckdb_apache::thrift::protocol::TType _etype71; - xfer += iprot->readListBegin(_etype71, _size68); - this->encodings.resize(_size68); - uint32_t _i72; - for (_i72 = 0; _i72 < _size68; ++_i72) + uint32_t _size98; + ::apache::thrift::protocol::TType _etype101; + xfer += iprot->readListBegin(_etype101, _size98); + this->encodings.resize(_size98); + uint32_t _i102; + for (_i102 = 0; _i102 < _size98; ++_i102) { - int32_t ecast73; - xfer += iprot->readI32(ecast73); - this->encodings[_i72] = (Encoding::type)ecast73; + int32_t ecast103; + xfer += iprot->readI32(ecast103); + this->encodings[_i102] = static_cast(ecast103); } xfer += iprot->readListEnd(); } @@ -3956,17 +5444,17 @@ uint32_t ColumnMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* ipro } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { + if (ftype == ::apache::thrift::protocol::T_LIST) { { this->path_in_schema.clear(); - uint32_t _size74; - ::duckdb_apache::thrift::protocol::TType _etype77; - xfer += iprot->readListBegin(_etype77, _size74); - this->path_in_schema.resize(_size74); - uint32_t _i78; - for (_i78 = 0; _i78 < _size74; ++_i78) + uint32_t _size104; + ::apache::thrift::protocol::TType _etype107; + xfer += iprot->readListBegin(_etype107, _size104); + this->path_in_schema.resize(_size104); + uint32_t _i108; + for (_i108 = 0; _i108 < _size104; ++_i108) { - xfer += iprot->readString(this->path_in_schema[_i78]); + xfer += iprot->readString(this->path_in_schema[_i108]); } xfer += iprot->readListEnd(); } @@ -3976,17 +5464,17 @@ uint32_t ColumnMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* ipro } break; case 4: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - int32_t ecast79; - xfer += iprot->readI32(ecast79); - this->codec = (CompressionCodec::type)ecast79; + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast109; + xfer += iprot->readI32(ecast109); + this->codec = static_cast(ecast109); isset_codec = true; } else { xfer += iprot->skip(ftype); } break; case 5: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->num_values); isset_num_values = true; } else { @@ -3994,7 +5482,7 @@ uint32_t ColumnMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* ipro } break; case 6: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->total_uncompressed_size); isset_total_uncompressed_size = true; } else { @@ -4002,7 +5490,7 @@ uint32_t ColumnMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* ipro } break; case 7: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->total_compressed_size); isset_total_compressed_size = true; } else { @@ -4010,17 +5498,17 @@ uint32_t ColumnMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* ipro } break; case 8: - if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { + if (ftype == ::apache::thrift::protocol::T_LIST) { { this->key_value_metadata.clear(); - uint32_t _size80; - ::duckdb_apache::thrift::protocol::TType _etype83; - xfer += iprot->readListBegin(_etype83, _size80); - this->key_value_metadata.resize(_size80); - uint32_t _i84; - for (_i84 = 0; _i84 < _size80; ++_i84) + uint32_t _size110; + ::apache::thrift::protocol::TType _etype113; + xfer += iprot->readListBegin(_etype113, _size110); + this->key_value_metadata.resize(_size110); + uint32_t _i114; + for (_i114 = 0; _i114 < _size110; ++_i114) { - xfer += this->key_value_metadata[_i84].read(iprot); + xfer += this->key_value_metadata[_i114].read(iprot); } xfer += iprot->readListEnd(); } @@ -4030,7 +5518,7 @@ uint32_t ColumnMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* ipro } break; case 9: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->data_page_offset); isset_data_page_offset = true; } else { @@ -4038,7 +5526,7 @@ uint32_t ColumnMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* ipro } break; case 10: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->index_page_offset); this->__isset.index_page_offset = true; } else { @@ -4046,7 +5534,7 @@ uint32_t ColumnMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* ipro } break; case 11: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->dictionary_page_offset); this->__isset.dictionary_page_offset = true; } else { @@ -4054,7 +5542,7 @@ uint32_t ColumnMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* ipro } break; case 12: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->statistics.read(iprot); this->__isset.statistics = true; } else { @@ -4062,17 +5550,17 @@ uint32_t ColumnMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* ipro } break; case 13: - if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { + if (ftype == ::apache::thrift::protocol::T_LIST) { { this->encoding_stats.clear(); - uint32_t _size85; - ::duckdb_apache::thrift::protocol::TType _etype88; - xfer += iprot->readListBegin(_etype88, _size85); - this->encoding_stats.resize(_size85); - uint32_t _i89; - for (_i89 = 0; _i89 < _size85; ++_i89) + uint32_t _size115; + ::apache::thrift::protocol::TType _etype118; + xfer += iprot->readListBegin(_etype118, _size115); + this->encoding_stats.resize(_size115); + uint32_t _i119; + for (_i119 = 0; _i119 < _size115; ++_i119) { - xfer += this->encoding_stats[_i89].read(iprot); + xfer += this->encoding_stats[_i119].read(iprot); } xfer += iprot->readListEnd(); } @@ -4081,6 +5569,30 @@ uint32_t ColumnMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* ipro xfer += iprot->skip(ftype); } break; + case 14: + if (ftype == ::apache::thrift::protocol::T_I64) { + xfer += iprot->readI64(this->bloom_filter_offset); + this->__isset.bloom_filter_offset = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 15: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->bloom_filter_length); + this->__isset.bloom_filter_length = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 16: + if (ftype == ::apache::thrift::protocol::T_STRUCT) { + xfer += this->size_statistics.read(iprot); + this->__isset.size_statistics = true; + } else { + xfer += iprot->skip(ftype); + } + break; default: xfer += iprot->skip(ftype); break; @@ -4109,100 +5621,115 @@ uint32_t ColumnMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* ipro return xfer; } -uint32_t ColumnMetaData::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t ColumnMetaData::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("ColumnMetaData"); - xfer += oprot->writeFieldBegin("type", ::duckdb_apache::thrift::protocol::T_I32, 1); - xfer += oprot->writeI32((int32_t)this->type); + xfer += oprot->writeFieldBegin("type", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32(static_cast(this->type)); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("encodings", ::duckdb_apache::thrift::protocol::T_LIST, 2); + xfer += oprot->writeFieldBegin("encodings", ::apache::thrift::protocol::T_LIST, 2); { - xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_I32, static_cast(this->encodings.size())); - duckdb::vector ::const_iterator _iter90; - for (_iter90 = this->encodings.begin(); _iter90 != this->encodings.end(); ++_iter90) + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I32, static_cast(this->encodings.size())); + duckdb::vector ::const_iterator _iter120; + for (_iter120 = this->encodings.begin(); _iter120 != this->encodings.end(); ++_iter120) { - xfer += oprot->writeI32((int32_t)(*_iter90)); + xfer += oprot->writeI32(static_cast((*_iter120))); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("path_in_schema", ::duckdb_apache::thrift::protocol::T_LIST, 3); + xfer += oprot->writeFieldBegin("path_in_schema", ::apache::thrift::protocol::T_LIST, 3); { - xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRING, static_cast(this->path_in_schema.size())); - duckdb::vector ::const_iterator _iter91; - for (_iter91 = this->path_in_schema.begin(); _iter91 != this->path_in_schema.end(); ++_iter91) + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRING, static_cast(this->path_in_schema.size())); + duckdb::vector ::const_iterator _iter121; + for (_iter121 = this->path_in_schema.begin(); _iter121 != this->path_in_schema.end(); ++_iter121) { - xfer += oprot->writeString((*_iter91)); + xfer += oprot->writeString((*_iter121)); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("codec", ::duckdb_apache::thrift::protocol::T_I32, 4); - xfer += oprot->writeI32((int32_t)this->codec); + xfer += oprot->writeFieldBegin("codec", ::apache::thrift::protocol::T_I32, 4); + xfer += oprot->writeI32(static_cast(this->codec)); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("num_values", ::duckdb_apache::thrift::protocol::T_I64, 5); + xfer += oprot->writeFieldBegin("num_values", ::apache::thrift::protocol::T_I64, 5); xfer += oprot->writeI64(this->num_values); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("total_uncompressed_size", ::duckdb_apache::thrift::protocol::T_I64, 6); + xfer += oprot->writeFieldBegin("total_uncompressed_size", ::apache::thrift::protocol::T_I64, 6); xfer += oprot->writeI64(this->total_uncompressed_size); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("total_compressed_size", ::duckdb_apache::thrift::protocol::T_I64, 7); + xfer += oprot->writeFieldBegin("total_compressed_size", ::apache::thrift::protocol::T_I64, 7); xfer += oprot->writeI64(this->total_compressed_size); xfer += oprot->writeFieldEnd(); if (this->__isset.key_value_metadata) { - xfer += oprot->writeFieldBegin("key_value_metadata", ::duckdb_apache::thrift::protocol::T_LIST, 8); + xfer += oprot->writeFieldBegin("key_value_metadata", ::apache::thrift::protocol::T_LIST, 8); { - xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->key_value_metadata.size())); - duckdb::vector ::const_iterator _iter92; - for (_iter92 = this->key_value_metadata.begin(); _iter92 != this->key_value_metadata.end(); ++_iter92) + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->key_value_metadata.size())); + duckdb::vector ::const_iterator _iter122; + for (_iter122 = this->key_value_metadata.begin(); _iter122 != this->key_value_metadata.end(); ++_iter122) { - xfer += (*_iter92).write(oprot); + xfer += (*_iter122).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); } - xfer += oprot->writeFieldBegin("data_page_offset", ::duckdb_apache::thrift::protocol::T_I64, 9); + xfer += oprot->writeFieldBegin("data_page_offset", ::apache::thrift::protocol::T_I64, 9); xfer += oprot->writeI64(this->data_page_offset); xfer += oprot->writeFieldEnd(); if (this->__isset.index_page_offset) { - xfer += oprot->writeFieldBegin("index_page_offset", ::duckdb_apache::thrift::protocol::T_I64, 10); + xfer += oprot->writeFieldBegin("index_page_offset", ::apache::thrift::protocol::T_I64, 10); xfer += oprot->writeI64(this->index_page_offset); xfer += oprot->writeFieldEnd(); } if (this->__isset.dictionary_page_offset) { - xfer += oprot->writeFieldBegin("dictionary_page_offset", ::duckdb_apache::thrift::protocol::T_I64, 11); + xfer += oprot->writeFieldBegin("dictionary_page_offset", ::apache::thrift::protocol::T_I64, 11); xfer += oprot->writeI64(this->dictionary_page_offset); xfer += oprot->writeFieldEnd(); } if (this->__isset.statistics) { - xfer += oprot->writeFieldBegin("statistics", ::duckdb_apache::thrift::protocol::T_STRUCT, 12); + xfer += oprot->writeFieldBegin("statistics", ::apache::thrift::protocol::T_STRUCT, 12); xfer += this->statistics.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.encoding_stats) { - xfer += oprot->writeFieldBegin("encoding_stats", ::duckdb_apache::thrift::protocol::T_LIST, 13); + xfer += oprot->writeFieldBegin("encoding_stats", ::apache::thrift::protocol::T_LIST, 13); { - xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->encoding_stats.size())); - duckdb::vector ::const_iterator _iter93; - for (_iter93 = this->encoding_stats.begin(); _iter93 != this->encoding_stats.end(); ++_iter93) + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->encoding_stats.size())); + duckdb::vector ::const_iterator _iter123; + for (_iter123 = this->encoding_stats.begin(); _iter123 != this->encoding_stats.end(); ++_iter123) { - xfer += (*_iter93).write(oprot); + xfer += (*_iter123).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); } + if (this->__isset.bloom_filter_offset) { + xfer += oprot->writeFieldBegin("bloom_filter_offset", ::apache::thrift::protocol::T_I64, 14); + xfer += oprot->writeI64(this->bloom_filter_offset); + xfer += oprot->writeFieldEnd(); + } + if (this->__isset.bloom_filter_length) { + xfer += oprot->writeFieldBegin("bloom_filter_length", ::apache::thrift::protocol::T_I32, 15); + xfer += oprot->writeI32(this->bloom_filter_length); + xfer += oprot->writeFieldEnd(); + } + if (this->__isset.size_statistics) { + xfer += oprot->writeFieldBegin("size_statistics", ::apache::thrift::protocol::T_STRUCT, 16); + xfer += this->size_statistics.write(oprot); + xfer += oprot->writeFieldEnd(); + } xfer += oprot->writeFieldStop(); xfer += oprot->writeStructEnd(); return xfer; @@ -4223,44 +5750,53 @@ void swap(ColumnMetaData &a, ColumnMetaData &b) { swap(a.dictionary_page_offset, b.dictionary_page_offset); swap(a.statistics, b.statistics); swap(a.encoding_stats, b.encoding_stats); + swap(a.bloom_filter_offset, b.bloom_filter_offset); + swap(a.bloom_filter_length, b.bloom_filter_length); + swap(a.size_statistics, b.size_statistics); swap(a.__isset, b.__isset); } -ColumnMetaData::ColumnMetaData(const ColumnMetaData& other94) { - type = other94.type; - encodings = other94.encodings; - path_in_schema = other94.path_in_schema; - codec = other94.codec; - num_values = other94.num_values; - total_uncompressed_size = other94.total_uncompressed_size; - total_compressed_size = other94.total_compressed_size; - key_value_metadata = other94.key_value_metadata; - data_page_offset = other94.data_page_offset; - index_page_offset = other94.index_page_offset; - dictionary_page_offset = other94.dictionary_page_offset; - statistics = other94.statistics; - encoding_stats = other94.encoding_stats; - __isset = other94.__isset; -} -ColumnMetaData& ColumnMetaData::operator=(const ColumnMetaData& other95) { - type = other95.type; - encodings = other95.encodings; - path_in_schema = other95.path_in_schema; - codec = other95.codec; - num_values = other95.num_values; - total_uncompressed_size = other95.total_uncompressed_size; - total_compressed_size = other95.total_compressed_size; - key_value_metadata = other95.key_value_metadata; - data_page_offset = other95.data_page_offset; - index_page_offset = other95.index_page_offset; - dictionary_page_offset = other95.dictionary_page_offset; - statistics = other95.statistics; - encoding_stats = other95.encoding_stats; - __isset = other95.__isset; +ColumnMetaData::ColumnMetaData(const ColumnMetaData& other124) { + type = other124.type; + encodings = other124.encodings; + path_in_schema = other124.path_in_schema; + codec = other124.codec; + num_values = other124.num_values; + total_uncompressed_size = other124.total_uncompressed_size; + total_compressed_size = other124.total_compressed_size; + key_value_metadata = other124.key_value_metadata; + data_page_offset = other124.data_page_offset; + index_page_offset = other124.index_page_offset; + dictionary_page_offset = other124.dictionary_page_offset; + statistics = other124.statistics; + encoding_stats = other124.encoding_stats; + bloom_filter_offset = other124.bloom_filter_offset; + bloom_filter_length = other124.bloom_filter_length; + size_statistics = other124.size_statistics; + __isset = other124.__isset; +} +ColumnMetaData& ColumnMetaData::operator=(const ColumnMetaData& other125) { + type = other125.type; + encodings = other125.encodings; + path_in_schema = other125.path_in_schema; + codec = other125.codec; + num_values = other125.num_values; + total_uncompressed_size = other125.total_uncompressed_size; + total_compressed_size = other125.total_compressed_size; + key_value_metadata = other125.key_value_metadata; + data_page_offset = other125.data_page_offset; + index_page_offset = other125.index_page_offset; + dictionary_page_offset = other125.dictionary_page_offset; + statistics = other125.statistics; + encoding_stats = other125.encoding_stats; + bloom_filter_offset = other125.bloom_filter_offset; + bloom_filter_length = other125.bloom_filter_length; + size_statistics = other125.size_statistics; + __isset = other125.__isset; return *this; } void ColumnMetaData::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "ColumnMetaData("; out << "type=" << to_string(type); out << ", " << "encodings=" << to_string(encodings); @@ -4275,13 +5811,18 @@ void ColumnMetaData::printTo(std::ostream& out) const { out << ", " << "dictionary_page_offset="; (__isset.dictionary_page_offset ? (out << to_string(dictionary_page_offset)) : (out << "")); out << ", " << "statistics="; (__isset.statistics ? (out << to_string(statistics)) : (out << "")); out << ", " << "encoding_stats="; (__isset.encoding_stats ? (out << to_string(encoding_stats)) : (out << "")); + out << ", " << "bloom_filter_offset="; (__isset.bloom_filter_offset ? (out << to_string(bloom_filter_offset)) : (out << "")); + out << ", " << "bloom_filter_length="; (__isset.bloom_filter_length ? (out << to_string(bloom_filter_length)) : (out << "")); + out << ", " << "size_statistics="; (__isset.size_statistics ? (out << to_string(size_statistics)) : (out << "")); out << ")"; } -EncryptionWithFooterKey::~EncryptionWithFooterKey() throw() { +EncryptionWithFooterKey::~EncryptionWithFooterKey() noexcept { } +EncryptionWithFooterKey::EncryptionWithFooterKey() noexcept { +} std::ostream& operator<<(std::ostream& out, const EncryptionWithFooterKey& obj) { obj.printTo(out); @@ -4289,23 +5830,23 @@ std::ostream& operator<<(std::ostream& out, const EncryptionWithFooterKey& obj) } -uint32_t EncryptionWithFooterKey::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t EncryptionWithFooterKey::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -4317,9 +5858,9 @@ uint32_t EncryptionWithFooterKey::read(::duckdb_apache::thrift::protocol::TProto return xfer; } -uint32_t EncryptionWithFooterKey::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t EncryptionWithFooterKey::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("EncryptionWithFooterKey"); xfer += oprot->writeFieldStop(); @@ -4333,23 +5874,26 @@ void swap(EncryptionWithFooterKey &a, EncryptionWithFooterKey &b) { (void) b; } -EncryptionWithFooterKey::EncryptionWithFooterKey(const EncryptionWithFooterKey& other96) { - (void) other96; +EncryptionWithFooterKey::EncryptionWithFooterKey(const EncryptionWithFooterKey& other126) noexcept { + (void) other126; } -EncryptionWithFooterKey& EncryptionWithFooterKey::operator=(const EncryptionWithFooterKey& other97) { - (void) other97; +EncryptionWithFooterKey& EncryptionWithFooterKey::operator=(const EncryptionWithFooterKey& other127) noexcept { + (void) other127; return *this; } void EncryptionWithFooterKey::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "EncryptionWithFooterKey("; out << ")"; } -EncryptionWithColumnKey::~EncryptionWithColumnKey() throw() { +EncryptionWithColumnKey::~EncryptionWithColumnKey() noexcept { } +EncryptionWithColumnKey::EncryptionWithColumnKey() noexcept + : key_metadata() { +} void EncryptionWithColumnKey::__set_path_in_schema(const duckdb::vector & val) { this->path_in_schema = val; @@ -4366,40 +5910,40 @@ std::ostream& operator<<(std::ostream& out, const EncryptionWithColumnKey& obj) } -uint32_t EncryptionWithColumnKey::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t EncryptionWithColumnKey::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_path_in_schema = false; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { + if (ftype == ::apache::thrift::protocol::T_LIST) { { this->path_in_schema.clear(); - uint32_t _size98; - ::duckdb_apache::thrift::protocol::TType _etype101; - xfer += iprot->readListBegin(_etype101, _size98); - this->path_in_schema.resize(_size98); - uint32_t _i102; - for (_i102 = 0; _i102 < _size98; ++_i102) + uint32_t _size128; + ::apache::thrift::protocol::TType _etype131; + xfer += iprot->readListBegin(_etype131, _size128); + this->path_in_schema.resize(_size128); + uint32_t _i132; + for (_i132 = 0; _i132 < _size128; ++_i132) { - xfer += iprot->readString(this->path_in_schema[_i102]); + xfer += iprot->readString(this->path_in_schema[_i132]); } xfer += iprot->readListEnd(); } @@ -4409,7 +5953,7 @@ uint32_t EncryptionWithColumnKey::read(::duckdb_apache::thrift::protocol::TProto } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->key_metadata); this->__isset.key_metadata = true; } else { @@ -4430,25 +5974,25 @@ uint32_t EncryptionWithColumnKey::read(::duckdb_apache::thrift::protocol::TProto return xfer; } -uint32_t EncryptionWithColumnKey::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t EncryptionWithColumnKey::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("EncryptionWithColumnKey"); - xfer += oprot->writeFieldBegin("path_in_schema", ::duckdb_apache::thrift::protocol::T_LIST, 1); + xfer += oprot->writeFieldBegin("path_in_schema", ::apache::thrift::protocol::T_LIST, 1); { - xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRING, static_cast(this->path_in_schema.size())); - duckdb::vector ::const_iterator _iter103; - for (_iter103 = this->path_in_schema.begin(); _iter103 != this->path_in_schema.end(); ++_iter103) + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRING, static_cast(this->path_in_schema.size())); + duckdb::vector ::const_iterator _iter133; + for (_iter133 = this->path_in_schema.begin(); _iter133 != this->path_in_schema.end(); ++_iter133) { - xfer += oprot->writeString((*_iter103)); + xfer += oprot->writeString((*_iter133)); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); if (this->__isset.key_metadata) { - xfer += oprot->writeFieldBegin("key_metadata", ::duckdb_apache::thrift::protocol::T_STRING, 2); + xfer += oprot->writeFieldBegin("key_metadata", ::apache::thrift::protocol::T_STRING, 2); xfer += oprot->writeBinary(this->key_metadata); xfer += oprot->writeFieldEnd(); } @@ -4464,19 +6008,19 @@ void swap(EncryptionWithColumnKey &a, EncryptionWithColumnKey &b) { swap(a.__isset, b.__isset); } -EncryptionWithColumnKey::EncryptionWithColumnKey(const EncryptionWithColumnKey& other104) { - path_in_schema = other104.path_in_schema; - key_metadata = other104.key_metadata; - __isset = other104.__isset; +EncryptionWithColumnKey::EncryptionWithColumnKey(const EncryptionWithColumnKey& other134) { + path_in_schema = other134.path_in_schema; + key_metadata = other134.key_metadata; + __isset = other134.__isset; } -EncryptionWithColumnKey& EncryptionWithColumnKey::operator=(const EncryptionWithColumnKey& other105) { - path_in_schema = other105.path_in_schema; - key_metadata = other105.key_metadata; - __isset = other105.__isset; +EncryptionWithColumnKey& EncryptionWithColumnKey::operator=(const EncryptionWithColumnKey& other135) { + path_in_schema = other135.path_in_schema; + key_metadata = other135.key_metadata; + __isset = other135.__isset; return *this; } void EncryptionWithColumnKey::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "EncryptionWithColumnKey("; out << "path_in_schema=" << to_string(path_in_schema); out << ", " << "key_metadata="; (__isset.key_metadata ? (out << to_string(key_metadata)) : (out << "")); @@ -4484,9 +6028,11 @@ void EncryptionWithColumnKey::printTo(std::ostream& out) const { } -ColumnCryptoMetaData::~ColumnCryptoMetaData() throw() { +ColumnCryptoMetaData::~ColumnCryptoMetaData() noexcept { } +ColumnCryptoMetaData::ColumnCryptoMetaData() noexcept { +} void ColumnCryptoMetaData::__set_ENCRYPTION_WITH_FOOTER_KEY(const EncryptionWithFooterKey& val) { this->ENCRYPTION_WITH_FOOTER_KEY = val; @@ -4504,29 +6050,29 @@ std::ostream& operator<<(std::ostream& out, const ColumnCryptoMetaData& obj) } -uint32_t ColumnCryptoMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t ColumnCryptoMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->ENCRYPTION_WITH_FOOTER_KEY.read(iprot); this->__isset.ENCRYPTION_WITH_FOOTER_KEY = true; } else { @@ -4534,7 +6080,7 @@ uint32_t ColumnCryptoMetaData::read(::duckdb_apache::thrift::protocol::TProtocol } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->ENCRYPTION_WITH_COLUMN_KEY.read(iprot); this->__isset.ENCRYPTION_WITH_COLUMN_KEY = true; } else { @@ -4553,18 +6099,18 @@ uint32_t ColumnCryptoMetaData::read(::duckdb_apache::thrift::protocol::TProtocol return xfer; } -uint32_t ColumnCryptoMetaData::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t ColumnCryptoMetaData::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("ColumnCryptoMetaData"); if (this->__isset.ENCRYPTION_WITH_FOOTER_KEY) { - xfer += oprot->writeFieldBegin("ENCRYPTION_WITH_FOOTER_KEY", ::duckdb_apache::thrift::protocol::T_STRUCT, 1); + xfer += oprot->writeFieldBegin("ENCRYPTION_WITH_FOOTER_KEY", ::apache::thrift::protocol::T_STRUCT, 1); xfer += this->ENCRYPTION_WITH_FOOTER_KEY.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.ENCRYPTION_WITH_COLUMN_KEY) { - xfer += oprot->writeFieldBegin("ENCRYPTION_WITH_COLUMN_KEY", ::duckdb_apache::thrift::protocol::T_STRUCT, 2); + xfer += oprot->writeFieldBegin("ENCRYPTION_WITH_COLUMN_KEY", ::apache::thrift::protocol::T_STRUCT, 2); xfer += this->ENCRYPTION_WITH_COLUMN_KEY.write(oprot); xfer += oprot->writeFieldEnd(); } @@ -4580,19 +6126,19 @@ void swap(ColumnCryptoMetaData &a, ColumnCryptoMetaData &b) { swap(a.__isset, b.__isset); } -ColumnCryptoMetaData::ColumnCryptoMetaData(const ColumnCryptoMetaData& other106) { - ENCRYPTION_WITH_FOOTER_KEY = other106.ENCRYPTION_WITH_FOOTER_KEY; - ENCRYPTION_WITH_COLUMN_KEY = other106.ENCRYPTION_WITH_COLUMN_KEY; - __isset = other106.__isset; +ColumnCryptoMetaData::ColumnCryptoMetaData(const ColumnCryptoMetaData& other136) { + ENCRYPTION_WITH_FOOTER_KEY = other136.ENCRYPTION_WITH_FOOTER_KEY; + ENCRYPTION_WITH_COLUMN_KEY = other136.ENCRYPTION_WITH_COLUMN_KEY; + __isset = other136.__isset; } -ColumnCryptoMetaData& ColumnCryptoMetaData::operator=(const ColumnCryptoMetaData& other107) { - ENCRYPTION_WITH_FOOTER_KEY = other107.ENCRYPTION_WITH_FOOTER_KEY; - ENCRYPTION_WITH_COLUMN_KEY = other107.ENCRYPTION_WITH_COLUMN_KEY; - __isset = other107.__isset; +ColumnCryptoMetaData& ColumnCryptoMetaData::operator=(const ColumnCryptoMetaData& other137) { + ENCRYPTION_WITH_FOOTER_KEY = other137.ENCRYPTION_WITH_FOOTER_KEY; + ENCRYPTION_WITH_COLUMN_KEY = other137.ENCRYPTION_WITH_COLUMN_KEY; + __isset = other137.__isset; return *this; } void ColumnCryptoMetaData::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "ColumnCryptoMetaData("; out << "ENCRYPTION_WITH_FOOTER_KEY="; (__isset.ENCRYPTION_WITH_FOOTER_KEY ? (out << to_string(ENCRYPTION_WITH_FOOTER_KEY)) : (out << "")); out << ", " << "ENCRYPTION_WITH_COLUMN_KEY="; (__isset.ENCRYPTION_WITH_COLUMN_KEY ? (out << to_string(ENCRYPTION_WITH_COLUMN_KEY)) : (out << "")); @@ -4600,9 +6146,18 @@ void ColumnCryptoMetaData::printTo(std::ostream& out) const { } -ColumnChunk::~ColumnChunk() throw() { +ColumnChunk::~ColumnChunk() noexcept { } +ColumnChunk::ColumnChunk() noexcept + : file_path(), + file_offset(0LL), + offset_index_offset(0), + offset_index_length(0), + column_index_offset(0), + column_index_length(0), + encrypted_column_metadata() { +} void ColumnChunk::__set_file_path(const std::string& val) { this->file_path = val; @@ -4654,30 +6209,30 @@ std::ostream& operator<<(std::ostream& out, const ColumnChunk& obj) } -uint32_t ColumnChunk::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t ColumnChunk::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_file_offset = false; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readString(this->file_path); this->__isset.file_path = true; } else { @@ -4685,7 +6240,7 @@ uint32_t ColumnChunk::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->file_offset); isset_file_offset = true; } else { @@ -4693,7 +6248,7 @@ uint32_t ColumnChunk::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->meta_data.read(iprot); this->__isset.meta_data = true; } else { @@ -4701,7 +6256,7 @@ uint32_t ColumnChunk::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 4: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->offset_index_offset); this->__isset.offset_index_offset = true; } else { @@ -4709,7 +6264,7 @@ uint32_t ColumnChunk::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 5: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->offset_index_length); this->__isset.offset_index_length = true; } else { @@ -4717,7 +6272,7 @@ uint32_t ColumnChunk::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 6: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->column_index_offset); this->__isset.column_index_offset = true; } else { @@ -4725,7 +6280,7 @@ uint32_t ColumnChunk::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 7: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->column_index_length); this->__isset.column_index_length = true; } else { @@ -4733,7 +6288,7 @@ uint32_t ColumnChunk::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 8: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->crypto_metadata.read(iprot); this->__isset.crypto_metadata = true; } else { @@ -4741,7 +6296,7 @@ uint32_t ColumnChunk::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 9: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->encrypted_column_metadata); this->__isset.encrypted_column_metadata = true; } else { @@ -4762,52 +6317,52 @@ uint32_t ColumnChunk::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) return xfer; } -uint32_t ColumnChunk::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t ColumnChunk::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("ColumnChunk"); if (this->__isset.file_path) { - xfer += oprot->writeFieldBegin("file_path", ::duckdb_apache::thrift::protocol::T_STRING, 1); + xfer += oprot->writeFieldBegin("file_path", ::apache::thrift::protocol::T_STRING, 1); xfer += oprot->writeString(this->file_path); xfer += oprot->writeFieldEnd(); } - xfer += oprot->writeFieldBegin("file_offset", ::duckdb_apache::thrift::protocol::T_I64, 2); + xfer += oprot->writeFieldBegin("file_offset", ::apache::thrift::protocol::T_I64, 2); xfer += oprot->writeI64(this->file_offset); xfer += oprot->writeFieldEnd(); if (this->__isset.meta_data) { - xfer += oprot->writeFieldBegin("meta_data", ::duckdb_apache::thrift::protocol::T_STRUCT, 3); + xfer += oprot->writeFieldBegin("meta_data", ::apache::thrift::protocol::T_STRUCT, 3); xfer += this->meta_data.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.offset_index_offset) { - xfer += oprot->writeFieldBegin("offset_index_offset", ::duckdb_apache::thrift::protocol::T_I64, 4); + xfer += oprot->writeFieldBegin("offset_index_offset", ::apache::thrift::protocol::T_I64, 4); xfer += oprot->writeI64(this->offset_index_offset); xfer += oprot->writeFieldEnd(); } if (this->__isset.offset_index_length) { - xfer += oprot->writeFieldBegin("offset_index_length", ::duckdb_apache::thrift::protocol::T_I32, 5); + xfer += oprot->writeFieldBegin("offset_index_length", ::apache::thrift::protocol::T_I32, 5); xfer += oprot->writeI32(this->offset_index_length); xfer += oprot->writeFieldEnd(); } if (this->__isset.column_index_offset) { - xfer += oprot->writeFieldBegin("column_index_offset", ::duckdb_apache::thrift::protocol::T_I64, 6); + xfer += oprot->writeFieldBegin("column_index_offset", ::apache::thrift::protocol::T_I64, 6); xfer += oprot->writeI64(this->column_index_offset); xfer += oprot->writeFieldEnd(); } if (this->__isset.column_index_length) { - xfer += oprot->writeFieldBegin("column_index_length", ::duckdb_apache::thrift::protocol::T_I32, 7); + xfer += oprot->writeFieldBegin("column_index_length", ::apache::thrift::protocol::T_I32, 7); xfer += oprot->writeI32(this->column_index_length); xfer += oprot->writeFieldEnd(); } if (this->__isset.crypto_metadata) { - xfer += oprot->writeFieldBegin("crypto_metadata", ::duckdb_apache::thrift::protocol::T_STRUCT, 8); + xfer += oprot->writeFieldBegin("crypto_metadata", ::apache::thrift::protocol::T_STRUCT, 8); xfer += this->crypto_metadata.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.encrypted_column_metadata) { - xfer += oprot->writeFieldBegin("encrypted_column_metadata", ::duckdb_apache::thrift::protocol::T_STRING, 9); + xfer += oprot->writeFieldBegin("encrypted_column_metadata", ::apache::thrift::protocol::T_STRING, 9); xfer += oprot->writeBinary(this->encrypted_column_metadata); xfer += oprot->writeFieldEnd(); } @@ -4830,33 +6385,33 @@ void swap(ColumnChunk &a, ColumnChunk &b) { swap(a.__isset, b.__isset); } -ColumnChunk::ColumnChunk(const ColumnChunk& other108) { - file_path = other108.file_path; - file_offset = other108.file_offset; - meta_data = other108.meta_data; - offset_index_offset = other108.offset_index_offset; - offset_index_length = other108.offset_index_length; - column_index_offset = other108.column_index_offset; - column_index_length = other108.column_index_length; - crypto_metadata = other108.crypto_metadata; - encrypted_column_metadata = other108.encrypted_column_metadata; - __isset = other108.__isset; -} -ColumnChunk& ColumnChunk::operator=(const ColumnChunk& other109) { - file_path = other109.file_path; - file_offset = other109.file_offset; - meta_data = other109.meta_data; - offset_index_offset = other109.offset_index_offset; - offset_index_length = other109.offset_index_length; - column_index_offset = other109.column_index_offset; - column_index_length = other109.column_index_length; - crypto_metadata = other109.crypto_metadata; - encrypted_column_metadata = other109.encrypted_column_metadata; - __isset = other109.__isset; +ColumnChunk::ColumnChunk(const ColumnChunk& other138) { + file_path = other138.file_path; + file_offset = other138.file_offset; + meta_data = other138.meta_data; + offset_index_offset = other138.offset_index_offset; + offset_index_length = other138.offset_index_length; + column_index_offset = other138.column_index_offset; + column_index_length = other138.column_index_length; + crypto_metadata = other138.crypto_metadata; + encrypted_column_metadata = other138.encrypted_column_metadata; + __isset = other138.__isset; +} +ColumnChunk& ColumnChunk::operator=(const ColumnChunk& other139) { + file_path = other139.file_path; + file_offset = other139.file_offset; + meta_data = other139.meta_data; + offset_index_offset = other139.offset_index_offset; + offset_index_length = other139.offset_index_length; + column_index_offset = other139.column_index_offset; + column_index_length = other139.column_index_length; + crypto_metadata = other139.crypto_metadata; + encrypted_column_metadata = other139.encrypted_column_metadata; + __isset = other139.__isset; return *this; } void ColumnChunk::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "ColumnChunk("; out << "file_path="; (__isset.file_path ? (out << to_string(file_path)) : (out << "")); out << ", " << "file_offset=" << to_string(file_offset); @@ -4871,9 +6426,16 @@ void ColumnChunk::printTo(std::ostream& out) const { } -RowGroup::~RowGroup() throw() { +RowGroup::~RowGroup() noexcept { } +RowGroup::RowGroup() noexcept + : total_byte_size(0), + num_rows(0), + file_offset(0), + total_compressed_size(0), + ordinal(0) { +} void RowGroup::__set_columns(const duckdb::vector & val) { this->columns = val; @@ -4913,17 +6475,17 @@ std::ostream& operator<<(std::ostream& out, const RowGroup& obj) } -uint32_t RowGroup::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t RowGroup::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_columns = false; bool isset_total_byte_size = false; @@ -4932,23 +6494,23 @@ uint32_t RowGroup::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { + if (ftype == ::apache::thrift::protocol::T_LIST) { { this->columns.clear(); - uint32_t _size110; - ::duckdb_apache::thrift::protocol::TType _etype113; - xfer += iprot->readListBegin(_etype113, _size110); - this->columns.resize(_size110); - uint32_t _i114; - for (_i114 = 0; _i114 < _size110; ++_i114) + uint32_t _size140; + ::apache::thrift::protocol::TType _etype143; + xfer += iprot->readListBegin(_etype143, _size140); + this->columns.resize(_size140); + uint32_t _i144; + for (_i144 = 0; _i144 < _size140; ++_i144) { - xfer += this->columns[_i114].read(iprot); + xfer += this->columns[_i144].read(iprot); } xfer += iprot->readListEnd(); } @@ -4958,7 +6520,7 @@ uint32_t RowGroup::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->total_byte_size); isset_total_byte_size = true; } else { @@ -4966,7 +6528,7 @@ uint32_t RowGroup::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->num_rows); isset_num_rows = true; } else { @@ -4974,17 +6536,17 @@ uint32_t RowGroup::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 4: - if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { + if (ftype == ::apache::thrift::protocol::T_LIST) { { this->sorting_columns.clear(); - uint32_t _size115; - ::duckdb_apache::thrift::protocol::TType _etype118; - xfer += iprot->readListBegin(_etype118, _size115); - this->sorting_columns.resize(_size115); - uint32_t _i119; - for (_i119 = 0; _i119 < _size115; ++_i119) + uint32_t _size145; + ::apache::thrift::protocol::TType _etype148; + xfer += iprot->readListBegin(_etype148, _size145); + this->sorting_columns.resize(_size145); + uint32_t _i149; + for (_i149 = 0; _i149 < _size145; ++_i149) { - xfer += this->sorting_columns[_i119].read(iprot); + xfer += this->sorting_columns[_i149].read(iprot); } xfer += iprot->readListEnd(); } @@ -4994,7 +6556,7 @@ uint32_t RowGroup::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 5: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->file_offset); this->__isset.file_offset = true; } else { @@ -5002,7 +6564,7 @@ uint32_t RowGroup::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 6: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->total_compressed_size); this->__isset.total_compressed_size = true; } else { @@ -5010,7 +6572,7 @@ uint32_t RowGroup::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 7: - if (ftype == ::duckdb_apache::thrift::protocol::T_I16) { + if (ftype == ::apache::thrift::protocol::T_I16) { xfer += iprot->readI16(this->ordinal); this->__isset.ordinal = true; } else { @@ -5035,56 +6597,56 @@ uint32_t RowGroup::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t RowGroup::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t RowGroup::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("RowGroup"); - xfer += oprot->writeFieldBegin("columns", ::duckdb_apache::thrift::protocol::T_LIST, 1); + xfer += oprot->writeFieldBegin("columns", ::apache::thrift::protocol::T_LIST, 1); { - xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->columns.size())); - duckdb::vector ::const_iterator _iter120; - for (_iter120 = this->columns.begin(); _iter120 != this->columns.end(); ++_iter120) + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->columns.size())); + duckdb::vector ::const_iterator _iter150; + for (_iter150 = this->columns.begin(); _iter150 != this->columns.end(); ++_iter150) { - xfer += (*_iter120).write(oprot); + xfer += (*_iter150).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("total_byte_size", ::duckdb_apache::thrift::protocol::T_I64, 2); + xfer += oprot->writeFieldBegin("total_byte_size", ::apache::thrift::protocol::T_I64, 2); xfer += oprot->writeI64(this->total_byte_size); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("num_rows", ::duckdb_apache::thrift::protocol::T_I64, 3); + xfer += oprot->writeFieldBegin("num_rows", ::apache::thrift::protocol::T_I64, 3); xfer += oprot->writeI64(this->num_rows); xfer += oprot->writeFieldEnd(); if (this->__isset.sorting_columns) { - xfer += oprot->writeFieldBegin("sorting_columns", ::duckdb_apache::thrift::protocol::T_LIST, 4); + xfer += oprot->writeFieldBegin("sorting_columns", ::apache::thrift::protocol::T_LIST, 4); { - xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->sorting_columns.size())); - duckdb::vector ::const_iterator _iter121; - for (_iter121 = this->sorting_columns.begin(); _iter121 != this->sorting_columns.end(); ++_iter121) + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->sorting_columns.size())); + duckdb::vector ::const_iterator _iter151; + for (_iter151 = this->sorting_columns.begin(); _iter151 != this->sorting_columns.end(); ++_iter151) { - xfer += (*_iter121).write(oprot); + xfer += (*_iter151).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); } if (this->__isset.file_offset) { - xfer += oprot->writeFieldBegin("file_offset", ::duckdb_apache::thrift::protocol::T_I64, 5); + xfer += oprot->writeFieldBegin("file_offset", ::apache::thrift::protocol::T_I64, 5); xfer += oprot->writeI64(this->file_offset); xfer += oprot->writeFieldEnd(); } if (this->__isset.total_compressed_size) { - xfer += oprot->writeFieldBegin("total_compressed_size", ::duckdb_apache::thrift::protocol::T_I64, 6); + xfer += oprot->writeFieldBegin("total_compressed_size", ::apache::thrift::protocol::T_I64, 6); xfer += oprot->writeI64(this->total_compressed_size); xfer += oprot->writeFieldEnd(); } if (this->__isset.ordinal) { - xfer += oprot->writeFieldBegin("ordinal", ::duckdb_apache::thrift::protocol::T_I16, 7); + xfer += oprot->writeFieldBegin("ordinal", ::apache::thrift::protocol::T_I16, 7); xfer += oprot->writeI16(this->ordinal); xfer += oprot->writeFieldEnd(); } @@ -5105,29 +6667,29 @@ void swap(RowGroup &a, RowGroup &b) { swap(a.__isset, b.__isset); } -RowGroup::RowGroup(const RowGroup& other122) { - columns = other122.columns; - total_byte_size = other122.total_byte_size; - num_rows = other122.num_rows; - sorting_columns = other122.sorting_columns; - file_offset = other122.file_offset; - total_compressed_size = other122.total_compressed_size; - ordinal = other122.ordinal; - __isset = other122.__isset; -} -RowGroup& RowGroup::operator=(const RowGroup& other123) { - columns = other123.columns; - total_byte_size = other123.total_byte_size; - num_rows = other123.num_rows; - sorting_columns = other123.sorting_columns; - file_offset = other123.file_offset; - total_compressed_size = other123.total_compressed_size; - ordinal = other123.ordinal; - __isset = other123.__isset; +RowGroup::RowGroup(const RowGroup& other152) { + columns = other152.columns; + total_byte_size = other152.total_byte_size; + num_rows = other152.num_rows; + sorting_columns = other152.sorting_columns; + file_offset = other152.file_offset; + total_compressed_size = other152.total_compressed_size; + ordinal = other152.ordinal; + __isset = other152.__isset; +} +RowGroup& RowGroup::operator=(const RowGroup& other153) { + columns = other153.columns; + total_byte_size = other153.total_byte_size; + num_rows = other153.num_rows; + sorting_columns = other153.sorting_columns; + file_offset = other153.file_offset; + total_compressed_size = other153.total_compressed_size; + ordinal = other153.ordinal; + __isset = other153.__isset; return *this; } void RowGroup::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "RowGroup("; out << "columns=" << to_string(columns); out << ", " << "total_byte_size=" << to_string(total_byte_size); @@ -5140,9 +6702,11 @@ void RowGroup::printTo(std::ostream& out) const { } -TypeDefinedOrder::~TypeDefinedOrder() throw() { +TypeDefinedOrder::~TypeDefinedOrder() noexcept { } +TypeDefinedOrder::TypeDefinedOrder() noexcept { +} std::ostream& operator<<(std::ostream& out, const TypeDefinedOrder& obj) { obj.printTo(out); @@ -5150,23 +6714,23 @@ std::ostream& operator<<(std::ostream& out, const TypeDefinedOrder& obj) } -uint32_t TypeDefinedOrder::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t TypeDefinedOrder::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -5178,9 +6742,9 @@ uint32_t TypeDefinedOrder::read(::duckdb_apache::thrift::protocol::TProtocol* ip return xfer; } -uint32_t TypeDefinedOrder::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t TypeDefinedOrder::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("TypeDefinedOrder"); xfer += oprot->writeFieldStop(); @@ -5194,23 +6758,25 @@ void swap(TypeDefinedOrder &a, TypeDefinedOrder &b) { (void) b; } -TypeDefinedOrder::TypeDefinedOrder(const TypeDefinedOrder& other124) { - (void) other124; +TypeDefinedOrder::TypeDefinedOrder(const TypeDefinedOrder& other154) noexcept { + (void) other154; } -TypeDefinedOrder& TypeDefinedOrder::operator=(const TypeDefinedOrder& other125) { - (void) other125; +TypeDefinedOrder& TypeDefinedOrder::operator=(const TypeDefinedOrder& other155) noexcept { + (void) other155; return *this; } void TypeDefinedOrder::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "TypeDefinedOrder("; out << ")"; } -ColumnOrder::~ColumnOrder() throw() { +ColumnOrder::~ColumnOrder() noexcept { } +ColumnOrder::ColumnOrder() noexcept { +} void ColumnOrder::__set_TYPE_ORDER(const TypeDefinedOrder& val) { this->TYPE_ORDER = val; @@ -5223,29 +6789,29 @@ std::ostream& operator<<(std::ostream& out, const ColumnOrder& obj) } -uint32_t ColumnOrder::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t ColumnOrder::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->TYPE_ORDER.read(iprot); this->__isset.TYPE_ORDER = true; } else { @@ -5264,13 +6830,13 @@ uint32_t ColumnOrder::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) return xfer; } -uint32_t ColumnOrder::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t ColumnOrder::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("ColumnOrder"); if (this->__isset.TYPE_ORDER) { - xfer += oprot->writeFieldBegin("TYPE_ORDER", ::duckdb_apache::thrift::protocol::T_STRUCT, 1); + xfer += oprot->writeFieldBegin("TYPE_ORDER", ::apache::thrift::protocol::T_STRUCT, 1); xfer += this->TYPE_ORDER.write(oprot); xfer += oprot->writeFieldEnd(); } @@ -5285,26 +6851,31 @@ void swap(ColumnOrder &a, ColumnOrder &b) { swap(a.__isset, b.__isset); } -ColumnOrder::ColumnOrder(const ColumnOrder& other126) { - TYPE_ORDER = other126.TYPE_ORDER; - __isset = other126.__isset; +ColumnOrder::ColumnOrder(const ColumnOrder& other156) noexcept { + TYPE_ORDER = other156.TYPE_ORDER; + __isset = other156.__isset; } -ColumnOrder& ColumnOrder::operator=(const ColumnOrder& other127) { - TYPE_ORDER = other127.TYPE_ORDER; - __isset = other127.__isset; +ColumnOrder& ColumnOrder::operator=(const ColumnOrder& other157) noexcept { + TYPE_ORDER = other157.TYPE_ORDER; + __isset = other157.__isset; return *this; } void ColumnOrder::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "ColumnOrder("; out << "TYPE_ORDER="; (__isset.TYPE_ORDER ? (out << to_string(TYPE_ORDER)) : (out << "")); out << ")"; } -PageLocation::~PageLocation() throw() { +PageLocation::~PageLocation() noexcept { } +PageLocation::PageLocation() noexcept + : offset(0), + compressed_page_size(0), + first_row_index(0) { +} void PageLocation::__set_offset(const int64_t val) { this->offset = val; @@ -5324,17 +6895,17 @@ std::ostream& operator<<(std::ostream& out, const PageLocation& obj) } -uint32_t PageLocation::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t PageLocation::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_offset = false; bool isset_compressed_page_size = false; @@ -5343,13 +6914,13 @@ uint32_t PageLocation::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->offset); isset_offset = true; } else { @@ -5357,7 +6928,7 @@ uint32_t PageLocation::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->compressed_page_size); isset_compressed_page_size = true; } else { @@ -5365,7 +6936,7 @@ uint32_t PageLocation::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->first_row_index); isset_first_row_index = true; } else { @@ -5390,20 +6961,20 @@ uint32_t PageLocation::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) return xfer; } -uint32_t PageLocation::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t PageLocation::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("PageLocation"); - xfer += oprot->writeFieldBegin("offset", ::duckdb_apache::thrift::protocol::T_I64, 1); + xfer += oprot->writeFieldBegin("offset", ::apache::thrift::protocol::T_I64, 1); xfer += oprot->writeI64(this->offset); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("compressed_page_size", ::duckdb_apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeFieldBegin("compressed_page_size", ::apache::thrift::protocol::T_I32, 2); xfer += oprot->writeI32(this->compressed_page_size); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("first_row_index", ::duckdb_apache::thrift::protocol::T_I64, 3); + xfer += oprot->writeFieldBegin("first_row_index", ::apache::thrift::protocol::T_I64, 3); xfer += oprot->writeI64(this->first_row_index); xfer += oprot->writeFieldEnd(); @@ -5419,19 +6990,19 @@ void swap(PageLocation &a, PageLocation &b) { swap(a.first_row_index, b.first_row_index); } -PageLocation::PageLocation(const PageLocation& other128) { - offset = other128.offset; - compressed_page_size = other128.compressed_page_size; - first_row_index = other128.first_row_index; +PageLocation::PageLocation(const PageLocation& other158) noexcept { + offset = other158.offset; + compressed_page_size = other158.compressed_page_size; + first_row_index = other158.first_row_index; } -PageLocation& PageLocation::operator=(const PageLocation& other129) { - offset = other129.offset; - compressed_page_size = other129.compressed_page_size; - first_row_index = other129.first_row_index; +PageLocation& PageLocation::operator=(const PageLocation& other159) noexcept { + offset = other159.offset; + compressed_page_size = other159.compressed_page_size; + first_row_index = other159.first_row_index; return *this; } void PageLocation::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "PageLocation("; out << "offset=" << to_string(offset); out << ", " << "compressed_page_size=" << to_string(compressed_page_size); @@ -5440,13 +7011,20 @@ void PageLocation::printTo(std::ostream& out) const { } -OffsetIndex::~OffsetIndex() throw() { +OffsetIndex::~OffsetIndex() noexcept { } +OffsetIndex::OffsetIndex() noexcept { +} void OffsetIndex::__set_page_locations(const duckdb::vector & val) { this->page_locations = val; } + +void OffsetIndex::__set_unencoded_byte_array_data_bytes(const duckdb::vector & val) { + this->unencoded_byte_array_data_bytes = val; +__isset.unencoded_byte_array_data_bytes = true; +} std::ostream& operator<<(std::ostream& out, const OffsetIndex& obj) { obj.printTo(out); @@ -5454,40 +7032,40 @@ std::ostream& operator<<(std::ostream& out, const OffsetIndex& obj) } -uint32_t OffsetIndex::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t OffsetIndex::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_page_locations = false; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { + if (ftype == ::apache::thrift::protocol::T_LIST) { { this->page_locations.clear(); - uint32_t _size130; - ::duckdb_apache::thrift::protocol::TType _etype133; - xfer += iprot->readListBegin(_etype133, _size130); - this->page_locations.resize(_size130); - uint32_t _i134; - for (_i134 = 0; _i134 < _size130; ++_i134) + uint32_t _size160; + ::apache::thrift::protocol::TType _etype163; + xfer += iprot->readListBegin(_etype163, _size160); + this->page_locations.resize(_size160); + uint32_t _i164; + for (_i164 = 0; _i164 < _size160; ++_i164) { - xfer += this->page_locations[_i134].read(iprot); + xfer += this->page_locations[_i164].read(iprot); } xfer += iprot->readListEnd(); } @@ -5496,6 +7074,26 @@ uint32_t OffsetIndex::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) xfer += iprot->skip(ftype); } break; + case 2: + if (ftype == ::apache::thrift::protocol::T_LIST) { + { + this->unencoded_byte_array_data_bytes.clear(); + uint32_t _size165; + ::apache::thrift::protocol::TType _etype168; + xfer += iprot->readListBegin(_etype168, _size165); + this->unencoded_byte_array_data_bytes.resize(_size165); + uint32_t _i169; + for (_i169 = 0; _i169 < _size165; ++_i169) + { + xfer += iprot->readI64(this->unencoded_byte_array_data_bytes[_i169]); + } + xfer += iprot->readListEnd(); + } + this->__isset.unencoded_byte_array_data_bytes = true; + } else { + xfer += iprot->skip(ftype); + } + break; default: xfer += iprot->skip(ftype); break; @@ -5510,23 +7108,36 @@ uint32_t OffsetIndex::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) return xfer; } -uint32_t OffsetIndex::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t OffsetIndex::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("OffsetIndex"); - xfer += oprot->writeFieldBegin("page_locations", ::duckdb_apache::thrift::protocol::T_LIST, 1); + xfer += oprot->writeFieldBegin("page_locations", ::apache::thrift::protocol::T_LIST, 1); { - xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->page_locations.size())); - duckdb::vector ::const_iterator _iter135; - for (_iter135 = this->page_locations.begin(); _iter135 != this->page_locations.end(); ++_iter135) + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->page_locations.size())); + duckdb::vector ::const_iterator _iter170; + for (_iter170 = this->page_locations.begin(); _iter170 != this->page_locations.end(); ++_iter170) { - xfer += (*_iter135).write(oprot); + xfer += (*_iter170).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); + if (this->__isset.unencoded_byte_array_data_bytes) { + xfer += oprot->writeFieldBegin("unencoded_byte_array_data_bytes", ::apache::thrift::protocol::T_LIST, 2); + { + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64, static_cast(this->unencoded_byte_array_data_bytes.size())); + duckdb::vector ::const_iterator _iter171; + for (_iter171 = this->unencoded_byte_array_data_bytes.begin(); _iter171 != this->unencoded_byte_array_data_bytes.end(); ++_iter171) + { + xfer += oprot->writeI64((*_iter171)); + } + xfer += oprot->writeListEnd(); + } + xfer += oprot->writeFieldEnd(); + } xfer += oprot->writeFieldStop(); xfer += oprot->writeStructEnd(); return xfer; @@ -5535,26 +7146,36 @@ uint32_t OffsetIndex::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) void swap(OffsetIndex &a, OffsetIndex &b) { using ::std::swap; swap(a.page_locations, b.page_locations); + swap(a.unencoded_byte_array_data_bytes, b.unencoded_byte_array_data_bytes); + swap(a.__isset, b.__isset); } -OffsetIndex::OffsetIndex(const OffsetIndex& other136) { - page_locations = other136.page_locations; +OffsetIndex::OffsetIndex(const OffsetIndex& other172) { + page_locations = other172.page_locations; + unencoded_byte_array_data_bytes = other172.unencoded_byte_array_data_bytes; + __isset = other172.__isset; } -OffsetIndex& OffsetIndex::operator=(const OffsetIndex& other137) { - page_locations = other137.page_locations; +OffsetIndex& OffsetIndex::operator=(const OffsetIndex& other173) { + page_locations = other173.page_locations; + unencoded_byte_array_data_bytes = other173.unencoded_byte_array_data_bytes; + __isset = other173.__isset; return *this; } void OffsetIndex::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "OffsetIndex("; out << "page_locations=" << to_string(page_locations); + out << ", " << "unencoded_byte_array_data_bytes="; (__isset.unencoded_byte_array_data_bytes ? (out << to_string(unencoded_byte_array_data_bytes)) : (out << "")); out << ")"; } -ColumnIndex::~ColumnIndex() throw() { +ColumnIndex::~ColumnIndex() noexcept { } +ColumnIndex::ColumnIndex() noexcept + : boundary_order(static_cast(0)) { +} void ColumnIndex::__set_null_pages(const duckdb::vector & val) { this->null_pages = val; @@ -5576,6 +7197,16 @@ void ColumnIndex::__set_null_counts(const duckdb::vector & val) { this->null_counts = val; __isset.null_counts = true; } + +void ColumnIndex::__set_repetition_level_histograms(const duckdb::vector & val) { + this->repetition_level_histograms = val; +__isset.repetition_level_histograms = true; +} + +void ColumnIndex::__set_definition_level_histograms(const duckdb::vector & val) { + this->definition_level_histograms = val; +__isset.definition_level_histograms = true; +} std::ostream& operator<<(std::ostream& out, const ColumnIndex& obj) { obj.printTo(out); @@ -5583,17 +7214,17 @@ std::ostream& operator<<(std::ostream& out, const ColumnIndex& obj) } -uint32_t ColumnIndex::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t ColumnIndex::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_null_pages = false; bool isset_min_values = false; @@ -5603,23 +7234,23 @@ uint32_t ColumnIndex::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { + if (ftype == ::apache::thrift::protocol::T_LIST) { { this->null_pages.clear(); - uint32_t _size138; - ::duckdb_apache::thrift::protocol::TType _etype141; - xfer += iprot->readListBegin(_etype141, _size138); - this->null_pages.resize(_size138); - uint32_t _i142; - for (_i142 = 0; _i142 < _size138; ++_i142) + uint32_t _size174; + ::apache::thrift::protocol::TType _etype177; + xfer += iprot->readListBegin(_etype177, _size174); + this->null_pages.resize(_size174); + uint32_t _i178; + for (_i178 = 0; _i178 < _size174; ++_i178) { - xfer += iprot->readBool(this->null_pages[_i142]); + xfer += iprot->readBool(this->null_pages[_i178]); } xfer += iprot->readListEnd(); } @@ -5629,17 +7260,17 @@ uint32_t ColumnIndex::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { + if (ftype == ::apache::thrift::protocol::T_LIST) { { this->min_values.clear(); - uint32_t _size143; - ::duckdb_apache::thrift::protocol::TType _etype146; - xfer += iprot->readListBegin(_etype146, _size143); - this->min_values.resize(_size143); - uint32_t _i147; - for (_i147 = 0; _i147 < _size143; ++_i147) + uint32_t _size179; + ::apache::thrift::protocol::TType _etype182; + xfer += iprot->readListBegin(_etype182, _size179); + this->min_values.resize(_size179); + uint32_t _i183; + for (_i183 = 0; _i183 < _size179; ++_i183) { - xfer += iprot->readBinary(this->min_values[_i147]); + xfer += iprot->readBinary(this->min_values[_i183]); } xfer += iprot->readListEnd(); } @@ -5649,17 +7280,17 @@ uint32_t ColumnIndex::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { + if (ftype == ::apache::thrift::protocol::T_LIST) { { this->max_values.clear(); - uint32_t _size148; - ::duckdb_apache::thrift::protocol::TType _etype151; - xfer += iprot->readListBegin(_etype151, _size148); - this->max_values.resize(_size148); - uint32_t _i152; - for (_i152 = 0; _i152 < _size148; ++_i152) + uint32_t _size184; + ::apache::thrift::protocol::TType _etype187; + xfer += iprot->readListBegin(_etype187, _size184); + this->max_values.resize(_size184); + uint32_t _i188; + for (_i188 = 0; _i188 < _size184; ++_i188) { - xfer += iprot->readBinary(this->max_values[_i152]); + xfer += iprot->readBinary(this->max_values[_i188]); } xfer += iprot->readListEnd(); } @@ -5669,27 +7300,27 @@ uint32_t ColumnIndex::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 4: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { - int32_t ecast153; - xfer += iprot->readI32(ecast153); - this->boundary_order = (BoundaryOrder::type)ecast153; + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast189; + xfer += iprot->readI32(ecast189); + this->boundary_order = static_cast(ecast189); isset_boundary_order = true; } else { xfer += iprot->skip(ftype); } break; case 5: - if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { + if (ftype == ::apache::thrift::protocol::T_LIST) { { this->null_counts.clear(); - uint32_t _size154; - ::duckdb_apache::thrift::protocol::TType _etype157; - xfer += iprot->readListBegin(_etype157, _size154); - this->null_counts.resize(_size154); - uint32_t _i158; - for (_i158 = 0; _i158 < _size154; ++_i158) + uint32_t _size190; + ::apache::thrift::protocol::TType _etype193; + xfer += iprot->readListBegin(_etype193, _size190); + this->null_counts.resize(_size190); + uint32_t _i194; + for (_i194 = 0; _i194 < _size190; ++_i194) { - xfer += iprot->readI64(this->null_counts[_i158]); + xfer += iprot->readI64(this->null_counts[_i194]); } xfer += iprot->readListEnd(); } @@ -5698,6 +7329,46 @@ uint32_t ColumnIndex::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) xfer += iprot->skip(ftype); } break; + case 6: + if (ftype == ::apache::thrift::protocol::T_LIST) { + { + this->repetition_level_histograms.clear(); + uint32_t _size195; + ::apache::thrift::protocol::TType _etype198; + xfer += iprot->readListBegin(_etype198, _size195); + this->repetition_level_histograms.resize(_size195); + uint32_t _i199; + for (_i199 = 0; _i199 < _size195; ++_i199) + { + xfer += iprot->readI64(this->repetition_level_histograms[_i199]); + } + xfer += iprot->readListEnd(); + } + this->__isset.repetition_level_histograms = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 7: + if (ftype == ::apache::thrift::protocol::T_LIST) { + { + this->definition_level_histograms.clear(); + uint32_t _size200; + ::apache::thrift::protocol::TType _etype203; + xfer += iprot->readListBegin(_etype203, _size200); + this->definition_level_histograms.resize(_size200); + uint32_t _i204; + for (_i204 = 0; _i204 < _size200; ++_i204) + { + xfer += iprot->readI64(this->definition_level_histograms[_i204]); + } + xfer += iprot->readListEnd(); + } + this->__isset.definition_level_histograms = true; + } else { + xfer += iprot->skip(ftype); + } + break; default: xfer += iprot->skip(ftype); break; @@ -5718,59 +7389,85 @@ uint32_t ColumnIndex::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) return xfer; } -uint32_t ColumnIndex::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t ColumnIndex::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("ColumnIndex"); - xfer += oprot->writeFieldBegin("null_pages", ::duckdb_apache::thrift::protocol::T_LIST, 1); + xfer += oprot->writeFieldBegin("null_pages", ::apache::thrift::protocol::T_LIST, 1); { - xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_BOOL, static_cast(this->null_pages.size())); - duckdb::vector ::const_iterator _iter159; - for (_iter159 = this->null_pages.begin(); _iter159 != this->null_pages.end(); ++_iter159) + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_BOOL, static_cast(this->null_pages.size())); + duckdb::vector ::const_iterator _iter205; + for (_iter205 = this->null_pages.begin(); _iter205 != this->null_pages.end(); ++_iter205) { - xfer += oprot->writeBool((*_iter159)); + xfer += oprot->writeBool((*_iter205)); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("min_values", ::duckdb_apache::thrift::protocol::T_LIST, 2); + xfer += oprot->writeFieldBegin("min_values", ::apache::thrift::protocol::T_LIST, 2); { - xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRING, static_cast(this->min_values.size())); - duckdb::vector ::const_iterator _iter160; - for (_iter160 = this->min_values.begin(); _iter160 != this->min_values.end(); ++_iter160) + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRING, static_cast(this->min_values.size())); + duckdb::vector ::const_iterator _iter206; + for (_iter206 = this->min_values.begin(); _iter206 != this->min_values.end(); ++_iter206) { - xfer += oprot->writeBinary((*_iter160)); + xfer += oprot->writeBinary((*_iter206)); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("max_values", ::duckdb_apache::thrift::protocol::T_LIST, 3); + xfer += oprot->writeFieldBegin("max_values", ::apache::thrift::protocol::T_LIST, 3); { - xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRING, static_cast(this->max_values.size())); - duckdb::vector ::const_iterator _iter161; - for (_iter161 = this->max_values.begin(); _iter161 != this->max_values.end(); ++_iter161) + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRING, static_cast(this->max_values.size())); + duckdb::vector ::const_iterator _iter207; + for (_iter207 = this->max_values.begin(); _iter207 != this->max_values.end(); ++_iter207) { - xfer += oprot->writeBinary((*_iter161)); + xfer += oprot->writeBinary((*_iter207)); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("boundary_order", ::duckdb_apache::thrift::protocol::T_I32, 4); - xfer += oprot->writeI32((int32_t)this->boundary_order); + xfer += oprot->writeFieldBegin("boundary_order", ::apache::thrift::protocol::T_I32, 4); + xfer += oprot->writeI32(static_cast(this->boundary_order)); xfer += oprot->writeFieldEnd(); if (this->__isset.null_counts) { - xfer += oprot->writeFieldBegin("null_counts", ::duckdb_apache::thrift::protocol::T_LIST, 5); + xfer += oprot->writeFieldBegin("null_counts", ::apache::thrift::protocol::T_LIST, 5); + { + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64, static_cast(this->null_counts.size())); + duckdb::vector ::const_iterator _iter208; + for (_iter208 = this->null_counts.begin(); _iter208 != this->null_counts.end(); ++_iter208) + { + xfer += oprot->writeI64((*_iter208)); + } + xfer += oprot->writeListEnd(); + } + xfer += oprot->writeFieldEnd(); + } + if (this->__isset.repetition_level_histograms) { + xfer += oprot->writeFieldBegin("repetition_level_histograms", ::apache::thrift::protocol::T_LIST, 6); + { + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64, static_cast(this->repetition_level_histograms.size())); + duckdb::vector ::const_iterator _iter209; + for (_iter209 = this->repetition_level_histograms.begin(); _iter209 != this->repetition_level_histograms.end(); ++_iter209) + { + xfer += oprot->writeI64((*_iter209)); + } + xfer += oprot->writeListEnd(); + } + xfer += oprot->writeFieldEnd(); + } + if (this->__isset.definition_level_histograms) { + xfer += oprot->writeFieldBegin("definition_level_histograms", ::apache::thrift::protocol::T_LIST, 7); { - xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_I64, static_cast(this->null_counts.size())); - duckdb::vector ::const_iterator _iter162; - for (_iter162 = this->null_counts.begin(); _iter162 != this->null_counts.end(); ++_iter162) + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64, static_cast(this->definition_level_histograms.size())); + duckdb::vector ::const_iterator _iter210; + for (_iter210 = this->definition_level_histograms.begin(); _iter210 != this->definition_level_histograms.end(); ++_iter210) { - xfer += oprot->writeI64((*_iter162)); + xfer += oprot->writeI64((*_iter210)); } xfer += oprot->writeListEnd(); } @@ -5788,41 +7485,54 @@ void swap(ColumnIndex &a, ColumnIndex &b) { swap(a.max_values, b.max_values); swap(a.boundary_order, b.boundary_order); swap(a.null_counts, b.null_counts); + swap(a.repetition_level_histograms, b.repetition_level_histograms); + swap(a.definition_level_histograms, b.definition_level_histograms); swap(a.__isset, b.__isset); } -ColumnIndex::ColumnIndex(const ColumnIndex& other163) { - null_pages = other163.null_pages; - min_values = other163.min_values; - max_values = other163.max_values; - boundary_order = other163.boundary_order; - null_counts = other163.null_counts; - __isset = other163.__isset; -} -ColumnIndex& ColumnIndex::operator=(const ColumnIndex& other164) { - null_pages = other164.null_pages; - min_values = other164.min_values; - max_values = other164.max_values; - boundary_order = other164.boundary_order; - null_counts = other164.null_counts; - __isset = other164.__isset; +ColumnIndex::ColumnIndex(const ColumnIndex& other211) { + null_pages = other211.null_pages; + min_values = other211.min_values; + max_values = other211.max_values; + boundary_order = other211.boundary_order; + null_counts = other211.null_counts; + repetition_level_histograms = other211.repetition_level_histograms; + definition_level_histograms = other211.definition_level_histograms; + __isset = other211.__isset; +} +ColumnIndex& ColumnIndex::operator=(const ColumnIndex& other212) { + null_pages = other212.null_pages; + min_values = other212.min_values; + max_values = other212.max_values; + boundary_order = other212.boundary_order; + null_counts = other212.null_counts; + repetition_level_histograms = other212.repetition_level_histograms; + definition_level_histograms = other212.definition_level_histograms; + __isset = other212.__isset; return *this; } void ColumnIndex::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "ColumnIndex("; out << "null_pages=" << to_string(null_pages); out << ", " << "min_values=" << to_string(min_values); out << ", " << "max_values=" << to_string(max_values); out << ", " << "boundary_order=" << to_string(boundary_order); out << ", " << "null_counts="; (__isset.null_counts ? (out << to_string(null_counts)) : (out << "")); + out << ", " << "repetition_level_histograms="; (__isset.repetition_level_histograms ? (out << to_string(repetition_level_histograms)) : (out << "")); + out << ", " << "definition_level_histograms="; (__isset.definition_level_histograms ? (out << to_string(definition_level_histograms)) : (out << "")); out << ")"; } -AesGcmV1::~AesGcmV1() throw() { +AesGcmV1::~AesGcmV1() noexcept { } +AesGcmV1::AesGcmV1() noexcept + : aad_prefix(), + aad_file_unique(), + supply_aad_prefix(0) { +} void AesGcmV1::__set_aad_prefix(const std::string& val) { this->aad_prefix = val; @@ -5845,29 +7555,29 @@ std::ostream& operator<<(std::ostream& out, const AesGcmV1& obj) } -uint32_t AesGcmV1::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t AesGcmV1::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->aad_prefix); this->__isset.aad_prefix = true; } else { @@ -5875,7 +7585,7 @@ uint32_t AesGcmV1::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->aad_file_unique); this->__isset.aad_file_unique = true; } else { @@ -5883,7 +7593,7 @@ uint32_t AesGcmV1::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { + if (ftype == ::apache::thrift::protocol::T_BOOL) { xfer += iprot->readBool(this->supply_aad_prefix); this->__isset.supply_aad_prefix = true; } else { @@ -5902,23 +7612,23 @@ uint32_t AesGcmV1::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t AesGcmV1::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t AesGcmV1::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("AesGcmV1"); if (this->__isset.aad_prefix) { - xfer += oprot->writeFieldBegin("aad_prefix", ::duckdb_apache::thrift::protocol::T_STRING, 1); + xfer += oprot->writeFieldBegin("aad_prefix", ::apache::thrift::protocol::T_STRING, 1); xfer += oprot->writeBinary(this->aad_prefix); xfer += oprot->writeFieldEnd(); } if (this->__isset.aad_file_unique) { - xfer += oprot->writeFieldBegin("aad_file_unique", ::duckdb_apache::thrift::protocol::T_STRING, 2); + xfer += oprot->writeFieldBegin("aad_file_unique", ::apache::thrift::protocol::T_STRING, 2); xfer += oprot->writeBinary(this->aad_file_unique); xfer += oprot->writeFieldEnd(); } if (this->__isset.supply_aad_prefix) { - xfer += oprot->writeFieldBegin("supply_aad_prefix", ::duckdb_apache::thrift::protocol::T_BOOL, 3); + xfer += oprot->writeFieldBegin("supply_aad_prefix", ::apache::thrift::protocol::T_BOOL, 3); xfer += oprot->writeBool(this->supply_aad_prefix); xfer += oprot->writeFieldEnd(); } @@ -5935,21 +7645,21 @@ void swap(AesGcmV1 &a, AesGcmV1 &b) { swap(a.__isset, b.__isset); } -AesGcmV1::AesGcmV1(const AesGcmV1& other165) { - aad_prefix = other165.aad_prefix; - aad_file_unique = other165.aad_file_unique; - supply_aad_prefix = other165.supply_aad_prefix; - __isset = other165.__isset; +AesGcmV1::AesGcmV1(const AesGcmV1& other213) { + aad_prefix = other213.aad_prefix; + aad_file_unique = other213.aad_file_unique; + supply_aad_prefix = other213.supply_aad_prefix; + __isset = other213.__isset; } -AesGcmV1& AesGcmV1::operator=(const AesGcmV1& other166) { - aad_prefix = other166.aad_prefix; - aad_file_unique = other166.aad_file_unique; - supply_aad_prefix = other166.supply_aad_prefix; - __isset = other166.__isset; +AesGcmV1& AesGcmV1::operator=(const AesGcmV1& other214) { + aad_prefix = other214.aad_prefix; + aad_file_unique = other214.aad_file_unique; + supply_aad_prefix = other214.supply_aad_prefix; + __isset = other214.__isset; return *this; } void AesGcmV1::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "AesGcmV1("; out << "aad_prefix="; (__isset.aad_prefix ? (out << to_string(aad_prefix)) : (out << "")); out << ", " << "aad_file_unique="; (__isset.aad_file_unique ? (out << to_string(aad_file_unique)) : (out << "")); @@ -5958,9 +7668,14 @@ void AesGcmV1::printTo(std::ostream& out) const { } -AesGcmCtrV1::~AesGcmCtrV1() throw() { +AesGcmCtrV1::~AesGcmCtrV1() noexcept { } +AesGcmCtrV1::AesGcmCtrV1() noexcept + : aad_prefix(), + aad_file_unique(), + supply_aad_prefix(0) { +} void AesGcmCtrV1::__set_aad_prefix(const std::string& val) { this->aad_prefix = val; @@ -5983,29 +7698,29 @@ std::ostream& operator<<(std::ostream& out, const AesGcmCtrV1& obj) } -uint32_t AesGcmCtrV1::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t AesGcmCtrV1::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->aad_prefix); this->__isset.aad_prefix = true; } else { @@ -6013,7 +7728,7 @@ uint32_t AesGcmCtrV1::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->aad_file_unique); this->__isset.aad_file_unique = true; } else { @@ -6021,7 +7736,7 @@ uint32_t AesGcmCtrV1::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { + if (ftype == ::apache::thrift::protocol::T_BOOL) { xfer += iprot->readBool(this->supply_aad_prefix); this->__isset.supply_aad_prefix = true; } else { @@ -6040,23 +7755,23 @@ uint32_t AesGcmCtrV1::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) return xfer; } -uint32_t AesGcmCtrV1::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t AesGcmCtrV1::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("AesGcmCtrV1"); if (this->__isset.aad_prefix) { - xfer += oprot->writeFieldBegin("aad_prefix", ::duckdb_apache::thrift::protocol::T_STRING, 1); + xfer += oprot->writeFieldBegin("aad_prefix", ::apache::thrift::protocol::T_STRING, 1); xfer += oprot->writeBinary(this->aad_prefix); xfer += oprot->writeFieldEnd(); } if (this->__isset.aad_file_unique) { - xfer += oprot->writeFieldBegin("aad_file_unique", ::duckdb_apache::thrift::protocol::T_STRING, 2); + xfer += oprot->writeFieldBegin("aad_file_unique", ::apache::thrift::protocol::T_STRING, 2); xfer += oprot->writeBinary(this->aad_file_unique); xfer += oprot->writeFieldEnd(); } if (this->__isset.supply_aad_prefix) { - xfer += oprot->writeFieldBegin("supply_aad_prefix", ::duckdb_apache::thrift::protocol::T_BOOL, 3); + xfer += oprot->writeFieldBegin("supply_aad_prefix", ::apache::thrift::protocol::T_BOOL, 3); xfer += oprot->writeBool(this->supply_aad_prefix); xfer += oprot->writeFieldEnd(); } @@ -6073,21 +7788,21 @@ void swap(AesGcmCtrV1 &a, AesGcmCtrV1 &b) { swap(a.__isset, b.__isset); } -AesGcmCtrV1::AesGcmCtrV1(const AesGcmCtrV1& other167) { - aad_prefix = other167.aad_prefix; - aad_file_unique = other167.aad_file_unique; - supply_aad_prefix = other167.supply_aad_prefix; - __isset = other167.__isset; +AesGcmCtrV1::AesGcmCtrV1(const AesGcmCtrV1& other215) { + aad_prefix = other215.aad_prefix; + aad_file_unique = other215.aad_file_unique; + supply_aad_prefix = other215.supply_aad_prefix; + __isset = other215.__isset; } -AesGcmCtrV1& AesGcmCtrV1::operator=(const AesGcmCtrV1& other168) { - aad_prefix = other168.aad_prefix; - aad_file_unique = other168.aad_file_unique; - supply_aad_prefix = other168.supply_aad_prefix; - __isset = other168.__isset; +AesGcmCtrV1& AesGcmCtrV1::operator=(const AesGcmCtrV1& other216) { + aad_prefix = other216.aad_prefix; + aad_file_unique = other216.aad_file_unique; + supply_aad_prefix = other216.supply_aad_prefix; + __isset = other216.__isset; return *this; } void AesGcmCtrV1::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "AesGcmCtrV1("; out << "aad_prefix="; (__isset.aad_prefix ? (out << to_string(aad_prefix)) : (out << "")); out << ", " << "aad_file_unique="; (__isset.aad_file_unique ? (out << to_string(aad_file_unique)) : (out << "")); @@ -6096,9 +7811,11 @@ void AesGcmCtrV1::printTo(std::ostream& out) const { } -EncryptionAlgorithm::~EncryptionAlgorithm() throw() { +EncryptionAlgorithm::~EncryptionAlgorithm() noexcept { } +EncryptionAlgorithm::EncryptionAlgorithm() noexcept { +} void EncryptionAlgorithm::__set_AES_GCM_V1(const AesGcmV1& val) { this->AES_GCM_V1 = val; @@ -6116,29 +7833,29 @@ std::ostream& operator<<(std::ostream& out, const EncryptionAlgorithm& obj) } -uint32_t EncryptionAlgorithm::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t EncryptionAlgorithm::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->AES_GCM_V1.read(iprot); this->__isset.AES_GCM_V1 = true; } else { @@ -6146,7 +7863,7 @@ uint32_t EncryptionAlgorithm::read(::duckdb_apache::thrift::protocol::TProtocol* } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->AES_GCM_CTR_V1.read(iprot); this->__isset.AES_GCM_CTR_V1 = true; } else { @@ -6165,18 +7882,18 @@ uint32_t EncryptionAlgorithm::read(::duckdb_apache::thrift::protocol::TProtocol* return xfer; } -uint32_t EncryptionAlgorithm::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t EncryptionAlgorithm::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("EncryptionAlgorithm"); if (this->__isset.AES_GCM_V1) { - xfer += oprot->writeFieldBegin("AES_GCM_V1", ::duckdb_apache::thrift::protocol::T_STRUCT, 1); + xfer += oprot->writeFieldBegin("AES_GCM_V1", ::apache::thrift::protocol::T_STRUCT, 1); xfer += this->AES_GCM_V1.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.AES_GCM_CTR_V1) { - xfer += oprot->writeFieldBegin("AES_GCM_CTR_V1", ::duckdb_apache::thrift::protocol::T_STRUCT, 2); + xfer += oprot->writeFieldBegin("AES_GCM_CTR_V1", ::apache::thrift::protocol::T_STRUCT, 2); xfer += this->AES_GCM_CTR_V1.write(oprot); xfer += oprot->writeFieldEnd(); } @@ -6192,19 +7909,19 @@ void swap(EncryptionAlgorithm &a, EncryptionAlgorithm &b) { swap(a.__isset, b.__isset); } -EncryptionAlgorithm::EncryptionAlgorithm(const EncryptionAlgorithm& other169) { - AES_GCM_V1 = other169.AES_GCM_V1; - AES_GCM_CTR_V1 = other169.AES_GCM_CTR_V1; - __isset = other169.__isset; +EncryptionAlgorithm::EncryptionAlgorithm(const EncryptionAlgorithm& other217) { + AES_GCM_V1 = other217.AES_GCM_V1; + AES_GCM_CTR_V1 = other217.AES_GCM_CTR_V1; + __isset = other217.__isset; } -EncryptionAlgorithm& EncryptionAlgorithm::operator=(const EncryptionAlgorithm& other170) { - AES_GCM_V1 = other170.AES_GCM_V1; - AES_GCM_CTR_V1 = other170.AES_GCM_CTR_V1; - __isset = other170.__isset; +EncryptionAlgorithm& EncryptionAlgorithm::operator=(const EncryptionAlgorithm& other218) { + AES_GCM_V1 = other218.AES_GCM_V1; + AES_GCM_CTR_V1 = other218.AES_GCM_CTR_V1; + __isset = other218.__isset; return *this; } void EncryptionAlgorithm::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "EncryptionAlgorithm("; out << "AES_GCM_V1="; (__isset.AES_GCM_V1 ? (out << to_string(AES_GCM_V1)) : (out << "")); out << ", " << "AES_GCM_CTR_V1="; (__isset.AES_GCM_CTR_V1 ? (out << to_string(AES_GCM_CTR_V1)) : (out << "")); @@ -6212,9 +7929,15 @@ void EncryptionAlgorithm::printTo(std::ostream& out) const { } -FileMetaData::~FileMetaData() throw() { +FileMetaData::~FileMetaData() noexcept { } +FileMetaData::FileMetaData() noexcept + : version(0), + num_rows(0), + created_by(), + footer_signing_key_metadata() { +} void FileMetaData::__set_version(const int32_t val) { this->version = val; @@ -6263,17 +7986,17 @@ std::ostream& operator<<(std::ostream& out, const FileMetaData& obj) } -uint32_t FileMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t FileMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_version = false; bool isset_schema = false; @@ -6283,13 +8006,13 @@ uint32_t FileMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + if (ftype == ::apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->version); isset_version = true; } else { @@ -6297,17 +8020,17 @@ uint32_t FileMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { + if (ftype == ::apache::thrift::protocol::T_LIST) { { this->schema.clear(); - uint32_t _size171; - ::duckdb_apache::thrift::protocol::TType _etype174; - xfer += iprot->readListBegin(_etype174, _size171); - this->schema.resize(_size171); - uint32_t _i175; - for (_i175 = 0; _i175 < _size171; ++_i175) + uint32_t _size219; + ::apache::thrift::protocol::TType _etype222; + xfer += iprot->readListBegin(_etype222, _size219); + this->schema.resize(_size219); + uint32_t _i223; + for (_i223 = 0; _i223 < _size219; ++_i223) { - xfer += this->schema[_i175].read(iprot); + xfer += this->schema[_i223].read(iprot); } xfer += iprot->readListEnd(); } @@ -6317,7 +8040,7 @@ uint32_t FileMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 3: - if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { + if (ftype == ::apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->num_rows); isset_num_rows = true; } else { @@ -6325,17 +8048,17 @@ uint32_t FileMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 4: - if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { + if (ftype == ::apache::thrift::protocol::T_LIST) { { this->row_groups.clear(); - uint32_t _size176; - ::duckdb_apache::thrift::protocol::TType _etype179; - xfer += iprot->readListBegin(_etype179, _size176); - this->row_groups.resize(_size176); - uint32_t _i180; - for (_i180 = 0; _i180 < _size176; ++_i180) + uint32_t _size224; + ::apache::thrift::protocol::TType _etype227; + xfer += iprot->readListBegin(_etype227, _size224); + this->row_groups.resize(_size224); + uint32_t _i228; + for (_i228 = 0; _i228 < _size224; ++_i228) { - xfer += this->row_groups[_i180].read(iprot); + xfer += this->row_groups[_i228].read(iprot); } xfer += iprot->readListEnd(); } @@ -6345,17 +8068,17 @@ uint32_t FileMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 5: - if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { + if (ftype == ::apache::thrift::protocol::T_LIST) { { this->key_value_metadata.clear(); - uint32_t _size181; - ::duckdb_apache::thrift::protocol::TType _etype184; - xfer += iprot->readListBegin(_etype184, _size181); - this->key_value_metadata.resize(_size181); - uint32_t _i185; - for (_i185 = 0; _i185 < _size181; ++_i185) + uint32_t _size229; + ::apache::thrift::protocol::TType _etype232; + xfer += iprot->readListBegin(_etype232, _size229); + this->key_value_metadata.resize(_size229); + uint32_t _i233; + for (_i233 = 0; _i233 < _size229; ++_i233) { - xfer += this->key_value_metadata[_i185].read(iprot); + xfer += this->key_value_metadata[_i233].read(iprot); } xfer += iprot->readListEnd(); } @@ -6365,7 +8088,7 @@ uint32_t FileMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 6: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readString(this->created_by); this->__isset.created_by = true; } else { @@ -6373,17 +8096,17 @@ uint32_t FileMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 7: - if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { + if (ftype == ::apache::thrift::protocol::T_LIST) { { this->column_orders.clear(); - uint32_t _size186; - ::duckdb_apache::thrift::protocol::TType _etype189; - xfer += iprot->readListBegin(_etype189, _size186); - this->column_orders.resize(_size186); - uint32_t _i190; - for (_i190 = 0; _i190 < _size186; ++_i190) + uint32_t _size234; + ::apache::thrift::protocol::TType _etype237; + xfer += iprot->readListBegin(_etype237, _size234); + this->column_orders.resize(_size234); + uint32_t _i238; + for (_i238 = 0; _i238 < _size234; ++_i238) { - xfer += this->column_orders[_i190].read(iprot); + xfer += this->column_orders[_i238].read(iprot); } xfer += iprot->readListEnd(); } @@ -6393,7 +8116,7 @@ uint32_t FileMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 8: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->encryption_algorithm.read(iprot); this->__isset.encryption_algorithm = true; } else { @@ -6401,7 +8124,7 @@ uint32_t FileMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) } break; case 9: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->footer_signing_key_metadata); this->__isset.footer_signing_key_metadata = true; } else { @@ -6428,81 +8151,81 @@ uint32_t FileMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) return xfer; } -uint32_t FileMetaData::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t FileMetaData::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("FileMetaData"); - xfer += oprot->writeFieldBegin("version", ::duckdb_apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeFieldBegin("version", ::apache::thrift::protocol::T_I32, 1); xfer += oprot->writeI32(this->version); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("schema", ::duckdb_apache::thrift::protocol::T_LIST, 2); + xfer += oprot->writeFieldBegin("schema", ::apache::thrift::protocol::T_LIST, 2); { - xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->schema.size())); - duckdb::vector ::const_iterator _iter191; - for (_iter191 = this->schema.begin(); _iter191 != this->schema.end(); ++_iter191) + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->schema.size())); + duckdb::vector ::const_iterator _iter239; + for (_iter239 = this->schema.begin(); _iter239 != this->schema.end(); ++_iter239) { - xfer += (*_iter191).write(oprot); + xfer += (*_iter239).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("num_rows", ::duckdb_apache::thrift::protocol::T_I64, 3); + xfer += oprot->writeFieldBegin("num_rows", ::apache::thrift::protocol::T_I64, 3); xfer += oprot->writeI64(this->num_rows); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("row_groups", ::duckdb_apache::thrift::protocol::T_LIST, 4); + xfer += oprot->writeFieldBegin("row_groups", ::apache::thrift::protocol::T_LIST, 4); { - xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->row_groups.size())); - duckdb::vector ::const_iterator _iter192; - for (_iter192 = this->row_groups.begin(); _iter192 != this->row_groups.end(); ++_iter192) + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->row_groups.size())); + duckdb::vector ::const_iterator _iter240; + for (_iter240 = this->row_groups.begin(); _iter240 != this->row_groups.end(); ++_iter240) { - xfer += (*_iter192).write(oprot); + xfer += (*_iter240).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); if (this->__isset.key_value_metadata) { - xfer += oprot->writeFieldBegin("key_value_metadata", ::duckdb_apache::thrift::protocol::T_LIST, 5); + xfer += oprot->writeFieldBegin("key_value_metadata", ::apache::thrift::protocol::T_LIST, 5); { - xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->key_value_metadata.size())); - duckdb::vector ::const_iterator _iter193; - for (_iter193 = this->key_value_metadata.begin(); _iter193 != this->key_value_metadata.end(); ++_iter193) + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->key_value_metadata.size())); + duckdb::vector ::const_iterator _iter241; + for (_iter241 = this->key_value_metadata.begin(); _iter241 != this->key_value_metadata.end(); ++_iter241) { - xfer += (*_iter193).write(oprot); + xfer += (*_iter241).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); } if (this->__isset.created_by) { - xfer += oprot->writeFieldBegin("created_by", ::duckdb_apache::thrift::protocol::T_STRING, 6); + xfer += oprot->writeFieldBegin("created_by", ::apache::thrift::protocol::T_STRING, 6); xfer += oprot->writeString(this->created_by); xfer += oprot->writeFieldEnd(); } if (this->__isset.column_orders) { - xfer += oprot->writeFieldBegin("column_orders", ::duckdb_apache::thrift::protocol::T_LIST, 7); + xfer += oprot->writeFieldBegin("column_orders", ::apache::thrift::protocol::T_LIST, 7); { - xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->column_orders.size())); - duckdb::vector ::const_iterator _iter194; - for (_iter194 = this->column_orders.begin(); _iter194 != this->column_orders.end(); ++_iter194) + xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->column_orders.size())); + duckdb::vector ::const_iterator _iter242; + for (_iter242 = this->column_orders.begin(); _iter242 != this->column_orders.end(); ++_iter242) { - xfer += (*_iter194).write(oprot); + xfer += (*_iter242).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); } if (this->__isset.encryption_algorithm) { - xfer += oprot->writeFieldBegin("encryption_algorithm", ::duckdb_apache::thrift::protocol::T_STRUCT, 8); + xfer += oprot->writeFieldBegin("encryption_algorithm", ::apache::thrift::protocol::T_STRUCT, 8); xfer += this->encryption_algorithm.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.footer_signing_key_metadata) { - xfer += oprot->writeFieldBegin("footer_signing_key_metadata", ::duckdb_apache::thrift::protocol::T_STRING, 9); + xfer += oprot->writeFieldBegin("footer_signing_key_metadata", ::apache::thrift::protocol::T_STRING, 9); xfer += oprot->writeBinary(this->footer_signing_key_metadata); xfer += oprot->writeFieldEnd(); } @@ -6525,34 +8248,33 @@ void swap(FileMetaData &a, FileMetaData &b) { swap(a.__isset, b.__isset); } -FileMetaData::FileMetaData(const FileMetaData& other195) { - version = other195.version; - schema = other195.schema; - num_rows = other195.num_rows; - row_groups = other195.row_groups; - key_value_metadata = other195.key_value_metadata; - created_by = other195.created_by; - column_orders = other195.column_orders; - encryption_algorithm = other195.encryption_algorithm; - footer_signing_key_metadata = other195.footer_signing_key_metadata; - __isset = other195.__isset; -} -FileMetaData& FileMetaData::operator=(const FileMetaData& other196) { - version = other196.version; - schema = other196.schema; - num_rows = other196.num_rows; - row_groups = other196.row_groups; - key_value_metadata = other196.key_value_metadata; - created_by = other196.created_by; - column_orders = other196.column_orders; - encryption_algorithm = other196.encryption_algorithm; - footer_signing_key_metadata = other196.footer_signing_key_metadata; - __isset = other196.__isset; +FileMetaData::FileMetaData(const FileMetaData& other243) { + version = other243.version; + schema = other243.schema; + num_rows = other243.num_rows; + row_groups = other243.row_groups; + key_value_metadata = other243.key_value_metadata; + created_by = other243.created_by; + column_orders = other243.column_orders; + encryption_algorithm = other243.encryption_algorithm; + footer_signing_key_metadata = other243.footer_signing_key_metadata; + __isset = other243.__isset; +} +FileMetaData& FileMetaData::operator=(const FileMetaData& other244) { + version = other244.version; + schema = other244.schema; + num_rows = other244.num_rows; + row_groups = other244.row_groups; + key_value_metadata = other244.key_value_metadata; + created_by = other244.created_by; + column_orders = other244.column_orders; + encryption_algorithm = other244.encryption_algorithm; + footer_signing_key_metadata = other244.footer_signing_key_metadata; + __isset = other244.__isset; return *this; } - void FileMetaData::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "FileMetaData("; out << "version=" << to_string(version); out << ", " << "schema=" << to_string(schema); @@ -6567,9 +8289,12 @@ void FileMetaData::printTo(std::ostream& out) const { } -FileCryptoMetaData::~FileCryptoMetaData() throw() { +FileCryptoMetaData::~FileCryptoMetaData() noexcept { } +FileCryptoMetaData::FileCryptoMetaData() noexcept + : key_metadata() { +} void FileCryptoMetaData::__set_encryption_algorithm(const EncryptionAlgorithm& val) { this->encryption_algorithm = val; @@ -6586,30 +8311,30 @@ std::ostream& operator<<(std::ostream& out, const FileCryptoMetaData& obj) } -uint32_t FileCryptoMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { +uint32_t FileCryptoMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { - ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::duckdb_apache::thrift::protocol::TType ftype; + ::apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::duckdb_apache::thrift::protocol::TProtocolException; + using ::apache::thrift::protocol::TProtocolException; bool isset_encryption_algorithm = false; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { + if (ftype == ::apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + if (ftype == ::apache::thrift::protocol::T_STRUCT) { xfer += this->encryption_algorithm.read(iprot); isset_encryption_algorithm = true; } else { @@ -6617,7 +8342,7 @@ uint32_t FileCryptoMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* } break; case 2: - if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { + if (ftype == ::apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->key_metadata); this->__isset.key_metadata = true; } else { @@ -6638,17 +8363,17 @@ uint32_t FileCryptoMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* return xfer; } -uint32_t FileCryptoMetaData::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { +uint32_t FileCryptoMetaData::write(::apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("FileCryptoMetaData"); - xfer += oprot->writeFieldBegin("encryption_algorithm", ::duckdb_apache::thrift::protocol::T_STRUCT, 1); + xfer += oprot->writeFieldBegin("encryption_algorithm", ::apache::thrift::protocol::T_STRUCT, 1); xfer += this->encryption_algorithm.write(oprot); xfer += oprot->writeFieldEnd(); if (this->__isset.key_metadata) { - xfer += oprot->writeFieldBegin("key_metadata", ::duckdb_apache::thrift::protocol::T_STRING, 2); + xfer += oprot->writeFieldBegin("key_metadata", ::apache::thrift::protocol::T_STRING, 2); xfer += oprot->writeBinary(this->key_metadata); xfer += oprot->writeFieldEnd(); } @@ -6664,24 +8389,23 @@ void swap(FileCryptoMetaData &a, FileCryptoMetaData &b) { swap(a.__isset, b.__isset); } -FileCryptoMetaData::FileCryptoMetaData(const FileCryptoMetaData& other197) { - encryption_algorithm = other197.encryption_algorithm; - key_metadata = other197.key_metadata; - __isset = other197.__isset; +FileCryptoMetaData::FileCryptoMetaData(const FileCryptoMetaData& other245) { + encryption_algorithm = other245.encryption_algorithm; + key_metadata = other245.key_metadata; + __isset = other245.__isset; } -FileCryptoMetaData& FileCryptoMetaData::operator=(const FileCryptoMetaData& other198) { - encryption_algorithm = other198.encryption_algorithm; - key_metadata = other198.key_metadata; - __isset = other198.__isset; +FileCryptoMetaData& FileCryptoMetaData::operator=(const FileCryptoMetaData& other246) { + encryption_algorithm = other246.encryption_algorithm; + key_metadata = other246.key_metadata; + __isset = other246.__isset; return *this; } void FileCryptoMetaData::printTo(std::ostream& out) const { - using ::duckdb_apache::thrift::to_string; + using ::apache::thrift::to_string; out << "FileCryptoMetaData("; out << "encryption_algorithm=" << to_string(encryption_algorithm); out << ", " << "key_metadata="; (__isset.key_metadata ? (out << to_string(key_metadata)) : (out << "")); out << ")"; } - -}} // namespace +} // namespace diff --git a/src/duckdb/third_party/parquet/parquet_types.h b/src/duckdb/third_party/parquet/parquet_types.h index af109ee97..df8cf5f17 100644 --- a/src/duckdb/third_party/parquet/parquet_types.h +++ b/src/duckdb/third_party/parquet/parquet_types.h @@ -1,5 +1,5 @@ /** - * Autogenerated by Thrift Compiler (0.11.0) + * Autogenerated by Thrift Compiler (0.21.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -9,20 +9,27 @@ #include -#include "duckdb/common/vector.hpp" +#include +#include +#include +#include +#include -#include "thrift/Thrift.h" -#include "thrift/TApplicationException.h" -#include "thrift/TBase.h" -#include "thrift/protocol/TProtocol.h" -#include "thrift/transport/TTransport.h" +#include +#include -#include "thrift/stdcxx.h" #include "windows_compatibility.h" +namespace apache = duckdb_apache; -namespace duckdb_parquet { namespace format { +namespace duckdb_parquet { +/** + * Types supported by Parquet. These types are intended to be used in combination + * with the encodings to control the on disk storage format. + * For example INT16 is not included as a type since a good encoding of INT32 + * would handle this. + */ struct Type { enum type { BOOLEAN = 0, @@ -36,66 +43,263 @@ struct Type { }; }; +extern const std::map _Type_VALUES_TO_NAMES; + std::ostream& operator<<(std::ostream& out, const Type::type& val); +std::string to_string(const Type::type& val); + +/** + * DEPRECATED: Common types used by frameworks(e.g. hive, pig) using parquet. + * ConvertedType is superseded by LogicalType. This enum should not be extended. + * + * See LogicalTypes.md for conversion between ConvertedType and LogicalType. + */ struct ConvertedType { enum type { + /** + * a BYTE_ARRAY actually contains UTF8 encoded chars + */ UTF8 = 0, + /** + * a map is converted as an optional field containing a repeated key/value pair + */ MAP = 1, + /** + * a key/value pair is converted into a group of two fields + */ MAP_KEY_VALUE = 2, + /** + * a list is converted into an optional field containing a repeated field for its + * values + */ LIST = 3, + /** + * an enum is converted into a BYTE_ARRAY field + */ ENUM = 4, + /** + * A decimal value. + * + * This may be used to annotate BYTE_ARRAY or FIXED_LEN_BYTE_ARRAY primitive + * types. The underlying byte array stores the unscaled value encoded as two's + * complement using big-endian byte order (the most significant byte is the + * zeroth element). The value of the decimal is the value * 10^{-scale}. + * + * This must be accompanied by a (maximum) precision and a scale in the + * SchemaElement. The precision specifies the number of digits in the decimal + * and the scale stores the location of the decimal point. For example 1.23 + * would have precision 3 (3 total digits) and scale 2 (the decimal point is + * 2 digits over). + */ DECIMAL = 5, + /** + * A Date + * + * Stored as days since Unix epoch, encoded as the INT32 physical type. + * + */ DATE = 6, + /** + * A time + * + * The total number of milliseconds since midnight. The value is stored + * as an INT32 physical type. + */ TIME_MILLIS = 7, + /** + * A time. + * + * The total number of microseconds since midnight. The value is stored as + * an INT64 physical type. + */ TIME_MICROS = 8, + /** + * A date/time combination + * + * Date and time recorded as milliseconds since the Unix epoch. Recorded as + * a physical type of INT64. + */ TIMESTAMP_MILLIS = 9, + /** + * A date/time combination + * + * Date and time recorded as microseconds since the Unix epoch. The value is + * stored as an INT64 physical type. + */ TIMESTAMP_MICROS = 10, + /** + * An unsigned integer value. + * + * The number describes the maximum number of meaningful data bits in + * the stored value. 8, 16 and 32 bit values are stored using the + * INT32 physical type. 64 bit values are stored using the INT64 + * physical type. + * + */ UINT_8 = 11, UINT_16 = 12, UINT_32 = 13, UINT_64 = 14, + /** + * A signed integer value. + * + * The number describes the maximum number of meaningful data bits in + * the stored value. 8, 16 and 32 bit values are stored using the + * INT32 physical type. 64 bit values are stored using the INT64 + * physical type. + * + */ INT_8 = 15, INT_16 = 16, INT_32 = 17, INT_64 = 18, + /** + * An embedded JSON document + * + * A JSON document embedded within a single UTF8 column. + */ JSON = 19, + /** + * An embedded BSON document + * + * A BSON document embedded within a single BYTE_ARRAY column. + */ BSON = 20, - INTERVAL = 21, - NULL_TYPE = 24 + /** + * An interval of time + * + * This type annotates data stored as a FIXED_LEN_BYTE_ARRAY of length 12 + * This data is composed of three separate little endian unsigned + * integers. Each stores a component of a duration of time. The first + * integer identifies the number of months associated with the duration, + * the second identifies the number of days associated with the duration + * and the third identifies the number of milliseconds associated with + * the provided duration. This duration of time is independent of any + * particular timezone or date. + */ + INTERVAL = 21 }; }; +extern const std::map _ConvertedType_VALUES_TO_NAMES; + std::ostream& operator<<(std::ostream& out, const ConvertedType::type& val); +std::string to_string(const ConvertedType::type& val); + +/** + * Representation of Schemas + */ struct FieldRepetitionType { enum type { + /** + * This field is required (can not be null) and each row has exactly 1 value. + */ REQUIRED = 0, + /** + * The field is optional (can be null) and each row has 0 or 1 values. + */ OPTIONAL = 1, + /** + * The field is repeated and can contain 0 or more values + */ REPEATED = 2 }; }; +extern const std::map _FieldRepetitionType_VALUES_TO_NAMES; + std::ostream& operator<<(std::ostream& out, const FieldRepetitionType::type& val); +std::string to_string(const FieldRepetitionType::type& val); + +/** + * Encodings supported by Parquet. Not all encodings are valid for all types. These + * enums are also used to specify the encoding of definition and repetition levels. + * See the accompanying doc for the details of the more complicated encodings. + */ struct Encoding { enum type { + /** + * Default encoding. + * BOOLEAN - 1 bit per value. 0 is false; 1 is true. + * INT32 - 4 bytes per value. Stored as little-endian. + * INT64 - 8 bytes per value. Stored as little-endian. + * FLOAT - 4 bytes per value. IEEE. Stored as little-endian. + * DOUBLE - 8 bytes per value. IEEE. Stored as little-endian. + * BYTE_ARRAY - 4 byte length stored as little endian, followed by bytes. + * FIXED_LEN_BYTE_ARRAY - Just the bytes. + */ PLAIN = 0, + /** + * Deprecated: Dictionary encoding. The values in the dictionary are encoded in the + * plain type. + * in a data page use RLE_DICTIONARY instead. + * in a Dictionary page use PLAIN instead + */ PLAIN_DICTIONARY = 2, + /** + * Group packed run length encoding. Usable for definition/repetition levels + * encoding and Booleans (on one bit: 0 is false; 1 is true.) + */ RLE = 3, + /** + * Bit packed encoding. This can only be used if the data has a known max + * width. Usable for definition/repetition levels encoding. + */ BIT_PACKED = 4, + /** + * Delta encoding for integers. This can be used for int columns and works best + * on sorted data + */ DELTA_BINARY_PACKED = 5, + /** + * Encoding for byte arrays to separate the length values and the data. The lengths + * are encoded using DELTA_BINARY_PACKED + */ DELTA_LENGTH_BYTE_ARRAY = 6, + /** + * Incremental-encoded byte array. Prefix lengths are encoded using DELTA_BINARY_PACKED. + * Suffixes are stored as delta length byte arrays. + */ DELTA_BYTE_ARRAY = 7, + /** + * Dictionary encoding: the ids are encoded using the RLE encoding + */ RLE_DICTIONARY = 8, - BYTE_STREAM_SPLIT = 9, + /** + * Encoding for fixed-width data (FLOAT, DOUBLE, INT32, INT64, FIXED_LEN_BYTE_ARRAY). + * K byte-streams are created where K is the size in bytes of the data type. + * The individual bytes of a value are scattered to the corresponding stream and + * the streams are concatenated. + * This itself does not reduce the size of the data but can lead to better compression + * afterwards. + * + * Added in 2.8 for FLOAT and DOUBLE. + * Support for INT32, INT64 and FIXED_LEN_BYTE_ARRAY added in 2.11. + */ + BYTE_STREAM_SPLIT = 9 }; }; +extern const std::map _Encoding_VALUES_TO_NAMES; + std::ostream& operator<<(std::ostream& out, const Encoding::type& val); +std::string to_string(const Encoding::type& val); + +/** + * Supported compression algorithms. + * + * Codecs added in format version X.Y can be read by readers based on X.Y and later. + * Codec support may vary between readers based on the format version and + * libraries available at runtime. + * + * See Compression.md for a detailed specification of these algorithms. + */ struct CompressionCodec { - enum type : uint8_t { + enum type { UNCOMPRESSED = 0, SNAPPY = 1, GZIP = 2, @@ -103,12 +307,16 @@ struct CompressionCodec { BROTLI = 4, LZ4 = 5, ZSTD = 6, - LZ4_RAW = 7 + LZ4_RAW = 7 }; }; +extern const std::map _CompressionCodec_VALUES_TO_NAMES; + std::ostream& operator<<(std::ostream& out, const CompressionCodec::type& val); +std::string to_string(const CompressionCodec::type& val); + struct PageType { enum type { DATA_PAGE = 0, @@ -118,8 +326,16 @@ struct PageType { }; }; +extern const std::map _PageType_VALUES_TO_NAMES; + std::ostream& operator<<(std::ostream& out, const PageType::type& val); +std::string to_string(const PageType::type& val); + +/** + * Enum to annotate whether lists of min/max elements inside ColumnIndex + * are ordered and if so, in which direction. + */ struct BoundaryOrder { enum type { UNORDERED = 0, @@ -128,8 +344,14 @@ struct BoundaryOrder { }; }; +extern const std::map _BoundaryOrder_VALUES_TO_NAMES; + std::ostream& operator<<(std::ostream& out, const BoundaryOrder::type& val); +std::string to_string(const BoundaryOrder::type& val); + +class SizeStatistics; + class Statistics; class StringType; @@ -144,6 +366,8 @@ class EnumType; class DateType; +class Float16Type; + class NullType; class DecimalType; @@ -178,6 +402,20 @@ class DictionaryPageHeader; class DataPageHeaderV2; +class SplitBlockAlgorithm; + +class BloomFilterAlgorithm; + +class XxHash; + +class BloomFilterHash; + +class Uncompressed; + +class BloomFilterCompression; + +class BloomFilterHeader; + class PageHeader; class KeyValue; @@ -218,31 +456,159 @@ class FileMetaData; class FileCryptoMetaData; +typedef struct _SizeStatistics__isset { + _SizeStatistics__isset() : unencoded_byte_array_data_bytes(false), repetition_level_histogram(false), definition_level_histogram(false) {} + bool unencoded_byte_array_data_bytes :1; + bool repetition_level_histogram :1; + bool definition_level_histogram :1; +} _SizeStatistics__isset; + +/** + * A structure for capturing metadata for estimating the unencoded, + * uncompressed size of data written. This is useful for readers to estimate + * how much memory is needed to reconstruct data in their memory model and for + * fine grained filter pushdown on nested structures (the histograms contained + * in this structure can help determine the number of nulls at a particular + * nesting level and maximum length of lists). + */ +class SizeStatistics : public virtual ::apache::thrift::TBase { + public: + + SizeStatistics(const SizeStatistics&); + SizeStatistics& operator=(const SizeStatistics&); + SizeStatistics() noexcept; + + virtual ~SizeStatistics() noexcept; + /** + * The number of physical bytes stored for BYTE_ARRAY data values assuming + * no encoding. This is exclusive of the bytes needed to store the length of + * each byte array. In other words, this field is equivalent to the `(size + * of PLAIN-ENCODING the byte array values) - (4 bytes * number of values + * written)`. To determine unencoded sizes of other types readers can use + * schema information multiplied by the number of non-null and null values. + * The number of null/non-null values can be inferred from the histograms + * below. + * + * For example, if a column chunk is dictionary-encoded with dictionary + * ["a", "bc", "cde"], and a data page contains the indices [0, 0, 1, 2], + * then this value for that data page should be 7 (1 + 1 + 2 + 3). + * + * This field should only be set for types that use BYTE_ARRAY as their + * physical type. + */ + int64_t unencoded_byte_array_data_bytes; + /** + * When present, there is expected to be one element corresponding to each + * repetition (i.e. size=max repetition_level+1) where each element + * represents the number of times the repetition level was observed in the + * data. + * + * This field may be omitted if max_repetition_level is 0 without loss + * of information. + * + */ + duckdb::vector repetition_level_histogram; + /** + * Same as repetition_level_histogram except for definition levels. + * + * This field may be omitted if max_definition_level is 0 or 1 without + * loss of information. + * + */ + duckdb::vector definition_level_histogram; + + _SizeStatistics__isset __isset; + + void __set_unencoded_byte_array_data_bytes(const int64_t val); + + void __set_repetition_level_histogram(const duckdb::vector & val); + + void __set_definition_level_histogram(const duckdb::vector & val); + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + + virtual void printTo(std::ostream& out) const; +}; + +void swap(SizeStatistics &a, SizeStatistics &b); + +std::ostream& operator<<(std::ostream& out, const SizeStatistics& obj); + typedef struct _Statistics__isset { - _Statistics__isset() : max(false), min(false), null_count(false), distinct_count(false), max_value(false), min_value(false) {} + _Statistics__isset() : max(false), min(false), null_count(false), distinct_count(false), max_value(false), min_value(false), is_max_value_exact(false), is_min_value_exact(false) {} bool max :1; bool min :1; bool null_count :1; bool distinct_count :1; bool max_value :1; bool min_value :1; + bool is_max_value_exact :1; + bool is_min_value_exact :1; } _Statistics__isset; -class Statistics : public virtual ::duckdb_apache::thrift::TBase { +/** + * Statistics per row group and per page + * All fields are optional. + */ +class Statistics : public virtual ::apache::thrift::TBase { public: Statistics(const Statistics&); Statistics& operator=(const Statistics&); - Statistics() : max(), min(), null_count(0), distinct_count(0), max_value(), min_value() { - } - - virtual ~Statistics() throw(); + Statistics() noexcept; + + virtual ~Statistics() noexcept; + /** + * DEPRECATED: min and max value of the column. Use min_value and max_value. + * + * Values are encoded using PLAIN encoding, except that variable-length byte + * arrays do not include a length prefix. + * + * These fields encode min and max values determined by signed comparison + * only. New files should use the correct order for a column's logical type + * and store the values in the min_value and max_value fields. + * + * To support older readers, these may be set when the column order is + * signed. + */ std::string max; std::string min; + /** + * Count of null values in the column. + * + * Writers SHOULD always write this field even if it is zero (i.e. no null value) + * or the column is not nullable. + * Readers MUST distinguish between null_count not being present and null_count == 0. + * If null_count is not present, readers MUST NOT assume null_count == 0. + */ int64_t null_count; + /** + * count of distinct values occurring + */ int64_t distinct_count; + /** + * Lower and upper bound values for the column, determined by its ColumnOrder. + * + * These may be the actual minimum and maximum values found on a page or column + * chunk, but can also be (more compact) values that do not exist on a page or + * column chunk. For example, instead of storing "Blart Versenwald III", a writer + * may set min_value="B", max_value="C". Such more compact values must still be + * valid values within the column's logical type. + * + * Values are encoded using PLAIN encoding, except that variable-length byte + * arrays do not include a length prefix. + */ std::string max_value; std::string min_value; + /** + * If true, max_value is the actual maximum value for a column + */ + bool is_max_value_exact; + /** + * If true, min_value is the actual minimum value for a column + */ + bool is_min_value_exact; _Statistics__isset __isset; @@ -258,42 +624,12 @@ class Statistics : public virtual ::duckdb_apache::thrift::TBase { void __set_min_value(const std::string& val); - bool operator == (const Statistics & rhs) const - { - if (__isset.max != rhs.__isset.max) - return false; - else if (__isset.max && !(max == rhs.max)) - return false; - if (__isset.min != rhs.__isset.min) - return false; - else if (__isset.min && !(min == rhs.min)) - return false; - if (__isset.null_count != rhs.__isset.null_count) - return false; - else if (__isset.null_count && !(null_count == rhs.null_count)) - return false; - if (__isset.distinct_count != rhs.__isset.distinct_count) - return false; - else if (__isset.distinct_count && !(distinct_count == rhs.distinct_count)) - return false; - if (__isset.max_value != rhs.__isset.max_value) - return false; - else if (__isset.max_value && !(max_value == rhs.max_value)) - return false; - if (__isset.min_value != rhs.__isset.min_value) - return false; - else if (__isset.min_value && !(min_value == rhs.min_value)) - return false; - return true; - } - bool operator != (const Statistics &rhs) const { - return !(*this == rhs); - } - - bool operator < (const Statistics & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + void __set_is_max_value_exact(const bool val); + + void __set_is_min_value_exact(const bool val); + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -303,28 +639,20 @@ void swap(Statistics &a, Statistics &b); std::ostream& operator<<(std::ostream& out, const Statistics& obj); -class StringType : public virtual ::duckdb_apache::thrift::TBase { +/** + * Empty structs to use as logical type annotations + */ +class StringType : public virtual ::apache::thrift::TBase { public: - StringType(const StringType&); - StringType& operator=(const StringType&); - StringType() { - } + StringType(const StringType&) noexcept; + StringType& operator=(const StringType&) noexcept; + StringType() noexcept; - virtual ~StringType() throw(); + virtual ~StringType() noexcept; - bool operator == (const StringType & /* rhs */) const - { - return true; - } - bool operator != (const StringType &rhs) const { - return !(*this == rhs); - } - - bool operator < (const StringType & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -334,28 +662,17 @@ void swap(StringType &a, StringType &b); std::ostream& operator<<(std::ostream& out, const StringType& obj); -class UUIDType : public virtual ::duckdb_apache::thrift::TBase { +class UUIDType : public virtual ::apache::thrift::TBase { public: - UUIDType(const UUIDType&); - UUIDType& operator=(const UUIDType&); - UUIDType() { - } - - virtual ~UUIDType() throw(); - - bool operator == (const UUIDType & /* rhs */) const - { - return true; - } - bool operator != (const UUIDType &rhs) const { - return !(*this == rhs); - } + UUIDType(const UUIDType&) noexcept; + UUIDType& operator=(const UUIDType&) noexcept; + UUIDType() noexcept; - bool operator < (const UUIDType & ) const; + virtual ~UUIDType() noexcept; - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -365,28 +682,17 @@ void swap(UUIDType &a, UUIDType &b); std::ostream& operator<<(std::ostream& out, const UUIDType& obj); -class MapType : public virtual ::duckdb_apache::thrift::TBase { +class MapType : public virtual ::apache::thrift::TBase { public: - MapType(const MapType&); - MapType& operator=(const MapType&); - MapType() { - } + MapType(const MapType&) noexcept; + MapType& operator=(const MapType&) noexcept; + MapType() noexcept; - virtual ~MapType() throw(); + virtual ~MapType() noexcept; - bool operator == (const MapType & /* rhs */) const - { - return true; - } - bool operator != (const MapType &rhs) const { - return !(*this == rhs); - } - - bool operator < (const MapType & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -396,28 +702,17 @@ void swap(MapType &a, MapType &b); std::ostream& operator<<(std::ostream& out, const MapType& obj); -class ListType : public virtual ::duckdb_apache::thrift::TBase { +class ListType : public virtual ::apache::thrift::TBase { public: - ListType(const ListType&); - ListType& operator=(const ListType&); - ListType() { - } - - virtual ~ListType() throw(); - - bool operator == (const ListType & /* rhs */) const - { - return true; - } - bool operator != (const ListType &rhs) const { - return !(*this == rhs); - } + ListType(const ListType&) noexcept; + ListType& operator=(const ListType&) noexcept; + ListType() noexcept; - bool operator < (const ListType & ) const; + virtual ~ListType() noexcept; - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -427,28 +722,17 @@ void swap(ListType &a, ListType &b); std::ostream& operator<<(std::ostream& out, const ListType& obj); -class EnumType : public virtual ::duckdb_apache::thrift::TBase { +class EnumType : public virtual ::apache::thrift::TBase { public: - EnumType(const EnumType&); - EnumType& operator=(const EnumType&); - EnumType() { - } + EnumType(const EnumType&) noexcept; + EnumType& operator=(const EnumType&) noexcept; + EnumType() noexcept; - virtual ~EnumType() throw(); + virtual ~EnumType() noexcept; - bool operator == (const EnumType & /* rhs */) const - { - return true; - } - bool operator != (const EnumType &rhs) const { - return !(*this == rhs); - } - - bool operator < (const EnumType & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -458,28 +742,17 @@ void swap(EnumType &a, EnumType &b); std::ostream& operator<<(std::ostream& out, const EnumType& obj); -class DateType : public virtual ::duckdb_apache::thrift::TBase { +class DateType : public virtual ::apache::thrift::TBase { public: - DateType(const DateType&); - DateType& operator=(const DateType&); - DateType() { - } - - virtual ~DateType() throw(); - - bool operator == (const DateType & /* rhs */) const - { - return true; - } - bool operator != (const DateType &rhs) const { - return !(*this == rhs); - } + DateType(const DateType&) noexcept; + DateType& operator=(const DateType&) noexcept; + DateType() noexcept; - bool operator < (const DateType & ) const; + virtual ~DateType() noexcept; - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -489,28 +762,44 @@ void swap(DateType &a, DateType &b); std::ostream& operator<<(std::ostream& out, const DateType& obj); -class NullType : public virtual ::duckdb_apache::thrift::TBase { +class Float16Type : public virtual ::apache::thrift::TBase { public: - NullType(const NullType&); - NullType& operator=(const NullType&); - NullType() { - } + Float16Type(const Float16Type&) noexcept; + Float16Type& operator=(const Float16Type&) noexcept; + Float16Type() noexcept; - virtual ~NullType() throw(); + virtual ~Float16Type() noexcept; - bool operator == (const NullType & /* rhs */) const - { - return true; - } - bool operator != (const NullType &rhs) const { - return !(*this == rhs); - } + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; - bool operator < (const NullType & ) const; + virtual void printTo(std::ostream& out) const; +}; + +void swap(Float16Type &a, Float16Type &b); + +std::ostream& operator<<(std::ostream& out, const Float16Type& obj); + + +/** + * Logical type to annotate a column that is always null. + * + * Sometimes when discovering the schema of existing data, values are always + * null and the physical type can't be determined. This annotation signals + * the case where the physical type was guessed from all null values. + */ +class NullType : public virtual ::apache::thrift::TBase { + public: - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + NullType(const NullType&) noexcept; + NullType& operator=(const NullType&) noexcept; + NullType() noexcept; + + virtual ~NullType() noexcept; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -520,15 +809,25 @@ void swap(NullType &a, NullType &b); std::ostream& operator<<(std::ostream& out, const NullType& obj); -class DecimalType : public virtual ::duckdb_apache::thrift::TBase { +/** + * Decimal logical type annotation + * + * Scale must be zero or a positive integer less than or equal to the precision. + * Precision must be a non-zero positive integer. + * + * To maintain forward-compatibility in v1, implementations using this logical + * type must also set scale and precision on the annotated SchemaElement. + * + * Allowed for physical types: INT32, INT64, FIXED_LEN_BYTE_ARRAY, and BYTE_ARRAY. + */ +class DecimalType : public virtual ::apache::thrift::TBase { public: - DecimalType(const DecimalType&); - DecimalType& operator=(const DecimalType&); - DecimalType() : scale(0), precision(0) { - } + DecimalType(const DecimalType&) noexcept; + DecimalType& operator=(const DecimalType&) noexcept; + DecimalType() noexcept; - virtual ~DecimalType() throw(); + virtual ~DecimalType() noexcept; int32_t scale; int32_t precision; @@ -536,22 +835,8 @@ class DecimalType : public virtual ::duckdb_apache::thrift::TBase { void __set_precision(const int32_t val); - bool operator == (const DecimalType & rhs) const - { - if (!(scale == rhs.scale)) - return false; - if (!(precision == rhs.precision)) - return false; - return true; - } - bool operator != (const DecimalType &rhs) const { - return !(*this == rhs); - } - - bool operator < (const DecimalType & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -561,28 +846,20 @@ void swap(DecimalType &a, DecimalType &b); std::ostream& operator<<(std::ostream& out, const DecimalType& obj); -class MilliSeconds : public virtual ::duckdb_apache::thrift::TBase { +/** + * Time units for logical types + */ +class MilliSeconds : public virtual ::apache::thrift::TBase { public: - MilliSeconds(const MilliSeconds&); - MilliSeconds& operator=(const MilliSeconds&); - MilliSeconds() { - } + MilliSeconds(const MilliSeconds&) noexcept; + MilliSeconds& operator=(const MilliSeconds&) noexcept; + MilliSeconds() noexcept; - virtual ~MilliSeconds() throw(); + virtual ~MilliSeconds() noexcept; - bool operator == (const MilliSeconds & /* rhs */) const - { - return true; - } - bool operator != (const MilliSeconds &rhs) const { - return !(*this == rhs); - } - - bool operator < (const MilliSeconds & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -592,28 +869,17 @@ void swap(MilliSeconds &a, MilliSeconds &b); std::ostream& operator<<(std::ostream& out, const MilliSeconds& obj); -class MicroSeconds : public virtual ::duckdb_apache::thrift::TBase { +class MicroSeconds : public virtual ::apache::thrift::TBase { public: - MicroSeconds(const MicroSeconds&); - MicroSeconds& operator=(const MicroSeconds&); - MicroSeconds() { - } - - virtual ~MicroSeconds() throw(); - - bool operator == (const MicroSeconds & /* rhs */) const - { - return true; - } - bool operator != (const MicroSeconds &rhs) const { - return !(*this == rhs); - } + MicroSeconds(const MicroSeconds&) noexcept; + MicroSeconds& operator=(const MicroSeconds&) noexcept; + MicroSeconds() noexcept; - bool operator < (const MicroSeconds & ) const; + virtual ~MicroSeconds() noexcept; - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -623,28 +889,17 @@ void swap(MicroSeconds &a, MicroSeconds &b); std::ostream& operator<<(std::ostream& out, const MicroSeconds& obj); -class NanoSeconds : public virtual ::duckdb_apache::thrift::TBase { +class NanoSeconds : public virtual ::apache::thrift::TBase { public: - NanoSeconds(const NanoSeconds&); - NanoSeconds& operator=(const NanoSeconds&); - NanoSeconds() { - } + NanoSeconds(const NanoSeconds&) noexcept; + NanoSeconds& operator=(const NanoSeconds&) noexcept; + NanoSeconds() noexcept; - virtual ~NanoSeconds() throw(); + virtual ~NanoSeconds() noexcept; - bool operator == (const NanoSeconds & /* rhs */) const - { - return true; - } - bool operator != (const NanoSeconds &rhs) const { - return !(*this == rhs); - } - - bool operator < (const NanoSeconds & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -660,15 +915,14 @@ typedef struct _TimeUnit__isset { bool NANOS :1; } _TimeUnit__isset; -class TimeUnit : public virtual ::duckdb_apache::thrift::TBase { +class TimeUnit : public virtual ::apache::thrift::TBase { public: - TimeUnit(const TimeUnit&); - TimeUnit& operator=(const TimeUnit&); - TimeUnit() { - } + TimeUnit(const TimeUnit&) noexcept; + TimeUnit& operator=(const TimeUnit&) noexcept; + TimeUnit() noexcept; - virtual ~TimeUnit() throw(); + virtual ~TimeUnit() noexcept; MilliSeconds MILLIS; MicroSeconds MICROS; NanoSeconds NANOS; @@ -681,30 +935,8 @@ class TimeUnit : public virtual ::duckdb_apache::thrift::TBase { void __set_NANOS(const NanoSeconds& val); - bool operator == (const TimeUnit & rhs) const - { - if (__isset.MILLIS != rhs.__isset.MILLIS) - return false; - else if (__isset.MILLIS && !(MILLIS == rhs.MILLIS)) - return false; - if (__isset.MICROS != rhs.__isset.MICROS) - return false; - else if (__isset.MICROS && !(MICROS == rhs.MICROS)) - return false; - if (__isset.NANOS != rhs.__isset.NANOS) - return false; - else if (__isset.NANOS && !(NANOS == rhs.NANOS)) - return false; - return true; - } - bool operator != (const TimeUnit &rhs) const { - return !(*this == rhs); - } - - bool operator < (const TimeUnit & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -714,15 +946,19 @@ void swap(TimeUnit &a, TimeUnit &b); std::ostream& operator<<(std::ostream& out, const TimeUnit& obj); -class TimestampType : public virtual ::duckdb_apache::thrift::TBase { +/** + * Timestamp logical type annotation + * + * Allowed for physical types: INT64 + */ +class TimestampType : public virtual ::apache::thrift::TBase { public: - TimestampType(const TimestampType&); - TimestampType& operator=(const TimestampType&); - TimestampType() : isAdjustedToUTC(0) { - } + TimestampType(const TimestampType&) noexcept; + TimestampType& operator=(const TimestampType&) noexcept; + TimestampType() noexcept; - virtual ~TimestampType() throw(); + virtual ~TimestampType() noexcept; bool isAdjustedToUTC; TimeUnit unit; @@ -730,22 +966,8 @@ class TimestampType : public virtual ::duckdb_apache::thrift::TBase { void __set_unit(const TimeUnit& val); - bool operator == (const TimestampType & rhs) const - { - if (!(isAdjustedToUTC == rhs.isAdjustedToUTC)) - return false; - if (!(unit == rhs.unit)) - return false; - return true; - } - bool operator != (const TimestampType &rhs) const { - return !(*this == rhs); - } - - bool operator < (const TimestampType & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -755,15 +977,19 @@ void swap(TimestampType &a, TimestampType &b); std::ostream& operator<<(std::ostream& out, const TimestampType& obj); -class TimeType : public virtual ::duckdb_apache::thrift::TBase { +/** + * Time logical type annotation + * + * Allowed for physical types: INT32 (millis), INT64 (micros, nanos) + */ +class TimeType : public virtual ::apache::thrift::TBase { public: - TimeType(const TimeType&); - TimeType& operator=(const TimeType&); - TimeType() : isAdjustedToUTC(0) { - } + TimeType(const TimeType&) noexcept; + TimeType& operator=(const TimeType&) noexcept; + TimeType() noexcept; - virtual ~TimeType() throw(); + virtual ~TimeType() noexcept; bool isAdjustedToUTC; TimeUnit unit; @@ -771,22 +997,8 @@ class TimeType : public virtual ::duckdb_apache::thrift::TBase { void __set_unit(const TimeUnit& val); - bool operator == (const TimeType & rhs) const - { - if (!(isAdjustedToUTC == rhs.isAdjustedToUTC)) - return false; - if (!(unit == rhs.unit)) - return false; - return true; - } - bool operator != (const TimeType &rhs) const { - return !(*this == rhs); - } - - bool operator < (const TimeType & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -796,15 +1008,21 @@ void swap(TimeType &a, TimeType &b); std::ostream& operator<<(std::ostream& out, const TimeType& obj); -class IntType : public virtual ::duckdb_apache::thrift::TBase { +/** + * Integer logical type annotation + * + * bitWidth must be 8, 16, 32, or 64. + * + * Allowed for physical types: INT32, INT64 + */ +class IntType : public virtual ::apache::thrift::TBase { public: - IntType(const IntType&); - IntType& operator=(const IntType&); - IntType() : bitWidth(0), isSigned(0) { - } + IntType(const IntType&) noexcept; + IntType& operator=(const IntType&) noexcept; + IntType() noexcept; - virtual ~IntType() throw(); + virtual ~IntType() noexcept; int8_t bitWidth; bool isSigned; @@ -812,22 +1030,8 @@ class IntType : public virtual ::duckdb_apache::thrift::TBase { void __set_isSigned(const bool val); - bool operator == (const IntType & rhs) const - { - if (!(bitWidth == rhs.bitWidth)) - return false; - if (!(isSigned == rhs.isSigned)) - return false; - return true; - } - bool operator != (const IntType &rhs) const { - return !(*this == rhs); - } - - bool operator < (const IntType & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -837,28 +1041,22 @@ void swap(IntType &a, IntType &b); std::ostream& operator<<(std::ostream& out, const IntType& obj); -class JsonType : public virtual ::duckdb_apache::thrift::TBase { +/** + * Embedded JSON logical type annotation + * + * Allowed for physical types: BYTE_ARRAY + */ +class JsonType : public virtual ::apache::thrift::TBase { public: - JsonType(const JsonType&); - JsonType& operator=(const JsonType&); - JsonType() { - } - - virtual ~JsonType() throw(); + JsonType(const JsonType&) noexcept; + JsonType& operator=(const JsonType&) noexcept; + JsonType() noexcept; - bool operator == (const JsonType & /* rhs */) const - { - return true; - } - bool operator != (const JsonType &rhs) const { - return !(*this == rhs); - } + virtual ~JsonType() noexcept; - bool operator < (const JsonType & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -868,28 +1066,22 @@ void swap(JsonType &a, JsonType &b); std::ostream& operator<<(std::ostream& out, const JsonType& obj); -class BsonType : public virtual ::duckdb_apache::thrift::TBase { +/** + * Embedded BSON logical type annotation + * + * Allowed for physical types: BYTE_ARRAY + */ +class BsonType : public virtual ::apache::thrift::TBase { public: - BsonType(const BsonType&); - BsonType& operator=(const BsonType&); - BsonType() { - } - - virtual ~BsonType() throw(); + BsonType(const BsonType&) noexcept; + BsonType& operator=(const BsonType&) noexcept; + BsonType() noexcept; - bool operator == (const BsonType & /* rhs */) const - { - return true; - } - bool operator != (const BsonType &rhs) const { - return !(*this == rhs); - } + virtual ~BsonType() noexcept; - bool operator < (const BsonType & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -899,7 +1091,7 @@ void swap(BsonType &a, BsonType &b); std::ostream& operator<<(std::ostream& out, const BsonType& obj); typedef struct _LogicalType__isset { - _LogicalType__isset() : STRING(false), MAP(false), LIST(false), ENUM(false), DECIMAL(false), DATE(false), TIME(false), TIMESTAMP(false), INTEGER(false), UNKNOWN(false), JSON(false), BSON(false), UUID(false) {} + _LogicalType__isset() : STRING(false), MAP(false), LIST(false), ENUM(false), DECIMAL(false), DATE(false), TIME(false), TIMESTAMP(false), INTEGER(false), UNKNOWN(false), JSON(false), BSON(false), UUID(false), FLOAT16(false) {} bool STRING :1; bool MAP :1; bool LIST :1; @@ -913,17 +1105,24 @@ typedef struct _LogicalType__isset { bool JSON :1; bool BSON :1; bool UUID :1; + bool FLOAT16 :1; } _LogicalType__isset; -class LogicalType : public virtual ::duckdb_apache::thrift::TBase { +/** + * LogicalType annotations to replace ConvertedType. + * + * To maintain compatibility, implementations using LogicalType for a + * SchemaElement must also set the corresponding ConvertedType (if any) + * from the following table. + */ +class LogicalType : public virtual ::apache::thrift::TBase { public: - LogicalType(const LogicalType&); - LogicalType& operator=(const LogicalType&); - LogicalType() { - } + LogicalType(const LogicalType&) noexcept; + LogicalType& operator=(const LogicalType&) noexcept; + LogicalType() noexcept; - virtual ~LogicalType() throw(); + virtual ~LogicalType() noexcept; StringType STRING; MapType MAP; ListType LIST; @@ -937,6 +1136,7 @@ class LogicalType : public virtual ::duckdb_apache::thrift::TBase { JsonType JSON; BsonType BSON; UUIDType UUID; + Float16Type FLOAT16; _LogicalType__isset __isset; @@ -966,70 +1166,10 @@ class LogicalType : public virtual ::duckdb_apache::thrift::TBase { void __set_UUID(const UUIDType& val); - bool operator == (const LogicalType & rhs) const - { - if (__isset.STRING != rhs.__isset.STRING) - return false; - else if (__isset.STRING && !(STRING == rhs.STRING)) - return false; - if (__isset.MAP != rhs.__isset.MAP) - return false; - else if (__isset.MAP && !(MAP == rhs.MAP)) - return false; - if (__isset.LIST != rhs.__isset.LIST) - return false; - else if (__isset.LIST && !(LIST == rhs.LIST)) - return false; - if (__isset.ENUM != rhs.__isset.ENUM) - return false; - else if (__isset.ENUM && !(ENUM == rhs.ENUM)) - return false; - if (__isset.DECIMAL != rhs.__isset.DECIMAL) - return false; - else if (__isset.DECIMAL && !(DECIMAL == rhs.DECIMAL)) - return false; - if (__isset.DATE != rhs.__isset.DATE) - return false; - else if (__isset.DATE && !(DATE == rhs.DATE)) - return false; - if (__isset.TIME != rhs.__isset.TIME) - return false; - else if (__isset.TIME && !(TIME == rhs.TIME)) - return false; - if (__isset.TIMESTAMP != rhs.__isset.TIMESTAMP) - return false; - else if (__isset.TIMESTAMP && !(TIMESTAMP == rhs.TIMESTAMP)) - return false; - if (__isset.INTEGER != rhs.__isset.INTEGER) - return false; - else if (__isset.INTEGER && !(INTEGER == rhs.INTEGER)) - return false; - if (__isset.UNKNOWN != rhs.__isset.UNKNOWN) - return false; - else if (__isset.UNKNOWN && !(UNKNOWN == rhs.UNKNOWN)) - return false; - if (__isset.JSON != rhs.__isset.JSON) - return false; - else if (__isset.JSON && !(JSON == rhs.JSON)) - return false; - if (__isset.BSON != rhs.__isset.BSON) - return false; - else if (__isset.BSON && !(BSON == rhs.BSON)) - return false; - if (__isset.UUID != rhs.__isset.UUID) - return false; - else if (__isset.UUID && !(UUID == rhs.UUID)) - return false; - return true; - } - bool operator != (const LogicalType &rhs) const { - return !(*this == rhs); - } - - bool operator < (const LogicalType & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + void __set_FLOAT16(const Float16Type& val); + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -1051,24 +1191,79 @@ typedef struct _SchemaElement__isset { bool logicalType :1; } _SchemaElement__isset; -class SchemaElement : public virtual ::duckdb_apache::thrift::TBase { +/** + * Represents a element inside a schema definition. + * - if it is a group (inner node) then type is undefined and num_children is defined + * - if it is a primitive type (leaf) then type is defined and num_children is undefined + * the nodes are listed in depth first traversal order. + */ +class SchemaElement : public virtual ::apache::thrift::TBase { public: SchemaElement(const SchemaElement&); SchemaElement& operator=(const SchemaElement&); - SchemaElement() : type((Type::type)0), type_length(0), repetition_type((FieldRepetitionType::type)0), name(), num_children(0), converted_type((ConvertedType::type)0), scale(0), precision(0), field_id(0) { - } - - virtual ~SchemaElement() throw(); + SchemaElement() noexcept; + + virtual ~SchemaElement() noexcept; + /** + * Data type for this field. Not set if the current element is a non-leaf node + * + * @see Type + */ Type::type type; + /** + * If type is FIXED_LEN_BYTE_ARRAY, this is the byte length of the values. + * Otherwise, if specified, this is the maximum bit length to store any of the values. + * (e.g. a low cardinality INT col could have this set to 3). Note that this is + * in the schema, and therefore fixed for the entire file. + */ int32_t type_length; + /** + * repetition of the field. The root of the schema does not have a repetition_type. + * All other nodes must have one + * + * @see FieldRepetitionType + */ FieldRepetitionType::type repetition_type; + /** + * Name of the field in the schema + */ std::string name; + /** + * Nested fields. Since thrift does not support nested fields, + * the nesting is flattened to a single list by a depth-first traversal. + * The children count is used to construct the nested relationship. + * This field is not set when the element is a primitive type + */ int32_t num_children; + /** + * DEPRECATED: When the schema is the result of a conversion from another model. + * Used to record the original type to help with cross conversion. + * + * This is superseded by logicalType. + * + * @see ConvertedType + */ ConvertedType::type converted_type; + /** + * DEPRECATED: Used when this column contains decimal data. + * See the DECIMAL converted type for more details. + * + * This is superseded by using the DecimalType annotation in logicalType. + */ int32_t scale; int32_t precision; + /** + * When the original schema supports field ids, this will save the + * original field id in the parquet schema + */ int32_t field_id; + /** + * The logical type of this SchemaElement + * + * LogicalType replaces ConvertedType, but ConvertedType is still required + * for some logical types to ensure forward-compatibility in format v1. + */ LogicalType logicalType; _SchemaElement__isset __isset; @@ -1093,56 +1288,8 @@ class SchemaElement : public virtual ::duckdb_apache::thrift::TBase { void __set_logicalType(const LogicalType& val); - bool operator == (const SchemaElement & rhs) const - { - if (__isset.type != rhs.__isset.type) - return false; - else if (__isset.type && !(type == rhs.type)) - return false; - if (__isset.type_length != rhs.__isset.type_length) - return false; - else if (__isset.type_length && !(type_length == rhs.type_length)) - return false; - if (__isset.repetition_type != rhs.__isset.repetition_type) - return false; - else if (__isset.repetition_type && !(repetition_type == rhs.repetition_type)) - return false; - if (!(name == rhs.name)) - return false; - if (__isset.num_children != rhs.__isset.num_children) - return false; - else if (__isset.num_children && !(num_children == rhs.num_children)) - return false; - if (__isset.converted_type != rhs.__isset.converted_type) - return false; - else if (__isset.converted_type && !(converted_type == rhs.converted_type)) - return false; - if (__isset.scale != rhs.__isset.scale) - return false; - else if (__isset.scale && !(scale == rhs.scale)) - return false; - if (__isset.precision != rhs.__isset.precision) - return false; - else if (__isset.precision && !(precision == rhs.precision)) - return false; - if (__isset.field_id != rhs.__isset.field_id) - return false; - else if (__isset.field_id && !(field_id == rhs.field_id)) - return false; - if (__isset.logicalType != rhs.__isset.logicalType) - return false; - else if (__isset.logicalType && !(logicalType == rhs.logicalType)) - return false; - return true; - } - bool operator != (const SchemaElement &rhs) const { - return !(*this == rhs); - } - - bool operator < (const SchemaElement & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -1156,19 +1303,47 @@ typedef struct _DataPageHeader__isset { bool statistics :1; } _DataPageHeader__isset; -class DataPageHeader : public virtual ::duckdb_apache::thrift::TBase { +/** + * Data page header + */ +class DataPageHeader : public virtual ::apache::thrift::TBase { public: DataPageHeader(const DataPageHeader&); DataPageHeader& operator=(const DataPageHeader&); - DataPageHeader() : num_values(0), encoding((Encoding::type)0), definition_level_encoding((Encoding::type)0), repetition_level_encoding((Encoding::type)0) { - } - - virtual ~DataPageHeader() throw(); + DataPageHeader() noexcept; + + virtual ~DataPageHeader() noexcept; + /** + * Number of values, including NULLs, in this data page. + * + * If a OffsetIndex is present, a page must begin at a row + * boundary (repetition_level = 0). Otherwise, pages may begin + * within a row (repetition_level > 0). + * + */ int32_t num_values; + /** + * Encoding used for this data page * + * + * @see Encoding + */ Encoding::type encoding; + /** + * Encoding used for definition levels * + * + * @see Encoding + */ Encoding::type definition_level_encoding; + /** + * Encoding used for repetition levels * + * + * @see Encoding + */ Encoding::type repetition_level_encoding; + /** + * Optional statistics for the data in this page * + */ Statistics statistics; _DataPageHeader__isset __isset; @@ -1183,30 +1358,8 @@ class DataPageHeader : public virtual ::duckdb_apache::thrift::TBase { void __set_statistics(const Statistics& val); - bool operator == (const DataPageHeader & rhs) const - { - if (!(num_values == rhs.num_values)) - return false; - if (!(encoding == rhs.encoding)) - return false; - if (!(definition_level_encoding == rhs.definition_level_encoding)) - return false; - if (!(repetition_level_encoding == rhs.repetition_level_encoding)) - return false; - if (__isset.statistics != rhs.__isset.statistics) - return false; - else if (__isset.statistics && !(statistics == rhs.statistics)) - return false; - return true; - } - bool operator != (const DataPageHeader &rhs) const { - return !(*this == rhs); - } - - bool operator < (const DataPageHeader & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -1216,28 +1369,17 @@ void swap(DataPageHeader &a, DataPageHeader &b); std::ostream& operator<<(std::ostream& out, const DataPageHeader& obj); -class IndexPageHeader : public virtual ::duckdb_apache::thrift::TBase { +class IndexPageHeader : public virtual ::apache::thrift::TBase { public: - IndexPageHeader(const IndexPageHeader&); - IndexPageHeader& operator=(const IndexPageHeader&); - IndexPageHeader() { - } - - virtual ~IndexPageHeader() throw(); - - bool operator == (const IndexPageHeader & /* rhs */) const - { - return true; - } - bool operator != (const IndexPageHeader &rhs) const { - return !(*this == rhs); - } + IndexPageHeader(const IndexPageHeader&) noexcept; + IndexPageHeader& operator=(const IndexPageHeader&) noexcept; + IndexPageHeader() noexcept; - bool operator < (const IndexPageHeader & ) const; + virtual ~IndexPageHeader() noexcept; - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -1251,17 +1393,33 @@ typedef struct _DictionaryPageHeader__isset { bool is_sorted :1; } _DictionaryPageHeader__isset; -class DictionaryPageHeader : public virtual ::duckdb_apache::thrift::TBase { +/** + * The dictionary page must be placed at the first position of the column chunk + * if it is partly or completely dictionary encoded. At most one dictionary page + * can be placed in a column chunk. + * + */ +class DictionaryPageHeader : public virtual ::apache::thrift::TBase { public: - DictionaryPageHeader(const DictionaryPageHeader&); - DictionaryPageHeader& operator=(const DictionaryPageHeader&); - DictionaryPageHeader() : num_values(0), encoding((Encoding::type)0), is_sorted(0) { - } + DictionaryPageHeader(const DictionaryPageHeader&) noexcept; + DictionaryPageHeader& operator=(const DictionaryPageHeader&) noexcept; + DictionaryPageHeader() noexcept; - virtual ~DictionaryPageHeader() throw(); + virtual ~DictionaryPageHeader() noexcept; + /** + * Number of values in the dictionary * + */ int32_t num_values; + /** + * Encoding using this dictionary page * + * + * @see Encoding + */ Encoding::type encoding; + /** + * If true, the entries in the dictionary are sorted in ascending order * + */ bool is_sorted; _DictionaryPageHeader__isset __isset; @@ -1272,26 +1430,8 @@ class DictionaryPageHeader : public virtual ::duckdb_apache::thrift::TBase { void __set_is_sorted(const bool val); - bool operator == (const DictionaryPageHeader & rhs) const - { - if (!(num_values == rhs.num_values)) - return false; - if (!(encoding == rhs.encoding)) - return false; - if (__isset.is_sorted != rhs.__isset.is_sorted) - return false; - else if (__isset.is_sorted && !(is_sorted == rhs.is_sorted)) - return false; - return true; - } - bool operator != (const DictionaryPageHeader &rhs) const { - return !(*this == rhs); - } - - bool operator < (const DictionaryPageHeader & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -1306,22 +1446,61 @@ typedef struct _DataPageHeaderV2__isset { bool statistics :1; } _DataPageHeaderV2__isset; -class DataPageHeaderV2 : public virtual ::duckdb_apache::thrift::TBase { +/** + * New page format allowing reading levels without decompressing the data + * Repetition and definition levels are uncompressed + * The remaining section containing the data is compressed if is_compressed is true + * + */ +class DataPageHeaderV2 : public virtual ::apache::thrift::TBase { public: DataPageHeaderV2(const DataPageHeaderV2&); DataPageHeaderV2& operator=(const DataPageHeaderV2&); - DataPageHeaderV2() : num_values(0), num_nulls(0), num_rows(0), encoding((Encoding::type)0), definition_levels_byte_length(0), repetition_levels_byte_length(0), is_compressed(true) { - } + DataPageHeaderV2() noexcept; - virtual ~DataPageHeaderV2() throw(); + virtual ~DataPageHeaderV2() noexcept; + /** + * Number of values, including NULLs, in this data page. * + */ int32_t num_values; + /** + * Number of NULL values, in this data page. + * Number of non-null = num_values - num_nulls which is also the number of values in the data section * + */ int32_t num_nulls; + /** + * Number of rows in this data page. Every page must begin at a + * row boundary (repetition_level = 0): rows must **not** be + * split across page boundaries when using V2 data pages. + * + */ int32_t num_rows; + /** + * Encoding used for data in this page * + * + * @see Encoding + */ Encoding::type encoding; + /** + * Length of the definition levels + */ int32_t definition_levels_byte_length; + /** + * Length of the repetition levels + */ int32_t repetition_levels_byte_length; + /** + * Whether the values are compressed. + * Which means the section of the page between + * definition_levels_byte_length + repetition_levels_byte_length + 1 and compressed_page_size (included) + * is compressed with the compression_codec. + * If missing it is considered compressed + */ bool is_compressed; + /** + * Optional statistics for the data in this page * + */ Statistics statistics; _DataPageHeaderV2__isset __isset; @@ -1342,38 +1521,8 @@ class DataPageHeaderV2 : public virtual ::duckdb_apache::thrift::TBase { void __set_statistics(const Statistics& val); - bool operator == (const DataPageHeaderV2 & rhs) const - { - if (!(num_values == rhs.num_values)) - return false; - if (!(num_nulls == rhs.num_nulls)) - return false; - if (!(num_rows == rhs.num_rows)) - return false; - if (!(encoding == rhs.encoding)) - return false; - if (!(definition_levels_byte_length == rhs.definition_levels_byte_length)) - return false; - if (!(repetition_levels_byte_length == rhs.repetition_levels_byte_length)) - return false; - if (__isset.is_compressed != rhs.__isset.is_compressed) - return false; - else if (__isset.is_compressed && !(is_compressed == rhs.is_compressed)) - return false; - if (__isset.statistics != rhs.__isset.statistics) - return false; - else if (__isset.statistics && !(statistics == rhs.statistics)) - return false; - return true; - } - bool operator != (const DataPageHeaderV2 &rhs) const { - return !(*this == rhs); - } - - bool operator < (const DataPageHeaderV2 & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -1382,6 +1531,228 @@ void swap(DataPageHeaderV2 &a, DataPageHeaderV2 &b); std::ostream& operator<<(std::ostream& out, const DataPageHeaderV2& obj); + +/** + * Block-based algorithm type annotation. * + */ +class SplitBlockAlgorithm : public virtual ::apache::thrift::TBase { + public: + + SplitBlockAlgorithm(const SplitBlockAlgorithm&) noexcept; + SplitBlockAlgorithm& operator=(const SplitBlockAlgorithm&) noexcept; + SplitBlockAlgorithm() noexcept; + + virtual ~SplitBlockAlgorithm() noexcept; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + + virtual void printTo(std::ostream& out) const; +}; + +void swap(SplitBlockAlgorithm &a, SplitBlockAlgorithm &b); + +std::ostream& operator<<(std::ostream& out, const SplitBlockAlgorithm& obj); + +typedef struct _BloomFilterAlgorithm__isset { + _BloomFilterAlgorithm__isset() : BLOCK(false) {} + bool BLOCK :1; +} _BloomFilterAlgorithm__isset; + +/** + * The algorithm used in Bloom filter. * + */ +class BloomFilterAlgorithm : public virtual ::apache::thrift::TBase { + public: + + BloomFilterAlgorithm(const BloomFilterAlgorithm&) noexcept; + BloomFilterAlgorithm& operator=(const BloomFilterAlgorithm&) noexcept; + BloomFilterAlgorithm() noexcept; + + virtual ~BloomFilterAlgorithm() noexcept; + /** + * Block-based Bloom filter. * + */ + SplitBlockAlgorithm BLOCK; + + _BloomFilterAlgorithm__isset __isset; + + void __set_BLOCK(const SplitBlockAlgorithm& val); + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + + virtual void printTo(std::ostream& out) const; +}; + +void swap(BloomFilterAlgorithm &a, BloomFilterAlgorithm &b); + +std::ostream& operator<<(std::ostream& out, const BloomFilterAlgorithm& obj); + + +/** + * Hash strategy type annotation. xxHash is an extremely fast non-cryptographic hash + * algorithm. It uses 64 bits version of xxHash. + * + */ +class XxHash : public virtual ::apache::thrift::TBase { + public: + + XxHash(const XxHash&) noexcept; + XxHash& operator=(const XxHash&) noexcept; + XxHash() noexcept; + + virtual ~XxHash() noexcept; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + + virtual void printTo(std::ostream& out) const; +}; + +void swap(XxHash &a, XxHash &b); + +std::ostream& operator<<(std::ostream& out, const XxHash& obj); + +typedef struct _BloomFilterHash__isset { + _BloomFilterHash__isset() : XXHASH(false) {} + bool XXHASH :1; +} _BloomFilterHash__isset; + +/** + * The hash function used in Bloom filter. This function takes the hash of a column value + * using plain encoding. + * + */ +class BloomFilterHash : public virtual ::apache::thrift::TBase { + public: + + BloomFilterHash(const BloomFilterHash&) noexcept; + BloomFilterHash& operator=(const BloomFilterHash&) noexcept; + BloomFilterHash() noexcept; + + virtual ~BloomFilterHash() noexcept; + /** + * xxHash Strategy. * + */ + XxHash XXHASH; + + _BloomFilterHash__isset __isset; + + void __set_XXHASH(const XxHash& val); + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + + virtual void printTo(std::ostream& out) const; +}; + +void swap(BloomFilterHash &a, BloomFilterHash &b); + +std::ostream& operator<<(std::ostream& out, const BloomFilterHash& obj); + + +/** + * The compression used in the Bloom filter. + * + */ +class Uncompressed : public virtual ::apache::thrift::TBase { + public: + + Uncompressed(const Uncompressed&) noexcept; + Uncompressed& operator=(const Uncompressed&) noexcept; + Uncompressed() noexcept; + + virtual ~Uncompressed() noexcept; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + + virtual void printTo(std::ostream& out) const; +}; + +void swap(Uncompressed &a, Uncompressed &b); + +std::ostream& operator<<(std::ostream& out, const Uncompressed& obj); + +typedef struct _BloomFilterCompression__isset { + _BloomFilterCompression__isset() : UNCOMPRESSED(false) {} + bool UNCOMPRESSED :1; +} _BloomFilterCompression__isset; + +class BloomFilterCompression : public virtual ::apache::thrift::TBase { + public: + + BloomFilterCompression(const BloomFilterCompression&) noexcept; + BloomFilterCompression& operator=(const BloomFilterCompression&) noexcept; + BloomFilterCompression() noexcept; + + virtual ~BloomFilterCompression() noexcept; + Uncompressed UNCOMPRESSED; + + _BloomFilterCompression__isset __isset; + + void __set_UNCOMPRESSED(const Uncompressed& val); + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + + virtual void printTo(std::ostream& out) const; +}; + +void swap(BloomFilterCompression &a, BloomFilterCompression &b); + +std::ostream& operator<<(std::ostream& out, const BloomFilterCompression& obj); + + +/** + * Bloom filter header is stored at beginning of Bloom filter data of each column + * and followed by its bitset. + * + */ +class BloomFilterHeader : public virtual ::apache::thrift::TBase { + public: + + BloomFilterHeader(const BloomFilterHeader&) noexcept; + BloomFilterHeader& operator=(const BloomFilterHeader&) noexcept; + BloomFilterHeader() noexcept; + + virtual ~BloomFilterHeader() noexcept; + /** + * The size of bitset in bytes * + */ + int32_t numBytes; + /** + * The algorithm for setting bits. * + */ + BloomFilterAlgorithm algorithm; + /** + * The hash function used for Bloom filter. * + */ + BloomFilterHash hash; + /** + * The compression used in the Bloom filter * + */ + BloomFilterCompression compression; + + void __set_numBytes(const int32_t val); + + void __set_algorithm(const BloomFilterAlgorithm& val); + + void __set_hash(const BloomFilterHash& val); + + void __set_compression(const BloomFilterCompression& val); + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + + virtual void printTo(std::ostream& out) const; +}; + +void swap(BloomFilterHeader &a, BloomFilterHeader &b); + +std::ostream& operator<<(std::ostream& out, const BloomFilterHeader& obj); + typedef struct _PageHeader__isset { _PageHeader__isset() : crc(false), data_page_header(false), index_page_header(false), dictionary_page_header(false), data_page_header_v2(false) {} bool crc :1; @@ -1391,18 +1762,46 @@ typedef struct _PageHeader__isset { bool data_page_header_v2 :1; } _PageHeader__isset; -class PageHeader : public virtual ::duckdb_apache::thrift::TBase { +class PageHeader : public virtual ::apache::thrift::TBase { public: PageHeader(const PageHeader&); PageHeader& operator=(const PageHeader&); - PageHeader() : type((PageType::type)0), uncompressed_page_size(0), compressed_page_size(0), crc(0) { - } - - virtual ~PageHeader() throw(); + PageHeader() noexcept; + + virtual ~PageHeader() noexcept; + /** + * the type of the page: indicates which of the *_header fields is set * + * + * @see PageType + */ PageType::type type; + /** + * Uncompressed page size in bytes (not including this header) * + */ int32_t uncompressed_page_size; + /** + * Compressed (and potentially encrypted) page size in bytes, not including this header * + */ int32_t compressed_page_size; + /** + * The 32-bit CRC checksum for the page, to be be calculated as follows: + * + * - The standard CRC32 algorithm is used (with polynomial 0x04C11DB7, + * the same as in e.g. GZip). + * - All page types can have a CRC (v1 and v2 data pages, dictionary pages, + * etc.). + * - The CRC is computed on the serialization binary representation of the page + * (as written to disk), excluding the page header. For example, for v1 + * data pages, the CRC is computed on the concatenation of repetition levels, + * definition levels and column values (optionally compressed, optionally + * encrypted). + * - The CRC computation therefore takes place after any compression + * and encryption steps, if any. + * + * If enabled, this allows for disabling checksumming in HDFS if only a few + * pages need to be read. + */ int32_t crc; DataPageHeader data_page_header; IndexPageHeader index_page_header; @@ -1427,44 +1826,8 @@ class PageHeader : public virtual ::duckdb_apache::thrift::TBase { void __set_data_page_header_v2(const DataPageHeaderV2& val); - bool operator == (const PageHeader & rhs) const - { - if (!(type == rhs.type)) - return false; - if (!(uncompressed_page_size == rhs.uncompressed_page_size)) - return false; - if (!(compressed_page_size == rhs.compressed_page_size)) - return false; - if (__isset.crc != rhs.__isset.crc) - return false; - else if (__isset.crc && !(crc == rhs.crc)) - return false; - if (__isset.data_page_header != rhs.__isset.data_page_header) - return false; - else if (__isset.data_page_header && !(data_page_header == rhs.data_page_header)) - return false; - if (__isset.index_page_header != rhs.__isset.index_page_header) - return false; - else if (__isset.index_page_header && !(index_page_header == rhs.index_page_header)) - return false; - if (__isset.dictionary_page_header != rhs.__isset.dictionary_page_header) - return false; - else if (__isset.dictionary_page_header && !(dictionary_page_header == rhs.dictionary_page_header)) - return false; - if (__isset.data_page_header_v2 != rhs.__isset.data_page_header_v2) - return false; - else if (__isset.data_page_header_v2 && !(data_page_header_v2 == rhs.data_page_header_v2)) - return false; - return true; - } - bool operator != (const PageHeader &rhs) const { - return !(*this == rhs); - } - - bool operator < (const PageHeader & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -1478,15 +1841,17 @@ typedef struct _KeyValue__isset { bool value :1; } _KeyValue__isset; -class KeyValue : public virtual ::duckdb_apache::thrift::TBase { +/** + * Wrapper struct to store key values + */ +class KeyValue : public virtual ::apache::thrift::TBase { public: KeyValue(const KeyValue&); KeyValue& operator=(const KeyValue&); - KeyValue() : key(), value() { - } + KeyValue() noexcept; - virtual ~KeyValue() throw(); + virtual ~KeyValue() noexcept; std::string key; std::string value; @@ -1496,24 +1861,8 @@ class KeyValue : public virtual ::duckdb_apache::thrift::TBase { void __set_value(const std::string& val); - bool operator == (const KeyValue & rhs) const - { - if (!(key == rhs.key)) - return false; - if (__isset.value != rhs.__isset.value) - return false; - else if (__isset.value && !(value == rhs.value)) - return false; - return true; - } - bool operator != (const KeyValue &rhs) const { - return !(*this == rhs); - } - - bool operator < (const KeyValue & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -1523,17 +1872,29 @@ void swap(KeyValue &a, KeyValue &b); std::ostream& operator<<(std::ostream& out, const KeyValue& obj); -class SortingColumn : public virtual ::duckdb_apache::thrift::TBase { +/** + * Sort order within a RowGroup of a leaf column + */ +class SortingColumn : public virtual ::apache::thrift::TBase { public: - SortingColumn(const SortingColumn&); - SortingColumn& operator=(const SortingColumn&); - SortingColumn() : column_idx(0), descending(0), nulls_first(0) { - } + SortingColumn(const SortingColumn&) noexcept; + SortingColumn& operator=(const SortingColumn&) noexcept; + SortingColumn() noexcept; - virtual ~SortingColumn() throw(); + virtual ~SortingColumn() noexcept; + /** + * The ordinal position of the column (in this row group) * + */ int32_t column_idx; + /** + * If true, indicates this column is sorted in descending order. * + */ bool descending; + /** + * If true, nulls will come before non-null values, otherwise, + * nulls go at the end. + */ bool nulls_first; void __set_column_idx(const int32_t val); @@ -1542,24 +1903,8 @@ class SortingColumn : public virtual ::duckdb_apache::thrift::TBase { void __set_nulls_first(const bool val); - bool operator == (const SortingColumn & rhs) const - { - if (!(column_idx == rhs.column_idx)) - return false; - if (!(descending == rhs.descending)) - return false; - if (!(nulls_first == rhs.nulls_first)) - return false; - return true; - } - bool operator != (const SortingColumn &rhs) const { - return !(*this == rhs); - } - - bool operator < (const SortingColumn & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -1569,17 +1914,32 @@ void swap(SortingColumn &a, SortingColumn &b); std::ostream& operator<<(std::ostream& out, const SortingColumn& obj); -class PageEncodingStats : public virtual ::duckdb_apache::thrift::TBase { +/** + * statistics of a given page type and encoding + */ +class PageEncodingStats : public virtual ::apache::thrift::TBase { public: - PageEncodingStats(const PageEncodingStats&); - PageEncodingStats& operator=(const PageEncodingStats&); - PageEncodingStats() : page_type((PageType::type)0), encoding((Encoding::type)0), count(0) { - } + PageEncodingStats(const PageEncodingStats&) noexcept; + PageEncodingStats& operator=(const PageEncodingStats&) noexcept; + PageEncodingStats() noexcept; - virtual ~PageEncodingStats() throw(); + virtual ~PageEncodingStats() noexcept; + /** + * the page type (data/dic/...) * + * + * @see PageType + */ PageType::type page_type; + /** + * encoding of the page * + * + * @see Encoding + */ Encoding::type encoding; + /** + * number of pages of this type with this encoding * + */ int32_t count; void __set_page_type(const PageType::type val); @@ -1588,24 +1948,8 @@ class PageEncodingStats : public virtual ::duckdb_apache::thrift::TBase { void __set_count(const int32_t val); - bool operator == (const PageEncodingStats & rhs) const - { - if (!(page_type == rhs.page_type)) - return false; - if (!(encoding == rhs.encoding)) - return false; - if (!(count == rhs.count)) - return false; - return true; - } - bool operator != (const PageEncodingStats &rhs) const { - return !(*this == rhs); - } - - bool operator < (const PageEncodingStats & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -1615,36 +1959,107 @@ void swap(PageEncodingStats &a, PageEncodingStats &b); std::ostream& operator<<(std::ostream& out, const PageEncodingStats& obj); typedef struct _ColumnMetaData__isset { - _ColumnMetaData__isset() : key_value_metadata(false), index_page_offset(false), dictionary_page_offset(false), statistics(false), encoding_stats(false) {} + _ColumnMetaData__isset() : key_value_metadata(false), index_page_offset(false), dictionary_page_offset(false), statistics(false), encoding_stats(false), bloom_filter_offset(false), bloom_filter_length(false), size_statistics(false) {} bool key_value_metadata :1; bool index_page_offset :1; bool dictionary_page_offset :1; bool statistics :1; bool encoding_stats :1; + bool bloom_filter_offset :1; + bool bloom_filter_length :1; + bool size_statistics :1; } _ColumnMetaData__isset; -class ColumnMetaData : public virtual ::duckdb_apache::thrift::TBase { +/** + * Description for column metadata + */ +class ColumnMetaData : public virtual ::apache::thrift::TBase { public: ColumnMetaData(const ColumnMetaData&); ColumnMetaData& operator=(const ColumnMetaData&); - ColumnMetaData() : type((Type::type)0), codec((CompressionCodec::type)0), num_values(0), total_uncompressed_size(0), total_compressed_size(0), data_page_offset(0), index_page_offset(0), dictionary_page_offset(0) { - } - - virtual ~ColumnMetaData() throw(); + ColumnMetaData() noexcept; + + virtual ~ColumnMetaData() noexcept; + /** + * Type of this column * + * + * @see Type + */ Type::type type; + /** + * Set of all encodings used for this column. The purpose is to validate + * whether we can decode those pages. * + */ duckdb::vector encodings; + /** + * Path in schema * + */ duckdb::vector path_in_schema; + /** + * Compression codec * + * + * @see CompressionCodec + */ CompressionCodec::type codec; + /** + * Number of values in this column * + */ int64_t num_values; + /** + * total byte size of all uncompressed pages in this column chunk (including the headers) * + */ int64_t total_uncompressed_size; + /** + * total byte size of all compressed, and potentially encrypted, pages + * in this column chunk (including the headers) * + */ int64_t total_compressed_size; + /** + * Optional key/value metadata * + */ duckdb::vector key_value_metadata; + /** + * Byte offset from beginning of file to first data page * + */ int64_t data_page_offset; + /** + * Byte offset from beginning of file to root index page * + */ int64_t index_page_offset; + /** + * Byte offset from the beginning of file to first (only) dictionary page * + */ int64_t dictionary_page_offset; + /** + * optional statistics for this column chunk + */ Statistics statistics; + /** + * Set of all encodings used for pages in this column chunk. + * This information can be used to determine if all data pages are + * dictionary encoded for example * + */ duckdb::vector encoding_stats; + /** + * Byte offset from beginning of file to Bloom filter data. * + */ + int64_t bloom_filter_offset; + /** + * Size of Bloom filter data including the serialized header, in bytes. + * Added in 2.10 so readers may not read this field from old files and + * it can be obtained after the BloomFilterHeader has been deserialized. + * Writers should write this field so readers can read the bloom filter + * in a single I/O. + */ + int32_t bloom_filter_length; + /** + * Optional statistics to help estimate total memory when converted to in-memory + * representations. The histograms contained in these statistics can + * also be useful in some cases for more fine-grained nullability/list length + * filter pushdown. + */ + SizeStatistics size_statistics; _ColumnMetaData__isset __isset; @@ -1674,54 +2089,14 @@ class ColumnMetaData : public virtual ::duckdb_apache::thrift::TBase { void __set_encoding_stats(const duckdb::vector & val); - bool operator == (const ColumnMetaData & rhs) const - { - if (!(type == rhs.type)) - return false; - if (!(encodings == rhs.encodings)) - return false; - if (!(path_in_schema == rhs.path_in_schema)) - return false; - if (!(codec == rhs.codec)) - return false; - if (!(num_values == rhs.num_values)) - return false; - if (!(total_uncompressed_size == rhs.total_uncompressed_size)) - return false; - if (!(total_compressed_size == rhs.total_compressed_size)) - return false; - if (__isset.key_value_metadata != rhs.__isset.key_value_metadata) - return false; - else if (__isset.key_value_metadata && !(key_value_metadata == rhs.key_value_metadata)) - return false; - if (!(data_page_offset == rhs.data_page_offset)) - return false; - if (__isset.index_page_offset != rhs.__isset.index_page_offset) - return false; - else if (__isset.index_page_offset && !(index_page_offset == rhs.index_page_offset)) - return false; - if (__isset.dictionary_page_offset != rhs.__isset.dictionary_page_offset) - return false; - else if (__isset.dictionary_page_offset && !(dictionary_page_offset == rhs.dictionary_page_offset)) - return false; - if (__isset.statistics != rhs.__isset.statistics) - return false; - else if (__isset.statistics && !(statistics == rhs.statistics)) - return false; - if (__isset.encoding_stats != rhs.__isset.encoding_stats) - return false; - else if (__isset.encoding_stats && !(encoding_stats == rhs.encoding_stats)) - return false; - return true; - } - bool operator != (const ColumnMetaData &rhs) const { - return !(*this == rhs); - } - - bool operator < (const ColumnMetaData & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + void __set_bloom_filter_offset(const int64_t val); + + void __set_bloom_filter_length(const int32_t val); + + void __set_size_statistics(const SizeStatistics& val); + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -1731,28 +2106,17 @@ void swap(ColumnMetaData &a, ColumnMetaData &b); std::ostream& operator<<(std::ostream& out, const ColumnMetaData& obj); -class EncryptionWithFooterKey : public virtual ::duckdb_apache::thrift::TBase { +class EncryptionWithFooterKey : public virtual ::apache::thrift::TBase { public: - EncryptionWithFooterKey(const EncryptionWithFooterKey&); - EncryptionWithFooterKey& operator=(const EncryptionWithFooterKey&); - EncryptionWithFooterKey() { - } - - virtual ~EncryptionWithFooterKey() throw(); + EncryptionWithFooterKey(const EncryptionWithFooterKey&) noexcept; + EncryptionWithFooterKey& operator=(const EncryptionWithFooterKey&) noexcept; + EncryptionWithFooterKey() noexcept; - bool operator == (const EncryptionWithFooterKey & /* rhs */) const - { - return true; - } - bool operator != (const EncryptionWithFooterKey &rhs) const { - return !(*this == rhs); - } + virtual ~EncryptionWithFooterKey() noexcept; - bool operator < (const EncryptionWithFooterKey & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -1766,16 +2130,21 @@ typedef struct _EncryptionWithColumnKey__isset { bool key_metadata :1; } _EncryptionWithColumnKey__isset; -class EncryptionWithColumnKey : public virtual ::duckdb_apache::thrift::TBase { +class EncryptionWithColumnKey : public virtual ::apache::thrift::TBase { public: EncryptionWithColumnKey(const EncryptionWithColumnKey&); EncryptionWithColumnKey& operator=(const EncryptionWithColumnKey&); - EncryptionWithColumnKey() : key_metadata() { - } + EncryptionWithColumnKey() noexcept; - virtual ~EncryptionWithColumnKey() throw(); + virtual ~EncryptionWithColumnKey() noexcept; + /** + * Column path in schema * + */ duckdb::vector path_in_schema; + /** + * Retrieval metadata of column encryption key * + */ std::string key_metadata; _EncryptionWithColumnKey__isset __isset; @@ -1784,24 +2153,8 @@ class EncryptionWithColumnKey : public virtual ::duckdb_apache::thrift::TBase { void __set_key_metadata(const std::string& val); - bool operator == (const EncryptionWithColumnKey & rhs) const - { - if (!(path_in_schema == rhs.path_in_schema)) - return false; - if (__isset.key_metadata != rhs.__isset.key_metadata) - return false; - else if (__isset.key_metadata && !(key_metadata == rhs.key_metadata)) - return false; - return true; - } - bool operator != (const EncryptionWithColumnKey &rhs) const { - return !(*this == rhs); - } - - bool operator < (const EncryptionWithColumnKey & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -1816,15 +2169,14 @@ typedef struct _ColumnCryptoMetaData__isset { bool ENCRYPTION_WITH_COLUMN_KEY :1; } _ColumnCryptoMetaData__isset; -class ColumnCryptoMetaData : public virtual ::duckdb_apache::thrift::TBase { +class ColumnCryptoMetaData : public virtual ::apache::thrift::TBase { public: ColumnCryptoMetaData(const ColumnCryptoMetaData&); ColumnCryptoMetaData& operator=(const ColumnCryptoMetaData&); - ColumnCryptoMetaData() { - } + ColumnCryptoMetaData() noexcept; - virtual ~ColumnCryptoMetaData() throw(); + virtual ~ColumnCryptoMetaData() noexcept; EncryptionWithFooterKey ENCRYPTION_WITH_FOOTER_KEY; EncryptionWithColumnKey ENCRYPTION_WITH_COLUMN_KEY; @@ -1834,26 +2186,8 @@ class ColumnCryptoMetaData : public virtual ::duckdb_apache::thrift::TBase { void __set_ENCRYPTION_WITH_COLUMN_KEY(const EncryptionWithColumnKey& val); - bool operator == (const ColumnCryptoMetaData & rhs) const - { - if (__isset.ENCRYPTION_WITH_FOOTER_KEY != rhs.__isset.ENCRYPTION_WITH_FOOTER_KEY) - return false; - else if (__isset.ENCRYPTION_WITH_FOOTER_KEY && !(ENCRYPTION_WITH_FOOTER_KEY == rhs.ENCRYPTION_WITH_FOOTER_KEY)) - return false; - if (__isset.ENCRYPTION_WITH_COLUMN_KEY != rhs.__isset.ENCRYPTION_WITH_COLUMN_KEY) - return false; - else if (__isset.ENCRYPTION_WITH_COLUMN_KEY && !(ENCRYPTION_WITH_COLUMN_KEY == rhs.ENCRYPTION_WITH_COLUMN_KEY)) - return false; - return true; - } - bool operator != (const ColumnCryptoMetaData &rhs) const { - return !(*this == rhs); - } - - bool operator < (const ColumnCryptoMetaData & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -1874,23 +2208,62 @@ typedef struct _ColumnChunk__isset { bool encrypted_column_metadata :1; } _ColumnChunk__isset; -class ColumnChunk : public virtual ::duckdb_apache::thrift::TBase { +class ColumnChunk : public virtual ::apache::thrift::TBase { public: ColumnChunk(const ColumnChunk&); ColumnChunk& operator=(const ColumnChunk&); - ColumnChunk() : file_path(), file_offset(0), offset_index_offset(0), offset_index_length(0), column_index_offset(0), column_index_length(0), encrypted_column_metadata() { - } - - virtual ~ColumnChunk() throw(); + ColumnChunk() noexcept; + + virtual ~ColumnChunk() noexcept; + /** + * File where column data is stored. If not set, assumed to be same file as + * metadata. This path is relative to the current file. + * + */ std::string file_path; + /** + * Deprecated: Byte offset in file_path to the ColumnMetaData + * + * Past use of this field has been inconsistent, with some implementations + * using it to point to the ColumnMetaData and some using it to point to + * the first page in the column chunk. In many cases, the ColumnMetaData at this + * location is wrong. This field is now deprecated and should not be used. + * Writers should set this field to 0 if no ColumnMetaData has been written outside + * the footer. + */ int64_t file_offset; + /** + * Column metadata for this chunk. Some writers may also replicate this at the + * location pointed to by file_path/file_offset. + * Note: while marked as optional, this field is in fact required by most major + * Parquet implementations. As such, writers MUST populate this field. + * + */ ColumnMetaData meta_data; + /** + * File offset of ColumnChunk's OffsetIndex * + */ int64_t offset_index_offset; + /** + * Size of ColumnChunk's OffsetIndex, in bytes * + */ int32_t offset_index_length; + /** + * File offset of ColumnChunk's ColumnIndex * + */ int64_t column_index_offset; + /** + * Size of ColumnChunk's ColumnIndex, in bytes * + */ int32_t column_index_length; + /** + * Crypto metadata of encrypted columns * + */ ColumnCryptoMetaData crypto_metadata; + /** + * Encrypted column metadata for this chunk * + */ std::string encrypted_column_metadata; _ColumnChunk__isset __isset; @@ -1913,52 +2286,8 @@ class ColumnChunk : public virtual ::duckdb_apache::thrift::TBase { void __set_encrypted_column_metadata(const std::string& val); - bool operator == (const ColumnChunk & rhs) const - { - if (__isset.file_path != rhs.__isset.file_path) - return false; - else if (__isset.file_path && !(file_path == rhs.file_path)) - return false; - if (!(file_offset == rhs.file_offset)) - return false; - if (__isset.meta_data != rhs.__isset.meta_data) - return false; - else if (__isset.meta_data && !(meta_data == rhs.meta_data)) - return false; - if (__isset.offset_index_offset != rhs.__isset.offset_index_offset) - return false; - else if (__isset.offset_index_offset && !(offset_index_offset == rhs.offset_index_offset)) - return false; - if (__isset.offset_index_length != rhs.__isset.offset_index_length) - return false; - else if (__isset.offset_index_length && !(offset_index_length == rhs.offset_index_length)) - return false; - if (__isset.column_index_offset != rhs.__isset.column_index_offset) - return false; - else if (__isset.column_index_offset && !(column_index_offset == rhs.column_index_offset)) - return false; - if (__isset.column_index_length != rhs.__isset.column_index_length) - return false; - else if (__isset.column_index_length && !(column_index_length == rhs.column_index_length)) - return false; - if (__isset.crypto_metadata != rhs.__isset.crypto_metadata) - return false; - else if (__isset.crypto_metadata && !(crypto_metadata == rhs.crypto_metadata)) - return false; - if (__isset.encrypted_column_metadata != rhs.__isset.encrypted_column_metadata) - return false; - else if (__isset.encrypted_column_metadata && !(encrypted_column_metadata == rhs.encrypted_column_metadata)) - return false; - return true; - } - bool operator != (const ColumnChunk &rhs) const { - return !(*this == rhs); - } - - bool operator < (const ColumnChunk & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -1975,21 +2304,46 @@ typedef struct _RowGroup__isset { bool ordinal :1; } _RowGroup__isset; -class RowGroup : public virtual ::duckdb_apache::thrift::TBase { +class RowGroup : public virtual ::apache::thrift::TBase { public: RowGroup(const RowGroup&); RowGroup& operator=(const RowGroup&); - RowGroup() : total_byte_size(0), num_rows(0), file_offset(0), total_compressed_size(0), ordinal(0) { - } - - virtual ~RowGroup() throw(); + RowGroup() noexcept; + + virtual ~RowGroup() noexcept; + /** + * Metadata for each column chunk in this row group. + * This list must have the same order as the SchemaElement list in FileMetaData. + * + */ duckdb::vector columns; + /** + * Total byte size of all the uncompressed column data in this row group * + */ int64_t total_byte_size; + /** + * Number of rows in this row group * + */ int64_t num_rows; + /** + * If set, specifies a sort ordering of the rows in this RowGroup. + * The sorting columns can be a subset of all the columns. + */ duckdb::vector sorting_columns; + /** + * Byte offset from beginning of file to first page (data or dictionary) + * in this row group * + */ int64_t file_offset; + /** + * Total byte size of all compressed (and potentially encrypted) column data + * in this row group * + */ int64_t total_compressed_size; + /** + * Row group ordinal in the file * + */ int16_t ordinal; _RowGroup__isset __isset; @@ -2008,40 +2362,8 @@ class RowGroup : public virtual ::duckdb_apache::thrift::TBase { void __set_ordinal(const int16_t val); - bool operator == (const RowGroup & rhs) const - { - if (!(columns == rhs.columns)) - return false; - if (!(total_byte_size == rhs.total_byte_size)) - return false; - if (!(num_rows == rhs.num_rows)) - return false; - if (__isset.sorting_columns != rhs.__isset.sorting_columns) - return false; - else if (__isset.sorting_columns && !(sorting_columns == rhs.sorting_columns)) - return false; - if (__isset.file_offset != rhs.__isset.file_offset) - return false; - else if (__isset.file_offset && !(file_offset == rhs.file_offset)) - return false; - if (__isset.total_compressed_size != rhs.__isset.total_compressed_size) - return false; - else if (__isset.total_compressed_size && !(total_compressed_size == rhs.total_compressed_size)) - return false; - if (__isset.ordinal != rhs.__isset.ordinal) - return false; - else if (__isset.ordinal && !(ordinal == rhs.ordinal)) - return false; - return true; - } - bool operator != (const RowGroup &rhs) const { - return !(*this == rhs); - } - - bool operator < (const RowGroup & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -2051,28 +2373,20 @@ void swap(RowGroup &a, RowGroup &b); std::ostream& operator<<(std::ostream& out, const RowGroup& obj); -class TypeDefinedOrder : public virtual ::duckdb_apache::thrift::TBase { +/** + * Empty struct to signal the order defined by the physical or logical type + */ +class TypeDefinedOrder : public virtual ::apache::thrift::TBase { public: - TypeDefinedOrder(const TypeDefinedOrder&); - TypeDefinedOrder& operator=(const TypeDefinedOrder&); - TypeDefinedOrder() { - } - - virtual ~TypeDefinedOrder() throw(); + TypeDefinedOrder(const TypeDefinedOrder&) noexcept; + TypeDefinedOrder& operator=(const TypeDefinedOrder&) noexcept; + TypeDefinedOrder() noexcept; - bool operator == (const TypeDefinedOrder & /* rhs */) const - { - return true; - } - bool operator != (const TypeDefinedOrder &rhs) const { - return !(*this == rhs); - } + virtual ~TypeDefinedOrder() noexcept; - bool operator < (const TypeDefinedOrder & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -2086,37 +2400,84 @@ typedef struct _ColumnOrder__isset { bool TYPE_ORDER :1; } _ColumnOrder__isset; -class ColumnOrder : public virtual ::duckdb_apache::thrift::TBase { +/** + * Union to specify the order used for the min_value and max_value fields for a + * column. This union takes the role of an enhanced enum that allows rich + * elements (which will be needed for a collation-based ordering in the future). + * + * Possible values are: + * * TypeDefinedOrder - the column uses the order defined by its logical or + * physical type (if there is no logical type). + * + * If the reader does not support the value of this union, min and max stats + * for this column should be ignored. + */ +class ColumnOrder : public virtual ::apache::thrift::TBase { public: - ColumnOrder(const ColumnOrder&); - ColumnOrder& operator=(const ColumnOrder&); - ColumnOrder() { - } - - virtual ~ColumnOrder() throw(); + ColumnOrder(const ColumnOrder&) noexcept; + ColumnOrder& operator=(const ColumnOrder&) noexcept; + ColumnOrder() noexcept; + + virtual ~ColumnOrder() noexcept; + /** + * The sort orders for logical types are: + * UTF8 - unsigned byte-wise comparison + * INT8 - signed comparison + * INT16 - signed comparison + * INT32 - signed comparison + * INT64 - signed comparison + * UINT8 - unsigned comparison + * UINT16 - unsigned comparison + * UINT32 - unsigned comparison + * UINT64 - unsigned comparison + * DECIMAL - signed comparison of the represented value + * DATE - signed comparison + * TIME_MILLIS - signed comparison + * TIME_MICROS - signed comparison + * TIMESTAMP_MILLIS - signed comparison + * TIMESTAMP_MICROS - signed comparison + * INTERVAL - undefined + * JSON - unsigned byte-wise comparison + * BSON - unsigned byte-wise comparison + * ENUM - unsigned byte-wise comparison + * LIST - undefined + * MAP - undefined + * + * In the absence of logical types, the sort order is determined by the physical type: + * BOOLEAN - false, true + * INT32 - signed comparison + * INT64 - signed comparison + * INT96 (only used for legacy timestamps) - undefined + * FLOAT - signed comparison of the represented value (*) + * DOUBLE - signed comparison of the represented value (*) + * BYTE_ARRAY - unsigned byte-wise comparison + * FIXED_LEN_BYTE_ARRAY - unsigned byte-wise comparison + * + * (*) Because the sorting order is not specified properly for floating + * point values (relations vs. total ordering) the following + * compatibility rules should be applied when reading statistics: + * - If the min is a NaN, it should be ignored. + * - If the max is a NaN, it should be ignored. + * - If the min is +0, the row group may contain -0 values as well. + * - If the max is -0, the row group may contain +0 values as well. + * - When looking for NaN values, min and max should be ignored. + * + * When writing statistics the following rules should be followed: + * - NaNs should not be written to min or max statistics fields. + * - If the computed max value is zero (whether negative or positive), + * `+0.0` should be written into the max statistics field. + * - If the computed min value is zero (whether negative or positive), + * `-0.0` should be written into the min statistics field. + */ TypeDefinedOrder TYPE_ORDER; _ColumnOrder__isset __isset; void __set_TYPE_ORDER(const TypeDefinedOrder& val); - bool operator == (const ColumnOrder & rhs) const - { - if (__isset.TYPE_ORDER != rhs.__isset.TYPE_ORDER) - return false; - else if (__isset.TYPE_ORDER && !(TYPE_ORDER == rhs.TYPE_ORDER)) - return false; - return true; - } - bool operator != (const ColumnOrder &rhs) const { - return !(*this == rhs); - } - - bool operator < (const ColumnOrder & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -2126,17 +2487,28 @@ void swap(ColumnOrder &a, ColumnOrder &b); std::ostream& operator<<(std::ostream& out, const ColumnOrder& obj); -class PageLocation : public virtual ::duckdb_apache::thrift::TBase { +class PageLocation : public virtual ::apache::thrift::TBase { public: - PageLocation(const PageLocation&); - PageLocation& operator=(const PageLocation&); - PageLocation() : offset(0), compressed_page_size(0), first_row_index(0) { - } + PageLocation(const PageLocation&) noexcept; + PageLocation& operator=(const PageLocation&) noexcept; + PageLocation() noexcept; - virtual ~PageLocation() throw(); + virtual ~PageLocation() noexcept; + /** + * Offset of the page in the file * + */ int64_t offset; + /** + * Size of the page, including header. Sum of compressed_page_size and header + * length + */ int32_t compressed_page_size; + /** + * Index within the RowGroup of the first row of the page. When an + * OffsetIndex is present, pages must begin on row boundaries + * (repetition_level = 0). + */ int64_t first_row_index; void __set_offset(const int64_t val); @@ -2145,24 +2517,8 @@ class PageLocation : public virtual ::duckdb_apache::thrift::TBase { void __set_first_row_index(const int64_t val); - bool operator == (const PageLocation & rhs) const - { - if (!(offset == rhs.offset)) - return false; - if (!(compressed_page_size == rhs.compressed_page_size)) - return false; - if (!(first_row_index == rhs.first_row_index)) - return false; - return true; - } - bool operator != (const PageLocation &rhs) const { - return !(*this == rhs); - } - - bool operator < (const PageLocation & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -2171,34 +2527,47 @@ void swap(PageLocation &a, PageLocation &b); std::ostream& operator<<(std::ostream& out, const PageLocation& obj); +typedef struct _OffsetIndex__isset { + _OffsetIndex__isset() : unencoded_byte_array_data_bytes(false) {} + bool unencoded_byte_array_data_bytes :1; +} _OffsetIndex__isset; -class OffsetIndex : public virtual ::duckdb_apache::thrift::TBase { +/** + * Optional offsets for each data page in a ColumnChunk. + * + * Forms part of the page index, along with ColumnIndex. + * + * OffsetIndex may be present even if ColumnIndex is not. + */ +class OffsetIndex : public virtual ::apache::thrift::TBase { public: OffsetIndex(const OffsetIndex&); OffsetIndex& operator=(const OffsetIndex&); - OffsetIndex() { - } + OffsetIndex() noexcept; - virtual ~OffsetIndex() throw(); + virtual ~OffsetIndex() noexcept; + /** + * PageLocations, ordered by increasing PageLocation.offset. It is required + * that page_locations[i].first_row_index < page_locations[i+1].first_row_index. + */ duckdb::vector page_locations; + /** + * Unencoded/uncompressed size for BYTE_ARRAY types. + * + * See documention for unencoded_byte_array_data_bytes in SizeStatistics for + * more details on this field. + */ + duckdb::vector unencoded_byte_array_data_bytes; - void __set_page_locations(const duckdb::vector & val); + _OffsetIndex__isset __isset; - bool operator == (const OffsetIndex & rhs) const - { - if (!(page_locations == rhs.page_locations)) - return false; - return true; - } - bool operator != (const OffsetIndex &rhs) const { - return !(*this == rhs); - } + void __set_page_locations(const duckdb::vector & val); - bool operator < (const OffsetIndex & ) const; + void __set_unencoded_byte_array_data_bytes(const duckdb::vector & val); - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -2208,24 +2577,89 @@ void swap(OffsetIndex &a, OffsetIndex &b); std::ostream& operator<<(std::ostream& out, const OffsetIndex& obj); typedef struct _ColumnIndex__isset { - _ColumnIndex__isset() : null_counts(false) {} + _ColumnIndex__isset() : null_counts(false), repetition_level_histograms(false), definition_level_histograms(false) {} bool null_counts :1; + bool repetition_level_histograms :1; + bool definition_level_histograms :1; } _ColumnIndex__isset; -class ColumnIndex : public virtual ::duckdb_apache::thrift::TBase { +/** + * Optional statistics for each data page in a ColumnChunk. + * + * Forms part the page index, along with OffsetIndex. + * + * If this structure is present, OffsetIndex must also be present. + * + * For each field in this structure, [i] refers to the page at + * OffsetIndex.page_locations[i] + */ +class ColumnIndex : public virtual ::apache::thrift::TBase { public: ColumnIndex(const ColumnIndex&); ColumnIndex& operator=(const ColumnIndex&); - ColumnIndex() : boundary_order((BoundaryOrder::type)0) { - } - - virtual ~ColumnIndex() throw(); + ColumnIndex() noexcept; + + virtual ~ColumnIndex() noexcept; + /** + * A list of Boolean values to determine the validity of the corresponding + * min and max values. If true, a page contains only null values, and writers + * have to set the corresponding entries in min_values and max_values to + * byte[0], so that all lists have the same length. If false, the + * corresponding entries in min_values and max_values must be valid. + */ duckdb::vector null_pages; + /** + * Two lists containing lower and upper bounds for the values of each page + * determined by the ColumnOrder of the column. These may be the actual + * minimum and maximum values found on a page, but can also be (more compact) + * values that do not exist on a page. For example, instead of storing ""Blart + * Versenwald III", a writer may set min_values[i]="B", max_values[i]="C". + * Such more compact values must still be valid values within the column's + * logical type. Readers must make sure that list entries are populated before + * using them by inspecting null_pages. + */ duckdb::vector min_values; duckdb::vector max_values; + /** + * Stores whether both min_values and max_values are ordered and if so, in + * which direction. This allows readers to perform binary searches in both + * lists. Readers cannot assume that max_values[i] <= min_values[i+1], even + * if the lists are ordered. + * + * @see BoundaryOrder + */ BoundaryOrder::type boundary_order; + /** + * A list containing the number of null values for each page + * + * Writers SHOULD always write this field even if no null values + * are present or the column is not nullable. + * Readers MUST distinguish between null_counts not being present + * and null_count being 0. + * If null_counts are not present, readers MUST NOT assume all + * null counts are 0. + */ duckdb::vector null_counts; + /** + * Contains repetition level histograms for each page + * concatenated together. The repetition_level_histogram field on + * SizeStatistics contains more details. + * + * When present the length should always be (number of pages * + * (max_repetition_level + 1)) elements. + * + * Element 0 is the first element of the histogram for the first page. + * Element (max_repetition_level + 1) is the first element of the histogram + * for the second page. + * + */ + duckdb::vector repetition_level_histograms; + /** + * Same as repetition_level_histograms except for definitions levels. + * + */ + duckdb::vector definition_level_histograms; _ColumnIndex__isset __isset; @@ -2239,30 +2673,12 @@ class ColumnIndex : public virtual ::duckdb_apache::thrift::TBase { void __set_null_counts(const duckdb::vector & val); - bool operator == (const ColumnIndex & rhs) const - { - if (!(null_pages == rhs.null_pages)) - return false; - if (!(min_values == rhs.min_values)) - return false; - if (!(max_values == rhs.max_values)) - return false; - if (!(boundary_order == rhs.boundary_order)) - return false; - if (__isset.null_counts != rhs.__isset.null_counts) - return false; - else if (__isset.null_counts && !(null_counts == rhs.null_counts)) - return false; - return true; - } - bool operator != (const ColumnIndex &rhs) const { - return !(*this == rhs); - } - - bool operator < (const ColumnIndex & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + void __set_repetition_level_histograms(const duckdb::vector & val); + + void __set_definition_level_histograms(const duckdb::vector & val); + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -2278,17 +2694,26 @@ typedef struct _AesGcmV1__isset { bool supply_aad_prefix :1; } _AesGcmV1__isset; -class AesGcmV1 : public virtual ::duckdb_apache::thrift::TBase { +class AesGcmV1 : public virtual ::apache::thrift::TBase { public: AesGcmV1(const AesGcmV1&); AesGcmV1& operator=(const AesGcmV1&); - AesGcmV1() : aad_prefix(), aad_file_unique(), supply_aad_prefix(0) { - } + AesGcmV1() noexcept; - virtual ~AesGcmV1() throw(); + virtual ~AesGcmV1() noexcept; + /** + * AAD prefix * + */ std::string aad_prefix; + /** + * Unique file identifier part of AAD suffix * + */ std::string aad_file_unique; + /** + * In files encrypted with AAD prefix without storing it, + * readers must supply the prefix * + */ bool supply_aad_prefix; _AesGcmV1__isset __isset; @@ -2299,30 +2724,8 @@ class AesGcmV1 : public virtual ::duckdb_apache::thrift::TBase { void __set_supply_aad_prefix(const bool val); - bool operator == (const AesGcmV1 & rhs) const - { - if (__isset.aad_prefix != rhs.__isset.aad_prefix) - return false; - else if (__isset.aad_prefix && !(aad_prefix == rhs.aad_prefix)) - return false; - if (__isset.aad_file_unique != rhs.__isset.aad_file_unique) - return false; - else if (__isset.aad_file_unique && !(aad_file_unique == rhs.aad_file_unique)) - return false; - if (__isset.supply_aad_prefix != rhs.__isset.supply_aad_prefix) - return false; - else if (__isset.supply_aad_prefix && !(supply_aad_prefix == rhs.supply_aad_prefix)) - return false; - return true; - } - bool operator != (const AesGcmV1 &rhs) const { - return !(*this == rhs); - } - - bool operator < (const AesGcmV1 & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -2338,17 +2741,26 @@ typedef struct _AesGcmCtrV1__isset { bool supply_aad_prefix :1; } _AesGcmCtrV1__isset; -class AesGcmCtrV1 : public virtual ::duckdb_apache::thrift::TBase { +class AesGcmCtrV1 : public virtual ::apache::thrift::TBase { public: AesGcmCtrV1(const AesGcmCtrV1&); AesGcmCtrV1& operator=(const AesGcmCtrV1&); - AesGcmCtrV1() : aad_prefix(), aad_file_unique(), supply_aad_prefix(0) { - } + AesGcmCtrV1() noexcept; - virtual ~AesGcmCtrV1() throw(); + virtual ~AesGcmCtrV1() noexcept; + /** + * AAD prefix * + */ std::string aad_prefix; + /** + * Unique file identifier part of AAD suffix * + */ std::string aad_file_unique; + /** + * In files encrypted with AAD prefix without storing it, + * readers must supply the prefix * + */ bool supply_aad_prefix; _AesGcmCtrV1__isset __isset; @@ -2359,30 +2771,8 @@ class AesGcmCtrV1 : public virtual ::duckdb_apache::thrift::TBase { void __set_supply_aad_prefix(const bool val); - bool operator == (const AesGcmCtrV1 & rhs) const - { - if (__isset.aad_prefix != rhs.__isset.aad_prefix) - return false; - else if (__isset.aad_prefix && !(aad_prefix == rhs.aad_prefix)) - return false; - if (__isset.aad_file_unique != rhs.__isset.aad_file_unique) - return false; - else if (__isset.aad_file_unique && !(aad_file_unique == rhs.aad_file_unique)) - return false; - if (__isset.supply_aad_prefix != rhs.__isset.supply_aad_prefix) - return false; - else if (__isset.supply_aad_prefix && !(supply_aad_prefix == rhs.supply_aad_prefix)) - return false; - return true; - } - bool operator != (const AesGcmCtrV1 &rhs) const { - return !(*this == rhs); - } - - bool operator < (const AesGcmCtrV1 & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -2397,15 +2787,14 @@ typedef struct _EncryptionAlgorithm__isset { bool AES_GCM_CTR_V1 :1; } _EncryptionAlgorithm__isset; -class EncryptionAlgorithm : public virtual ::duckdb_apache::thrift::TBase { +class EncryptionAlgorithm : public virtual ::apache::thrift::TBase { public: EncryptionAlgorithm(const EncryptionAlgorithm&); EncryptionAlgorithm& operator=(const EncryptionAlgorithm&); - EncryptionAlgorithm() { - } + EncryptionAlgorithm() noexcept; - virtual ~EncryptionAlgorithm() throw(); + virtual ~EncryptionAlgorithm() noexcept; AesGcmV1 AES_GCM_V1; AesGcmCtrV1 AES_GCM_CTR_V1; @@ -2415,26 +2804,8 @@ class EncryptionAlgorithm : public virtual ::duckdb_apache::thrift::TBase { void __set_AES_GCM_CTR_V1(const AesGcmCtrV1& val); - bool operator == (const EncryptionAlgorithm & rhs) const - { - if (__isset.AES_GCM_V1 != rhs.__isset.AES_GCM_V1) - return false; - else if (__isset.AES_GCM_V1 && !(AES_GCM_V1 == rhs.AES_GCM_V1)) - return false; - if (__isset.AES_GCM_CTR_V1 != rhs.__isset.AES_GCM_CTR_V1) - return false; - else if (__isset.AES_GCM_CTR_V1 && !(AES_GCM_CTR_V1 == rhs.AES_GCM_CTR_V1)) - return false; - return true; - } - bool operator != (const EncryptionAlgorithm &rhs) const { - return !(*this == rhs); - } - - bool operator < (const EncryptionAlgorithm & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -2452,23 +2823,76 @@ typedef struct _FileMetaData__isset { bool footer_signing_key_metadata :1; } _FileMetaData__isset; -class FileMetaData : public virtual ::duckdb_apache::thrift::TBase { +/** + * Description for file metadata + */ +class FileMetaData : public virtual ::apache::thrift::TBase { public: FileMetaData(const FileMetaData&); FileMetaData& operator=(const FileMetaData&); - FileMetaData() : version(0), num_rows(0), created_by(), footer_signing_key_metadata() { - } + FileMetaData() noexcept; - virtual ~FileMetaData() throw(); + virtual ~FileMetaData() noexcept; + /** + * Version of this file * + */ int32_t version; + /** + * Parquet schema for this file. This schema contains metadata for all the columns. + * The schema is represented as a tree with a single root. The nodes of the tree + * are flattened to a list by doing a depth-first traversal. + * The column metadata contains the path in the schema for that column which can be + * used to map columns to nodes in the schema. + * The first element is the root * + */ duckdb::vector schema; + /** + * Number of rows in this file * + */ int64_t num_rows; + /** + * Row groups in this file * + */ duckdb::vector row_groups; + /** + * Optional key/value metadata * + */ duckdb::vector key_value_metadata; + /** + * String for application that wrote this file. This should be in the format + * version (build ). + * e.g. impala version 1.0 (build 6cf94d29b2b7115df4de2c06e2ab4326d721eb55) + * + */ std::string created_by; + /** + * Sort order used for the min_value and max_value fields in the Statistics + * objects and the min_values and max_values fields in the ColumnIndex + * objects of each column in this file. Sort orders are listed in the order + * matching the columns in the schema. The indexes are not necessary the same + * though, because only leaf nodes of the schema are represented in the list + * of sort orders. + * + * Without column_orders, the meaning of the min_value and max_value fields + * in the Statistics object and the ColumnIndex object is undefined. To ensure + * well-defined behaviour, if these fields are written to a Parquet file, + * column_orders must be written as well. + * + * The obsolete min and max fields in the Statistics object are always sorted + * by signed comparison regardless of column_orders. + */ duckdb::vector column_orders; + /** + * Encryption algorithm. This field is set only in encrypted files + * with plaintext footer. Files with encrypted footer store algorithm id + * in FileCryptoMetaData structure. + */ EncryptionAlgorithm encryption_algorithm; + /** + * Retrieval metadata of key used for signing the footer. + * Used only in encrypted files with plaintext footer. + */ std::string footer_signing_key_metadata; _FileMetaData__isset __isset; @@ -2491,46 +2915,8 @@ class FileMetaData : public virtual ::duckdb_apache::thrift::TBase { void __set_footer_signing_key_metadata(const std::string& val); - bool operator == (const FileMetaData & rhs) const - { - if (!(version == rhs.version)) - return false; - if (!(schema == rhs.schema)) - return false; - if (!(num_rows == rhs.num_rows)) - return false; - if (!(row_groups == rhs.row_groups)) - return false; - if (__isset.key_value_metadata != rhs.__isset.key_value_metadata) - return false; - else if (__isset.key_value_metadata && !(key_value_metadata == rhs.key_value_metadata)) - return false; - if (__isset.created_by != rhs.__isset.created_by) - return false; - else if (__isset.created_by && !(created_by == rhs.created_by)) - return false; - if (__isset.column_orders != rhs.__isset.column_orders) - return false; - else if (__isset.column_orders && !(column_orders == rhs.column_orders)) - return false; - if (__isset.encryption_algorithm != rhs.__isset.encryption_algorithm) - return false; - else if (__isset.encryption_algorithm && !(encryption_algorithm == rhs.encryption_algorithm)) - return false; - if (__isset.footer_signing_key_metadata != rhs.__isset.footer_signing_key_metadata) - return false; - else if (__isset.footer_signing_key_metadata && !(footer_signing_key_metadata == rhs.footer_signing_key_metadata)) - return false; - return true; - } - bool operator != (const FileMetaData &rhs) const { - return !(*this == rhs); - } - - bool operator < (const FileMetaData & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -2544,16 +2930,27 @@ typedef struct _FileCryptoMetaData__isset { bool key_metadata :1; } _FileCryptoMetaData__isset; -class FileCryptoMetaData : public virtual ::duckdb_apache::thrift::TBase { +/** + * Crypto metadata for files with encrypted footer * + */ +class FileCryptoMetaData : public virtual ::apache::thrift::TBase { public: FileCryptoMetaData(const FileCryptoMetaData&); FileCryptoMetaData& operator=(const FileCryptoMetaData&); - FileCryptoMetaData() : key_metadata() { - } - - virtual ~FileCryptoMetaData() throw(); + FileCryptoMetaData() noexcept; + + virtual ~FileCryptoMetaData() noexcept; + /** + * Encryption algorithm. This field is only used for files + * with encrypted footer. Files with plaintext footer store algorithm id + * inside footer (FileMetaData structure). + */ EncryptionAlgorithm encryption_algorithm; + /** + * Retrieval metadata of key used for encryption of footer, + * and (possibly) columns * + */ std::string key_metadata; _FileCryptoMetaData__isset __isset; @@ -2562,24 +2959,8 @@ class FileCryptoMetaData : public virtual ::duckdb_apache::thrift::TBase { void __set_key_metadata(const std::string& val); - bool operator == (const FileCryptoMetaData & rhs) const - { - if (!(encryption_algorithm == rhs.encryption_algorithm)) - return false; - if (__isset.key_metadata != rhs.__isset.key_metadata) - return false; - else if (__isset.key_metadata && !(key_metadata == rhs.key_metadata)) - return false; - return true; - } - bool operator != (const FileCryptoMetaData &rhs) const { - return !(*this == rhs); - } - - bool operator < (const FileCryptoMetaData & ) const; - - uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); - uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; + uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; virtual void printTo(std::ostream& out) const; }; @@ -2588,6 +2969,6 @@ void swap(FileCryptoMetaData &a, FileCryptoMetaData &b); std::ostream& operator<<(std::ostream& out, const FileCryptoMetaData& obj); -}} // namespace +} // namespace #endif diff --git a/src/duckdb/third_party/snappy/snappy-stubs-internal.h b/src/duckdb/third_party/snappy/snappy-stubs-internal.h index 6b06b6ba1..b18689f54 100644 --- a/src/duckdb/third_party/snappy/snappy-stubs-internal.h +++ b/src/duckdb/third_party/snappy/snappy-stubs-internal.h @@ -31,6 +31,19 @@ #ifndef THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ #define THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ +// DuckDB - LNK: define here instead of in CMake +#ifdef __GNUC__ +#define HAVE_BUILTIN_EXPECT 1 +#define HAVE_BUILTIN_CTZ 1 +#define HAVE_BUILTIN_PREFETCH 1 +#endif + +#if defined(__aarch64__) +// These are always enabled on aarch64 +#define SNAPPY_HAVE_NEON 1 +#define SNAPPY_HAVE_NEON_CRC32 1 +#endif + #include "snappy_version.hpp" #if SNAPPY_NEW_VERSION @@ -47,14 +60,6 @@ #include #include -// DuckDB - LNK: define here instead of in CMake -#ifdef __GNUC__ -#define HAVE_BUILTIN_EXPECT 1 -#define HAVE_BUILTIN_CTZ 1 -#define HAVE_BUILTIN_PREFETCH 1 -#endif - - #if HAVE_SYS_MMAN_H #include #endif @@ -552,13 +557,6 @@ inline char* string_as_array(std::string* str) { #include #include -// DuckDB - LNK: define here instead of in CMake -#ifdef __GNUC__ -#define HAVE_BUILTIN_EXPECT -#define HAVE_BUILTIN_CTZ -#define HAVE_BUILTIN_PREFETCH -#endif - #ifdef HAVE_SYS_MMAN_H #include #endif diff --git a/src/duckdb/third_party/zstd/common/debug.cpp b/src/duckdb/third_party/zstd/common/debug.cpp new file mode 100644 index 000000000..01010e4eb --- /dev/null +++ b/src/duckdb/third_party/zstd/common/debug.cpp @@ -0,0 +1,36 @@ +/* ****************************************************************** + * debug + * Part of FSE library + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + + +/* + * This module only hosts one global variable + * which can be used to dynamically influence the verbosity of traces, + * such as DEBUGLOG and RAWLOG + */ + +#include "zstd/common/debug.h" + +#if !defined(ZSTD_LINUX_KERNEL) || (DEBUGLEVEL>=2) + +namespace duckdb_zstd { + +/* We only use this when DEBUGLEVEL>=2, but we get -Werror=pedantic errors if a + * translation unit is empty. So remove this from Linux kernel builds, but + * otherwise just leave it in. + */ +int g_debuglevel = DEBUGLEVEL; + +} // namespace duckdb_zstd + +#endif diff --git a/src/duckdb/third_party/zstd/common/entropy_common.cpp b/src/duckdb/third_party/zstd/common/entropy_common.cpp index bd41d220a..9a33c2dfc 100644 --- a/src/duckdb/third_party/zstd/common/entropy_common.cpp +++ b/src/duckdb/third_party/zstd/common/entropy_common.cpp @@ -1,6 +1,6 @@ /* ****************************************************************** * Common functions of New Generation Entropy library - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * You can contact the author at : * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -17,10 +17,10 @@ ***************************************/ #include "zstd/common/mem.h" #include "zstd/common/error_private.h" /* ERR_*, ERROR */ +#define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */ #include "zstd/common/fse.h" -#include "zstd/common/fse_static.h" #include "zstd/common/huf.h" -#include "zstd/common/huf_static.h" +#include "zstd/common/bits.h" /* ZSDT_highbit32, ZSTD_countTrailingZeros32 */ namespace duckdb_zstd { @@ -39,8 +39,9 @@ const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); } /*-************************************************************** * FSE NCount encoding-decoding ****************************************************************/ -size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, - const void* headerBuffer, size_t hbSize) +FORCE_INLINE_TEMPLATE +size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) { const BYTE* const istart = (const BYTE*) headerBuffer; const BYTE* const iend = istart + hbSize; @@ -51,23 +52,23 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t U32 bitStream; int bitCount; unsigned charnum = 0; + unsigned const maxSV1 = *maxSVPtr + 1; int previous0 = 0; - if (hbSize < 4) { - /* This function only works when hbSize >= 4 */ - char buffer[4]; - memset(buffer, 0, sizeof(buffer)); - memcpy(buffer, headerBuffer, hbSize); + if (hbSize < 8) { + /* This function only works when hbSize >= 8 */ + char buffer[8] = {0}; + ZSTD_memcpy(buffer, headerBuffer, hbSize); { size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr, buffer, sizeof(buffer)); if (FSE_isError(countSize)) return countSize; if (countSize > hbSize) return ERROR(corruption_detected); return countSize; } } - assert(hbSize >= 4); + assert(hbSize >= 8); /* init */ - memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */ + ZSTD_memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */ bitStream = MEM_readLE32(ip); nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */ if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge); @@ -78,36 +79,58 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t threshold = 1<1) & (charnum<=*maxSVPtr)) { + for (;;) { if (previous0) { - unsigned n0 = charnum; - while ((bitStream & 0xFFFF) == 0xFFFF) { - n0 += 24; - if (ip < iend-5) { - ip += 2; - bitStream = MEM_readLE32(ip) >> bitCount; + /* Count the number of repeats. Each time the + * 2-bit repeat code is 0b11 there is another + * repeat. + * Avoid UB by setting the high bit to 1. + */ + int repeats = ZSTD_countTrailingZeros32(~bitStream | 0x80000000) >> 1; + while (repeats >= 12) { + charnum += 3 * 12; + if (LIKELY(ip <= iend-7)) { + ip += 3; } else { - bitStream >>= 16; - bitCount += 16; - } } - while ((bitStream & 3) == 3) { - n0 += 3; - bitStream >>= 2; - bitCount += 2; + bitCount -= (int)(8 * (iend - 7 - ip)); + bitCount &= 31; + ip = iend - 4; + } + bitStream = MEM_readLE32(ip) >> bitCount; + repeats = ZSTD_countTrailingZeros32(~bitStream | 0x80000000) >> 1; } - n0 += bitStream & 3; + charnum += 3 * repeats; + bitStream >>= 2 * repeats; + bitCount += 2 * repeats; + + /* Add the final repeat which isn't 0b11. */ + assert((bitStream & 3) < 3); + charnum += bitStream & 3; bitCount += 2; - if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall); - while (charnum < n0) normalizedCounter[charnum++] = 0; - if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { + + /* This is an error, but break and return an error + * at the end, because returning out of a loop makes + * it harder for the compiler to optimize. + */ + if (charnum >= maxSV1) break; + + /* We don't need to set the normalized count to 0 + * because we already memset the whole buffer to 0. + */ + + if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { assert((bitCount >> 3) <= 3); /* For first condition to work */ ip += bitCount>>3; bitCount &= 7; - bitStream = MEM_readLE32(ip) >> bitCount; } else { - bitStream >>= 2; - } } - { int const max = (2*threshold-1) - remaining; + bitCount -= (int)(8 * (iend - 4 - ip)); + bitCount &= 31; + ip = iend - 4; + } + bitStream = MEM_readLE32(ip) >> bitCount; + } + { + int const max = (2*threshold-1) - remaining; int count; if ((bitStream & (threshold-1)) < (U32)max) { @@ -120,24 +143,43 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t } count--; /* extra accuracy */ - remaining -= count < 0 ? -count : count; /* -1 means +1 */ + /* When it matters (small blocks), this is a + * predictable branch, because we don't use -1. + */ + if (count >= 0) { + remaining -= count; + } else { + assert(count == -1); + remaining += count; + } normalizedCounter[charnum++] = (short)count; previous0 = !count; - while (remaining < threshold) { - nbBits--; - threshold >>= 1; + + assert(threshold > 1); + if (remaining < threshold) { + /* This branch can be folded into the + * threshold update condition because we + * know that threshold > 1. + */ + if (remaining <= 1) break; + nbBits = ZSTD_highbit32(remaining) + 1; + threshold = 1 << (nbBits - 1); } + if (charnum >= maxSV1) break; - if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { + if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { ip += bitCount>>3; bitCount &= 7; } else { bitCount -= (int)(8 * (iend - 4 - ip)); + bitCount &= 31; ip = iend - 4; } - bitStream = MEM_readLE32(ip) >> (bitCount & 31); - } } /* while ((remaining>1) & (charnum<=*maxSVPtr)) */ + bitStream = MEM_readLE32(ip) >> bitCount; + } } if (remaining != 1) return ERROR(corruption_detected); + /* Only possible when there are too many zeros. */ + if (charnum > maxSV1) return ERROR(maxSymbolValue_tooSmall); if (bitCount > 32) return ERROR(corruption_detected); *maxSVPtr = charnum-1; @@ -145,6 +187,43 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t return ip-istart; } +/* Avoids the FORCE_INLINE of the _body() function. */ +static size_t FSE_readNCount_body_default( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); +} + +#if DYNAMIC_BMI2 +BMI2_TARGET_ATTRIBUTE static size_t FSE_readNCount_body_bmi2( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); +} +#endif + +size_t FSE_readNCount_bmi2( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize, int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { + return FSE_readNCount_body_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); + } +#endif + (void)bmi2; + return FSE_readNCount_body_default(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); +} + +size_t FSE_readNCount( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + return FSE_readNCount_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize, /* bmi2 */ 0); +} + /*! HUF_readStats() : Read compact Huffman tree, saved by HUF_writeCTable(). @@ -156,6 +235,17 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, const void* src, size_t srcSize) +{ + U32 wksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; + return HUF_readStats_wksp(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, wksp, sizeof(wksp), /* flags */ 0); +} + +FORCE_INLINE_TEMPLATE size_t +HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize, + int bmi2) { U32 weightTotal; const BYTE* ip = (const BYTE*) src; @@ -164,7 +254,7 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, if (!srcSize) return ERROR(srcSize_wrong); iSize = ip[0]; - /* memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */ + /* ZSTD_memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */ if (iSize >= 128) { /* special header */ oSize = iSize - 127; @@ -178,31 +268,31 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, huffWeight[n+1] = ip[n/2] & 15; } } } else { /* header compressed with FSE (normal case) */ - FSE_DTable fseWorkspace[FSE_DTABLE_SIZE_U32(6)]; /* 6 is max possible tableLog for HUF header (maybe even 5, to be tested) */ if (iSize+1 > srcSize) return ERROR(srcSize_wrong); - oSize = FSE_decompress_wksp(huffWeight, hwSize-1, ip+1, iSize, fseWorkspace, 6); /* max (hwSize-1) values decoded, as last one is implied */ + /* max (hwSize-1) values decoded, as last one is implied */ + oSize = FSE_decompress_wksp_bmi2(huffWeight, hwSize-1, ip+1, iSize, 6, workSpace, wkspSize, bmi2); if (FSE_isError(oSize)) return oSize; } /* collect weight stats */ - memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32)); + ZSTD_memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32)); weightTotal = 0; { U32 n; for (n=0; n= HUF_TABLELOG_MAX) return ERROR(corruption_detected); + if (huffWeight[n] > HUF_TABLELOG_MAX) return ERROR(corruption_detected); rankStats[huffWeight[n]]++; weightTotal += (1 << huffWeight[n]) >> 1; } } if (weightTotal == 0) return ERROR(corruption_detected); /* get last non-null symbol weight (implied, total must be 2^n) */ - { U32 const tableLog = BIT_highbit32(weightTotal) + 1; + { U32 const tableLog = ZSTD_highbit32(weightTotal) + 1; if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected); *tableLogPtr = tableLog; /* determine last weight */ { U32 const total = 1 << tableLog; U32 const rest = total - weightTotal; - U32 const verif = 1 << BIT_highbit32(rest); - U32 const lastWeight = BIT_highbit32(rest) + 1; + U32 const verif = 1 << ZSTD_highbit32(rest); + U32 const lastWeight = ZSTD_highbit32(rest) + 1; if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */ huffWeight[oSize] = (BYTE)lastWeight; rankStats[lastWeight]++; @@ -216,4 +306,38 @@ size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, return iSize+1; } +/* Avoids the FORCE_INLINE of the _body() function. */ +static size_t HUF_readStats_body_default(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 0); +} + +#if DYNAMIC_BMI2 +static BMI2_TARGET_ATTRIBUTE size_t HUF_readStats_body_bmi2(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 1); +} +#endif + +size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize, + int flags) +{ +#if DYNAMIC_BMI2 + if (flags & HUF_flags_bmi2) { + return HUF_readStats_body_bmi2(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize); + } +#endif + (void)flags; + return HUF_readStats_body_default(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize); } + +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/common/error_private.cpp b/src/duckdb/third_party/zstd/common/error_private.cpp index 207ef006d..c3ba4728b 100644 --- a/src/duckdb/third_party/zstd/common/error_private.cpp +++ b/src/duckdb/third_party/zstd/common/error_private.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -29,9 +29,11 @@ const char* ERR_getErrorString(ERR_enum code) case PREFIX(version_unsupported): return "Version not supported"; case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter"; case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding"; - case PREFIX(corruption_detected): return "Corrupted block detected"; + case PREFIX(corruption_detected): return "Data corruption detected"; case PREFIX(checksum_wrong): return "Restored data doesn't match checksum"; + case PREFIX(literals_headerWrong): return "Header of Literals' block doesn't respect format specification"; case PREFIX(parameter_unsupported): return "Unsupported parameter"; + case PREFIX(parameter_combination_unsupported): return "Unsupported combination of parameters"; case PREFIX(parameter_outOfBound): return "Parameter is out of bound"; case PREFIX(init_missing): return "Context should be init first"; case PREFIX(memory_allocation): return "Allocation error : not enough memory"; @@ -40,20 +42,26 @@ const char* ERR_getErrorString(ERR_enum code) case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported"; case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large"; case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small"; + case PREFIX(stabilityCondition_notRespected): return "pledged buffer stability condition is not respected"; case PREFIX(dictionary_corrupted): return "Dictionary is corrupted"; case PREFIX(dictionary_wrong): return "Dictionary mismatch"; case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples"; case PREFIX(dstSize_tooSmall): return "Destination buffer is too small"; case PREFIX(srcSize_wrong): return "Src size is incorrect"; case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer"; + case PREFIX(noForwardProgress_destFull): return "Operation made no progress over multiple calls, due to output buffer being full"; + case PREFIX(noForwardProgress_inputEmpty): return "Operation made no progress over multiple calls, due to input being empty"; /* following error codes are not stable and may be removed or changed in a future version */ case PREFIX(frameIndex_tooLarge): return "Frame index is too large"; case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking"; case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong"; + case PREFIX(srcBuffer_wrong): return "Source buffer is wrong"; + case PREFIX(sequenceProducer_failed): return "Block-level external sequence producer returned an error code"; + case PREFIX(externalSequences_invalid): return "External sequences are not valid"; case PREFIX(maxCode): default: return notErrorCode; } #endif } -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/common/fse_decompress.cpp b/src/duckdb/third_party/zstd/common/fse_decompress.cpp index 8845948e0..9b6957409 100644 --- a/src/duckdb/third_party/zstd/common/fse_decompress.cpp +++ b/src/duckdb/third_party/zstd/common/fse_decompress.cpp @@ -1,6 +1,6 @@ /* ****************************************************************** * FSE : Finite State Entropy decoder - * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * You can contact the author at : * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -16,19 +16,21 @@ /* ************************************************************** * Includes ****************************************************************/ -#include /* malloc, free, qsort */ -#include /* memcpy, memset */ +#include "zstd/common/debug.h" /* assert */ #include "zstd/common/bitstream.h" #include "zstd/common/compiler.h" +#define FSE_STATIC_LINKING_ONLY #include "zstd/common/fse.h" -#include "zstd/common/fse_static.h" #include "zstd/common/error_private.h" +#include "zstd/common/zstd_deps.h" /* ZSTD_memcpy */ +#include "zstd/common/bits.h" /* ZSTD_highbit32 */ +namespace duckdb_zstd { /* ************************************************************** * Error Management ****************************************************************/ -// #define FSE_isError ERR_isError +#define FSE_isError ERR_isError #define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */ @@ -54,31 +56,19 @@ #define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y) #define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y) -namespace duckdb_zstd { - -/* Function templates */ -FSE_DTable* FSE_createDTable (unsigned tableLog) -{ - if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX; - return (FSE_DTable*)malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) ); -} - -void FSE_freeDTable (FSE_DTable* dt) -{ - free(dt); -} - -size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) +static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize) { void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */ FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr); - U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1]; + U16* symbolNext = (U16*)workSpace; + BYTE* spread = (BYTE*)(symbolNext + maxSymbolValue + 1); U32 const maxSV1 = maxSymbolValue + 1; U32 const tableSize = 1 << tableLog; U32 highThreshold = tableSize-1; /* Sanity Checks */ + if (FSE_BUILD_DTABLE_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(maxSymbolValue_tooLarge); if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge); if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); @@ -94,13 +84,57 @@ size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned symbolNext[s] = 1; } else { if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0; - symbolNext[s] = normalizedCounter[s]; + symbolNext[s] = (U16)normalizedCounter[s]; } } } - memcpy(dt, &DTableH, sizeof(DTableH)); + ZSTD_memcpy(dt, &DTableH, sizeof(DTableH)); } /* Spread symbols */ - { U32 const tableMask = tableSize-1; + if (highThreshold == tableSize - 1) { + size_t const tableMask = tableSize-1; + size_t const step = FSE_TABLESTEP(tableSize); + /* First lay down the symbols in order. + * We use a uint64_t to lay down 8 bytes at a time. This reduces branch + * misses since small blocks generally have small table logs, so nearly + * all symbols have counts <= 8. We ensure we have 8 bytes at the end of + * our buffer to handle the over-write. + */ + { U64 const add = 0x0101010101010101ull; + size_t pos = 0; + U64 sv = 0; + U32 s; + for (s=0; stableLog = 0; - DTableH->fastMode = 0; - - cell->newState = 0; - cell->symbol = symbolValue; - cell->nbBits = 0; - - return 0; -} - - -size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits) -{ - void* ptr = dt; - FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr; - void* dPtr = dt + 1; - FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr; - const unsigned tableSize = 1 << nbBits; - const unsigned tableMask = tableSize - 1; - const unsigned maxSV1 = tableMask+1; - unsigned s; - - /* Sanity checks */ - if (nbBits < 1) return ERROR(GENERIC); /* min size */ - - /* Build Decoding Table */ - DTableH->tableLog = (U16)nbBits; - DTableH->fastMode = 1; - for (s=0; s= ostart); + return (size_t)(op-ostart); } - -size_t FSE_decompress_usingDTable(void* dst, size_t originalSize, - const void* cSrc, size_t cSrcSize, - const FSE_DTable* dt) -{ - const void* ptr = dt; - const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr; - const U32 fastMode = DTableH->fastMode; - - /* select fast mode (static) */ - if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1); - return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0); -} +typedef struct { + short ncount[FSE_MAX_SYMBOL_VALUE + 1]; +} FSE_DecompressWksp; -size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog) +FORCE_INLINE_TEMPLATE size_t FSE_decompress_wksp_body( + void* dst, size_t dstCapacity, + const void* cSrc, size_t cSrcSize, + unsigned maxLog, void* workSpace, size_t wkspSize, + int bmi2) { const BYTE* const istart = (const BYTE*)cSrc; const BYTE* ip = istart; - short counting[FSE_MAX_SYMBOL_VALUE+1]; unsigned tableLog; unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE; + FSE_DecompressWksp* const wksp = (FSE_DecompressWksp*)workSpace; + size_t const dtablePos = sizeof(FSE_DecompressWksp) / sizeof(FSE_DTable); + FSE_DTable* const dtable = (FSE_DTable*)workSpace + dtablePos; + + FSE_STATIC_ASSERT((FSE_MAX_SYMBOL_VALUE + 1) % 2 == 0); + if (wkspSize < sizeof(*wksp)) return ERROR(GENERIC); + + /* correct offset to dtable depends on this property */ + FSE_STATIC_ASSERT(sizeof(FSE_DecompressWksp) % sizeof(FSE_DTable) == 0); /* normal FSE decoding mode */ - size_t const NCountLength = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize); - if (FSE_isError(NCountLength)) return NCountLength; - /* if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); */ /* too small input size; supposed to be already checked in NCountLength, only remaining case : NCountLength==cSrcSize */ - if (tableLog > maxLog) return ERROR(tableLog_tooLarge); - ip += NCountLength; - cSrcSize -= NCountLength; + { size_t const NCountLength = + FSE_readNCount_bmi2(wksp->ncount, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2); + if (FSE_isError(NCountLength)) return NCountLength; + if (tableLog > maxLog) return ERROR(tableLog_tooLarge); + assert(NCountLength <= cSrcSize); + ip += NCountLength; + cSrcSize -= NCountLength; + } - CHECK_F( FSE_buildDTable (workSpace, counting, maxSymbolValue, tableLog) ); + if (FSE_DECOMPRESS_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(tableLog_tooLarge); + assert(sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog) <= wkspSize); + workSpace = (BYTE*)workSpace + sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog); + wkspSize -= sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog); - return FSE_decompress_usingDTable (dst, dstCapacity, ip, cSrcSize, workSpace); /* always return, even if it is an error code */ -} + CHECK_F( FSE_buildDTable_internal(dtable, wksp->ncount, maxSymbolValue, tableLog, workSpace, wkspSize) ); + { + const void* ptr = dtable; + const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr; + const U32 fastMode = DTableH->fastMode; -typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)]; + /* select fast mode (static) */ + if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, dtable, 1); + return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, dtable, 0); + } +} -size_t FSE_decompress(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize) +/* Avoids the FORCE_INLINE of the _body() function. */ +static size_t FSE_decompress_wksp_body_default(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) { - DTable_max_t dt; /* Static analyzer seems unable to understand this table will be properly initialized later */ - return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, dt, FSE_MAX_TABLELOG); + return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 0); } +#if DYNAMIC_BMI2 +BMI2_TARGET_ATTRIBUTE static size_t FSE_decompress_wksp_body_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) +{ + return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 1); +} +#endif + +size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { + return FSE_decompress_wksp_body_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); + } +#endif + (void)bmi2; + return FSE_decompress_wksp_body_default(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); } #endif /* FSE_COMMONDEFS_ONLY */ + +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/common/pool.cpp b/src/duckdb/third_party/zstd/common/pool.cpp new file mode 100644 index 000000000..79df927e6 --- /dev/null +++ b/src/duckdb/third_party/zstd/common/pool.cpp @@ -0,0 +1,376 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +/* ====== Dependencies ======= */ +#include "zstd/common/allocations.h" /* ZSTD_customCalloc, ZSTD_customFree */ +#include "zstd/common/zstd_deps.h" /* size_t */ +#include "zstd/common/debug.h" /* assert */ +#include "zstd/common/pool.h" + +/* ====== Compiler specifics ====== */ +#if defined(_MSC_VER) +# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ +#endif + + +#ifdef ZSTD_MULTITHREAD +#include "zstd/common/threading.h" /* pthread adaptation */ +#endif + +namespace duckdb_zstd { + +#ifdef ZSTD_MULTITHREAD + +/* A job is a function and an opaque argument */ +typedef struct POOL_job_s { + POOL_function function; + void *opaque; +} POOL_job; + +struct POOL_ctx_s { + ZSTD_customMem customMem; + /* Keep track of the threads */ + ZSTD_pthread_t* threads; + size_t threadCapacity; + size_t threadLimit; + + /* The queue is a circular buffer */ + POOL_job *queue; + size_t queueHead; + size_t queueTail; + size_t queueSize; + + /* The number of threads working on jobs */ + size_t numThreadsBusy; + /* Indicates if the queue is empty */ + int queueEmpty; + + /* The mutex protects the queue */ + ZSTD_pthread_mutex_t queueMutex; + /* Condition variable for pushers to wait on when the queue is full */ + ZSTD_pthread_cond_t queuePushCond; + /* Condition variables for poppers to wait on when the queue is empty */ + ZSTD_pthread_cond_t queuePopCond; + /* Indicates if the queue is shutting down */ + int shutdown; +}; + +/* POOL_thread() : + * Work thread for the thread pool. + * Waits for jobs and executes them. + * @returns : NULL on failure else non-null. + */ +static void* POOL_thread(void* opaque) { + POOL_ctx* const ctx = (POOL_ctx*)opaque; + if (!ctx) { return NULL; } + for (;;) { + /* Lock the mutex and wait for a non-empty queue or until shutdown */ + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + + while ( ctx->queueEmpty + || (ctx->numThreadsBusy >= ctx->threadLimit) ) { + if (ctx->shutdown) { + /* even if !queueEmpty, (possible if numThreadsBusy >= threadLimit), + * a few threads will be shutdown while !queueEmpty, + * but enough threads will remain active to finish the queue */ + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + return opaque; + } + ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex); + } + /* Pop a job off the queue */ + { POOL_job const job = ctx->queue[ctx->queueHead]; + ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize; + ctx->numThreadsBusy++; + ctx->queueEmpty = (ctx->queueHead == ctx->queueTail); + /* Unlock the mutex, signal a pusher, and run the job */ + ZSTD_pthread_cond_signal(&ctx->queuePushCond); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + + job.function(job.opaque); + + /* If the intended queue size was 0, signal after finishing job */ + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + ctx->numThreadsBusy--; + ZSTD_pthread_cond_signal(&ctx->queuePushCond); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + } + } /* for (;;) */ + assert(0); /* Unreachable */ +} + +/* ZSTD_createThreadPool() : public access point */ +POOL_ctx* ZSTD_createThreadPool(size_t numThreads) { + return POOL_create (numThreads, 0); +} + +POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { + return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); +} + +POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, + ZSTD_customMem customMem) +{ + POOL_ctx* ctx; + /* Check parameters */ + if (!numThreads) { return NULL; } + /* Allocate the context and zero initialize */ + ctx = (POOL_ctx*)ZSTD_customCalloc(sizeof(POOL_ctx), customMem); + if (!ctx) { return NULL; } + /* Initialize the job queue. + * It needs one extra space since one space is wasted to differentiate + * empty and full queues. + */ + ctx->queueSize = queueSize + 1; + ctx->queue = (POOL_job*)ZSTD_customCalloc(ctx->queueSize * sizeof(POOL_job), customMem); + ctx->queueHead = 0; + ctx->queueTail = 0; + ctx->numThreadsBusy = 0; + ctx->queueEmpty = 1; + { + int error = 0; + error |= ZSTD_pthread_mutex_init(&ctx->queueMutex, NULL); + error |= ZSTD_pthread_cond_init(&ctx->queuePushCond, NULL); + error |= ZSTD_pthread_cond_init(&ctx->queuePopCond, NULL); + if (error) { POOL_free(ctx); return NULL; } + } + ctx->shutdown = 0; + /* Allocate space for the thread handles */ + ctx->threads = (ZSTD_pthread_t*)ZSTD_customCalloc(numThreads * sizeof(ZSTD_pthread_t), customMem); + ctx->threadCapacity = 0; + ctx->customMem = customMem; + /* Check for errors */ + if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; } + /* Initialize the threads */ + { size_t i; + for (i = 0; i < numThreads; ++i) { + if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) { + ctx->threadCapacity = i; + POOL_free(ctx); + return NULL; + } } + ctx->threadCapacity = numThreads; + ctx->threadLimit = numThreads; + } + return ctx; +} + +/*! POOL_join() : + Shutdown the queue, wake any sleeping threads, and join all of the threads. +*/ +static void POOL_join(POOL_ctx* ctx) { + /* Shut down the queue */ + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + ctx->shutdown = 1; + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + /* Wake up sleeping threads */ + ZSTD_pthread_cond_broadcast(&ctx->queuePushCond); + ZSTD_pthread_cond_broadcast(&ctx->queuePopCond); + /* Join all of the threads */ + { size_t i; + for (i = 0; i < ctx->threadCapacity; ++i) { + ZSTD_pthread_join(ctx->threads[i]); /* note : could fail */ + } } +} + +void POOL_free(POOL_ctx *ctx) { + if (!ctx) { return; } + POOL_join(ctx); + ZSTD_pthread_mutex_destroy(&ctx->queueMutex); + ZSTD_pthread_cond_destroy(&ctx->queuePushCond); + ZSTD_pthread_cond_destroy(&ctx->queuePopCond); + ZSTD_customFree(ctx->queue, ctx->customMem); + ZSTD_customFree(ctx->threads, ctx->customMem); + ZSTD_customFree(ctx, ctx->customMem); +} + +/*! POOL_joinJobs() : + * Waits for all queued jobs to finish executing. + */ +void POOL_joinJobs(POOL_ctx* ctx) { + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + while(!ctx->queueEmpty || ctx->numThreadsBusy > 0) { + ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex); + } + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); +} + +void ZSTD_freeThreadPool (ZSTD_threadPool* pool) { + POOL_free (pool); +} + +size_t POOL_sizeof(const POOL_ctx* ctx) { + if (ctx==NULL) return 0; /* supports sizeof NULL */ + return sizeof(*ctx) + + ctx->queueSize * sizeof(POOL_job) + + ctx->threadCapacity * sizeof(ZSTD_pthread_t); +} + + +/* @return : 0 on success, 1 on error */ +static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads) +{ + if (numThreads <= ctx->threadCapacity) { + if (!numThreads) return 1; + ctx->threadLimit = numThreads; + return 0; + } + /* numThreads > threadCapacity */ + { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_customCalloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem); + if (!threadPool) return 1; + /* replace existing thread pool */ + ZSTD_memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(ZSTD_pthread_t)); + ZSTD_customFree(ctx->threads, ctx->customMem); + ctx->threads = threadPool; + /* Initialize additional threads */ + { size_t threadId; + for (threadId = ctx->threadCapacity; threadId < numThreads; ++threadId) { + if (ZSTD_pthread_create(&threadPool[threadId], NULL, &POOL_thread, ctx)) { + ctx->threadCapacity = threadId; + return 1; + } } + } } + /* successfully expanded */ + ctx->threadCapacity = numThreads; + ctx->threadLimit = numThreads; + return 0; +} + +/* @return : 0 on success, 1 on error */ +int POOL_resize(POOL_ctx* ctx, size_t numThreads) +{ + int result; + if (ctx==NULL) return 1; + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + result = POOL_resize_internal(ctx, numThreads); + ZSTD_pthread_cond_broadcast(&ctx->queuePopCond); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + return result; +} + +/** + * Returns 1 if the queue is full and 0 otherwise. + * + * When queueSize is 1 (pool was created with an intended queueSize of 0), + * then a queue is empty if there is a thread free _and_ no job is waiting. + */ +static int isQueueFull(POOL_ctx const* ctx) { + if (ctx->queueSize > 1) { + return ctx->queueHead == ((ctx->queueTail + 1) % ctx->queueSize); + } else { + return (ctx->numThreadsBusy == ctx->threadLimit) || + !ctx->queueEmpty; + } +} + + +static void +POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque) +{ + POOL_job job; + job.function = function; + job.opaque = opaque; + assert(ctx != NULL); + if (ctx->shutdown) return; + + ctx->queueEmpty = 0; + ctx->queue[ctx->queueTail] = job; + ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize; + ZSTD_pthread_cond_signal(&ctx->queuePopCond); +} + +void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) +{ + assert(ctx != NULL); + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + /* Wait until there is space in the queue for the new job */ + while (isQueueFull(ctx) && (!ctx->shutdown)) { + ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex); + } + POOL_add_internal(ctx, function, opaque); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); +} + + +int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) +{ + assert(ctx != NULL); + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + if (isQueueFull(ctx)) { + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + return 0; + } + POOL_add_internal(ctx, function, opaque); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + return 1; +} + +#else /* ZSTD_MULTITHREAD not defined */ + +/* ========================== */ +/* No multi-threading support */ +/* ========================== */ + + +/* We don't need any data, but if it is empty, malloc() might return NULL. */ +struct POOL_ctx_s { + int dummy; +}; +static POOL_ctx g_poolCtx; + +POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { + return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); +} + +POOL_ctx* +POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) +{ + (void)numThreads; + (void)queueSize; + (void)customMem; + return &g_poolCtx; +} + +void POOL_free(POOL_ctx* ctx) { + assert(!ctx || ctx == &g_poolCtx); + (void)ctx; +} + +void POOL_joinJobs(POOL_ctx* ctx){ + assert(!ctx || ctx == &g_poolCtx); + (void)ctx; +} + +int POOL_resize(POOL_ctx* ctx, size_t numThreads) { + (void)ctx; (void)numThreads; + return 0; +} + +void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) { + (void)ctx; + function(opaque); +} + +int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) { + (void)ctx; + function(opaque); + return 1; +} + +size_t POOL_sizeof(const POOL_ctx* ctx) { + if (ctx==NULL) return 0; /* supports sizeof NULL */ + assert(ctx == &g_poolCtx); + return sizeof(*ctx); +} + +#endif /* ZSTD_MULTITHREAD */ + +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/common/threading.cpp b/src/duckdb/third_party/zstd/common/threading.cpp new file mode 100644 index 000000000..5c63f0af0 --- /dev/null +++ b/src/duckdb/third_party/zstd/common/threading.cpp @@ -0,0 +1,193 @@ +/** + * Copyright (c) 2016 Tino Reichardt + * All rights reserved. + * + * You can contact the author at: + * - zstdmt source repository: https://github.com/mcmilk/zstdmt + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/** + * This file will hold wrapper for systems, which do not support pthreads + */ + +#include "zstd/common/threading.h" + +namespace duckdb_zstd { + +/* create fake symbol to avoid empty translation unit warning */ +int g_ZSTD_threading_useless_symbol; + +} // namespace duckdb_zstd + +#if defined(ZSTD_MULTITHREAD) && defined(_WIN32) + +/** + * Windows minimalist Pthread Wrapper + */ + + +/* === Dependencies === */ +#include +#include + +namespace duckdb_zstd { + +/* === Implementation === */ + +typedef struct { + void* (*start_routine)(void*); + void* arg; + int initialized; + ZSTD_pthread_cond_t initialized_cond; + ZSTD_pthread_mutex_t initialized_mutex; +} ZSTD_thread_params_t; + +static unsigned __stdcall worker(void *arg) +{ + void* (*start_routine)(void*); + void* thread_arg; + + /* Initialized thread_arg and start_routine and signal main thread that we don't need it + * to wait any longer. + */ + { + ZSTD_thread_params_t* thread_param = (ZSTD_thread_params_t*)arg; + thread_arg = thread_param->arg; + start_routine = thread_param->start_routine; + + /* Signal main thread that we are running and do not depend on its memory anymore */ + ZSTD_pthread_mutex_lock(&thread_param->initialized_mutex); + thread_param->initialized = 1; + ZSTD_pthread_cond_signal(&thread_param->initialized_cond); + ZSTD_pthread_mutex_unlock(&thread_param->initialized_mutex); + } + + start_routine(thread_arg); + + return 0; +} + +int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, + void* (*start_routine) (void*), void* arg) +{ + ZSTD_thread_params_t thread_param; + (void)unused; + + if (thread==NULL) return -1; + *thread = NULL; + + thread_param.start_routine = start_routine; + thread_param.arg = arg; + thread_param.initialized = 0; + + /* Setup thread initialization synchronization */ + if(ZSTD_pthread_cond_init(&thread_param.initialized_cond, NULL)) { + /* Should never happen on Windows */ + return -1; + } + if(ZSTD_pthread_mutex_init(&thread_param.initialized_mutex, NULL)) { + /* Should never happen on Windows */ + ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); + return -1; + } + + /* Spawn thread */ + *thread = (HANDLE)_beginthreadex(NULL, 0, worker, &thread_param, 0, NULL); + if (*thread==NULL) { + ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex); + ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); + return errno; + } + + /* Wait for thread to be initialized */ + ZSTD_pthread_mutex_lock(&thread_param.initialized_mutex); + while(!thread_param.initialized) { + ZSTD_pthread_cond_wait(&thread_param.initialized_cond, &thread_param.initialized_mutex); + } + ZSTD_pthread_mutex_unlock(&thread_param.initialized_mutex); + ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex); + ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); + + return 0; +} + +int ZSTD_pthread_join(ZSTD_pthread_t thread) +{ + DWORD result; + + if (!thread) return 0; + + result = WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + + switch (result) { + case WAIT_OBJECT_0: + return 0; + case WAIT_ABANDONED: + return EINVAL; + default: + return GetLastError(); + } +} + +} // namespace duckdb_zstd + +#endif /* ZSTD_MULTITHREAD */ + +#if defined(ZSTD_MULTITHREAD) && DEBUGLEVEL >= 1 && !defined(_WIN32) + +#define ZSTD_DEPS_NEED_MALLOC +#include "zstd/common/zstd_deps.h" + +namespace duckdb_zstd { + +int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr) +{ + assert(mutex != NULL); + *mutex = (pthread_mutex_t*)ZSTD_malloc(sizeof(pthread_mutex_t)); + if (!*mutex) + return 1; + return pthread_mutex_init(*mutex, attr); +} + +int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex) +{ + assert(mutex != NULL); + if (!*mutex) + return 0; + { + int const ret = pthread_mutex_destroy(*mutex); + ZSTD_free(*mutex); + return ret; + } +} + +int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr) +{ + assert(cond != NULL); + *cond = (pthread_cond_t*)ZSTD_malloc(sizeof(pthread_cond_t)); + if (!*cond) + return 1; + return pthread_cond_init(*cond, attr); +} + +int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond) +{ + assert(cond != NULL); + if (!*cond) + return 0; + { + int const ret = pthread_cond_destroy(*cond); + ZSTD_free(*cond); + return ret; + } +} + +} // namespace duckdb_zstd + +#endif diff --git a/src/duckdb/third_party/zstd/common/xxhash.cpp b/src/duckdb/third_party/zstd/common/xxhash.cpp index 9ec937522..fc4d18b2e 100644 --- a/src/duckdb/third_party/zstd/common/xxhash.cpp +++ b/src/duckdb/third_party/zstd/common/xxhash.cpp @@ -83,8 +83,8 @@ /* for memcpy() */ #include -#include "zstd/common/xxhash.h" -#include "zstd/common/xxhash_static.h" +#include "zstd/common/xxhash.hpp" +#include "zstd/common/xxhash_static.hpp" /* ************************************* * Compiler Specific Options @@ -103,7 +103,8 @@ # define FORCE_INLINE_ATTR #endif -#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR +// DuckDB: prefixed with XXHASH_ to avoid name conflicts +#define XXHASH_FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR /* ************************************* @@ -169,6 +170,7 @@ static U64 XXH_read64(const void* memPtr) #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ +} // namespace duckdb_zstd /* **************************************** * Compiler-specific Functions and Macros @@ -189,6 +191,8 @@ static U64 XXH_read64(const void* memPtr) # define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r))) #endif +namespace duckdb_zstd { + #if defined(_MSC_VER) /* Visual Studio */ # define XXH_swap32 _byteswap_ulong # define XXH_swap64 _byteswap_uint64 @@ -234,7 +238,7 @@ typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess; *****************************/ typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment; -FORCE_INLINE_TEMPLATE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align) +XXHASH_FORCE_INLINE_TEMPLATE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align) { if (align==XXH_unaligned) return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); @@ -242,7 +246,7 @@ FORCE_INLINE_TEMPLATE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endi return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr); } -FORCE_INLINE_TEMPLATE U32 XXH_readLE32(const void* ptr, XXH_endianess endian) +XXHASH_FORCE_INLINE_TEMPLATE U32 XXH_readLE32(const void* ptr, XXH_endianess endian) { return XXH_readLE32_align(ptr, endian, XXH_unaligned); } @@ -252,7 +256,7 @@ static U32 XXH_readBE32(const void* ptr) return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); } -FORCE_INLINE_TEMPLATE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align) +XXHASH_FORCE_INLINE_TEMPLATE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align) { if (align==XXH_unaligned) return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); @@ -260,7 +264,7 @@ FORCE_INLINE_TEMPLATE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endi return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr); } -FORCE_INLINE_TEMPLATE U64 XXH_readLE64(const void* ptr, XXH_endianess endian) +XXHASH_FORCE_INLINE_TEMPLATE U64 XXH_readLE64(const void* ptr, XXH_endianess endian) { return XXH_readLE64_align(ptr, endian, XXH_unaligned); } @@ -321,7 +325,7 @@ static U32 XXH32_round(U32 seed, U32 input) return seed; } -FORCE_INLINE_TEMPLATE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align) +XXHASH_FORCE_INLINE_TEMPLATE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align) { const BYTE* p = (const BYTE*)input; const BYTE* bEnd = p + len; @@ -421,7 +425,7 @@ static U64 XXH64_mergeRound(U64 acc, U64 val) return acc; } -FORCE_INLINE_TEMPLATE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align) +XXHASH_FORCE_INLINE_TEMPLATE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align) { const BYTE* p = (const BYTE*)input; const BYTE* const bEnd = p + len; @@ -570,7 +574,7 @@ XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long } -FORCE_INLINE_TEMPLATE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian) +XXHASH_FORCE_INLINE_TEMPLATE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian) { const BYTE* p = (const BYTE*)input; const BYTE* const bEnd = p + len; @@ -640,7 +644,7 @@ XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* -FORCE_INLINE_TEMPLATE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian) +XXHASH_FORCE_INLINE_TEMPLATE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian) { const BYTE * p = (const BYTE*)state->mem32; const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize; @@ -690,7 +694,7 @@ XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in) /* **** XXH64 **** */ -FORCE_INLINE_TEMPLATE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian) +XXHASH_FORCE_INLINE_TEMPLATE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian) { const BYTE* p = (const BYTE*)input; const BYTE* const bEnd = p + len; @@ -759,7 +763,7 @@ XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* -FORCE_INLINE_TEMPLATE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian) +XXHASH_FORCE_INLINE_TEMPLATE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian) { const BYTE * p = (const BYTE*)state->mem64; const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize; @@ -856,4 +860,4 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src return XXH_readBE64(src); } -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/common/zstd_common.cpp b/src/duckdb/third_party/zstd/common/zstd_common.cpp index d7700be3b..e36727c0a 100644 --- a/src/duckdb/third_party/zstd/common/zstd_common.cpp +++ b/src/duckdb/third_party/zstd/common/zstd_common.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -13,8 +13,7 @@ /*-************************************* * Dependencies ***************************************/ -#include /* malloc, calloc, free */ -#include /* memset */ +#define ZSTD_DEPS_NEED_MALLOC #include "zstd/common/error_private.h" #include "zstd/common/zstd_internal.h" @@ -49,38 +48,4 @@ ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); } * provides error code string from enum */ const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); } - - -/*=************************************************************** -* Custom allocator -****************************************************************/ -void* ZSTD_malloc(size_t size, ZSTD_customMem customMem) -{ - if (customMem.customAlloc) - return customMem.customAlloc(customMem.opaque, size); - return malloc(size); -} - -void* ZSTD_calloc(size_t size, ZSTD_customMem customMem) -{ - if (customMem.customAlloc) { - /* calloc implemented as malloc+memset; - * not as efficient as calloc, but next best guess for custom malloc */ - void* const ptr = customMem.customAlloc(customMem.opaque, size); - memset(ptr, 0, size); - return ptr; - } - return calloc(1, size); -} - -void ZSTD_free(void* ptr, ZSTD_customMem customMem) -{ - if (ptr!=NULL) { - if (customMem.customFree) - customMem.customFree(customMem.opaque, ptr); - else - free(ptr); - } -} - -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/compress/fse_compress.cpp b/src/duckdb/third_party/zstd/compress/fse_compress.cpp index 378e2925c..495377f9f 100644 --- a/src/duckdb/third_party/zstd/compress/fse_compress.cpp +++ b/src/duckdb/third_party/zstd/compress/fse_compress.cpp @@ -1,6 +1,6 @@ /* ****************************************************************** * FSE : Finite State Entropy encoder - * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * You can contact the author at : * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -15,22 +15,25 @@ /* ************************************************************** * Includes ****************************************************************/ -#include /* malloc, free, qsort */ -#include /* memcpy, memset */ #include "zstd/common/compiler.h" #include "zstd/common/mem.h" /* U32, U16, etc. */ #include "zstd/common/debug.h" /* assert, DEBUGLOG */ #include "zstd/compress/hist.h" /* HIST_count_wksp */ #include "zstd/common/bitstream.h" +#define FSE_STATIC_LINKING_ONLY #include "zstd/common/fse.h" -#include "zstd/common/fse_static.h" #include "zstd/common/error_private.h" +#define ZSTD_DEPS_NEED_MALLOC +#define ZSTD_DEPS_NEED_MATH64 +#include "zstd/common/zstd_deps.h" /* ZSTD_memset */ +#include "zstd/common/bits.h" /* ZSTD_highbit32 */ +namespace duckdb_zstd { /* ************************************************************** * Error Management ****************************************************************/ -// #define FSE_isError ERR_isError +#define FSE_isError ERR_isError /* ************************************************************** @@ -55,7 +58,6 @@ #define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y) #define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y) -namespace duckdb_zstd { /* Function templates */ @@ -75,41 +77,85 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableLog ? tableSize>>1 : 1) ; FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT); U32 const step = FSE_TABLESTEP(tableSize); - U32 cumul[FSE_MAX_SYMBOL_VALUE+2]; + U32 const maxSV1 = maxSymbolValue+1; + + U16* cumul = (U16*)workSpace; /* size = maxSV1 */ + FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)(cumul + (maxSV1+1)); /* size = tableSize */ - FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)workSpace; U32 highThreshold = tableSize-1; + assert(((size_t)workSpace & 1) == 0); /* Must be 2 bytes-aligned */ + if (FSE_BUILD_CTABLE_WORKSPACE_SIZE(maxSymbolValue, tableLog) > wkspSize) return ERROR(tableLog_tooLarge); /* CTable header */ - if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge); tableU16[-2] = (U16) tableLog; tableU16[-1] = (U16) maxSymbolValue; assert(tableLog < 16); /* required for threshold strategy to work */ /* For explanations on how to distribute symbol values over the table : - * http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */ + * https://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */ #ifdef __clang_analyzer__ - memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize); /* useless initialization, just to keep scan-build happy */ + ZSTD_memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize); /* useless initialization, just to keep scan-build happy */ #endif /* symbol start positions */ { U32 u; cumul[0] = 0; - for (u=1; u <= maxSymbolValue+1; u++) { + for (u=1; u <= maxSV1; u++) { if (normalizedCounter[u-1]==-1) { /* Low proba symbol */ cumul[u] = cumul[u-1] + 1; tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u-1); } else { - cumul[u] = cumul[u-1] + normalizedCounter[u-1]; + assert(normalizedCounter[u-1] >= 0); + cumul[u] = cumul[u-1] + (U16)normalizedCounter[u-1]; + assert(cumul[u] >= cumul[u-1]); /* no overflow */ } } - cumul[maxSymbolValue+1] = tableSize+1; + cumul[maxSV1] = (U16)(tableSize+1); } /* Spread symbols */ - { U32 position = 0; + if (highThreshold == tableSize - 1) { + /* Case for no low prob count symbols. Lay down 8 bytes at a time + * to reduce branch misses since we are operating on a small block + */ + BYTE* const spread = tableSymbol + tableSize; /* size = tableSize + 8 (may write beyond tableSize) */ + { U64 const add = 0x0101010101010101ull; + size_t pos = 0; + U64 sv = 0; + U32 s; + for (s=0; s=0); + pos += (size_t)n; + } + } + /* Spread symbols across the table. Lack of lowprob symbols means that + * we don't need variable sized inner loop, so we can unroll the loop and + * reduce branch misses. + */ + { size_t position = 0; + size_t s; + size_t const unroll = 2; /* Experimentally determined optimal unroll */ + assert(tableSize % unroll == 0); /* FSE_MIN_TABLELOG is 5 */ + for (s = 0; s < (size_t)tableSize; s += unroll) { + size_t u; + for (u = 0; u < unroll; ++u) { + size_t const uPosition = (position + (u * step)) & tableMask; + tableSymbol[uPosition] = spread[s + u]; + } + position = (position + (unroll * step)) & tableMask; + } + assert(position == 0); /* Must have initialized all positions */ + } + } else { + U32 position = 0; U32 symbol; - for (symbol=0; symbol<=maxSymbolValue; symbol++) { + for (symbol=0; symbol highThreshold) position = (position + step) & tableMask; /* Low proba area */ } } - assert(position==0); /* Must have initialized all positions */ } @@ -142,16 +187,17 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, case -1: case 1: symbolTT[s].deltaNbBits = (tableLog << 16) - (1< 1); + { U32 const maxBitsOut = tableLog - ZSTD_highbit32 ((U32)normalizedCounter[s]-1); + U32 const minStatePlus = (U32)normalizedCounter[s] << maxBitsOut; symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus; - symbolTT[s].deltaFindState = total - normalizedCounter[s]; - total += normalizedCounter[s]; + symbolTT[s].deltaFindState = (int)(total - (unsigned)normalizedCounter[s]); + total += (unsigned)normalizedCounter[s]; } } } } #if 0 /* debug : symbol costs */ @@ -162,31 +208,26 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, symbol, normalizedCounter[symbol], FSE_getMaxNbBits(symbolTT, symbol), (double)FSE_bitCost(symbolTT, tableLog, symbol, 8) / 256); - } - } + } } #endif return 0; } -size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) -{ - FSE_FUNCTION_TYPE tableSymbol[FSE_MAX_TABLESIZE]; /* memset() is not necessary, even if static analyzer complain about it */ - return FSE_buildCTable_wksp(ct, normalizedCounter, maxSymbolValue, tableLog, tableSymbol, sizeof(tableSymbol)); -} - - #ifndef FSE_COMMONDEFS_ONLY - /*-************************************************************** * FSE NCount encoding ****************************************************************/ size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog) { - size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog) >> 3) + 3; + size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog + + 4 /* bitCount initialized at 4 */ + + 2 /* first two symbols may use one additional bit each */) / 8) + + 1 /* round up to whole nb bytes */ + + 2 /* additional two bytes for bitstream flush */; return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */ } @@ -215,7 +256,7 @@ FSE_writeNCount_generic (void* header, size_t headerBufferSize, /* Init */ remaining = tableSize+1; /* +1 for extra accuracy */ threshold = tableSize; - nbBits = tableLog+1; + nbBits = (int)tableLog+1; while ((symbol < alphabetSize) && (remaining>1)) { /* stops at 1 */ if (previousIs0) { @@ -234,7 +275,7 @@ FSE_writeNCount_generic (void* header, size_t headerBufferSize, } while (symbol >= start+3) { start+=3; - bitStream += 3 << bitCount; + bitStream += 3U << bitCount; bitCount += 2; } bitStream += (symbol-start) << bitCount; @@ -254,7 +295,7 @@ FSE_writeNCount_generic (void* header, size_t headerBufferSize, count++; /* +1 for extra accuracy */ if (count>=threshold) count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */ - bitStream += count << bitCount; + bitStream += (U32)count << bitCount; bitCount += nbBits; bitCount -= (count>8); out+= (bitCount+7) /8; - return (out-ostart); + assert(out >= ostart); + return (size_t)(out-ostart); } @@ -303,21 +345,11 @@ size_t FSE_writeNCount (void* buffer, size_t bufferSize, * FSE Compression Code ****************************************************************/ -FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog) -{ - size_t size; - if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX; - size = FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32); - return (FSE_CTable*)malloc(size); -} - -void FSE_freeCTable (FSE_CTable* ct) { free(ct); } - /* provides the minimum logSize to safely represent a distribution */ static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue) { - U32 minBitsSrc = BIT_highbit32((U32)(srcSize)) + 1; - U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2; + U32 minBitsSrc = ZSTD_highbit32((U32)(srcSize)) + 1; + U32 minBitsSymbols = ZSTD_highbit32(maxSymbolValue) + 2; U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols; assert(srcSize > 1); /* Not supported, RLE should be used instead */ return minBits; @@ -325,7 +357,7 @@ static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue) unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus) { - U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus; + U32 maxBitsSrc = ZSTD_highbit32((U32)(srcSize - 1)) - minus; U32 tableLog = maxTableLog; U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue); assert(srcSize > 1); /* Not supported, RLE should be used instead */ @@ -342,11 +374,10 @@ unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxS return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 2); } - /* Secondary normalization method. To be used when primary method fails. */ -static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue) +static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue, short lowProbCount) { short const NOT_YET_ASSIGNED = -2; U32 s; @@ -363,7 +394,7 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, continue; } if (count[s] <= lowThreshold) { - norm[s] = -1; + norm[s] = lowProbCount; distributed++; total -= count[s]; continue; @@ -415,7 +446,7 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, { U64 const vStepLog = 62 - tableLog; U64 const mid = (1ULL << (vStepLog-1)) - 1; - U64 const rStep = ((((U64)1<> scale); @@ -471,7 +502,7 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog, } } if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) { /* corner case, need another normalization method */ - size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue); + size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue, lowProbCount); if (FSE_isError(errorCode)) return errorCode; } else normalizedCounter[largest] += (short)stillToDistribute; @@ -494,40 +525,6 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog, return tableLog; } - -/* fake FSE_CTable, for raw (uncompressed) input */ -size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits) -{ - const unsigned tableSize = 1 << nbBits; - const unsigned tableMask = tableSize - 1; - const unsigned maxSymbolValue = tableMask; - void* const ptr = ct; - U16* const tableU16 = ( (U16*) ptr) + 2; - void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableSize>>1); /* assumption : tableLog >= 1 */ - FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT); - unsigned s; - - /* Sanity checks */ - if (nbBits < 1) return ERROR(GENERIC); /* min size */ - - /* header */ - tableU16[-2] = (U16) nbBits; - tableU16[-1] = (U16) maxSymbolValue; - - /* Build table */ - for (s=0; s not compressible */ - if (maxCount < (srcSize >> 7)) return 0; /* Heuristic : not compressible enough */ - } - - tableLog = FSE_optimalTableLog(tableLog, srcSize, maxSymbolValue); - CHECK_F( FSE_normalizeCount(norm, tableLog, count, srcSize, maxSymbolValue) ); - - /* Write table description header */ - { CHECK_V_F(nc_err, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) ); - op += nc_err; - } - - /* Compress */ - CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, scratchBufferSize) ); - { CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, src, srcSize, CTable) ); - if (cSize == 0) return 0; /* not enough space for compressed data */ - op += cSize; - } - - /* check compressibility */ - if ( (size_t)(op-ostart) >= srcSize-1 ) return 0; - - return op-ostart; -} - -typedef struct { - FSE_CTable CTable_max[FSE_CTABLE_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)]; - BYTE scratchBuffer[1 << FSE_MAX_TABLELOG]; -} fseWkspMax_t; - -size_t FSE_compress2 (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog) -{ - fseWkspMax_t scratchBuffer; - DEBUG_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)); /* compilation failures here means scratchBuffer is not large enough */ - if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); - return FSE_compress_wksp(dst, dstCapacity, src, srcSize, maxSymbolValue, tableLog, &scratchBuffer, sizeof(scratchBuffer)); -} - -size_t FSE_compress (void* dst, size_t dstCapacity, const void* src, size_t srcSize) -{ - return FSE_compress2(dst, dstCapacity, src, srcSize, FSE_MAX_SYMBOL_VALUE, FSE_DEFAULT_TABLELOG); -} - -} - #endif /* FSE_COMMONDEFS_ONLY */ + +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/compress/hist.cpp b/src/duckdb/third_party/zstd/compress/hist.cpp index 0a3d04a00..6b7f82c90 100644 --- a/src/duckdb/third_party/zstd/compress/hist.cpp +++ b/src/duckdb/third_party/zstd/compress/hist.cpp @@ -1,7 +1,7 @@ /* ****************************************************************** * hist : Histogram functions * part of Finite State Entropy project - * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * You can contact the author at : * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -19,7 +19,6 @@ #include "zstd/common/error_private.h" /* ERROR */ #include "zstd/compress/hist.h" - namespace duckdb_zstd { /* --- Error management --- */ @@ -36,7 +35,7 @@ unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, unsigned maxSymbolValue = *maxSymbolValuePtr; unsigned largestCount=0; - memset(count, 0, (maxSymbolValue+1) * sizeof(*count)); + ZSTD_memset(count, 0, (maxSymbolValue+1) * sizeof(*count)); if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; } while (ip= HIST_WKSP_SIZE_U32. + * `workSpace` must be a U32 table of size >= HIST_WKSP_SIZE_U32. * @return : largest histogram frequency, - * or an error code (notably when histogram would be larger than *maxSymbolValuePtr). */ + * or an error code (notably when histogram's alphabet is larger than *maxSymbolValuePtr) */ static size_t HIST_count_parallel_wksp( unsigned* count, unsigned* maxSymbolValuePtr, const void* source, size_t sourceSize, @@ -73,22 +72,21 @@ static size_t HIST_count_parallel_wksp( { const BYTE* ip = (const BYTE*)source; const BYTE* const iend = ip+sourceSize; - unsigned maxSymbolValue = *maxSymbolValuePtr; + size_t const countSize = (*maxSymbolValuePtr + 1) * sizeof(*count); unsigned max=0; U32* const Counting1 = workSpace; U32* const Counting2 = Counting1 + 256; U32* const Counting3 = Counting2 + 256; U32* const Counting4 = Counting3 + 256; - memset(workSpace, 0, 4*256*sizeof(unsigned)); - /* safety checks */ + assert(*maxSymbolValuePtr <= 255); if (!sourceSize) { - memset(count, 0, maxSymbolValue + 1); + ZSTD_memset(count, 0, countSize); *maxSymbolValuePtr = 0; return 0; } - if (!maxSymbolValue) maxSymbolValue = 255; /* 0 == default */ + ZSTD_memset(workSpace, 0, 4*256*sizeof(unsigned)); /* by stripes of 16 bytes */ { U32 cached = MEM_read32(ip); ip += 4; @@ -120,21 +118,18 @@ static size_t HIST_count_parallel_wksp( /* finish last symbols */ while (ipmaxSymbolValue; s--) { - Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s]; - if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall); - } } - { U32 s; - if (maxSymbolValue > 255) maxSymbolValue = 255; - for (s=0; s<=maxSymbolValue; s++) { - count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s]; - if (count[s] > max) max = count[s]; + for (s=0; s<256; s++) { + Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s]; + if (Counting1[s] > max) max = Counting1[s]; } } - while (!count[maxSymbolValue]) maxSymbolValue--; - *maxSymbolValuePtr = maxSymbolValue; + { unsigned maxSymbolValue = 255; + while (!Counting1[maxSymbolValue]) maxSymbolValue--; + if (check && maxSymbolValue > *maxSymbolValuePtr) return ERROR(maxSymbolValue_tooSmall); + *maxSymbolValuePtr = maxSymbolValue; + ZSTD_memmove(count, Counting1, countSize); /* in case count & Counting1 are overlapping */ + } return (size_t)max; } @@ -154,14 +149,6 @@ size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, trustInput, (U32*)workSpace); } -/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */ -size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr, - const void* source, size_t sourceSize) -{ - unsigned tmpCounters[HIST_WKSP_SIZE_U32]; - return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters, sizeof(tmpCounters)); -} - /* HIST_count_wksp() : * Same as HIST_count(), but using an externally provided scratch buffer. * `workSpace` size must be table of >= HIST_WKSP_SIZE_U32 unsigned */ @@ -177,11 +164,21 @@ size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr, return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace, workSpaceSize); } +#ifndef ZSTD_NO_UNUSED_FUNCTIONS +/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */ +size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr, + const void* source, size_t sourceSize) +{ + unsigned tmpCounters[HIST_WKSP_SIZE_U32]; + return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters, sizeof(tmpCounters)); +} + size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize) { unsigned tmpCounters[HIST_WKSP_SIZE_U32]; return HIST_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters, sizeof(tmpCounters)); } +#endif -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/compress/huf_compress.cpp b/src/duckdb/third_party/zstd/compress/huf_compress.cpp index a7fa092e4..c0c783166 100644 --- a/src/duckdb/third_party/zstd/compress/huf_compress.cpp +++ b/src/duckdb/third_party/zstd/compress/huf_compress.cpp @@ -1,6 +1,6 @@ /* ****************************************************************** * Huffman encoder, part of New Generation Entropy library - * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * You can contact the author at : * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -23,45 +23,131 @@ /* ************************************************************** * Includes ****************************************************************/ -#include /* memcpy, memset */ -#include /* printf (debug) */ +#include "zstd/common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset */ #include "zstd/common/compiler.h" #include "zstd/common/bitstream.h" #include "zstd/compress/hist.h" +#define FSE_STATIC_LINKING_ONLY /* FSE_optimalTableLog_internal */ #include "zstd/common/fse.h" /* header compression */ -#include "zstd/common/fse_static.h" #include "zstd/common/huf.h" -#include "zstd/common/huf_static.h" #include "zstd/common/error_private.h" +#include "zstd/common/bits.h" /* ZSTD_highbit32 */ +namespace duckdb_zstd { /* ************************************************************** * Error Management ****************************************************************/ -// #define HUF_isError ERR_isError +#define HUF_isError ERR_isError #define HUF_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */ -namespace duckdb_zstd { /* ************************************************************** -* Utils +* Required declarations +****************************************************************/ +typedef struct nodeElt_s { + U32 count; + U16 parent; + BYTE byte; + BYTE nbBits; +} nodeElt; + + +/* ************************************************************** +* Debug Traces ****************************************************************/ -unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue) + +#if DEBUGLEVEL >= 2 + +static size_t showU32(const U32* arr, size_t size) { - return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1); + size_t u; + for (u=0; u= add) { + assert(add < align); + assert(((size_t)aligned & mask) == 0); + *workspaceSizePtr -= add; + return aligned; + } else { + *workspaceSizePtr = 0; + return NULL; + } +} + + /* HUF_compressWeights() : * Same as FSE_compress(), but dedicated to huff0's weights compression. * The use case needs much less stack memory. * Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX. */ #define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6 -static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize) + +typedef struct { + FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)]; + U32 scratchBuffer[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(HUF_TABLELOG_MAX, MAX_FSE_TABLELOG_FOR_HUFF_HEADER)]; + unsigned count[HUF_TABLELOG_MAX+1]; + S16 norm[HUF_TABLELOG_MAX+1]; +} HUF_CompressWeightsWksp; + +static size_t +HUF_compressWeights(void* dst, size_t dstSize, + const void* weightTable, size_t wtSize, + void* workspace, size_t workspaceSize) { BYTE* const ostart = (BYTE*) dst; BYTE* op = ostart; @@ -69,33 +155,30 @@ static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weight unsigned maxSymbolValue = HUF_TABLELOG_MAX; U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER; + HUF_CompressWeightsWksp* wksp = (HUF_CompressWeightsWksp*)HUF_alignUpWorkspace(workspace, &workspaceSize, ZSTD_ALIGNOF(U32)); - FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)]; - BYTE scratchBuffer[1<count, &maxSymbolValue, weightTable, wtSize); /* never fails */ if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */ if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */ } tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue); - CHECK_F( FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue) ); + CHECK_F( FSE_normalizeCount(wksp->norm, tableLog, wksp->count, wtSize, maxSymbolValue, /* useLowProbCount */ 0) ); /* Write table description header */ - { CHECK_V_F(hSize, FSE_writeNCount(op, (size_t)(oend-op), norm, maxSymbolValue, tableLog) ); + { CHECK_V_F(hSize, FSE_writeNCount(op, (size_t)(oend-op), wksp->norm, maxSymbolValue, tableLog) ); op += hSize; } /* Compress */ - CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, sizeof(scratchBuffer)) ); - { CHECK_V_F(cSize, FSE_compress_usingCTable(op, (size_t)(oend - op), weightTable, wtSize, CTable) ); + CHECK_F( FSE_buildCTable_wksp(wksp->CTable, wksp->norm, maxSymbolValue, tableLog, wksp->scratchBuffer, sizeof(wksp->scratchBuffer)) ); + { CHECK_V_F(cSize, FSE_compress_usingCTable(op, (size_t)(oend - op), weightTable, wtSize, wksp->CTable) ); if (cSize == 0) return 0; /* not enough space for compressed data */ op += cSize; } @@ -103,35 +186,94 @@ static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weight return (size_t)(op-ostart); } +static size_t HUF_getNbBits(HUF_CElt elt) +{ + return elt & 0xFF; +} + +static size_t HUF_getNbBitsFast(HUF_CElt elt) +{ + return elt; +} + +static size_t HUF_getValue(HUF_CElt elt) +{ + return elt & ~(size_t)0xFF; +} + +static size_t HUF_getValueFast(HUF_CElt elt) +{ + return elt; +} + +static void HUF_setNbBits(HUF_CElt* elt, size_t nbBits) +{ + assert(nbBits <= HUF_TABLELOG_ABSOLUTEMAX); + *elt = nbBits; +} + +static void HUF_setValue(HUF_CElt* elt, size_t value) +{ + size_t const nbBits = HUF_getNbBits(*elt); + if (nbBits > 0) { + assert((value >> nbBits) == 0); + *elt |= value << (sizeof(HUF_CElt) * 8 - nbBits); + } +} -struct HUF_CElt_s { - U16 val; - BYTE nbBits; -}; /* typedef'd to HUF_CElt within "zstd/common/huf.h" */ +HUF_CTableHeader HUF_readCTableHeader(HUF_CElt const* ctable) +{ + HUF_CTableHeader header; + ZSTD_memcpy(&header, ctable, sizeof(header)); + return header; +} -/*! HUF_writeCTable() : - `CTable` : Huffman tree to save, using huf representation. - @return : size of saved CTable */ -size_t HUF_writeCTable (void* dst, size_t maxDstSize, - const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog) +static void HUF_writeCTableHeader(HUF_CElt* ctable, U32 tableLog, U32 maxSymbolValue) { + HUF_CTableHeader header; + HUF_STATIC_ASSERT(sizeof(ctable[0]) == sizeof(header)); + ZSTD_memset(&header, 0, sizeof(header)); + assert(tableLog < 256); + header.tableLog = (BYTE)tableLog; + assert(maxSymbolValue < 256); + header.maxSymbolValue = (BYTE)maxSymbolValue; + ZSTD_memcpy(ctable, &header, sizeof(header)); +} + +typedef struct { + HUF_CompressWeightsWksp wksp; BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */ BYTE huffWeight[HUF_SYMBOLVALUE_MAX]; +} HUF_WriteCTableWksp; + +size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, + const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, + void* workspace, size_t workspaceSize) +{ + HUF_CElt const* const ct = CTable + 1; BYTE* op = (BYTE*)dst; U32 n; + HUF_WriteCTableWksp* wksp = (HUF_WriteCTableWksp*)HUF_alignUpWorkspace(workspace, &workspaceSize, ZSTD_ALIGNOF(U32)); - /* check conditions */ + HUF_STATIC_ASSERT(HUF_CTABLE_WORKSPACE_SIZE >= sizeof(HUF_WriteCTableWksp)); + + assert(HUF_readCTableHeader(CTable).maxSymbolValue == maxSymbolValue); + assert(HUF_readCTableHeader(CTable).tableLog == huffLog); + + /* check conditions */ + if (workspaceSize < sizeof(HUF_WriteCTableWksp)) return ERROR(GENERIC); if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge); /* convert to weight */ - bitsToWeight[0] = 0; + wksp->bitsToWeight[0] = 0; for (n=1; nbitsToWeight[n] = (BYTE)(huffLog + 1 - n); for (n=0; nhuffWeight[n] = wksp->bitsToWeight[HUF_getNbBits(ct[n])]; /* attempt weights compression by FSE */ - { CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, huffWeight, maxSymbolValue) ); + if (maxDstSize < 1) return ERROR(dstSize_tooSmall); + { CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, wksp->huffWeight, maxSymbolValue, &wksp->wksp, sizeof(wksp->wksp)) ); if ((hSize>1) & (hSize < maxSymbolValue/2)) { /* FSE compressed */ op[0] = (BYTE)hSize; return hSize+1; @@ -141,9 +283,9 @@ size_t HUF_writeCTable (void* dst, size_t maxDstSize, if (maxSymbolValue > (256-128)) return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */ if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */ op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1)); - huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */ + wksp->huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */ for (n=0; nhuffWeight[n] << 4) + wksp->huffWeight[n+1]); return ((maxSymbolValue+1)/2) + 1; } @@ -154,34 +296,38 @@ size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; /* large enough for values from 0 to 16 */ U32 tableLog = 0; U32 nbSymbols = 0; + HUF_CElt* const ct = CTable + 1; /* get symbol weights */ CHECK_V_F(readSize, HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX+1, rankVal, &nbSymbols, &tableLog, src, srcSize)); + *hasZeroWeights = (rankVal[0] > 0); /* check result */ if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge); if (nbSymbols > *maxSymbolValuePtr+1) return ERROR(maxSymbolValue_tooSmall); + *maxSymbolValuePtr = nbSymbols - 1; + + HUF_writeCTableHeader(CTable, tableLog, *maxSymbolValuePtr); + /* Prepare base value per rank */ { U32 n, nextRankStart = 0; for (n=1; n<=tableLog; n++) { - U32 current = nextRankStart; + U32 curr = nextRankStart; nextRankStart += (rankVal[n] << (n-1)); - rankVal[n] = current; + rankVal[n] = curr; } } /* fill nbBits */ - *hasZeroWeights = 0; { U32 n; for (n=0; nn=tableLog+1 */ U16 valPerRank[HUF_TABLELOG_MAX+2] = {0}; - { U32 n; for (n=0; n>= 1; } } /* assign value within rank, symbol order */ - { U32 n; for (n=0; n HUF_readCTableHeader(CTable).maxSymbolValue) + return 0; + return (U32)HUF_getNbBits(ct[symbolValue]); } -typedef struct nodeElt_s { - U32 count; - U16 parent; - BYTE byte; - BYTE nbBits; -} nodeElt; - -static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) +/** + * HUF_setMaxHeight(): + * Try to enforce @targetNbBits on the Huffman tree described in @huffNode. + * + * It attempts to convert all nodes with nbBits > @targetNbBits + * to employ @targetNbBits instead. Then it adjusts the tree + * so that it remains a valid canonical Huffman tree. + * + * @pre The sum of the ranks of each symbol == 2^largestBits, + * where largestBits == huffNode[lastNonNull].nbBits. + * @post The sum of the ranks of each symbol == 2^largestBits, + * where largestBits is the return value (expected <= targetNbBits). + * + * @param huffNode The Huffman tree modified in place to enforce targetNbBits. + * It's presumed sorted, from most frequent to rarest symbol. + * @param lastNonNull The symbol with the lowest count in the Huffman tree. + * @param targetNbBits The allowed number of bits, which the Huffman tree + * may not respect. After this function the Huffman tree will + * respect targetNbBits. + * @return The maximum number of bits of the Huffman tree after adjustment. + */ +static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 targetNbBits) { const U32 largestBits = huffNode[lastNonNull].nbBits; - if (largestBits <= maxNbBits) return largestBits; /* early exit : no elt > maxNbBits */ + /* early exit : no elt > targetNbBits, so the tree is already valid. */ + if (largestBits <= targetNbBits) return largestBits; + + DEBUGLOG(5, "HUF_setMaxHeight (targetNbBits = %u)", targetNbBits); /* there are several too large elements (at least >= 2) */ { int totalCost = 0; - const U32 baseCost = 1 << (largestBits - maxNbBits); + const U32 baseCost = 1 << (largestBits - targetNbBits); int n = (int)lastNonNull; - while (huffNode[n].nbBits > maxNbBits) { + /* Adjust any ranks > targetNbBits to targetNbBits. + * Compute totalCost, which is how far the sum of the ranks is + * we are over 2^largestBits after adjust the offending ranks. + */ + while (huffNode[n].nbBits > targetNbBits) { totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits)); - huffNode[n].nbBits = (BYTE)maxNbBits; - n --; - } /* n stops at huffNode[n].nbBits <= maxNbBits */ - while (huffNode[n].nbBits == maxNbBits) n--; /* n end at index of smallest symbol using < maxNbBits */ + huffNode[n].nbBits = (BYTE)targetNbBits; + n--; + } + /* n stops at huffNode[n].nbBits <= targetNbBits */ + assert(huffNode[n].nbBits <= targetNbBits); + /* n end at index of smallest symbol using < targetNbBits */ + while (huffNode[n].nbBits == targetNbBits) --n; - /* renorm totalCost */ - totalCost >>= (largestBits - maxNbBits); /* note : totalCost is necessarily a multiple of baseCost */ + /* renorm totalCost from 2^largestBits to 2^targetNbBits + * note : totalCost is necessarily a multiple of baseCost */ + assert(((U32)totalCost & (baseCost - 1)) == 0); + totalCost >>= (largestBits - targetNbBits); + assert(totalCost > 0); /* repay normalized cost */ { U32 const noSymbol = 0xF0F0F0F0; U32 rankLast[HUF_TABLELOG_MAX+2]; - /* Get pos of last (smallest) symbol per rank */ - memset(rankLast, 0xF0, sizeof(rankLast)); - { U32 currentNbBits = maxNbBits; + /* Get pos of last (smallest = lowest cum. count) symbol per rank */ + ZSTD_memset(rankLast, 0xF0, sizeof(rankLast)); + { U32 currentNbBits = targetNbBits; int pos; for (pos=n ; pos >= 0; pos--) { if (huffNode[pos].nbBits >= currentNbBits) continue; - currentNbBits = huffNode[pos].nbBits; /* < maxNbBits */ - rankLast[maxNbBits-currentNbBits] = (U32)pos; + currentNbBits = huffNode[pos].nbBits; /* < targetNbBits */ + rankLast[targetNbBits-currentNbBits] = (U32)pos; } } while (totalCost > 0) { - U32 nBitsToDecrease = BIT_highbit32((U32)totalCost) + 1; + /* Try to reduce the next power of 2 above totalCost because we + * gain back half the rank. + */ + U32 nBitsToDecrease = ZSTD_highbit32((U32)totalCost) + 1; for ( ; nBitsToDecrease > 1; nBitsToDecrease--) { U32 const highPos = rankLast[nBitsToDecrease]; U32 const lowPos = rankLast[nBitsToDecrease-1]; if (highPos == noSymbol) continue; + /* Decrease highPos if no symbols of lowPos or if it is + * not cheaper to remove 2 lowPos than highPos. + */ if (lowPos == noSymbol) break; { U32 const highTotal = huffNode[highPos].count; U32 const lowTotal = 2 * huffNode[lowPos].count; if (highTotal <= lowTotal) break; } } /* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */ + assert(rankLast[nBitsToDecrease] != noSymbol || nBitsToDecrease == 1); /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */ while ((nBitsToDecrease<=HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol)) - nBitsToDecrease ++; + nBitsToDecrease++; + assert(rankLast[nBitsToDecrease] != noSymbol); + /* Increase the number of bits to gain back half the rank cost. */ totalCost -= 1 << (nBitsToDecrease-1); + huffNode[rankLast[nBitsToDecrease]].nbBits++; + + /* Fix up the new rank. + * If the new rank was empty, this symbol is now its smallest. + * Otherwise, this symbol will be the largest in the new rank so no adjustment. + */ if (rankLast[nBitsToDecrease-1] == noSymbol) - rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]; /* this rank is no longer empty */ - huffNode[rankLast[nBitsToDecrease]].nbBits ++; + rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]; + /* Fix up the old rank. + * If the symbol was at position 0, meaning it was the highest weight symbol in the tree, + * it must be the only symbol in its rank, so the old rank now has no symbols. + * Otherwise, since the Huffman nodes are sorted by count, the previous position is now + * the smallest node in the rank. If the previous position belongs to a different rank, + * then the rank is now empty. + */ if (rankLast[nBitsToDecrease] == 0) /* special case, reached largest symbol */ rankLast[nBitsToDecrease] = noSymbol; else { rankLast[nBitsToDecrease]--; - if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease) + if (huffNode[rankLast[nBitsToDecrease]].nbBits != targetNbBits-nBitsToDecrease) rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */ - } } /* while (totalCost > 0) */ - + } + } /* while (totalCost > 0) */ + + /* If we've removed too much weight, then we have to add it back. + * To avoid overshooting again, we only adjust the smallest rank. + * We take the largest nodes from the lowest rank 0 and move them + * to rank 1. There's guaranteed to be enough rank 0 symbols because + * TODO. + */ while (totalCost < 0) { /* Sometimes, cost correction overshoot */ - if (rankLast[1] == noSymbol) { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */ - while (huffNode[n].nbBits == maxNbBits) n--; + /* special case : no rank 1 symbol (using targetNbBits-1); + * let's create one from largest rank 0 (using targetNbBits). + */ + if (rankLast[1] == noSymbol) { + while (huffNode[n].nbBits == targetNbBits) n--; huffNode[n+1].nbBits--; assert(n >= 0); rankLast[1] = (U32)(n+1); @@ -286,47 +491,178 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) huffNode[ rankLast[1] + 1 ].nbBits--; rankLast[1]++; totalCost ++; - } } } /* there are several too large elements (at least >= 2) */ + } + } /* repay normalized cost */ + } /* there are several too large elements (at least >= 2) */ - return maxNbBits; + return targetNbBits; } typedef struct { - U32 base; - U32 current; + U16 base; + U16 curr; } rankPos; -typedef nodeElt huffNodeTable[HUF_CTABLE_WORKSPACE_SIZE_U32]; +typedef nodeElt huffNodeTable[2 * (HUF_SYMBOLVALUE_MAX + 1)]; -#define RANK_POSITION_TABLE_SIZE 32 +/* Number of buckets available for HUF_sort() */ +#define RANK_POSITION_TABLE_SIZE 192 typedef struct { huffNodeTable huffNodeTbl; rankPos rankPosition[RANK_POSITION_TABLE_SIZE]; } HUF_buildCTable_wksp_tables; -static void HUF_sort(nodeElt* huffNode, const unsigned* count, U32 maxSymbolValue, rankPos* rankPosition) -{ +/* RANK_POSITION_DISTINCT_COUNT_CUTOFF == Cutoff point in HUF_sort() buckets for which we use log2 bucketing. + * Strategy is to use as many buckets as possible for representing distinct + * counts while using the remainder to represent all "large" counts. + * + * To satisfy this requirement for 192 buckets, we can do the following: + * Let buckets 0-166 represent distinct counts of [0, 166] + * Let buckets 166 to 192 represent all remaining counts up to RANK_POSITION_MAX_COUNT_LOG using log2 bucketing. + */ +#define RANK_POSITION_MAX_COUNT_LOG 32 +#define RANK_POSITION_LOG_BUCKETS_BEGIN ((RANK_POSITION_TABLE_SIZE - 1) - RANK_POSITION_MAX_COUNT_LOG - 1 /* == 158 */) +#define RANK_POSITION_DISTINCT_COUNT_CUTOFF (RANK_POSITION_LOG_BUCKETS_BEGIN + ZSTD_highbit32(RANK_POSITION_LOG_BUCKETS_BEGIN) /* == 166 */) + +/* Return the appropriate bucket index for a given count. See definition of + * RANK_POSITION_DISTINCT_COUNT_CUTOFF for explanation of bucketing strategy. + */ +static U32 HUF_getIndex(U32 const count) { + return (count < RANK_POSITION_DISTINCT_COUNT_CUTOFF) + ? count + : ZSTD_highbit32(count) + RANK_POSITION_LOG_BUCKETS_BEGIN; +} + +/* Helper swap function for HUF_quickSortPartition() */ +static void HUF_swapNodes(nodeElt* a, nodeElt* b) { + nodeElt tmp = *a; + *a = *b; + *b = tmp; +} + +/* Returns 0 if the huffNode array is not sorted by descending count */ +MEM_STATIC int HUF_isSorted(nodeElt huffNode[], U32 const maxSymbolValue1) { + U32 i; + for (i = 1; i < maxSymbolValue1; ++i) { + if (huffNode[i].count > huffNode[i-1].count) { + return 0; + } + } + return 1; +} + +/* Insertion sort by descending order */ +HINT_INLINE void HUF_insertionSort(nodeElt huffNode[], int const low, int const high) { + int i; + int const size = high-low+1; + huffNode += low; + for (i = 1; i < size; ++i) { + nodeElt const key = huffNode[i]; + int j = i - 1; + while (j >= 0 && huffNode[j].count < key.count) { + huffNode[j + 1] = huffNode[j]; + j--; + } + huffNode[j + 1] = key; + } +} + +/* Pivot helper function for quicksort. */ +static int HUF_quickSortPartition(nodeElt arr[], int const low, int const high) { + /* Simply select rightmost element as pivot. "Better" selectors like + * median-of-three don't experimentally appear to have any benefit. + */ + U32 const pivot = arr[high].count; + int i = low - 1; + int j = low; + for ( ; j < high; j++) { + if (arr[j].count > pivot) { + i++; + HUF_swapNodes(&arr[i], &arr[j]); + } + } + HUF_swapNodes(&arr[i + 1], &arr[high]); + return i + 1; +} + +/* Classic quicksort by descending with partially iterative calls + * to reduce worst case callstack size. + */ +static void HUF_simpleQuickSort(nodeElt arr[], int low, int high) { + int const kInsertionSortThreshold = 8; + if (high - low < kInsertionSortThreshold) { + HUF_insertionSort(arr, low, high); + return; + } + while (low < high) { + int const idx = HUF_quickSortPartition(arr, low, high); + if (idx - low < high - idx) { + HUF_simpleQuickSort(arr, low, idx - 1); + low = idx + 1; + } else { + HUF_simpleQuickSort(arr, idx + 1, high); + high = idx - 1; + } + } +} + +/** + * HUF_sort(): + * Sorts the symbols [0, maxSymbolValue] by count[symbol] in decreasing order. + * This is a typical bucket sorting strategy that uses either quicksort or insertion sort to sort each bucket. + * + * @param[out] huffNode Sorted symbols by decreasing count. Only members `.count` and `.byte` are filled. + * Must have (maxSymbolValue + 1) entries. + * @param[in] count Histogram of the symbols. + * @param[in] maxSymbolValue Maximum symbol value. + * @param rankPosition This is a scratch workspace. Must have RANK_POSITION_TABLE_SIZE entries. + */ +static void HUF_sort(nodeElt huffNode[], const unsigned count[], U32 const maxSymbolValue, rankPos rankPosition[]) { U32 n; + U32 const maxSymbolValue1 = maxSymbolValue+1; + + /* Compute base and set curr to base. + * For symbol s let lowerRank = HUF_getIndex(count[n]) and rank = lowerRank + 1. + * See HUF_getIndex to see bucketing strategy. + * We attribute each symbol to lowerRank's base value, because we want to know where + * each rank begins in the output, so for rank R we want to count ranks R+1 and above. + */ + ZSTD_memset(rankPosition, 0, sizeof(*rankPosition) * RANK_POSITION_TABLE_SIZE); + for (n = 0; n < maxSymbolValue1; ++n) { + U32 lowerRank = HUF_getIndex(count[n]); + assert(lowerRank < RANK_POSITION_TABLE_SIZE - 1); + rankPosition[lowerRank].base++; + } - memset(rankPosition, 0, sizeof(*rankPosition) * RANK_POSITION_TABLE_SIZE); - for (n=0; n<=maxSymbolValue; n++) { - U32 r = BIT_highbit32(count[n] + 1); - rankPosition[r].base ++; + assert(rankPosition[RANK_POSITION_TABLE_SIZE - 1].base == 0); + /* Set up the rankPosition table */ + for (n = RANK_POSITION_TABLE_SIZE - 1; n > 0; --n) { + rankPosition[n-1].base += rankPosition[n].base; + rankPosition[n-1].curr = rankPosition[n-1].base; } - for (n=30; n>0; n--) rankPosition[n-1].base += rankPosition[n].base; - for (n=0; n<32; n++) rankPosition[n].current = rankPosition[n].base; - for (n=0; n<=maxSymbolValue; n++) { + + /* Insert each symbol into their appropriate bucket, setting up rankPosition table. */ + for (n = 0; n < maxSymbolValue1; ++n) { U32 const c = count[n]; - U32 const r = BIT_highbit32(c+1) + 1; - U32 pos = rankPosition[r].current++; - while ((pos > rankPosition[r].base) && (c > huffNode[pos-1].count)) { - huffNode[pos] = huffNode[pos-1]; - pos--; - } + U32 const r = HUF_getIndex(c) + 1; + U32 const pos = rankPosition[r].curr++; + assert(pos < maxSymbolValue1); huffNode[pos].count = c; huffNode[pos].byte = (BYTE)n; } + + /* Sort each bucket. */ + for (n = RANK_POSITION_DISTINCT_COUNT_CUTOFF; n < RANK_POSITION_TABLE_SIZE - 1; ++n) { + int const bucketSize = rankPosition[n].curr - rankPosition[n].base; + U32 const bucketStartIdx = rankPosition[n].base; + if (bucketSize > 1) { + assert(bucketStartIdx < maxSymbolValue1); + HUF_simpleQuickSort(huffNode + bucketStartIdx, 0, bucketSize-1); + } + } + + assert(HUF_isSorted(huffNode, maxSymbolValue1)); } @@ -336,28 +672,21 @@ static void HUF_sort(nodeElt* huffNode, const unsigned* count, U32 maxSymbolValu */ #define STARTNODE (HUF_SYMBOLVALUE_MAX+1) -size_t HUF_buildCTable_wksp (HUF_CElt* tree, const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize) +/* HUF_buildTree(): + * Takes the huffNode array sorted by HUF_sort() and builds an unlimited-depth Huffman tree. + * + * @param huffNode The array sorted by HUF_sort(). Builds the Huffman tree in this array. + * @param maxSymbolValue The maximum symbol value. + * @return The smallest node in the Huffman tree (by count). + */ +static int HUF_buildTree(nodeElt* huffNode, U32 maxSymbolValue) { - HUF_buildCTable_wksp_tables* const wksp_tables = (HUF_buildCTable_wksp_tables*)workSpace; - nodeElt* const huffNode0 = wksp_tables->huffNodeTbl; - nodeElt* const huffNode = huffNode0+1; + nodeElt* const huffNode0 = huffNode - 1; int nonNullRank; int lowS, lowN; int nodeNb = STARTNODE; int n, nodeRoot; - - /* safety checks */ - if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */ - if (wkspSize < sizeof(HUF_buildCTable_wksp_tables)) - return ERROR(workSpace_tooSmall); - if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT; - if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) - return ERROR(maxSymbolValue_tooLarge); - memset(huffNode0, 0, sizeof(huffNodeTable)); - - /* sort, decreasing order */ - HUF_sort(huffNode, count, maxSymbolValue, wksp_tables->rankPosition); - + DEBUGLOG(5, "HUF_buildTree (alphabet size = %u)", maxSymbolValue + 1); /* init for parents */ nonNullRank = (int)maxSymbolValue; while(huffNode[nonNullRank].count == 0) nonNullRank--; @@ -384,127 +713,414 @@ size_t HUF_buildCTable_wksp (HUF_CElt* tree, const unsigned* count, U32 maxSymbo for (n=0; n<=nonNullRank; n++) huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1; - /* enforce maxTableLog */ - maxNbBits = HUF_setMaxHeight(huffNode, (U32)nonNullRank, maxNbBits); + DEBUGLOG(6, "Initial distribution of bits completed (%zu sorted symbols)", showHNodeBits(huffNode, maxSymbolValue+1)); - /* fill result into tree (val, nbBits) */ - { U16 nbPerRank[HUF_TABLELOG_MAX+1] = {0}; - U16 valPerRank[HUF_TABLELOG_MAX+1] = {0}; - int const alphabetSize = (int)(maxSymbolValue + 1); - if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */ - for (n=0; n<=nonNullRank; n++) - nbPerRank[huffNode[n].nbBits]++; - /* determine stating value per rank */ - { U16 min = 0; - for (n=(int)maxNbBits; n>0; n--) { - valPerRank[n] = min; /* get starting value within each rank */ - min += nbPerRank[n]; - min >>= 1; - } } - for (n=0; n0; n--) { + valPerRank[n] = min; /* get starting value within each rank */ + min += nbPerRank[n]; + min >>= 1; + } } + for (n=0; nhuffNodeTbl; + nodeElt* const huffNode = huffNode0+1; + int nonNullRank; + + HUF_STATIC_ASSERT(HUF_CTABLE_WORKSPACE_SIZE == sizeof(HUF_buildCTable_wksp_tables)); + + DEBUGLOG(5, "HUF_buildCTable_wksp (alphabet size = %u)", maxSymbolValue+1); + + /* safety checks */ + if (wkspSize < sizeof(HUF_buildCTable_wksp_tables)) + return ERROR(workSpace_tooSmall); + if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT; + if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) + return ERROR(maxSymbolValue_tooLarge); + ZSTD_memset(huffNode0, 0, sizeof(huffNodeTable)); + + /* sort, decreasing order */ + HUF_sort(huffNode, count, maxSymbolValue, wksp_tables->rankPosition); + DEBUGLOG(6, "sorted symbols completed (%zu symbols)", showHNodeSymbols(huffNode, maxSymbolValue+1)); + + /* build tree */ + nonNullRank = HUF_buildTree(huffNode, maxSymbolValue); + + /* determine and enforce maxTableLog */ + maxNbBits = HUF_setMaxHeight(huffNode, (U32)nonNullRank, maxNbBits); + if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */ + + HUF_buildCTableFromTree(CTable, huffNode, nonNullRank, maxSymbolValue, maxNbBits); + + return maxNbBits; } size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) { + HUF_CElt const* ct = CTable + 1; size_t nbBits = 0; int s; for (s = 0; s <= (int)maxSymbolValue; ++s) { - nbBits += CTable[s].nbBits * count[s]; + nbBits += HUF_getNbBits(ct[s]) * count[s]; } return nbBits >> 3; } int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) { - int bad = 0; - int s; - for (s = 0; s <= (int)maxSymbolValue; ++s) { - bad |= (count[s] != 0) & (CTable[s].nbBits == 0); - } - return !bad; + HUF_CTableHeader header = HUF_readCTableHeader(CTable); + HUF_CElt const* ct = CTable + 1; + int bad = 0; + int s; + + assert(header.tableLog <= HUF_TABLELOG_ABSOLUTEMAX); + + if (header.maxSymbolValue < maxSymbolValue) + return 0; + + for (s = 0; s <= (int)maxSymbolValue; ++s) { + bad |= (count[s] != 0) & (HUF_getNbBits(ct[s]) == 0); + } + return !bad; } size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); } +/** HUF_CStream_t: + * Huffman uses its own BIT_CStream_t implementation. + * There are three major differences from BIT_CStream_t: + * 1. HUF_addBits() takes a HUF_CElt (size_t) which is + * the pair (nbBits, value) in the format: + * format: + * - Bits [0, 4) = nbBits + * - Bits [4, 64 - nbBits) = 0 + * - Bits [64 - nbBits, 64) = value + * 2. The bitContainer is built from the upper bits and + * right shifted. E.g. to add a new value of N bits + * you right shift the bitContainer by N, then or in + * the new value into the N upper bits. + * 3. The bitstream has two bit containers. You can add + * bits to the second container and merge them into + * the first container. + */ + +#define HUF_BITS_IN_CONTAINER (sizeof(size_t) * 8) + +typedef struct { + size_t bitContainer[2]; + size_t bitPos[2]; + + BYTE* startPtr; + BYTE* ptr; + BYTE* endPtr; +} HUF_CStream_t; + +/**! HUF_initCStream(): + * Initializes the bitstream. + * @returns 0 or an error code. + */ +static size_t HUF_initCStream(HUF_CStream_t* bitC, + void* startPtr, size_t dstCapacity) +{ + ZSTD_memset(bitC, 0, sizeof(*bitC)); + bitC->startPtr = (BYTE*)startPtr; + bitC->ptr = bitC->startPtr; + bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer[0]); + if (dstCapacity <= sizeof(bitC->bitContainer[0])) return ERROR(dstSize_tooSmall); + return 0; +} + +/*! HUF_addBits(): + * Adds the symbol stored in HUF_CElt elt to the bitstream. + * + * @param elt The element we're adding. This is a (nbBits, value) pair. + * See the HUF_CStream_t docs for the format. + * @param idx Insert into the bitstream at this idx. + * @param kFast This is a template parameter. If the bitstream is guaranteed + * to have at least 4 unused bits after this call it may be 1, + * otherwise it must be 0. HUF_addBits() is faster when fast is set. + */ +FORCE_INLINE_TEMPLATE void HUF_addBits(HUF_CStream_t* bitC, HUF_CElt elt, int idx, int kFast) +{ + assert(idx <= 1); + assert(HUF_getNbBits(elt) <= HUF_TABLELOG_ABSOLUTEMAX); + /* This is efficient on x86-64 with BMI2 because shrx + * only reads the low 6 bits of the register. The compiler + * knows this and elides the mask. When fast is set, + * every operation can use the same value loaded from elt. + */ + bitC->bitContainer[idx] >>= HUF_getNbBits(elt); + bitC->bitContainer[idx] |= kFast ? HUF_getValueFast(elt) : HUF_getValue(elt); + /* We only read the low 8 bits of bitC->bitPos[idx] so it + * doesn't matter that the high bits have noise from the value. + */ + bitC->bitPos[idx] += HUF_getNbBitsFast(elt); + assert((bitC->bitPos[idx] & 0xFF) <= HUF_BITS_IN_CONTAINER); + /* The last 4-bits of elt are dirty if fast is set, + * so we must not be overwriting bits that have already been + * inserted into the bit container. + */ +#if DEBUGLEVEL >= 1 + { + size_t const nbBits = HUF_getNbBits(elt); + size_t const dirtyBits = nbBits == 0 ? 0 : ZSTD_highbit32((U32)nbBits) + 1; + (void)dirtyBits; + /* Middle bits are 0. */ + assert(((elt >> dirtyBits) << (dirtyBits + nbBits)) == 0); + /* We didn't overwrite any bits in the bit container. */ + assert(!kFast || (bitC->bitPos[idx] & 0xFF) <= HUF_BITS_IN_CONTAINER); + (void)dirtyBits; + } +#endif +} + +FORCE_INLINE_TEMPLATE void HUF_zeroIndex1(HUF_CStream_t* bitC) +{ + bitC->bitContainer[1] = 0; + bitC->bitPos[1] = 0; +} + +/*! HUF_mergeIndex1() : + * Merges the bit container @ index 1 into the bit container @ index 0 + * and zeros the bit container @ index 1. + */ +FORCE_INLINE_TEMPLATE void HUF_mergeIndex1(HUF_CStream_t* bitC) +{ + assert((bitC->bitPos[1] & 0xFF) < HUF_BITS_IN_CONTAINER); + bitC->bitContainer[0] >>= (bitC->bitPos[1] & 0xFF); + bitC->bitContainer[0] |= bitC->bitContainer[1]; + bitC->bitPos[0] += bitC->bitPos[1]; + assert((bitC->bitPos[0] & 0xFF) <= HUF_BITS_IN_CONTAINER); +} + +/*! HUF_flushBits() : +* Flushes the bits in the bit container @ index 0. +* +* @post bitPos will be < 8. +* @param kFast If kFast is set then we must know a-priori that +* the bit container will not overflow. +*/ +FORCE_INLINE_TEMPLATE void HUF_flushBits(HUF_CStream_t* bitC, int kFast) +{ + /* The upper bits of bitPos are noisy, so we must mask by 0xFF. */ + size_t const nbBits = bitC->bitPos[0] & 0xFF; + size_t const nbBytes = nbBits >> 3; + /* The top nbBits bits of bitContainer are the ones we need. */ + size_t const bitContainer = bitC->bitContainer[0] >> (HUF_BITS_IN_CONTAINER - nbBits); + /* Mask bitPos to account for the bytes we consumed. */ + bitC->bitPos[0] &= 7; + assert(nbBits > 0); + assert(nbBits <= sizeof(bitC->bitContainer[0]) * 8); + assert(bitC->ptr <= bitC->endPtr); + MEM_writeLEST(bitC->ptr, bitContainer); + bitC->ptr += nbBytes; + assert(!kFast || bitC->ptr <= bitC->endPtr); + if (!kFast && bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr; + /* bitContainer doesn't need to be modified because the leftover + * bits are already the top bitPos bits. And we don't care about + * noise in the lower values. + */ +} + +/*! HUF_endMark() + * @returns The Huffman stream end mark: A 1-bit value = 1. + */ +static HUF_CElt HUF_endMark(void) +{ + HUF_CElt endMark; + HUF_setNbBits(&endMark, 1); + HUF_setValue(&endMark, 1); + return endMark; +} + +/*! HUF_closeCStream() : + * @return Size of CStream, in bytes, + * or 0 if it could not fit into dstBuffer */ +static size_t HUF_closeCStream(HUF_CStream_t* bitC) +{ + HUF_addBits(bitC, HUF_endMark(), /* idx */ 0, /* kFast */ 0); + HUF_flushBits(bitC, /* kFast */ 0); + { + size_t const nbBits = bitC->bitPos[0] & 0xFF; + if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */ + return (size_t)(bitC->ptr - bitC->startPtr) + (nbBits > 0); + } +} + FORCE_INLINE_TEMPLATE void -HUF_encodeSymbol(BIT_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable) +HUF_encodeSymbol(HUF_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable, int idx, int fast) { - BIT_addBitsFast(bitCPtr, CTable[symbol].val, CTable[symbol].nbBits); + HUF_addBits(bitCPtr, CTable[symbol], idx, fast); } -#define HUF_FLUSHBITS(s) BIT_flushBits(s) +FORCE_INLINE_TEMPLATE void +HUF_compress1X_usingCTable_internal_body_loop(HUF_CStream_t* bitC, + const BYTE* ip, size_t srcSize, + const HUF_CElt* ct, + int kUnroll, int kFastFlush, int kLastFast) +{ + /* Join to kUnroll */ + int n = (int)srcSize; + int rem = n % kUnroll; + if (rem > 0) { + for (; rem > 0; --rem) { + HUF_encodeSymbol(bitC, ip[--n], ct, 0, /* fast */ 0); + } + HUF_flushBits(bitC, kFastFlush); + } + assert(n % kUnroll == 0); -#define HUF_FLUSHBITS_1(stream) \ - if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*2+7) HUF_FLUSHBITS(stream) + /* Join to 2 * kUnroll */ + if (n % (2 * kUnroll)) { + int u; + for (u = 1; u < kUnroll; ++u) { + HUF_encodeSymbol(bitC, ip[n - u], ct, 0, 1); + } + HUF_encodeSymbol(bitC, ip[n - kUnroll], ct, 0, kLastFast); + HUF_flushBits(bitC, kFastFlush); + n -= kUnroll; + } + assert(n % (2 * kUnroll) == 0); + + for (; n>0; n-= 2 * kUnroll) { + /* Encode kUnroll symbols into the bitstream @ index 0. */ + int u; + for (u = 1; u < kUnroll; ++u) { + HUF_encodeSymbol(bitC, ip[n - u], ct, /* idx */ 0, /* fast */ 1); + } + HUF_encodeSymbol(bitC, ip[n - kUnroll], ct, /* idx */ 0, /* fast */ kLastFast); + HUF_flushBits(bitC, kFastFlush); + /* Encode kUnroll symbols into the bitstream @ index 1. + * This allows us to start filling the bit container + * without any data dependencies. + */ + HUF_zeroIndex1(bitC); + for (u = 1; u < kUnroll; ++u) { + HUF_encodeSymbol(bitC, ip[n - kUnroll - u], ct, /* idx */ 1, /* fast */ 1); + } + HUF_encodeSymbol(bitC, ip[n - kUnroll - kUnroll], ct, /* idx */ 1, /* fast */ kLastFast); + /* Merge bitstream @ index 1 into the bitstream @ index 0 */ + HUF_mergeIndex1(bitC); + HUF_flushBits(bitC, kFastFlush); + } + assert(n == 0); + +} + +/** + * Returns a tight upper bound on the output space needed by Huffman + * with 8 bytes buffer to handle over-writes. If the output is at least + * this large we don't need to do bounds checks during Huffman encoding. + */ +static size_t HUF_tightCompressBound(size_t srcSize, size_t tableLog) +{ + return ((srcSize * tableLog) >> 3) + 8; +} -#define HUF_FLUSHBITS_2(stream) \ - if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*4+7) HUF_FLUSHBITS(stream) FORCE_INLINE_TEMPLATE size_t HUF_compress1X_usingCTable_internal_body(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) { + U32 const tableLog = HUF_readCTableHeader(CTable).tableLog; + HUF_CElt const* ct = CTable + 1; const BYTE* ip = (const BYTE*) src; BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + dstSize; - BYTE* op = ostart; - size_t n; - BIT_CStream_t bitC; + HUF_CStream_t bitC; /* init */ if (dstSize < 8) return 0; /* not enough space to compress */ - { size_t const initErr = BIT_initCStream(&bitC, op, (size_t)(oend-op)); + { BYTE* op = ostart; + size_t const initErr = HUF_initCStream(&bitC, op, (size_t)(oend-op)); if (HUF_isError(initErr)) return 0; } - n = srcSize & ~3; /* join to mod 4 */ - switch (srcSize & 3) - { - case 3 : HUF_encodeSymbol(&bitC, ip[n+ 2], CTable); - HUF_FLUSHBITS_2(&bitC); - /* fall-through */ - case 2 : HUF_encodeSymbol(&bitC, ip[n+ 1], CTable); - HUF_FLUSHBITS_1(&bitC); - /* fall-through */ - case 1 : HUF_encodeSymbol(&bitC, ip[n+ 0], CTable); - HUF_FLUSHBITS(&bitC); - /* fall-through */ - case 0 : /* fall-through */ - default: break; - } - - for (; n>0; n-=4) { /* note : n&3==0 at this stage */ - HUF_encodeSymbol(&bitC, ip[n- 1], CTable); - HUF_FLUSHBITS_1(&bitC); - HUF_encodeSymbol(&bitC, ip[n- 2], CTable); - HUF_FLUSHBITS_2(&bitC); - HUF_encodeSymbol(&bitC, ip[n- 3], CTable); - HUF_FLUSHBITS_1(&bitC); - HUF_encodeSymbol(&bitC, ip[n- 4], CTable); - HUF_FLUSHBITS(&bitC); + if (dstSize < HUF_tightCompressBound(srcSize, (size_t)tableLog) || tableLog > 11) + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ MEM_32bits() ? 2 : 4, /* kFast */ 0, /* kLastFast */ 0); + else { + if (MEM_32bits()) { + switch (tableLog) { + case 11: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 2, /* kFastFlush */ 1, /* kLastFast */ 0); + break; + case 10: ZSTD_FALLTHROUGH; + case 9: ZSTD_FALLTHROUGH; + case 8: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 2, /* kFastFlush */ 1, /* kLastFast */ 1); + break; + case 7: ZSTD_FALLTHROUGH; + default: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 3, /* kFastFlush */ 1, /* kLastFast */ 1); + break; + } + } else { + switch (tableLog) { + case 11: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 5, /* kFastFlush */ 1, /* kLastFast */ 0); + break; + case 10: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 5, /* kFastFlush */ 1, /* kLastFast */ 1); + break; + case 9: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 6, /* kFastFlush */ 1, /* kLastFast */ 0); + break; + case 8: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 7, /* kFastFlush */ 1, /* kLastFast */ 0); + break; + case 7: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 8, /* kFastFlush */ 1, /* kLastFast */ 0); + break; + case 6: ZSTD_FALLTHROUGH; + default: + HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 9, /* kFastFlush */ 1, /* kLastFast */ 1); + break; + } + } } + assert(bitC.ptr <= bitC.endPtr); - return BIT_closeCStream(&bitC); + return HUF_closeCStream(&bitC); } #if DYNAMIC_BMI2 -static TARGET_ATTRIBUTE("bmi2") size_t +static BMI2_TARGET_ATTRIBUTE size_t HUF_compress1X_usingCTable_internal_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) @@ -523,9 +1139,9 @@ HUF_compress1X_usingCTable_internal_default(void* dst, size_t dstSize, static size_t HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize, const void* src, size_t srcSize, - const HUF_CElt* CTable, const int bmi2) + const HUF_CElt* CTable, const int flags) { - if (bmi2) { + if (flags & HUF_flags_bmi2) { return HUF_compress1X_usingCTable_internal_bmi2(dst, dstSize, src, srcSize, CTable); } return HUF_compress1X_usingCTable_internal_default(dst, dstSize, src, srcSize, CTable); @@ -536,24 +1152,23 @@ HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize, static size_t HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize, const void* src, size_t srcSize, - const HUF_CElt* CTable, const int bmi2) + const HUF_CElt* CTable, const int flags) { - (void)bmi2; + (void)flags; return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable); } #endif -size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) +size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags) { - return HUF_compress1X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0); + return HUF_compress1X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, flags); } - static size_t HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize, const void* src, size_t srcSize, - const HUF_CElt* CTable, int bmi2) + const HUF_CElt* CTable, int flags) { size_t const segmentSize = (srcSize+3)/4; /* first 3 segments */ const BYTE* ip = (const BYTE*) src; @@ -567,27 +1182,24 @@ HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize, op += 6; /* jumpTable */ assert(op <= oend); - { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) ); - if (cSize==0) return 0; - assert(cSize <= 65535); + { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, flags) ); + if (cSize == 0 || cSize > 65535) return 0; MEM_writeLE16(ostart, (U16)cSize); op += cSize; } ip += segmentSize; assert(op <= oend); - { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) ); - if (cSize==0) return 0; - assert(cSize <= 65535); + { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, flags) ); + if (cSize == 0 || cSize > 65535) return 0; MEM_writeLE16(ostart+2, (U16)cSize); op += cSize; } ip += segmentSize; assert(op <= oend); - { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) ); - if (cSize==0) return 0; - assert(cSize <= 65535); + { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, flags) ); + if (cSize == 0 || cSize > 65535) return 0; MEM_writeLE16(ostart+4, (U16)cSize); op += cSize; } @@ -595,17 +1207,17 @@ HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize, ip += segmentSize; assert(op <= oend); assert(ip <= iend); - { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, (size_t)(iend-ip), CTable, bmi2) ); - if (cSize==0) return 0; + { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, (size_t)(iend-ip), CTable, flags) ); + if (cSize == 0 || cSize > 65535) return 0; op += cSize; } return (size_t)(op-ostart); } -size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) +size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags) { - return HUF_compress4X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0); + return HUF_compress4X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, flags); } typedef enum { HUF_singleStream, HUF_fourStreams } HUF_nbStreams_e; @@ -613,11 +1225,11 @@ typedef enum { HUF_singleStream, HUF_fourStreams } HUF_nbStreams_e; static size_t HUF_compressCTable_internal( BYTE* const ostart, BYTE* op, BYTE* const oend, const void* src, size_t srcSize, - HUF_nbStreams_e nbStreams, const HUF_CElt* CTable, const int bmi2) + HUF_nbStreams_e nbStreams, const HUF_CElt* CTable, const int flags) { size_t const cSize = (nbStreams==HUF_singleStream) ? - HUF_compress1X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, bmi2) : - HUF_compress4X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, bmi2); + HUF_compress1X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, flags) : + HUF_compress4X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, flags); if (HUF_isError(cSize)) { return cSize; } if (cSize==0) { return 0; } /* uncompressible */ op += cSize; @@ -629,31 +1241,113 @@ static size_t HUF_compressCTable_internal( typedef struct { unsigned count[HUF_SYMBOLVALUE_MAX + 1]; - HUF_CElt CTable[HUF_SYMBOLVALUE_MAX + 1]; - HUF_buildCTable_wksp_tables buildCTable_wksp; + HUF_CElt CTable[HUF_CTABLE_SIZE_ST(HUF_SYMBOLVALUE_MAX)]; + union { + HUF_buildCTable_wksp_tables buildCTable_wksp; + HUF_WriteCTableWksp writeCTable_wksp; + U32 hist_wksp[HIST_WKSP_SIZE_U32]; + } wksps; } HUF_compress_tables_t; +#define SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE 4096 +#define SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO 10 /* Must be >= 2 */ + +unsigned HUF_cardinality(const unsigned* count, unsigned maxSymbolValue) +{ + unsigned cardinality = 0; + unsigned i; + + for (i = 0; i < maxSymbolValue + 1; i++) { + if (count[i] != 0) cardinality += 1; + } + + return cardinality; +} + +unsigned HUF_minTableLog(unsigned symbolCardinality) +{ + U32 minBitsSymbols = ZSTD_highbit32(symbolCardinality) + 1; + return minBitsSymbols; +} + +unsigned HUF_optimalTableLog( + unsigned maxTableLog, + size_t srcSize, + unsigned maxSymbolValue, + void* workSpace, size_t wkspSize, + HUF_CElt* table, + const unsigned* count, + int flags) +{ + assert(srcSize > 1); /* Not supported, RLE should be used instead */ + assert(wkspSize >= sizeof(HUF_buildCTable_wksp_tables)); + + if (!(flags & HUF_flags_optimalDepth)) { + /* cheap evaluation, based on FSE */ + return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1); + } + + { BYTE* dst = (BYTE*)workSpace + sizeof(HUF_WriteCTableWksp); + size_t dstSize = wkspSize - sizeof(HUF_WriteCTableWksp); + size_t hSize, newSize; + const unsigned symbolCardinality = HUF_cardinality(count, maxSymbolValue); + const unsigned minTableLog = HUF_minTableLog(symbolCardinality); + size_t optSize = ((size_t) ~0) - 1; + unsigned optLog = maxTableLog, optLogGuess; + + DEBUGLOG(6, "HUF_optimalTableLog: probing huf depth (srcSize=%zu)", srcSize); + + /* Search until size increases */ + for (optLogGuess = minTableLog; optLogGuess <= maxTableLog; optLogGuess++) { + DEBUGLOG(7, "checking for huffLog=%u", optLogGuess); + + { size_t maxBits = HUF_buildCTable_wksp(table, count, maxSymbolValue, optLogGuess, workSpace, wkspSize); + if (ERR_isError(maxBits)) continue; + + if (maxBits < optLogGuess && optLogGuess > minTableLog) break; + + hSize = HUF_writeCTable_wksp(dst, dstSize, table, maxSymbolValue, (U32)maxBits, workSpace, wkspSize); + } + + if (ERR_isError(hSize)) continue; + + newSize = HUF_estimateCompressedSize(table, count, maxSymbolValue) + hSize; + + if (newSize > optSize + 1) { + break; + } + + if (newSize < optSize) { + optSize = newSize; + optLog = optLogGuess; + } + } + assert(optLog <= HUF_TABLELOG_MAX); + return optLog; + } +} + /* HUF_compress_internal() : - * `workSpace` must a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */ + * `workSpace_align4` must be aligned on 4-bytes boundaries, + * and occupies the same space as a table of HUF_WORKSPACE_SIZE_U64 unsigned */ static size_t HUF_compress_internal (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, HUF_nbStreams_e nbStreams, void* workSpace, size_t wkspSize, - HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat, - const int bmi2) + HUF_CElt* oldHufTable, HUF_repeat* repeat, int flags) { - HUF_compress_tables_t* const table = (HUF_compress_tables_t*)workSpace; + HUF_compress_tables_t* const table = (HUF_compress_tables_t*)HUF_alignUpWorkspace(workSpace, &wkspSize, ZSTD_ALIGNOF(size_t)); BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + dstSize; BYTE* op = ostart; - HUF_STATIC_ASSERT(sizeof(*table) <= HUF_WORKSPACE_SIZE); + DEBUGLOG(5, "HUF_compress_internal (srcSize=%zu)", srcSize); + HUF_STATIC_ASSERT(sizeof(*table) + HUF_WORKSPACE_MAX_ALIGNMENT <= HUF_WORKSPACE_SIZE); /* checks & inits */ - if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */ - if (wkspSize < HUF_WORKSPACE_SIZE) return ERROR(workSpace_tooSmall); + if (wkspSize < sizeof(*table)) return ERROR(workSpace_tooSmall); if (!srcSize) return 0; /* Uncompressed */ if (!dstSize) return 0; /* cannot fit anything within dst budget */ if (srcSize > HUF_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); /* current block size limit */ @@ -663,17 +1357,34 @@ HUF_compress_internal (void* dst, size_t dstSize, if (!huffLog) huffLog = HUF_TABLELOG_DEFAULT; /* Heuristic : If old table is valid, use it for small inputs */ - if (preferRepeat && repeat && *repeat == HUF_repeat_valid) { + if ((flags & HUF_flags_preferRepeat) && repeat && *repeat == HUF_repeat_valid) { return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, - nbStreams, oldHufTable, bmi2); + nbStreams, oldHufTable, flags); + } + + /* If uncompressible data is suspected, do a smaller sampling first */ + DEBUG_STATIC_ASSERT(SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO >= 2); + if ((flags & HUF_flags_suspectUncompressible) && srcSize >= (SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE * SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO)) { + size_t largestTotal = 0; + DEBUGLOG(5, "input suspected incompressible : sampling to check"); + { unsigned maxSymbolValueBegin = maxSymbolValue; + CHECK_V_F(largestBegin, HIST_count_simple (table->count, &maxSymbolValueBegin, (const BYTE*)src, SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) ); + largestTotal += largestBegin; + } + { unsigned maxSymbolValueEnd = maxSymbolValue; + CHECK_V_F(largestEnd, HIST_count_simple (table->count, &maxSymbolValueEnd, (const BYTE*)src + srcSize - SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE, SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) ); + largestTotal += largestEnd; + } + if (largestTotal <= ((2 * SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) >> 7)+4) return 0; /* heuristic : probably not compressible enough */ } /* Scan input and build symbol stats */ - { CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, workSpace, wkspSize) ); + { CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, table->wksps.hist_wksp, sizeof(table->wksps.hist_wksp)) ); if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */ if (largest <= (srcSize >> 7)+4) return 0; /* heuristic : probably not compressible enough */ } + DEBUGLOG(6, "histogram detail completed (%zu symbols)", showU32(table->count, maxSymbolValue+1)); /* Check validity of previous table */ if ( repeat @@ -682,26 +1393,25 @@ HUF_compress_internal (void* dst, size_t dstSize, *repeat = HUF_repeat_none; } /* Heuristic : use existing table for small inputs */ - if (preferRepeat && repeat && *repeat != HUF_repeat_none) { + if ((flags & HUF_flags_preferRepeat) && repeat && *repeat != HUF_repeat_none) { return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, - nbStreams, oldHufTable, bmi2); + nbStreams, oldHufTable, flags); } /* Build Huffman Tree */ - huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue); + huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue, &table->wksps, sizeof(table->wksps), table->CTable, table->count, flags); { size_t const maxBits = HUF_buildCTable_wksp(table->CTable, table->count, maxSymbolValue, huffLog, - &table->buildCTable_wksp, sizeof(table->buildCTable_wksp)); + &table->wksps.buildCTable_wksp, sizeof(table->wksps.buildCTable_wksp)); CHECK_F(maxBits); huffLog = (U32)maxBits; - /* Zero unused symbols in CTable, so we can check it for validity */ - memset(table->CTable + (maxSymbolValue + 1), 0, - sizeof(table->CTable) - ((maxSymbolValue + 1) * sizeof(HUF_CElt))); + DEBUGLOG(6, "bit distribution completed (%zu symbols)", showCTableBits(table->CTable + 1, maxSymbolValue+1)); } /* Write table description header */ - { CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, table->CTable, maxSymbolValue, huffLog) ); + { CHECK_V_F(hSize, HUF_writeCTable_wksp(op, dstSize, table->CTable, maxSymbolValue, huffLog, + &table->wksps.writeCTable_wksp, sizeof(table->wksps.writeCTable_wksp)) ); /* Check if using previous huffman table is beneficial */ if (repeat && *repeat != HUF_repeat_none) { size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, table->count, maxSymbolValue); @@ -709,7 +1419,7 @@ HUF_compress_internal (void* dst, size_t dstSize, if (oldSize <= hSize + newSize || hSize + 12 >= srcSize) { return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, - nbStreams, oldHufTable, bmi2); + nbStreams, oldHufTable, flags); } } /* Use the new huffman table */ @@ -717,85 +1427,41 @@ HUF_compress_internal (void* dst, size_t dstSize, op += hSize; if (repeat) { *repeat = HUF_repeat_none; } if (oldHufTable) - memcpy(oldHufTable, table->CTable, sizeof(table->CTable)); /* Save new table */ + ZSTD_memcpy(oldHufTable, table->CTable, sizeof(table->CTable)); /* Save new table */ } return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, - nbStreams, table->CTable, bmi2); -} - - -size_t HUF_compress1X_wksp (void* dst, size_t dstSize, - const void* src, size_t srcSize, - unsigned maxSymbolValue, unsigned huffLog, - void* workSpace, size_t wkspSize) -{ - return HUF_compress_internal(dst, dstSize, src, srcSize, - maxSymbolValue, huffLog, HUF_singleStream, - workSpace, wkspSize, - NULL, NULL, 0, 0 /*bmi2*/); + nbStreams, table->CTable, flags); } size_t HUF_compress1X_repeat (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, void* workSpace, size_t wkspSize, - HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2) + HUF_CElt* hufTable, HUF_repeat* repeat, int flags) { + DEBUGLOG(5, "HUF_compress1X_repeat (srcSize = %zu)", srcSize); return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, HUF_singleStream, workSpace, wkspSize, hufTable, - repeat, preferRepeat, bmi2); -} - -size_t HUF_compress1X (void* dst, size_t dstSize, - const void* src, size_t srcSize, - unsigned maxSymbolValue, unsigned huffLog) -{ - unsigned workSpace[HUF_WORKSPACE_SIZE_U32]; - return HUF_compress1X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace)); + repeat, flags); } /* HUF_compress4X_repeat(): * compress input using 4 streams. - * provide workspace to generate compression tables */ -size_t HUF_compress4X_wksp (void* dst, size_t dstSize, - const void* src, size_t srcSize, - unsigned maxSymbolValue, unsigned huffLog, - void* workSpace, size_t wkspSize) -{ - return HUF_compress_internal(dst, dstSize, src, srcSize, - maxSymbolValue, huffLog, HUF_fourStreams, - workSpace, wkspSize, - NULL, NULL, 0, 0 /*bmi2*/); -} - -/* HUF_compress4X_repeat(): - * compress input using 4 streams. - * re-use an existing huffman compression table */ + * consider skipping quickly + * reuse an existing huffman compression table */ size_t HUF_compress4X_repeat (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, void* workSpace, size_t wkspSize, - HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2) + HUF_CElt* hufTable, HUF_repeat* repeat, int flags) { + DEBUGLOG(5, "HUF_compress4X_repeat (srcSize = %zu)", srcSize); return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, HUF_fourStreams, workSpace, wkspSize, - hufTable, repeat, preferRepeat, bmi2); -} - -size_t HUF_compress2 (void* dst, size_t dstSize, - const void* src, size_t srcSize, - unsigned maxSymbolValue, unsigned huffLog) -{ - unsigned workSpace[HUF_WORKSPACE_SIZE_U32]; - return HUF_compress4X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace)); + hufTable, repeat, flags); } -size_t HUF_compress (void* dst, size_t maxDstSize, const void* src, size_t srcSize) -{ - return HUF_compress2(dst, maxDstSize, src, srcSize, 255, HUF_TABLELOG_DEFAULT); -} - -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/compress/zstd_compress.cpp b/src/duckdb/third_party/zstd/compress/zstd_compress.cpp index 649e53571..df5626e5f 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_compress.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_compress.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,14 +11,13 @@ /*-************************************* * Dependencies ***************************************/ -#include /* INT_MAX */ -#include /* memset */ +#include "zstd/common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */ +#include "zstd/common/zstd_deps.h" /* INT_MAX, ZSTD_memset, ZSTD_memcpy */ #include "zstd/common/mem.h" #include "zstd/compress/hist.h" /* HIST_countFast_wksp */ +#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */ #include "zstd/common/fse.h" -#include "zstd/common/fse_static.h" #include "zstd/common/huf.h" -#include "zstd/common/huf_static.h" #include "zstd/compress/zstd_compress_internal.h" #include "zstd/compress/zstd_compress_sequences.h" #include "zstd/compress/zstd_compress_literals.h" @@ -28,24 +27,51 @@ #include "zstd/compress/zstd_opt.h" #include "zstd/compress/zstd_ldm.h" #include "zstd/compress/zstd_compress_superblock.h" +#include "zstd/common/bits.h" /* ZSTD_highbit32, ZSTD_rotateRight_U64 */ + +/* *************************************************************** +* Tuning parameters +*****************************************************************/ +/*! + * COMPRESS_HEAPMODE : + * Select how default decompression function ZSTD_compress() allocates its context, + * on stack (0, default), or into heap (1). + * Note that functions with explicit context such as ZSTD_compressCCtx() are unaffected. + */ +#ifndef ZSTD_COMPRESS_HEAPMODE +# define ZSTD_COMPRESS_HEAPMODE 0 +#endif -#if defined (MEMORY_SANITIZER) -#include +/*! + * ZSTD_HASHLOG3_MAX : + * Maximum size of the hash table dedicated to find 3-bytes matches, + * in log format, aka 17 => 1 << 17 == 128Ki positions. + * This structure is only used in zstd_opt. + * Since allocation is centralized for all strategies, it has to be known here. + * The actual (selected) size of the hash table is then stored in ZSTD_matchState_t.hashLog3, + * so that zstd_opt.c doesn't need to know about this constant. + */ +#ifndef ZSTD_HASHLOG3_MAX +# define ZSTD_HASHLOG3_MAX 17 #endif namespace duckdb_zstd { + /*-************************************* * Helper functions ***************************************/ /* ZSTD_compressBound() - * Note that the result from this function is only compatible with the "normal" - * full-block strategy. - * When there are a lot of small blocks due to frequent flush in streaming mode - * the overhead of headers can make the compressed data to be larger than the - * return value of ZSTD_compressBound(). + * Note that the result from this function is only valid for + * the one-pass compression functions. + * When employing the streaming mode, + * if flushes are frequently altering the size of blocks, + * the overhead from block headers can make the compressed data larger + * than the return value of ZSTD_compressBound(). */ size_t ZSTD_compressBound(size_t srcSize) { - return ZSTD_COMPRESSBOUND(srcSize); + size_t const r = ZSTD_COMPRESSBOUND(srcSize); + if (r==0) return ERROR(srcSize_wrong); + return r; } @@ -55,6 +81,7 @@ size_t ZSTD_compressBound(size_t srcSize) { struct ZSTD_CDict_s { const void* dictContent; size_t dictContentSize; + ZSTD_dictContentType_e dictContentType; /* The dictContentType the CDict was created with */ U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */ ZSTD_cwksp workspace; ZSTD_matchState_t matchState; @@ -62,19 +89,23 @@ struct ZSTD_CDict_s { ZSTD_customMem customMem; U32 dictID; int compressionLevel; /* 0 indicates that advanced API was used to select CDict params */ + ZSTD_paramSwitch_e useRowMatchFinder; /* Indicates whether the CDict was created with params that would use + * row-based matchfinder. Unless the cdict is reloaded, we will use + * the same greedy/lazy matchfinder at compression time. + */ }; /* typedef'd to ZSTD_CDict within "zstd.h" */ ZSTD_CCtx* ZSTD_createCCtx(void) { - return ZSTD_createCCtx_advanced({NULL, NULL, NULL}); + return ZSTD_createCCtx_advanced(ZSTD_defaultCMem); } static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager) { assert(cctx != NULL); - memset(cctx, 0, sizeof(*cctx)); + ZSTD_memset(cctx, 0, sizeof(*cctx)); cctx->customMem = memManager; - cctx->bmi2 = 0; + cctx->bmi2 = ZSTD_cpuSupportsBmi2(); { size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters); assert(!ZSTD_isError(err)); (void)err; @@ -85,8 +116,8 @@ ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem) { ZSTD_STATIC_ASSERT(zcss_init==0); ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1)); - if (!customMem.customAlloc ^ !customMem.customFree) return NULL; - { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem); + if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; + { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_customMalloc(sizeof(ZSTD_CCtx), customMem); if (!cctx) return NULL; ZSTD_initCCtx(cctx, customMem); return cctx; @@ -99,21 +130,21 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize) ZSTD_CCtx* cctx; if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */ if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */ - ZSTD_cwksp_init(&ws, workspace, workspaceSize); + ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc); cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CCtx)); if (cctx == NULL) return NULL; - memset(cctx, 0, sizeof(ZSTD_CCtx)); + ZSTD_memset(cctx, 0, sizeof(ZSTD_CCtx)); ZSTD_cwksp_move(&cctx->workspace, &ws); cctx->staticSize = workspaceSize; /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */ - if (!ZSTD_cwksp_check_available(&cctx->workspace, HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL; + if (!ZSTD_cwksp_check_available(&cctx->workspace, ENTROPY_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL; cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t)); cctx->blockState.nextCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t)); - cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cctx->workspace, HUF_WORKSPACE_SIZE); - cctx->bmi2 = 0; + cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cctx->workspace, ENTROPY_WORKSPACE_SIZE); + cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); return cctx; } @@ -122,10 +153,10 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize) */ static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx) { - ZSTD_free(cctx->localDict.dictBuffer, cctx->customMem); + ZSTD_customFree(cctx->localDict.dictBuffer, cctx->customMem); ZSTD_freeCDict(cctx->localDict.cdict); - memset(&cctx->localDict, 0, sizeof(cctx->localDict)); - memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); + ZSTD_memset(&cctx->localDict, 0, sizeof(cctx->localDict)); + ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); cctx->cdict = NULL; } @@ -149,15 +180,13 @@ static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx) size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) { + DEBUGLOG(3, "ZSTD_freeCCtx (address: %p)", (void*)cctx); if (cctx==NULL) return 0; /* support free on NULL */ RETURN_ERROR_IF(cctx->staticSize, memory_allocation, "not compatible with static CCtx"); - { - int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx); + { int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx); ZSTD_freeCCtxContent(cctx); - if (!cctxInWorkspace) { - ZSTD_free(cctx, cctx->customMem); - } + if (!cctxInWorkspace) ZSTD_customFree(cctx, cctx->customMem); } return 0; } @@ -192,15 +221,116 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) /* private API call, for dictBuilder only */ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } +/* Returns true if the strategy supports using a row based matchfinder */ +static int ZSTD_rowMatchFinderSupported(const ZSTD_strategy strategy) { + return (strategy >= ZSTD_greedy && strategy <= ZSTD_lazy2); +} + +/* Returns true if the strategy and useRowMatchFinder mode indicate that we will use the row based matchfinder + * for this compression. + */ +static int ZSTD_rowMatchFinderUsed(const ZSTD_strategy strategy, const ZSTD_paramSwitch_e mode) { + assert(mode != ZSTD_ps_auto); + return ZSTD_rowMatchFinderSupported(strategy) && (mode == ZSTD_ps_enable); +} + +/* Returns row matchfinder usage given an initial mode and cParams */ +static ZSTD_paramSwitch_e ZSTD_resolveRowMatchFinderMode(ZSTD_paramSwitch_e mode, + const ZSTD_compressionParameters* const cParams) { +#if defined(ZSTD_ARCH_X86_SSE2) || defined(ZSTD_ARCH_ARM_NEON) + int const kHasSIMD128 = 1; +#else + int const kHasSIMD128 = 0; +#endif + if (mode != ZSTD_ps_auto) return mode; /* if requested enabled, but no SIMD, we still will use row matchfinder */ + mode = ZSTD_ps_disable; + if (!ZSTD_rowMatchFinderSupported(cParams->strategy)) return mode; + if (kHasSIMD128) { + if (cParams->windowLog > 14) mode = ZSTD_ps_enable; + } else { + if (cParams->windowLog > 17) mode = ZSTD_ps_enable; + } + return mode; +} + +/* Returns block splitter usage (generally speaking, when using slower/stronger compression modes) */ +static ZSTD_paramSwitch_e ZSTD_resolveBlockSplitterMode(ZSTD_paramSwitch_e mode, + const ZSTD_compressionParameters* const cParams) { + if (mode != ZSTD_ps_auto) return mode; + return (cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 17) ? ZSTD_ps_enable : ZSTD_ps_disable; +} + +/* Returns 1 if the arguments indicate that we should allocate a chainTable, 0 otherwise */ +static int ZSTD_allocateChainTable(const ZSTD_strategy strategy, + const ZSTD_paramSwitch_e useRowMatchFinder, + const U32 forDDSDict) { + assert(useRowMatchFinder != ZSTD_ps_auto); + /* We always should allocate a chaintable if we are allocating a matchstate for a DDS dictionary matchstate. + * We do not allocate a chaintable if we are using ZSTD_fast, or are using the row-based matchfinder. + */ + return forDDSDict || ((strategy != ZSTD_fast) && !ZSTD_rowMatchFinderUsed(strategy, useRowMatchFinder)); +} + +/* Returns ZSTD_ps_enable if compression parameters are such that we should + * enable long distance matching (wlog >= 27, strategy >= btopt). + * Returns ZSTD_ps_disable otherwise. + */ +static ZSTD_paramSwitch_e ZSTD_resolveEnableLdm(ZSTD_paramSwitch_e mode, + const ZSTD_compressionParameters* const cParams) { + if (mode != ZSTD_ps_auto) return mode; + return (cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 27) ? ZSTD_ps_enable : ZSTD_ps_disable; +} + +static int ZSTD_resolveExternalSequenceValidation(int mode) { + return mode; +} + +/* Resolves maxBlockSize to the default if no value is present. */ +static size_t ZSTD_resolveMaxBlockSize(size_t maxBlockSize) { + if (maxBlockSize == 0) { + return ZSTD_BLOCKSIZE_MAX; + } else { + return maxBlockSize; + } +} + +static ZSTD_paramSwitch_e ZSTD_resolveExternalRepcodeSearch(ZSTD_paramSwitch_e value, int cLevel) { + if (value != ZSTD_ps_auto) return value; + if (cLevel < 10) { + return ZSTD_ps_disable; + } else { + return ZSTD_ps_enable; + } +} + +/* Returns 1 if compression parameters are such that CDict hashtable and chaintable indices are tagged. + * If so, the tags need to be removed in ZSTD_resetCCtx_byCopyingCDict. */ +static int ZSTD_CDictIndicesAreTagged(const ZSTD_compressionParameters* const cParams) { + return cParams->strategy == ZSTD_fast || cParams->strategy == ZSTD_dfast; +} + static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( ZSTD_compressionParameters cParams) { ZSTD_CCtx_params cctxParams; - memset(&cctxParams, 0, sizeof(cctxParams)); + /* should not matter, as all cParams are presumed properly defined */ + ZSTD_CCtxParams_init(&cctxParams, ZSTD_CLEVEL_DEFAULT); cctxParams.cParams = cParams; - cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ + + /* Adjust advanced params according to cParams */ + cctxParams.ldmParams.enableLdm = ZSTD_resolveEnableLdm(cctxParams.ldmParams.enableLdm, &cParams); + if (cctxParams.ldmParams.enableLdm == ZSTD_ps_enable) { + ZSTD_ldm_adjustParameters(&cctxParams.ldmParams, &cParams); + assert(cctxParams.ldmParams.hashLog >= cctxParams.ldmParams.bucketSizeLog); + assert(cctxParams.ldmParams.hashRateLog < 32); + } + cctxParams.useBlockSplitter = ZSTD_resolveBlockSplitterMode(cctxParams.useBlockSplitter, &cParams); + cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams); + cctxParams.validateSequences = ZSTD_resolveExternalSequenceValidation(cctxParams.validateSequences); + cctxParams.maxBlockSize = ZSTD_resolveMaxBlockSize(cctxParams.maxBlockSize); + cctxParams.searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(cctxParams.searchForExternalRepcodes, + cctxParams.compressionLevel); assert(!ZSTD_checkCParams(cParams)); - cctxParams.fParams.contentSizeFlag = 1; return cctxParams; } @@ -208,25 +338,24 @@ static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced( ZSTD_customMem customMem) { ZSTD_CCtx_params* params; - if (!customMem.customAlloc ^ !customMem.customFree) return NULL; - params = (ZSTD_CCtx_params*)ZSTD_calloc( + if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; + params = (ZSTD_CCtx_params*)ZSTD_customCalloc( sizeof(ZSTD_CCtx_params), customMem); if (!params) { return NULL; } + ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT); params->customMem = customMem; - params->compressionLevel = ZSTD_CLEVEL_DEFAULT; - params->fParams.contentSizeFlag = 1; return params; } ZSTD_CCtx_params* ZSTD_createCCtxParams(void) { - return ZSTD_createCCtxParams_advanced(ZSTDInternalConstants::ZSTD_defaultCMem); + return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem); } size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) { if (params == NULL) { return 0; } - ZSTD_free(params, params->customMem); + ZSTD_customFree(params, params->customMem); return 0; } @@ -237,35 +366,63 @@ size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params) size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) { RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!"); - memset(cctxParams, 0, sizeof(*cctxParams)); + ZSTD_memset(cctxParams, 0, sizeof(*cctxParams)); cctxParams->compressionLevel = compressionLevel; cctxParams->fParams.contentSizeFlag = 1; return 0; } +#define ZSTD_NO_CLEVEL 0 + +/** + * Initializes `cctxParams` from `params` and `compressionLevel`. + * @param compressionLevel If params are derived from a compression level then that compression level, otherwise ZSTD_NO_CLEVEL. + */ +static void +ZSTD_CCtxParams_init_internal(ZSTD_CCtx_params* cctxParams, + const ZSTD_parameters* params, + int compressionLevel) +{ + assert(!ZSTD_checkCParams(params->cParams)); + ZSTD_memset(cctxParams, 0, sizeof(*cctxParams)); + cctxParams->cParams = params->cParams; + cctxParams->fParams = params->fParams; + /* Should not matter, as all cParams are presumed properly defined. + * But, set it for tracing anyway. + */ + cctxParams->compressionLevel = compressionLevel; + cctxParams->useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams->useRowMatchFinder, ¶ms->cParams); + cctxParams->useBlockSplitter = ZSTD_resolveBlockSplitterMode(cctxParams->useBlockSplitter, ¶ms->cParams); + cctxParams->ldmParams.enableLdm = ZSTD_resolveEnableLdm(cctxParams->ldmParams.enableLdm, ¶ms->cParams); + cctxParams->validateSequences = ZSTD_resolveExternalSequenceValidation(cctxParams->validateSequences); + cctxParams->maxBlockSize = ZSTD_resolveMaxBlockSize(cctxParams->maxBlockSize); + cctxParams->searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(cctxParams->searchForExternalRepcodes, compressionLevel); + DEBUGLOG(4, "ZSTD_CCtxParams_init_internal: useRowMatchFinder=%d, useBlockSplitter=%d ldm=%d", + cctxParams->useRowMatchFinder, cctxParams->useBlockSplitter, cctxParams->ldmParams.enableLdm); +} + size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) { RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!"); FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , ""); - memset(cctxParams, 0, sizeof(*cctxParams)); - assert(!ZSTD_checkCParams(params.cParams)); - cctxParams->cParams = params.cParams; - cctxParams->fParams = params.fParams; - cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ + ZSTD_CCtxParams_init_internal(cctxParams, ¶ms, ZSTD_NO_CLEVEL); return 0; } -/* ZSTD_assignParamsToCCtxParams() : - * params is presumed valid at this stage */ -static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams( - const ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params) +/** + * Sets cctxParams' cParams and fParams from params, but otherwise leaves them alone. + * @param params Validated zstd parameters. + */ +static void ZSTD_CCtxParams_setZstdParams( + ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params) { - ZSTD_CCtx_params ret = *cctxParams; assert(!ZSTD_checkCParams(params->cParams)); - ret.cParams = params->cParams; - ret.fParams = params->fParams; - ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ - return ret; + cctxParams->cParams = params->cParams; + cctxParams->fParams = params->fParams; + /* Should not matter, as all cParams are presumed properly defined. + * But, set it for tracing anyway. + */ + cctxParams->compressionLevel = ZSTD_NO_CLEVEL; } ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) @@ -357,11 +514,16 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) #endif return bounds; - case ZSTD_c_enableLongDistanceMatching: + case ZSTD_c_enableDedicatedDictSearch: bounds.lowerBound = 0; bounds.upperBound = 1; return bounds; + case ZSTD_c_enableLongDistanceMatching: + bounds.lowerBound = (int)ZSTD_ps_auto; + bounds.upperBound = (int)ZSTD_ps_disable; + return bounds; + case ZSTD_c_ldmHashLog: bounds.lowerBound = ZSTD_LDM_HASHLOG_MIN; bounds.upperBound = ZSTD_LDM_HASHLOG_MAX; @@ -400,15 +562,15 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) return bounds; case ZSTD_c_forceAttachDict: - ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceCopy); + ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceLoad); bounds.lowerBound = ZSTD_dictDefaultAttach; bounds.upperBound = ZSTD_dictForceLoad; /* note : how to ensure at compile time that this is the highest value enum ? */ return bounds; case ZSTD_c_literalCompressionMode: - ZSTD_STATIC_ASSERT(ZSTD_lcm_auto < ZSTD_lcm_huffman && ZSTD_lcm_huffman < ZSTD_lcm_uncompressed); - bounds.lowerBound = ZSTD_lcm_auto; - bounds.upperBound = ZSTD_lcm_uncompressed; + ZSTD_STATIC_ASSERT(ZSTD_ps_auto < ZSTD_ps_enable && ZSTD_ps_enable < ZSTD_ps_disable); + bounds.lowerBound = (int)ZSTD_ps_auto; + bounds.upperBound = (int)ZSTD_ps_disable; return bounds; case ZSTD_c_targetCBlockSize: @@ -421,6 +583,57 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) bounds.upperBound = ZSTD_SRCSIZEHINT_MAX; return bounds; + case ZSTD_c_stableInBuffer: + case ZSTD_c_stableOutBuffer: + bounds.lowerBound = (int)ZSTD_bm_buffered; + bounds.upperBound = (int)ZSTD_bm_stable; + return bounds; + + case ZSTD_c_blockDelimiters: + bounds.lowerBound = (int)ZSTD_sf_noBlockDelimiters; + bounds.upperBound = (int)ZSTD_sf_explicitBlockDelimiters; + return bounds; + + case ZSTD_c_validateSequences: + bounds.lowerBound = 0; + bounds.upperBound = 1; + return bounds; + + case ZSTD_c_useBlockSplitter: + bounds.lowerBound = (int)ZSTD_ps_auto; + bounds.upperBound = (int)ZSTD_ps_disable; + return bounds; + + case ZSTD_c_useRowMatchFinder: + bounds.lowerBound = (int)ZSTD_ps_auto; + bounds.upperBound = (int)ZSTD_ps_disable; + return bounds; + + case ZSTD_c_deterministicRefPrefix: + bounds.lowerBound = 0; + bounds.upperBound = 1; + return bounds; + + case ZSTD_c_prefetchCDictTables: + bounds.lowerBound = (int)ZSTD_ps_auto; + bounds.upperBound = (int)ZSTD_ps_disable; + return bounds; + + case ZSTD_c_enableSeqProducerFallback: + bounds.lowerBound = 0; + bounds.upperBound = 1; + return bounds; + + case ZSTD_c_maxBlockSize: + bounds.lowerBound = ZSTD_BLOCKSIZE_MAX_MIN; + bounds.upperBound = ZSTD_BLOCKSIZE_MAX; + return bounds; + + case ZSTD_c_searchForExternalRepcodes: + bounds.lowerBound = (int)ZSTD_ps_auto; + bounds.upperBound = (int)ZSTD_ps_disable; + return bounds; + default: bounds.error = ERROR(parameter_unsupported); return bounds; @@ -439,10 +652,11 @@ static size_t ZSTD_cParam_clampBounds(ZSTD_cParameter cParam, int* value) return 0; } -#define BOUNDCHECK(cParam, val) { \ - RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \ - parameter_outOfBound, "Param out of bounds"); \ -} +#define BOUNDCHECK(cParam, val) \ + do { \ + RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \ + parameter_outOfBound, "Param out of bounds"); \ + } while (0) static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) @@ -468,6 +682,7 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) case ZSTD_c_jobSize: case ZSTD_c_overlapLog: case ZSTD_c_rsyncable: + case ZSTD_c_enableDedicatedDictSearch: case ZSTD_c_enableLongDistanceMatching: case ZSTD_c_ldmHashLog: case ZSTD_c_ldmMinMatch: @@ -477,6 +692,17 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) case ZSTD_c_literalCompressionMode: case ZSTD_c_targetCBlockSize: case ZSTD_c_srcSizeHint: + case ZSTD_c_stableInBuffer: + case ZSTD_c_stableOutBuffer: + case ZSTD_c_blockDelimiters: + case ZSTD_c_validateSequences: + case ZSTD_c_useBlockSplitter: + case ZSTD_c_useRowMatchFinder: + case ZSTD_c_deterministicRefPrefix: + case ZSTD_c_prefetchCDictTables: + case ZSTD_c_enableSeqProducerFallback: + case ZSTD_c_maxBlockSize: + case ZSTD_c_searchForExternalRepcodes: default: return 0; } @@ -489,7 +715,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value) if (ZSTD_isUpdateAuthorized(param)) { cctx->cParamsChanged = 1; } else { - RETURN_ERROR(stage_wrong, "can only set params in ctx init stage"); + RETURN_ERROR(stage_wrong, "can only set params in cctx init stage"); } } switch(param) @@ -518,12 +744,24 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value) case ZSTD_c_jobSize: case ZSTD_c_overlapLog: case ZSTD_c_rsyncable: + case ZSTD_c_enableDedicatedDictSearch: case ZSTD_c_enableLongDistanceMatching: case ZSTD_c_ldmHashLog: case ZSTD_c_ldmMinMatch: case ZSTD_c_ldmBucketSizeLog: case ZSTD_c_targetCBlockSize: case ZSTD_c_srcSizeHint: + case ZSTD_c_stableInBuffer: + case ZSTD_c_stableOutBuffer: + case ZSTD_c_blockDelimiters: + case ZSTD_c_validateSequences: + case ZSTD_c_useBlockSplitter: + case ZSTD_c_useRowMatchFinder: + case ZSTD_c_deterministicRefPrefix: + case ZSTD_c_prefetchCDictTables: + case ZSTD_c_enableSeqProducerFallback: + case ZSTD_c_maxBlockSize: + case ZSTD_c_searchForExternalRepcodes: break; default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); @@ -544,9 +782,10 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, case ZSTD_c_compressionLevel : { FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), ""); - if (value) { /* 0 : does not change current level */ + if (value == 0) + CCtxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ + else CCtxParams->compressionLevel = value; - } if (CCtxParams->compressionLevel >= 0) return (size_t)CCtxParams->compressionLevel; return 0; /* return type (size_t) cannot represent negative values */ } @@ -578,12 +817,12 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, case ZSTD_c_minMatch : if (value!=0) /* 0 => use default */ BOUNDCHECK(ZSTD_c_minMatch, value); - CCtxParams->cParams.minMatch = value; + CCtxParams->cParams.minMatch = (U32)value; return CCtxParams->cParams.minMatch; case ZSTD_c_targetLength : BOUNDCHECK(ZSTD_c_targetLength, value); - CCtxParams->cParams.targetLength = value; + CCtxParams->cParams.targetLength = (U32)value; return CCtxParams->cParams.targetLength; case ZSTD_c_strategy : @@ -596,12 +835,12 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, /* Content size written in frame header _when known_ (default:1) */ DEBUGLOG(4, "set content size flag = %u", (value!=0)); CCtxParams->fParams.contentSizeFlag = value != 0; - return CCtxParams->fParams.contentSizeFlag; + return (size_t)CCtxParams->fParams.contentSizeFlag; case ZSTD_c_checksumFlag : /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */ CCtxParams->fParams.checksumFlag = value != 0; - return CCtxParams->fParams.checksumFlag; + return (size_t)CCtxParams->fParams.checksumFlag; case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */ DEBUGLOG(4, "set dictIDFlag = %u", (value!=0)); @@ -610,18 +849,18 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, case ZSTD_c_forceMaxWindow : CCtxParams->forceWindow = (value != 0); - return CCtxParams->forceWindow; + return (size_t)CCtxParams->forceWindow; case ZSTD_c_forceAttachDict : { const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value; - BOUNDCHECK(ZSTD_c_forceAttachDict, pref); + BOUNDCHECK(ZSTD_c_forceAttachDict, (int)pref); CCtxParams->attachDictPref = pref; return CCtxParams->attachDictPref; } case ZSTD_c_literalCompressionMode : { - const ZSTD_literalCompressionMode_e lcm = (ZSTD_literalCompressionMode_e)value; - BOUNDCHECK(ZSTD_c_literalCompressionMode, lcm); + const ZSTD_paramSwitch_e lcm = (ZSTD_paramSwitch_e)value; + BOUNDCHECK(ZSTD_c_literalCompressionMode, (int)lcm); CCtxParams->literalCompressionMode = lcm; return CCtxParams->literalCompressionMode; } @@ -633,7 +872,7 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, #else FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), ""); CCtxParams->nbWorkers = value; - return CCtxParams->nbWorkers; + return (size_t)(CCtxParams->nbWorkers); #endif case ZSTD_c_jobSize : @@ -657,7 +896,7 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, #else FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value), ""); CCtxParams->overlapLog = value; - return CCtxParams->overlapLog; + return (size_t)CCtxParams->overlapLog; #endif case ZSTD_c_rsyncable : @@ -667,60 +906,123 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, #else FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value), ""); CCtxParams->rsyncable = value; - return CCtxParams->rsyncable; + return (size_t)CCtxParams->rsyncable; #endif + case ZSTD_c_enableDedicatedDictSearch : + CCtxParams->enableDedicatedDictSearch = (value!=0); + return (size_t)CCtxParams->enableDedicatedDictSearch; + case ZSTD_c_enableLongDistanceMatching : - CCtxParams->ldmParams.enableLdm = (value!=0); + BOUNDCHECK(ZSTD_c_enableLongDistanceMatching, value); + CCtxParams->ldmParams.enableLdm = (ZSTD_paramSwitch_e)value; return CCtxParams->ldmParams.enableLdm; case ZSTD_c_ldmHashLog : if (value!=0) /* 0 ==> auto */ BOUNDCHECK(ZSTD_c_ldmHashLog, value); - CCtxParams->ldmParams.hashLog = value; + CCtxParams->ldmParams.hashLog = (U32)value; return CCtxParams->ldmParams.hashLog; case ZSTD_c_ldmMinMatch : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_ldmMinMatch, value); - CCtxParams->ldmParams.minMatchLength = value; + CCtxParams->ldmParams.minMatchLength = (U32)value; return CCtxParams->ldmParams.minMatchLength; case ZSTD_c_ldmBucketSizeLog : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value); - CCtxParams->ldmParams.bucketSizeLog = value; + CCtxParams->ldmParams.bucketSizeLog = (U32)value; return CCtxParams->ldmParams.bucketSizeLog; case ZSTD_c_ldmHashRateLog : - RETURN_ERROR_IF(value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN, - parameter_outOfBound, "Param out of bounds!"); - CCtxParams->ldmParams.hashRateLog = value; + if (value!=0) /* 0 ==> default */ + BOUNDCHECK(ZSTD_c_ldmHashRateLog, value); + CCtxParams->ldmParams.hashRateLog = (U32)value; return CCtxParams->ldmParams.hashRateLog; case ZSTD_c_targetCBlockSize : - if (value!=0) /* 0 ==> default */ + if (value!=0) { /* 0 ==> default */ + value = MAX(value, ZSTD_TARGETCBLOCKSIZE_MIN); BOUNDCHECK(ZSTD_c_targetCBlockSize, value); - CCtxParams->targetCBlockSize = value; + } + CCtxParams->targetCBlockSize = (U32)value; return CCtxParams->targetCBlockSize; case ZSTD_c_srcSizeHint : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_srcSizeHint, value); CCtxParams->srcSizeHint = value; - return CCtxParams->srcSizeHint; + return (size_t)CCtxParams->srcSizeHint; + + case ZSTD_c_stableInBuffer: + BOUNDCHECK(ZSTD_c_stableInBuffer, value); + CCtxParams->inBufferMode = (ZSTD_bufferMode_e)value; + return CCtxParams->inBufferMode; + + case ZSTD_c_stableOutBuffer: + BOUNDCHECK(ZSTD_c_stableOutBuffer, value); + CCtxParams->outBufferMode = (ZSTD_bufferMode_e)value; + return CCtxParams->outBufferMode; + + case ZSTD_c_blockDelimiters: + BOUNDCHECK(ZSTD_c_blockDelimiters, value); + CCtxParams->blockDelimiters = (ZSTD_sequenceFormat_e)value; + return CCtxParams->blockDelimiters; + + case ZSTD_c_validateSequences: + BOUNDCHECK(ZSTD_c_validateSequences, value); + CCtxParams->validateSequences = value; + return (size_t)CCtxParams->validateSequences; + + case ZSTD_c_useBlockSplitter: + BOUNDCHECK(ZSTD_c_useBlockSplitter, value); + CCtxParams->useBlockSplitter = (ZSTD_paramSwitch_e)value; + return CCtxParams->useBlockSplitter; + + case ZSTD_c_useRowMatchFinder: + BOUNDCHECK(ZSTD_c_useRowMatchFinder, value); + CCtxParams->useRowMatchFinder = (ZSTD_paramSwitch_e)value; + return CCtxParams->useRowMatchFinder; + + case ZSTD_c_deterministicRefPrefix: + BOUNDCHECK(ZSTD_c_deterministicRefPrefix, value); + CCtxParams->deterministicRefPrefix = !!value; + return (size_t)CCtxParams->deterministicRefPrefix; + + case ZSTD_c_prefetchCDictTables: + BOUNDCHECK(ZSTD_c_prefetchCDictTables, value); + CCtxParams->prefetchCDictTables = (ZSTD_paramSwitch_e)value; + return CCtxParams->prefetchCDictTables; + + case ZSTD_c_enableSeqProducerFallback: + BOUNDCHECK(ZSTD_c_enableSeqProducerFallback, value); + CCtxParams->enableMatchFinderFallback = value; + return (size_t)CCtxParams->enableMatchFinderFallback; + + case ZSTD_c_maxBlockSize: + if (value!=0) /* 0 ==> default */ + BOUNDCHECK(ZSTD_c_maxBlockSize, value); + CCtxParams->maxBlockSize = value; + return CCtxParams->maxBlockSize; + + case ZSTD_c_searchForExternalRepcodes: + BOUNDCHECK(ZSTD_c_searchForExternalRepcodes, value); + CCtxParams->searchForExternalRepcodes = (ZSTD_paramSwitch_e)value; + return CCtxParams->searchForExternalRepcodes; default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); } } -size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value) +size_t ZSTD_CCtx_getParameter(ZSTD_CCtx const* cctx, ZSTD_cParameter param, int* value) { return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value); } size_t ZSTD_CCtxParams_getParameter( - ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, int* value) + ZSTD_CCtx_params const* CCtxParams, ZSTD_cParameter param, int* value) { switch(param) { @@ -797,6 +1099,9 @@ size_t ZSTD_CCtxParams_getParameter( *value = CCtxParams->rsyncable; break; #endif + case ZSTD_c_enableDedicatedDictSearch : + *value = CCtxParams->enableDedicatedDictSearch; + break; case ZSTD_c_enableLongDistanceMatching : *value = CCtxParams->ldmParams.enableLdm; break; @@ -818,6 +1123,39 @@ size_t ZSTD_CCtxParams_getParameter( case ZSTD_c_srcSizeHint : *value = (int)CCtxParams->srcSizeHint; break; + case ZSTD_c_stableInBuffer : + *value = (int)CCtxParams->inBufferMode; + break; + case ZSTD_c_stableOutBuffer : + *value = (int)CCtxParams->outBufferMode; + break; + case ZSTD_c_blockDelimiters : + *value = (int)CCtxParams->blockDelimiters; + break; + case ZSTD_c_validateSequences : + *value = (int)CCtxParams->validateSequences; + break; + case ZSTD_c_useBlockSplitter : + *value = (int)CCtxParams->useBlockSplitter; + break; + case ZSTD_c_useRowMatchFinder : + *value = (int)CCtxParams->useRowMatchFinder; + break; + case ZSTD_c_deterministicRefPrefix: + *value = (int)CCtxParams->deterministicRefPrefix; + break; + case ZSTD_c_prefetchCDictTables: + *value = (int)CCtxParams->prefetchCDictTables; + break; + case ZSTD_c_enableSeqProducerFallback: + *value = CCtxParams->enableMatchFinderFallback; + break; + case ZSTD_c_maxBlockSize: + *value = (int)CCtxParams->maxBlockSize; + break; + case ZSTD_c_searchForExternalRepcodes: + *value = (int)CCtxParams->searchForExternalRepcodes; + break; default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); } return 0; @@ -844,25 +1182,69 @@ size_t ZSTD_CCtx_setParametersUsingCCtxParams( return 0; } -ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) +size_t ZSTD_CCtx_setCParams(ZSTD_CCtx* cctx, ZSTD_compressionParameters cparams) +{ + ZSTD_STATIC_ASSERT(sizeof(cparams) == 7 * 4 /* all params are listed below */); + DEBUGLOG(4, "ZSTD_CCtx_setCParams"); + /* only update if all parameters are valid */ + FORWARD_IF_ERROR(ZSTD_checkCParams(cparams), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, cparams.windowLog), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_chainLog, cparams.chainLog), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_hashLog, cparams.hashLog), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_searchLog, cparams.searchLog), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, cparams.minMatch), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_targetLength, cparams.targetLength), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_strategy, cparams.strategy), ""); + return 0; +} + +size_t ZSTD_CCtx_setFParams(ZSTD_CCtx* cctx, ZSTD_frameParameters fparams) +{ + ZSTD_STATIC_ASSERT(sizeof(fparams) == 3 * 4 /* all params are listed below */); + DEBUGLOG(4, "ZSTD_CCtx_setFParams"); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_contentSizeFlag, fparams.contentSizeFlag != 0), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, fparams.checksumFlag != 0), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_dictIDFlag, fparams.noDictIDFlag == 0), ""); + return 0; +} + +size_t ZSTD_CCtx_setParams(ZSTD_CCtx* cctx, ZSTD_parameters params) +{ + DEBUGLOG(4, "ZSTD_CCtx_setParams"); + /* First check cParams, because we want to update all or none. */ + FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), ""); + /* Next set fParams, because this could fail if the cctx isn't in init stage. */ + FORWARD_IF_ERROR(ZSTD_CCtx_setFParams(cctx, params.fParams), ""); + /* Finally set cParams, which should succeed. */ + FORWARD_IF_ERROR(ZSTD_CCtx_setCParams(cctx, params.cParams), ""); + return 0; +} + +size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) { - DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize); + DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %llu bytes", pledgedSrcSize); RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, "Can't set pledgedSrcSize when not in init stage."); cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; return 0; } +static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams( + int const compressionLevel, + size_t const dictSize); +static int ZSTD_dedicatedDictSearch_isSupported( + const ZSTD_compressionParameters* cParams); +static void ZSTD_dedicatedDictSearch_revertCParams( + ZSTD_compressionParameters* cParams); + /** - * Initializes the local dict using the requested parameters. - * NOTE: This does not use the pledged src size, because it may be used for more - * than one compression. + * Initializes the local dictionary using requested parameters. + * NOTE: Initialization does not employ the pledged src size, + * because the dictionary may be used for multiple compressions. */ static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx) { ZSTD_localDict* const dl = &cctx->localDict; - ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams( - &cctx->requestedParams, ZSTD_CONTENTSIZE_UNKNOWN, dl->dictSize); if (dl->dict == NULL) { /* No local dictionary. */ assert(dl->dictBuffer == NULL); @@ -871,20 +1253,20 @@ static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx) return 0; } if (dl->cdict != NULL) { - assert(cctx->cdict == dl->cdict); /* Local dictionary already initialized. */ + assert(cctx->cdict == dl->cdict); return 0; } assert(dl->dictSize > 0); assert(cctx->cdict == NULL); assert(cctx->prefixDict.dict == NULL); - dl->cdict = ZSTD_createCDict_advanced( + dl->cdict = ZSTD_createCDict_advanced2( dl->dict, dl->dictSize, ZSTD_dlm_byRef, dl->dictContentType, - cParams, + &cctx->requestedParams, cctx->customMem); RETURN_ERROR_IF(!dl->cdict, memory_allocation, "ZSTD_createCDict_advanced failed"); cctx->cdict = dl->cdict; @@ -892,39 +1274,44 @@ static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx) } size_t ZSTD_CCtx_loadDictionary_advanced( - ZSTD_CCtx* cctx, const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType) + ZSTD_CCtx* cctx, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType) { - RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, - "Can't load a dictionary when ctx is not in init stage."); - RETURN_ERROR_IF(cctx->staticSize, memory_allocation, - "no malloc for static CCtx"); DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize); - ZSTD_clearAllDicts(cctx); /* in case one already exists */ - if (dict == NULL || dictSize == 0) /* no dictionary mode */ + RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, + "Can't load a dictionary when cctx is not in init stage."); + ZSTD_clearAllDicts(cctx); /* erase any previously set dictionary */ + if (dict == NULL || dictSize == 0) /* no dictionary */ return 0; if (dictLoadMethod == ZSTD_dlm_byRef) { cctx->localDict.dict = dict; } else { - void* dictBuffer = ZSTD_malloc(dictSize, cctx->customMem); - RETURN_ERROR_IF(!dictBuffer, memory_allocation, "NULL pointer!"); - memcpy(dictBuffer, dict, dictSize); - cctx->localDict.dictBuffer = dictBuffer; - cctx->localDict.dict = dictBuffer; + /* copy dictionary content inside CCtx to own its lifetime */ + void* dictBuffer; + RETURN_ERROR_IF(cctx->staticSize, memory_allocation, + "static CCtx can't allocate for an internal copy of dictionary"); + dictBuffer = ZSTD_customMalloc(dictSize, cctx->customMem); + RETURN_ERROR_IF(dictBuffer==NULL, memory_allocation, + "allocation failed for dictionary content"); + ZSTD_memcpy(dictBuffer, dict, dictSize); + cctx->localDict.dictBuffer = dictBuffer; /* owned ptr to free */ + cctx->localDict.dict = dictBuffer; /* read-only reference */ } cctx->localDict.dictSize = dictSize; cctx->localDict.dictContentType = dictContentType; return 0; } -ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference( +size_t ZSTD_CCtx_loadDictionary_byReference( ZSTD_CCtx* cctx, const void* dict, size_t dictSize) { return ZSTD_CCtx_loadDictionary_advanced( cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto); } -ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) +size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) { return ZSTD_CCtx_loadDictionary_advanced( cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto); @@ -941,6 +1328,14 @@ size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) return 0; } +size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool) +{ + RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, + "Can't ref a pool when ctx not in init stage."); + cctx->pool = pool; + return 0; +} + size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize) { return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent); @@ -972,7 +1367,7 @@ size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset) if ( (reset == ZSTD_reset_parameters) || (reset == ZSTD_reset_session_and_parameters) ) { RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, - "Can't reset parameters only when not in init stage."); + "Reset parameters is only possible during init stage."); ZSTD_clearAllDicts(cctx); return ZSTD_CCtxParams_reset(&cctx->requestedParams); } @@ -1001,11 +1396,12 @@ size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) static ZSTD_compressionParameters ZSTD_clampCParams(ZSTD_compressionParameters cParams) { -# define CLAMP_TYPE(cParam, val, type) { \ - ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \ - if ((int)valbounds.upperBound) val=(type)bounds.upperBound; \ - } +# define CLAMP_TYPE(cParam, val, type) \ + do { \ + ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \ + if ((int)valbounds.upperBound) val=(type)bounds.upperBound; \ + } while (0) # define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, unsigned) CLAMP(ZSTD_c_windowLog, cParams.windowLog); CLAMP(ZSTD_c_chainLog, cParams.chainLog); @@ -1025,42 +1421,183 @@ U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) return hashLog - btScale; } +/** ZSTD_dictAndWindowLog() : + * Returns an adjusted window log that is large enough to fit the source and the dictionary. + * The zstd format says that the entire dictionary is valid if one byte of the dictionary + * is within the window. So the hashLog and chainLog should be large enough to reference both + * the dictionary and the window. So we must use this adjusted dictAndWindowLog when downsizing + * the hashLog and windowLog. + * NOTE: srcSize must not be ZSTD_CONTENTSIZE_UNKNOWN. + */ +static U32 ZSTD_dictAndWindowLog(U32 windowLog, U64 srcSize, U64 dictSize) +{ + const U64 maxWindowSize = 1ULL << ZSTD_WINDOWLOG_MAX; + /* No dictionary ==> No change */ + if (dictSize == 0) { + return windowLog; + } + assert(windowLog <= ZSTD_WINDOWLOG_MAX); + assert(srcSize != ZSTD_CONTENTSIZE_UNKNOWN); /* Handled in ZSTD_adjustCParams_internal() */ + { + U64 const windowSize = 1ULL << windowLog; + U64 const dictAndWindowSize = dictSize + windowSize; + /* If the window size is already large enough to fit both the source and the dictionary + * then just use the window size. Otherwise adjust so that it fits the dictionary and + * the window. + */ + if (windowSize >= dictSize + srcSize) { + return windowLog; /* Window size large enough already */ + } else if (dictAndWindowSize >= maxWindowSize) { + return ZSTD_WINDOWLOG_MAX; /* Larger than max window log */ + } else { + return ZSTD_highbit32((U32)dictAndWindowSize - 1) + 1; + } + } +} + /** ZSTD_adjustCParams_internal() : * optimize `cPar` for a specified input (`srcSize` and `dictSize`). * mostly downsize to reduce memory consumption and initialization latency. * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known. + * `mode` is the mode for parameter adjustment. See docs for `ZSTD_cParamMode_e`. * note : `srcSize==0` means 0! * condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */ static ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, unsigned long long srcSize, - size_t dictSize) + size_t dictSize, + ZSTD_cParamMode_e mode, + ZSTD_paramSwitch_e useRowMatchFinder) { - static const U64 minSrcSize = 513; /* (1<<9) + 1 */ - static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); + const U64 minSrcSize = 513; /* (1<<9) + 1 */ + const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); assert(ZSTD_checkCParams(cPar)==0); - if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN) - srcSize = minSrcSize; + /* Cascade the selected strategy down to the next-highest one built into + * this binary. */ +#ifdef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR + if (cPar.strategy == ZSTD_btultra2) { + cPar.strategy = ZSTD_btultra; + } + if (cPar.strategy == ZSTD_btultra) { + cPar.strategy = ZSTD_btopt; + } +#endif +#ifdef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR + if (cPar.strategy == ZSTD_btopt) { + cPar.strategy = ZSTD_btlazy2; + } +#endif +#ifdef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR + if (cPar.strategy == ZSTD_btlazy2) { + cPar.strategy = ZSTD_lazy2; + } +#endif +#ifdef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR + if (cPar.strategy == ZSTD_lazy2) { + cPar.strategy = ZSTD_lazy; + } +#endif +#ifdef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR + if (cPar.strategy == ZSTD_lazy) { + cPar.strategy = ZSTD_greedy; + } +#endif +#ifdef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR + if (cPar.strategy == ZSTD_greedy) { + cPar.strategy = ZSTD_dfast; + } +#endif +#ifdef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR + if (cPar.strategy == ZSTD_dfast) { + cPar.strategy = ZSTD_fast; + cPar.targetLength = 0; + } +#endif + + switch (mode) { + case ZSTD_cpm_unknown: + case ZSTD_cpm_noAttachDict: + /* If we don't know the source size, don't make any + * assumptions about it. We will already have selected + * smaller parameters if a dictionary is in use. + */ + break; + case ZSTD_cpm_createCDict: + /* Assume a small source size when creating a dictionary + * with an unknown source size. + */ + if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN) + srcSize = minSrcSize; + break; + case ZSTD_cpm_attachDict: + /* Dictionary has its own dedicated parameters which have + * already been selected. We are selecting parameters + * for only the source. + */ + dictSize = 0; + break; + default: + assert(0); + break; + } /* resize windowLog if input is small enough, to use less memory */ - if ( (srcSize < maxWindowResize) - && (dictSize < maxWindowResize) ) { + if ( (srcSize <= maxWindowResize) + && (dictSize <= maxWindowResize) ) { U32 const tSize = (U32)(srcSize + dictSize); static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN; U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN : ZSTD_highbit32(tSize-1) + 1; if (cPar.windowLog > srcLog) cPar.windowLog = srcLog; } - if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1; - { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); - if (cycleLog > cPar.windowLog) - cPar.chainLog -= (cycleLog - cPar.windowLog); + if (srcSize != ZSTD_CONTENTSIZE_UNKNOWN) { + U32 const dictAndWindowLog = ZSTD_dictAndWindowLog(cPar.windowLog, (U64)srcSize, (U64)dictSize); + U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); + if (cPar.hashLog > dictAndWindowLog+1) cPar.hashLog = dictAndWindowLog+1; + if (cycleLog > dictAndWindowLog) + cPar.chainLog -= (cycleLog - dictAndWindowLog); } if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* minimum wlog required for valid frame header */ + /* We can't use more than 32 bits of hash in total, so that means that we require: + * (hashLog + 8) <= 32 && (chainLog + 8) <= 32 + */ + if (mode == ZSTD_cpm_createCDict && ZSTD_CDictIndicesAreTagged(&cPar)) { + U32 const maxShortCacheHashLog = 32 - ZSTD_SHORT_CACHE_TAG_BITS; + if (cPar.hashLog > maxShortCacheHashLog) { + cPar.hashLog = maxShortCacheHashLog; + } + if (cPar.chainLog > maxShortCacheHashLog) { + cPar.chainLog = maxShortCacheHashLog; + } + } + + + /* At this point, we aren't 100% sure if we are using the row match finder. + * Unless it is explicitly disabled, conservatively assume that it is enabled. + * In this case it will only be disabled for small sources, so shrinking the + * hash log a little bit shouldn't result in any ratio loss. + */ + if (useRowMatchFinder == ZSTD_ps_auto) + useRowMatchFinder = ZSTD_ps_enable; + + /* We can't hash more than 32-bits in total. So that means that we require: + * (hashLog - rowLog + 8) <= 32 + */ + if (ZSTD_rowMatchFinderUsed(cPar.strategy, useRowMatchFinder)) { + /* Switch to 32-entry rows if searchLog is 5 (or more) */ + U32 const rowLog = BOUNDED(4, cPar.searchLog, 6); + U32 const maxRowHashLog = 32 - ZSTD_ROW_HASH_TAG_BITS; + U32 const maxHashLog = maxRowHashLog + rowLog; + assert(cPar.hashLog >= rowLog); + if (cPar.hashLog > maxHashLog) { + cPar.hashLog = maxHashLog; + } + } + return cPar; } @@ -1071,38 +1608,50 @@ ZSTD_adjustCParams(ZSTD_compressionParameters cPar, { cPar = ZSTD_clampCParams(cPar); /* resulting cPar is necessarily valid (all parameters within range) */ if (srcSize == 0) srcSize = ZSTD_CONTENTSIZE_UNKNOWN; - return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize); + return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize, ZSTD_cpm_unknown, ZSTD_ps_auto); } -static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize); -static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize); +static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode); +static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode); + +static void ZSTD_overrideCParams( + ZSTD_compressionParameters* cParams, + const ZSTD_compressionParameters* overrides) +{ + if (overrides->windowLog) cParams->windowLog = overrides->windowLog; + if (overrides->hashLog) cParams->hashLog = overrides->hashLog; + if (overrides->chainLog) cParams->chainLog = overrides->chainLog; + if (overrides->searchLog) cParams->searchLog = overrides->searchLog; + if (overrides->minMatch) cParams->minMatch = overrides->minMatch; + if (overrides->targetLength) cParams->targetLength = overrides->targetLength; + if (overrides->strategy) cParams->strategy = overrides->strategy; +} ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( - const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize) + const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) { ZSTD_compressionParameters cParams; if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && CCtxParams->srcSizeHint > 0) { srcSizeHint = CCtxParams->srcSizeHint; } - cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize); - if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; - if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog; - if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog; - if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog; - if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog; - if (CCtxParams->cParams.minMatch) cParams.minMatch = CCtxParams->cParams.minMatch; - if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength; - if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy; + cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize, mode); + if (CCtxParams->ldmParams.enableLdm == ZSTD_ps_enable) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; + ZSTD_overrideCParams(&cParams, &CCtxParams->cParams); assert(!ZSTD_checkCParams(cParams)); /* srcSizeHint == 0 means 0 */ - return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize); + return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize, mode, CCtxParams->useRowMatchFinder); } static size_t ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams, + const ZSTD_paramSwitch_e useRowMatchFinder, + const U32 enableDedicatedDictSearch, const U32 forCCtx) { - size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); + /* chain table size should be 0 for fast or row-hash strategies */ + size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder, enableDedicatedDictSearch && !forCCtx) + ? ((size_t)1 << cParams->chainLog) + : 0; size_t const hSize = ((size_t)1) << cParams->hashLog; U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0; @@ -1112,71 +1661,131 @@ ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams, + hSize * sizeof(U32) + h3Size * sizeof(U32); size_t const optPotentialSpace = - ZSTD_cwksp_alloc_size((MaxML+1) * sizeof(U32)) - + ZSTD_cwksp_alloc_size((MaxLL+1) * sizeof(U32)) - + ZSTD_cwksp_alloc_size((MaxOff+1) * sizeof(U32)) - + ZSTD_cwksp_alloc_size((1<strategy, useRowMatchFinder) + ? ZSTD_cwksp_aligned_alloc_size(hSize) + : 0; size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt)) ? optPotentialSpace : 0; + size_t const slackSpace = ZSTD_cwksp_slack_space_required(); + + /* tables are guaranteed to be sized in multiples of 64 bytes (or 16 uint32_t) */ + ZSTD_STATIC_ASSERT(ZSTD_HASHLOG_MIN >= 4 && ZSTD_WINDOWLOG_MIN >= 4 && ZSTD_CHAINLOG_MIN >= 4); + assert(useRowMatchFinder != ZSTD_ps_auto); + DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u", (U32)chainSize, (U32)hSize, (U32)h3Size); - return tableSpace + optSpace; + return tableSpace + optSpace + slackSpace + lazyAdditionalSpace; +} + +/* Helper function for calculating memory requirements. + * Gives a tighter bound than ZSTD_sequenceBound() by taking minMatch into account. */ +static size_t ZSTD_maxNbSeq(size_t blockSize, unsigned minMatch, int useSequenceProducer) { + U32 const divider = (minMatch==3 || useSequenceProducer) ? 3 : 4; + return blockSize / divider; +} + +static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal( + const ZSTD_compressionParameters* cParams, + const ldmParams_t* ldmParams, + const int isStatic, + const ZSTD_paramSwitch_e useRowMatchFinder, + const size_t buffInSize, + const size_t buffOutSize, + const U64 pledgedSrcSize, + int useSequenceProducer, + size_t maxBlockSize) +{ + size_t const windowSize = (size_t) BOUNDED(1ULL, 1ULL << cParams->windowLog, pledgedSrcSize); + size_t const blockSize = MIN(ZSTD_resolveMaxBlockSize(maxBlockSize), windowSize); + size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, cParams->minMatch, useSequenceProducer); + size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) + + ZSTD_cwksp_aligned_alloc_size(maxNbSeq * sizeof(seqDef)) + + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); + size_t const entropySpace = ZSTD_cwksp_alloc_size(ENTROPY_WORKSPACE_SIZE); + size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); + size_t const matchStateSize = ZSTD_sizeof_matchState(cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 0, /* forCCtx */ 1); + + size_t const ldmSpace = ZSTD_ldm_getTableSize(*ldmParams); + size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(*ldmParams, blockSize); + size_t const ldmSeqSpace = ldmParams->enableLdm == ZSTD_ps_enable ? + ZSTD_cwksp_aligned_alloc_size(maxNbLdmSeq * sizeof(rawSeq)) : 0; + + + size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) + + ZSTD_cwksp_alloc_size(buffOutSize); + + size_t const cctxSpace = isStatic ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0; + + size_t const maxNbExternalSeq = ZSTD_sequenceBound(blockSize); + size_t const externalSeqSpace = useSequenceProducer + ? ZSTD_cwksp_aligned_alloc_size(maxNbExternalSeq * sizeof(ZSTD_Sequence)) + : 0; + + size_t const neededSpace = + cctxSpace + + entropySpace + + blockStateSpace + + ldmSpace + + ldmSeqSpace + + matchStateSize + + tokenSpace + + bufferSpace + + externalSeqSpace; + + DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace); + return neededSpace; } size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params) { - RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); - { ZSTD_compressionParameters const cParams = - ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0); - size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); - U32 const divider = (cParams.minMatch==3) ? 3 : 4; - size_t const maxNbSeq = blockSize / divider; - size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) - + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef)) - + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); - size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE); - size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); - size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1); - - size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams); - size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq)); - - /* estimateCCtxSize is for one-shot compression. So no buffers should - * be needed. However, we still allocate two 0-sized buffers, which can - * take space under ASAN. */ - size_t const bufferSpace = ZSTD_cwksp_alloc_size(0) - + ZSTD_cwksp_alloc_size(0); - - size_t const cctxSpace = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)); - - size_t const neededSpace = - cctxSpace + - entropySpace + - blockStateSpace + - ldmSpace + - ldmSeqSpace + - matchStateSize + - tokenSpace + - bufferSpace; + ZSTD_compressionParameters const cParams = + ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); + ZSTD_paramSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, + &cParams); - DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace); - return neededSpace; - } + RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); + /* estimateCCtxSize is for one-shot compression. So no buffers should + * be needed. However, we still allocate two 0-sized buffers, which can + * take space under ASAN. */ + return ZSTD_estimateCCtxSize_usingCCtxParams_internal( + &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_hasExtSeqProd(params), params->maxBlockSize); } size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) { - ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); - return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms); + ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams); + if (ZSTD_rowMatchFinderSupported(cParams.strategy)) { + /* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */ + size_t noRowCCtxSize; + size_t rowCCtxSize; + initialParams.useRowMatchFinder = ZSTD_ps_disable; + noRowCCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams); + initialParams.useRowMatchFinder = ZSTD_ps_enable; + rowCCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams); + return MAX(noRowCCtxSize, rowCCtxSize); + } else { + return ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams); + } } static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel) { - ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0); - return ZSTD_estimateCCtxSize_usingCParams(cParams); + int tier = 0; + size_t largestSize = 0; + static const unsigned long long srcSizeTiers[4] = {16 KB, 128 KB, 256 KB, ZSTD_CONTENTSIZE_UNKNOWN}; + for (; tier < 4; ++tier) { + /* Choose the set of cParams for a given level across all srcSizes that give the largest cctxSize */ + ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeTiers[tier], 0, ZSTD_cpm_noAttachDict); + largestSize = MAX(ZSTD_estimateCCtxSize_usingCParams(cParams), largestSize); + } + return largestSize; } size_t ZSTD_estimateCCtxSize(int compressionLevel) @@ -1184,6 +1793,7 @@ size_t ZSTD_estimateCCtxSize(int compressionLevel) int level; size_t memBudget = 0; for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) { + /* Ensure monotonically increasing memory usage as compression level increases */ size_t const newMB = ZSTD_estimateCCtxSize_internal(level); if (newMB > memBudget) memBudget = newMB; } @@ -1194,27 +1804,42 @@ size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params) { RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); { ZSTD_compressionParameters const cParams = - ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0); - size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params); - size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); - size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize; - size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; - size_t const streamingSize = ZSTD_cwksp_alloc_size(inBuffSize) - + ZSTD_cwksp_alloc_size(outBuffSize); - - return CCtxSize + streamingSize; + ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); + size_t const blockSize = MIN(ZSTD_resolveMaxBlockSize(params->maxBlockSize), (size_t)1 << cParams.windowLog); + size_t const inBuffSize = (params->inBufferMode == ZSTD_bm_buffered) + ? ((size_t)1 << cParams.windowLog) + blockSize + : 0; + size_t const outBuffSize = (params->outBufferMode == ZSTD_bm_buffered) + ? ZSTD_compressBound(blockSize) + 1 + : 0; + ZSTD_paramSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, ¶ms->cParams); + + return ZSTD_estimateCCtxSize_usingCCtxParams_internal( + &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, inBuffSize, outBuffSize, + ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_hasExtSeqProd(params), params->maxBlockSize); } } size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams) { - ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); - return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms); + ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams); + if (ZSTD_rowMatchFinderSupported(cParams.strategy)) { + /* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */ + size_t noRowCCtxSize; + size_t rowCCtxSize; + initialParams.useRowMatchFinder = ZSTD_ps_disable; + noRowCCtxSize = ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams); + initialParams.useRowMatchFinder = ZSTD_ps_enable; + rowCCtxSize = ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams); + return MAX(noRowCCtxSize, rowCCtxSize); + } else { + return ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams); + } } static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) { - ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0); + ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); return ZSTD_estimateCStreamSize_usingCParams(cParams); } @@ -1286,7 +1911,7 @@ void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs) { int i; for (i = 0; i < ZSTD_REP_NUM; ++i) - bs->rep[i] = ZSTDInternalConstants::repStartValue[i]; + bs->rep[i] = repStartValue[i]; bs->entropy.huf.repeatMode = HUF_repeat_none; bs->entropy.fse.offcode_repeatMode = FSE_repeat_none; bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none; @@ -1307,16 +1932,6 @@ static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms) ms->dictMatchState = NULL; } -/** - * Indicates whether this compression proceeds directly from user-provided - * source buffer to user-provided destination buffer (ZSTDb_not_buffered), or - * whether the context needs to buffer the input/output (ZSTDb_buffered). - */ -typedef enum { - ZSTDb_not_buffered, - ZSTDb_buffered -} ZSTD_buffered_policy_e; - /** * Controls, for this matchState reset, whether the tables need to be cleared / * prepared for the coming compression (ZSTDcrp_makeClean), or whether the @@ -1344,26 +1959,47 @@ typedef enum { ZSTD_resetTarget_CCtx } ZSTD_resetTarget_e; +/* Mixes bits in a 64 bits in a value, based on XXH3_rrmxmx */ +static U64 ZSTD_bitmix(U64 val, U64 len) { + val ^= ZSTD_rotateRight_U64(val, 49) ^ ZSTD_rotateRight_U64(val, 24); + val *= 0x9FB21C651E98DF25ULL; + val ^= (val >> 35) + len ; + val *= 0x9FB21C651E98DF25ULL; + return val ^ (val >> 28); +} + +/* Mixes in the hashSalt and hashSaltEntropy to create a new hashSalt */ +static void ZSTD_advanceHashSalt(ZSTD_matchState_t* ms) { + ms->hashSalt = ZSTD_bitmix(ms->hashSalt, 8) ^ ZSTD_bitmix((U64) ms->hashSaltEntropy, 4); +} + static size_t ZSTD_reset_matchState(ZSTD_matchState_t* ms, ZSTD_cwksp* ws, const ZSTD_compressionParameters* cParams, + const ZSTD_paramSwitch_e useRowMatchFinder, const ZSTD_compResetPolicy_e crp, const ZSTD_indexResetPolicy_e forceResetIndex, const ZSTD_resetTarget_e forWho) { - size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); + /* disable chain table allocation for fast or row-based strategies */ + size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder, + ms->dedicatedDictSearch && (forWho == ZSTD_resetTarget_CDict)) + ? ((size_t)1 << cParams->chainLog) + : 0; size_t const hSize = ((size_t)1) << cParams->hashLog; U32 const hashLog3 = ((forWho == ZSTD_resetTarget_CCtx) && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0; DEBUGLOG(4, "reset indices : %u", forceResetIndex == ZSTDirp_reset); + assert(useRowMatchFinder != ZSTD_ps_auto); if (forceResetIndex == ZSTDirp_reset) { ZSTD_window_init(&ms->window); ZSTD_cwksp_mark_tables_dirty(ws); } ms->hashLog3 = hashLog3; + ms->lazySkipping = 0; ZSTD_invalidateMatchState(ms); @@ -1385,6 +2021,27 @@ ZSTD_reset_matchState(ZSTD_matchState_t* ms, ZSTD_cwksp_clean_tables(ws); } + if (ZSTD_rowMatchFinderUsed(cParams->strategy, useRowMatchFinder)) { + /* Row match finder needs an additional table of hashes ("tags") */ + size_t const tagTableSize = hSize; + /* We want to generate a new salt in case we reset a Cctx, but we always want to use + * 0 when we reset a Cdict */ + if(forWho == ZSTD_resetTarget_CCtx) { + ms->tagTable = (BYTE*) ZSTD_cwksp_reserve_aligned_init_once(ws, tagTableSize); + ZSTD_advanceHashSalt(ms); + } else { + /* When we are not salting we want to always memset the memory */ + ms->tagTable = (BYTE*) ZSTD_cwksp_reserve_aligned(ws, tagTableSize); + ZSTD_memset(ms->tagTable, 0, tagTableSize); + ms->hashSalt = 0; + } + { /* Switch to 32-entry rows if searchLog is 5 (or more) */ + U32 const rowLog = BOUNDED(4, cParams->searchLog, 6); + assert(cParams->hashLog >= rowLog); + ms->rowHashLog = cParams->hashLog - rowLog; + } + } + /* opt parser space */ if ((forWho == ZSTD_resetTarget_CCtx) && (cParams->strategy >= ZSTD_btopt)) { DEBUGLOG(4, "reserving optimal parser space"); @@ -1392,15 +2049,14 @@ ZSTD_reset_matchState(ZSTD_matchState_t* ms, ms->opt.litLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxLL+1) * sizeof(unsigned)); ms->opt.matchLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxML+1) * sizeof(unsigned)); ms->opt.offCodeFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxOff+1) * sizeof(unsigned)); - ms->opt.matchTable = (ZSTD_match_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t)); - ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t)); + ms->opt.matchTable = (ZSTD_match_t*)ZSTD_cwksp_reserve_aligned(ws, ZSTD_OPT_SIZE * sizeof(ZSTD_match_t)); + ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, ZSTD_OPT_SIZE * sizeof(ZSTD_optimal_t)); } ms->cParams = *cParams; RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation, "failed a workspace allocation in ZSTD_reset_matchState"); - return 0; } @@ -1417,75 +2073,86 @@ static int ZSTD_indexTooCloseToMax(ZSTD_window_t w) return (size_t)(w.nextSrc - w.base) > (ZSTD_CURRENT_MAX - ZSTD_INDEXOVERFLOW_MARGIN); } +/** ZSTD_dictTooBig(): + * When dictionaries are larger than ZSTD_CHUNKSIZE_MAX they can't be loaded in + * one go generically. So we ensure that in that case we reset the tables to zero, + * so that we can load as much of the dictionary as possible. + */ +static int ZSTD_dictTooBig(size_t const loadedDictSize) +{ + return loadedDictSize > ZSTD_CHUNKSIZE_MAX; +} + /*! ZSTD_resetCCtx_internal() : - note : `params` are assumed fully validated at this stage */ + * @param loadedDictSize The size of the dictionary to be loaded + * into the context, if any. If no dictionary is used, or the + * dictionary is being attached / copied, then pass 0. + * note : `params` are assumed fully validated at this stage. + */ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, - ZSTD_CCtx_params params, + ZSTD_CCtx_params const* params, U64 const pledgedSrcSize, + size_t const loadedDictSize, ZSTD_compResetPolicy_e const crp, ZSTD_buffered_policy_e const zbuff) { ZSTD_cwksp* const ws = &zc->workspace; - DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u", - (U32)pledgedSrcSize, params.cParams.windowLog); - assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); + DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u, useRowMatchFinder=%d useBlockSplitter=%d", + (U32)pledgedSrcSize, params->cParams.windowLog, (int)params->useRowMatchFinder, (int)params->useBlockSplitter); + assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); zc->isFirstBlock = 1; - if (params.ldmParams.enableLdm) { + /* Set applied params early so we can modify them for LDM, + * and point params at the applied params. + */ + zc->appliedParams = *params; + params = &zc->appliedParams; + + assert(params->useRowMatchFinder != ZSTD_ps_auto); + assert(params->useBlockSplitter != ZSTD_ps_auto); + assert(params->ldmParams.enableLdm != ZSTD_ps_auto); + assert(params->maxBlockSize != 0); + if (params->ldmParams.enableLdm == ZSTD_ps_enable) { /* Adjust long distance matching parameters */ - ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams); - assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); - assert(params.ldmParams.hashRateLog < 32); - zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength); - } - - { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize)); - size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); - U32 const divider = (params.cParams.minMatch==3) ? 3 : 4; - size_t const maxNbSeq = blockSize / divider; - size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) - + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef)) - + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); - size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0; - size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0; - size_t const matchStateSize = ZSTD_sizeof_matchState(¶ms.cParams, /* forCCtx */ 1); - size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize); - - ZSTD_indexResetPolicy_e needsIndexReset = zc->initialized ? ZSTDirp_continue : ZSTDirp_reset; - - if (ZSTD_indexTooCloseToMax(zc->blockState.matchState.window)) { - needsIndexReset = ZSTDirp_reset; - } + ZSTD_ldm_adjustParameters(&zc->appliedParams.ldmParams, ¶ms->cParams); + assert(params->ldmParams.hashLog >= params->ldmParams.bucketSizeLog); + assert(params->ldmParams.hashRateLog < 32); + } - if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0); + { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params->cParams.windowLog), pledgedSrcSize)); + size_t const blockSize = MIN(params->maxBlockSize, windowSize); + size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, params->cParams.minMatch, ZSTD_hasExtSeqProd(params)); + size_t const buffOutSize = (zbuff == ZSTDb_buffered && params->outBufferMode == ZSTD_bm_buffered) + ? ZSTD_compressBound(blockSize) + 1 + : 0; + size_t const buffInSize = (zbuff == ZSTDb_buffered && params->inBufferMode == ZSTD_bm_buffered) + ? windowSize + blockSize + : 0; + size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize); + + int const indexTooClose = ZSTD_indexTooCloseToMax(zc->blockState.matchState.window); + int const dictTooBig = ZSTD_dictTooBig(loadedDictSize); + ZSTD_indexResetPolicy_e needsIndexReset = + (indexTooClose || dictTooBig || !zc->initialized) ? ZSTDirp_reset : ZSTDirp_continue; + + size_t const neededSpace = + ZSTD_estimateCCtxSize_usingCCtxParams_internal( + ¶ms->cParams, ¶ms->ldmParams, zc->staticSize != 0, params->useRowMatchFinder, + buffInSize, buffOutSize, pledgedSrcSize, ZSTD_hasExtSeqProd(params), params->maxBlockSize); + + FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!"); - /* Check if workspace is large enough, alloc a new one if needed */ - { size_t const cctxSpace = zc->staticSize ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0; - size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE); - size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); - size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) + ZSTD_cwksp_alloc_size(buffOutSize); - size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams); - size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq)); - - size_t const neededSpace = - cctxSpace + - entropySpace + - blockStateSpace + - ldmSpace + - ldmSeqSpace + - matchStateSize + - tokenSpace + - bufferSpace; + if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0); + { /* Check if workspace is large enough, alloc a new one if needed */ int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace; int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace); - - DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers", - neededSpace>>10, matchStateSize>>10, bufferSpace>>10); + int resizeWorkspace = workspaceTooSmall || workspaceWasteful; + DEBUGLOG(4, "Need %zu B workspace", neededSpace); DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize); - if (workspaceTooSmall || workspaceWasteful) { + if (resizeWorkspace) { DEBUGLOG(4, "Resize workspaceSize from %zuKB to %zuKB", ZSTD_cwksp_sizeof(ws) >> 10, neededSpace >> 10); @@ -1506,15 +2173,15 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, RETURN_ERROR_IF(zc->blockState.prevCBlock == NULL, memory_allocation, "couldn't allocate prevCBlock"); zc->blockState.nextCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t)); RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate nextCBlock"); - zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, HUF_WORKSPACE_SIZE); - RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate entropyWorkspace"); + zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, ENTROPY_WORKSPACE_SIZE); + RETURN_ERROR_IF(zc->entropyWorkspace == NULL, memory_allocation, "couldn't allocate entropyWorkspace"); } } ZSTD_cwksp_clear(ws); /* init params */ - zc->appliedParams = params; - zc->blockState.matchState.cParams = params.cParams; + zc->blockState.matchState.cParams = params->cParams; + zc->blockState.matchState.prefetchCDictTables = params->prefetchCDictTables == ZSTD_ps_enable; zc->pledgedSrcSizePlusOne = pledgedSrcSize+1; zc->consumedSrcSize = 0; zc->producedCSize = 0; @@ -1527,29 +2194,64 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, XXH64_reset(&zc->xxhState, 0); zc->stage = ZSTDcs_init; zc->dictID = 0; + zc->dictContentSize = 0; ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock); + FORWARD_IF_ERROR(ZSTD_reset_matchState( + &zc->blockState.matchState, + ws, + ¶ms->cParams, + params->useRowMatchFinder, + crp, + needsIndexReset, + ZSTD_resetTarget_CCtx), ""); + + zc->seqStore.sequencesStart = (seqDef*)ZSTD_cwksp_reserve_aligned(ws, maxNbSeq * sizeof(seqDef)); + + /* ldm hash table */ + if (params->ldmParams.enableLdm == ZSTD_ps_enable) { + /* TODO: avoid memset? */ + size_t const ldmHSize = ((size_t)1) << params->ldmParams.hashLog; + zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t)); + ZSTD_memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t)); + zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq)); + zc->maxNbLdmSequences = maxNbLdmSeq; + + ZSTD_window_init(&zc->ldmState.window); + zc->ldmState.loadedDictEnd = 0; + } + + /* reserve space for block-level external sequences */ + if (ZSTD_hasExtSeqProd(params)) { + size_t const maxNbExternalSeq = ZSTD_sequenceBound(blockSize); + zc->extSeqBufCapacity = maxNbExternalSeq; + zc->extSeqBuf = + (ZSTD_Sequence*)ZSTD_cwksp_reserve_aligned(ws, maxNbExternalSeq * sizeof(ZSTD_Sequence)); + } + + /* buffers */ + /* ZSTD_wildcopy() is used to copy into the literals buffer, * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes. */ zc->seqStore.litStart = ZSTD_cwksp_reserve_buffer(ws, blockSize + WILDCOPY_OVERLENGTH); zc->seqStore.maxNbLit = blockSize; - /* buffers */ + zc->bufferedPolicy = zbuff; zc->inBuffSize = buffInSize; zc->inBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffInSize); zc->outBuffSize = buffOutSize; zc->outBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffOutSize); /* ldm bucketOffsets table */ - if (params.ldmParams.enableLdm) { + if (params->ldmParams.enableLdm == ZSTD_ps_enable) { /* TODO: avoid memset? */ - size_t const ldmBucketSize = - ((size_t)1) << (params.ldmParams.hashLog - - params.ldmParams.bucketSizeLog); - zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, ldmBucketSize); - memset(zc->ldmState.bucketOffsets, 0, ldmBucketSize); + size_t const numBuckets = + ((size_t)1) << (params->ldmParams.hashLog - + params->ldmParams.bucketSizeLog); + zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, numBuckets); + ZSTD_memset(zc->ldmState.bucketOffsets, 0, numBuckets); } /* sequences storage */ @@ -1558,32 +2260,11 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, zc->seqStore.llCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); zc->seqStore.mlCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); zc->seqStore.ofCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); - zc->seqStore.sequencesStart = (seqDef*)ZSTD_cwksp_reserve_aligned(ws, maxNbSeq * sizeof(seqDef)); - FORWARD_IF_ERROR(ZSTD_reset_matchState( - &zc->blockState.matchState, - ws, - ¶ms.cParams, - crp, - needsIndexReset, - ZSTD_resetTarget_CCtx), ""); + DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws)); + assert(ZSTD_cwksp_estimated_space_within_bounds(ws, neededSpace)); - /* ldm hash table */ - if (params.ldmParams.enableLdm) { - /* TODO: avoid memset? */ - size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog; - zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t)); - memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t)); - zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq)); - zc->maxNbLdmSequences = maxNbLdmSeq; - - ZSTD_window_init(&zc->ldmState.window); - ZSTD_window_clear(&zc->ldmState.window); - zc->ldmState.loadedDictEnd = 0; - } - - DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws)); - zc->initialized = 1; + zc->initialized = 1; return 0; } @@ -1621,12 +2302,14 @@ static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict, U64 pledgedSrcSize) { size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy]; - return ( pledgedSrcSize <= cutoff - || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN - || params->attachDictPref == ZSTD_dictForceAttach ) - && params->attachDictPref != ZSTD_dictForceCopy - && !params->forceWindow; /* dictMatchState isn't correctly - * handled in _enforceMaxDist */ + int const dedicatedDictSearch = cdict->matchState.dedicatedDictSearch; + return dedicatedDictSearch + || ( ( pledgedSrcSize <= cutoff + || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN + || params->attachDictPref == ZSTD_dictForceAttach ) + && params->attachDictPref != ZSTD_dictForceCopy + && !params->forceWindow ); /* dictMatchState isn't correctly + * handled in _enforceMaxDist */ } static size_t @@ -1636,17 +2319,29 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx, U64 pledgedSrcSize, ZSTD_buffered_policy_e zbuff) { - { const ZSTD_compressionParameters* const cdict_cParams = &cdict->matchState.cParams; + DEBUGLOG(4, "ZSTD_resetCCtx_byAttachingCDict() pledgedSrcSize=%llu", + (unsigned long long)pledgedSrcSize); + { + ZSTD_compressionParameters adjusted_cdict_cParams = cdict->matchState.cParams; unsigned const windowLog = params.cParams.windowLog; assert(windowLog != 0); /* Resize working context table params for input only, since the dict * has its own tables. */ - /* pledgeSrcSize == 0 means 0! */ - params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0); + /* pledgedSrcSize == 0 means 0! */ + + if (cdict->matchState.dedicatedDictSearch) { + ZSTD_dedicatedDictSearch_revertCParams(&adjusted_cdict_cParams); + } + + params.cParams = ZSTD_adjustCParams_internal(adjusted_cdict_cParams, pledgedSrcSize, + cdict->dictContentSize, ZSTD_cpm_attachDict, + params.useRowMatchFinder); params.cParams.windowLog = windowLog; - FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, + params.useRowMatchFinder = cdict->useRowMatchFinder; /* cdict overrides */ + FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, ¶ms, pledgedSrcSize, + /* loadedDictSize */ 0, ZSTDcrp_makeClean, zbuff), ""); - assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); + assert(cctx->appliedParams.cParams.strategy == adjusted_cdict_cParams.strategy); } { const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc @@ -1671,13 +2366,30 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx, } } cctx->dictID = cdict->dictID; + cctx->dictContentSize = cdict->dictContentSize; /* copy block state */ - memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); + ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); return 0; } +static void ZSTD_copyCDictTableIntoCCtx(U32* dst, U32 const* src, size_t tableSize, + ZSTD_compressionParameters const* cParams) { + if (ZSTD_CDictIndicesAreTagged(cParams)){ + /* Remove tags from the CDict table if they are present. + * See docs on "short cache" in zstd_compress_internal.h for context. */ + size_t i; + for (i = 0; i < tableSize; i++) { + U32 const taggedIndex = src[i]; + U32 const index = taggedIndex >> ZSTD_SHORT_CACHE_TAG_BITS; + dst[i] = index; + } + } else { + ZSTD_memcpy(dst, src, tableSize * sizeof(U32)); + } +} + static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, ZSTD_CCtx_params params, @@ -1686,14 +2398,18 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, { const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams; - DEBUGLOG(4, "copying dictionary into context"); + assert(!cdict->matchState.dedicatedDictSearch); + DEBUGLOG(4, "ZSTD_resetCCtx_byCopyingCDict() pledgedSrcSize=%llu", + (unsigned long long)pledgedSrcSize); { unsigned const windowLog = params.cParams.windowLog; assert(windowLog != 0); /* Copy only compression parameters related to tables. */ params.cParams = *cdict_cParams; params.cParams.windowLog = windowLog; - FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, + params.useRowMatchFinder = cdict->useRowMatchFinder; + FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, ¶ms, pledgedSrcSize, + /* loadedDictSize */ 0, ZSTDcrp_leaveDirty, zbuff), ""); assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog); @@ -1701,24 +2417,39 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, } ZSTD_cwksp_mark_tables_dirty(&cctx->workspace); + assert(params.useRowMatchFinder != ZSTD_ps_auto); /* copy tables */ - { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog); + { size_t const chainSize = ZSTD_allocateChainTable(cdict_cParams->strategy, cdict->useRowMatchFinder, 0 /* DDS guaranteed disabled */) + ? ((size_t)1 << cdict_cParams->chainLog) + : 0; size_t const hSize = (size_t)1 << cdict_cParams->hashLog; - memcpy(cctx->blockState.matchState.hashTable, - cdict->matchState.hashTable, - hSize * sizeof(U32)); - memcpy(cctx->blockState.matchState.chainTable, - cdict->matchState.chainTable, - chainSize * sizeof(U32)); + ZSTD_copyCDictTableIntoCCtx(cctx->blockState.matchState.hashTable, + cdict->matchState.hashTable, + hSize, cdict_cParams); + + /* Do not copy cdict's chainTable if cctx has parameters such that it would not use chainTable */ + if (ZSTD_allocateChainTable(cctx->appliedParams.cParams.strategy, cctx->appliedParams.useRowMatchFinder, 0 /* forDDSDict */)) { + ZSTD_copyCDictTableIntoCCtx(cctx->blockState.matchState.chainTable, + cdict->matchState.chainTable, + chainSize, cdict_cParams); + } + /* copy tag table */ + if (ZSTD_rowMatchFinderUsed(cdict_cParams->strategy, cdict->useRowMatchFinder)) { + size_t const tagTableSize = hSize; + ZSTD_memcpy(cctx->blockState.matchState.tagTable, + cdict->matchState.tagTable, + tagTableSize); + cctx->blockState.matchState.hashSalt = cdict->matchState.hashSalt; + } } /* Zero the hashTable3, since the cdict never fills it */ { int const h3log = cctx->blockState.matchState.hashLog3; size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0; assert(cdict->matchState.hashLog3 == 0); - memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32)); + ZSTD_memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32)); } ZSTD_cwksp_mark_tables_clean(&cctx->workspace); @@ -1732,9 +2463,10 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, } cctx->dictID = cdict->dictID; + cctx->dictContentSize = cdict->dictContentSize; /* copy block state */ - memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); + ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); return 0; } @@ -1774,16 +2506,23 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, U64 pledgedSrcSize, ZSTD_buffered_policy_e zbuff) { - DEBUGLOG(5, "ZSTD_copyCCtx_internal"); RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong, "Can't copy a ctx that's not in init stage."); - - memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); + DEBUGLOG(5, "ZSTD_copyCCtx_internal"); + ZSTD_memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); { ZSTD_CCtx_params params = dstCCtx->requestedParams; /* Copy only compression parameters related to tables. */ params.cParams = srcCCtx->appliedParams.cParams; + assert(srcCCtx->appliedParams.useRowMatchFinder != ZSTD_ps_auto); + assert(srcCCtx->appliedParams.useBlockSplitter != ZSTD_ps_auto); + assert(srcCCtx->appliedParams.ldmParams.enableLdm != ZSTD_ps_auto); + params.useRowMatchFinder = srcCCtx->appliedParams.useRowMatchFinder; + params.useBlockSplitter = srcCCtx->appliedParams.useBlockSplitter; + params.ldmParams = srcCCtx->appliedParams.ldmParams; params.fParams = fParams; - ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, + params.maxBlockSize = srcCCtx->appliedParams.maxBlockSize; + ZSTD_resetCCtx_internal(dstCCtx, ¶ms, pledgedSrcSize, + /* loadedDictSize */ 0, ZSTDcrp_leaveDirty, zbuff); assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog); assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy); @@ -1795,18 +2534,22 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, ZSTD_cwksp_mark_tables_dirty(&dstCCtx->workspace); /* copy tables */ - { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog); + { size_t const chainSize = ZSTD_allocateChainTable(srcCCtx->appliedParams.cParams.strategy, + srcCCtx->appliedParams.useRowMatchFinder, + 0 /* forDDSDict */) + ? ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog) + : 0; size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog; int const h3log = srcCCtx->blockState.matchState.hashLog3; size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0; - memcpy(dstCCtx->blockState.matchState.hashTable, + ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable, srcCCtx->blockState.matchState.hashTable, hSize * sizeof(U32)); - memcpy(dstCCtx->blockState.matchState.chainTable, + ZSTD_memcpy(dstCCtx->blockState.matchState.chainTable, srcCCtx->blockState.matchState.chainTable, chainSize * sizeof(U32)); - memcpy(dstCCtx->blockState.matchState.hashTable3, + ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable3, srcCCtx->blockState.matchState.hashTable3, h3Size * sizeof(U32)); } @@ -1822,9 +2565,10 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; } dstCCtx->dictID = srcCCtx->dictID; + dstCCtx->dictContentSize = srcCCtx->dictContentSize; /* copy block state */ - memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock)); + ZSTD_memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock)); return 0; } @@ -1837,7 +2581,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize) { ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; - ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0); + ZSTD_buffered_policy_e const zbuff = srcCCtx->bufferedPolicy; ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1); if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN); @@ -1861,31 +2605,25 @@ ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerVa int const nbRows = (int)size / ZSTD_ROWSIZE; int cellNb = 0; int rowNb; + /* Protect special index values < ZSTD_WINDOW_START_INDEX. */ + U32 const reducerThreshold = reducerValue + ZSTD_WINDOW_START_INDEX; assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */ assert(size < (1U<<31)); /* can be casted to int */ -#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) - /* To validate that the table re-use logic is sound, and that we don't - * access table space that we haven't cleaned, we re-"poison" the table - * space every time we mark it dirty. - * - * This function however is intended to operate on those dirty tables and - * re-clean them. So when this function is used correctly, we can unpoison - * the memory it operated on. This introduces a blind spot though, since - * if we now try to operate on __actually__ poisoned memory, we will not - * detect that. */ - __msan_unpoison(table, size * sizeof(U32)); -#endif - for (rowNb=0 ; rowNb < nbRows ; rowNb++) { int column; for (column=0; columnhashTable, hSize, reducerValue); } - if (params->cParams.strategy != ZSTD_fast) { + if (ZSTD_allocateChainTable(params->cParams.strategy, params->useRowMatchFinder, (U32)ms->dedicatedDictSearch)) { U32 const chainSize = (U32)1 << params->cParams.chainLog; if (params->cParams.strategy == ZSTD_btlazy2) ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue); @@ -1929,7 +2667,7 @@ static void ZSTD_reduceIndex (ZSTD_matchState_t* ms, ZSTD_CCtx_params const* par /* See doc/zstd_compression_format.md for detailed format description */ -void ZSTD_seqToCodes(const seqStore_t* seqStorePtr) +int ZSTD_seqToCodes(const seqStore_t* seqStorePtr) { const seqDef* const sequences = seqStorePtr->sequencesStart; BYTE* const llCodeTable = seqStorePtr->llCode; @@ -1937,18 +2675,24 @@ void ZSTD_seqToCodes(const seqStore_t* seqStorePtr) BYTE* const mlCodeTable = seqStorePtr->mlCode; U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); U32 u; + int longOffsets = 0; assert(nbSeq <= seqStorePtr->maxNbSeq); for (u=0; u= STREAM_ACCUMULATOR_MIN)); + if (MEM_32bits() && ofCode >= STREAM_ACCUMULATOR_MIN) + longOffsets = 1; } - if (seqStorePtr->longLengthID==1) + if (seqStorePtr->longLengthType==ZSTD_llt_literalLength) llCodeTable[seqStorePtr->longLengthPos] = MaxLL; - if (seqStorePtr->longLengthID==2) + if (seqStorePtr->longLengthType==ZSTD_llt_matchLength) mlCodeTable[seqStorePtr->longLengthPos] = MaxML; + return longOffsets; } /* ZSTD_useTargetCBlockSize(): @@ -1961,49 +2705,211 @@ static int ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params* cctxParams) return (cctxParams->targetCBlockSize != 0); } -/* ZSTD_compressSequences_internal(): - * actually compresses both literals and sequences */ +/* ZSTD_blockSplitterEnabled(): + * Returns if block splitting param is being used + * If used, compression will do best effort to split a block in order to improve compression ratio. + * At the time this function is called, the parameter must be finalized. + * Returns 1 if true, 0 otherwise. */ +static int ZSTD_blockSplitterEnabled(ZSTD_CCtx_params* cctxParams) +{ + DEBUGLOG(5, "ZSTD_blockSplitterEnabled (useBlockSplitter=%d)", cctxParams->useBlockSplitter); + assert(cctxParams->useBlockSplitter != ZSTD_ps_auto); + return (cctxParams->useBlockSplitter == ZSTD_ps_enable); +} + +/* Type returned by ZSTD_buildSequencesStatistics containing finalized symbol encoding types + * and size of the sequences statistics + */ +typedef struct { + U32 LLtype; + U32 Offtype; + U32 MLtype; + size_t size; + size_t lastCountSize; /* Accounts for bug in 1.3.4. More detail in ZSTD_entropyCompressSeqStore_internal() */ + int longOffsets; +} ZSTD_symbolEncodingTypeStats_t; + +/* ZSTD_buildSequencesStatistics(): + * Returns a ZSTD_symbolEncodingTypeStats_t, or a zstd error code in the `size` field. + * Modifies `nextEntropy` to have the appropriate values as a side effect. + * nbSeq must be greater than 0. + * + * entropyWkspSize must be of size at least ENTROPY_WORKSPACE_SIZE - (MaxSeq + 1)*sizeof(U32) + */ +static ZSTD_symbolEncodingTypeStats_t +ZSTD_buildSequencesStatistics( + const seqStore_t* seqStorePtr, size_t nbSeq, + const ZSTD_fseCTables_t* prevEntropy, ZSTD_fseCTables_t* nextEntropy, + BYTE* dst, const BYTE* const dstEnd, + ZSTD_strategy strategy, unsigned* countWorkspace, + void* entropyWorkspace, size_t entropyWkspSize) +{ + BYTE* const ostart = dst; + const BYTE* const oend = dstEnd; + BYTE* op = ostart; + FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable; + FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable; + FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable; + const BYTE* const ofCodeTable = seqStorePtr->ofCode; + const BYTE* const llCodeTable = seqStorePtr->llCode; + const BYTE* const mlCodeTable = seqStorePtr->mlCode; + ZSTD_symbolEncodingTypeStats_t stats; + + stats.lastCountSize = 0; + /* convert length/distances into codes */ + stats.longOffsets = ZSTD_seqToCodes(seqStorePtr); + assert(op <= oend); + assert(nbSeq != 0); /* ZSTD_selectEncodingType() divides by nbSeq */ + /* build CTable for Literal Lengths */ + { unsigned max = MaxLL; + size_t const mostFrequent = HIST_countFast_wksp(countWorkspace, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ + DEBUGLOG(5, "Building LL table"); + nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode; + stats.LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode, + countWorkspace, max, mostFrequent, nbSeq, + LLFSELog, prevEntropy->litlengthCTable, + LL_defaultNorm, LL_defaultNormLog, + ZSTD_defaultAllowed, strategy); + assert(set_basic < set_compressed && set_rle < set_compressed); + assert(!(stats.LLtype < set_compressed && nextEntropy->litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ + { size_t const countSize = ZSTD_buildCTable( + op, (size_t)(oend - op), + CTable_LitLength, LLFSELog, (symbolEncodingType_e)stats.LLtype, + countWorkspace, max, llCodeTable, nbSeq, + LL_defaultNorm, LL_defaultNormLog, MaxLL, + prevEntropy->litlengthCTable, + sizeof(prevEntropy->litlengthCTable), + entropyWorkspace, entropyWkspSize); + if (ZSTD_isError(countSize)) { + DEBUGLOG(3, "ZSTD_buildCTable for LitLens failed"); + stats.size = countSize; + return stats; + } + if (stats.LLtype == set_compressed) + stats.lastCountSize = countSize; + op += countSize; + assert(op <= oend); + } } + /* build CTable for Offsets */ + { unsigned max = MaxOff; + size_t const mostFrequent = HIST_countFast_wksp( + countWorkspace, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ + /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ + ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; + DEBUGLOG(5, "Building OF table"); + nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode; + stats.Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode, + countWorkspace, max, mostFrequent, nbSeq, + OffFSELog, prevEntropy->offcodeCTable, + OF_defaultNorm, OF_defaultNormLog, + defaultPolicy, strategy); + assert(!(stats.Offtype < set_compressed && nextEntropy->offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ + { size_t const countSize = ZSTD_buildCTable( + op, (size_t)(oend - op), + CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)stats.Offtype, + countWorkspace, max, ofCodeTable, nbSeq, + OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, + prevEntropy->offcodeCTable, + sizeof(prevEntropy->offcodeCTable), + entropyWorkspace, entropyWkspSize); + if (ZSTD_isError(countSize)) { + DEBUGLOG(3, "ZSTD_buildCTable for Offsets failed"); + stats.size = countSize; + return stats; + } + if (stats.Offtype == set_compressed) + stats.lastCountSize = countSize; + op += countSize; + assert(op <= oend); + } } + /* build CTable for MatchLengths */ + { unsigned max = MaxML; + size_t const mostFrequent = HIST_countFast_wksp( + countWorkspace, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ + DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op)); + nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode; + stats.MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode, + countWorkspace, max, mostFrequent, nbSeq, + MLFSELog, prevEntropy->matchlengthCTable, + ML_defaultNorm, ML_defaultNormLog, + ZSTD_defaultAllowed, strategy); + assert(!(stats.MLtype < set_compressed && nextEntropy->matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ + { size_t const countSize = ZSTD_buildCTable( + op, (size_t)(oend - op), + CTable_MatchLength, MLFSELog, (symbolEncodingType_e)stats.MLtype, + countWorkspace, max, mlCodeTable, nbSeq, + ML_defaultNorm, ML_defaultNormLog, MaxML, + prevEntropy->matchlengthCTable, + sizeof(prevEntropy->matchlengthCTable), + entropyWorkspace, entropyWkspSize); + if (ZSTD_isError(countSize)) { + DEBUGLOG(3, "ZSTD_buildCTable for MatchLengths failed"); + stats.size = countSize; + return stats; + } + if (stats.MLtype == set_compressed) + stats.lastCountSize = countSize; + op += countSize; + assert(op <= oend); + } } + stats.size = (size_t)(op-ostart); + return stats; +} + +/* ZSTD_entropyCompressSeqStore_internal(): + * compresses both literals and sequences + * Returns compressed size of block, or a zstd error. + */ +#define SUSPECT_UNCOMPRESSIBLE_LITERAL_RATIO 20 MEM_STATIC size_t -ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, - const ZSTD_entropyCTables_t* prevEntropy, - ZSTD_entropyCTables_t* nextEntropy, - const ZSTD_CCtx_params* cctxParams, - void* dst, size_t dstCapacity, - void* entropyWorkspace, size_t entropyWkspSize, - const int bmi2) +ZSTD_entropyCompressSeqStore_internal( + const seqStore_t* seqStorePtr, + const ZSTD_entropyCTables_t* prevEntropy, + ZSTD_entropyCTables_t* nextEntropy, + const ZSTD_CCtx_params* cctxParams, + void* dst, size_t dstCapacity, + void* entropyWorkspace, size_t entropyWkspSize, + const int bmi2) { - const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN; ZSTD_strategy const strategy = cctxParams->cParams.strategy; - unsigned count[MaxSeq+1]; + unsigned* count = (unsigned*)entropyWorkspace; FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable; FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable; FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable; - U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */ const seqDef* const sequences = seqStorePtr->sequencesStart; + const size_t nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); const BYTE* const ofCodeTable = seqStorePtr->ofCode; const BYTE* const llCodeTable = seqStorePtr->llCode; const BYTE* const mlCodeTable = seqStorePtr->mlCode; BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + dstCapacity; BYTE* op = ostart; - size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); - BYTE* seqHead; - BYTE* lastNCount = NULL; + size_t lastCountSize; + int longOffsets = 0; + + entropyWorkspace = count + (MaxSeq + 1); + entropyWkspSize -= (MaxSeq + 1) * sizeof(*count); - DEBUGLOG(5, "ZSTD_compressSequences_internal (nbSeq=%zu)", nbSeq); + DEBUGLOG(5, "ZSTD_entropyCompressSeqStore_internal (nbSeq=%zu, dstCapacity=%zu)", nbSeq, dstCapacity); ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<= HUF_WORKSPACE_SIZE); /* Compress literals */ { const BYTE* const literals = seqStorePtr->litStart; + size_t const numSequences = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); + size_t const numLiterals = (size_t)(seqStorePtr->lit - seqStorePtr->litStart); + /* Base suspicion of uncompressibility on ratio of literals to sequences */ + unsigned const suspectUncompressible = (numSequences == 0) || (numLiterals / numSequences >= SUSPECT_UNCOMPRESSIBLE_LITERAL_RATIO); size_t const litSize = (size_t)(seqStorePtr->lit - literals); + size_t const cSize = ZSTD_compressLiterals( - &prevEntropy->huf, &nextEntropy->huf, - cctxParams->cParams.strategy, - ZSTD_disableLiteralsCompression(cctxParams), op, dstCapacity, literals, litSize, entropyWorkspace, entropyWkspSize, - bmi2); + &prevEntropy->huf, &nextEntropy->huf, + cctxParams->cParams.strategy, + ZSTD_literalsCompressionIsDisabled(cctxParams), + suspectUncompressible, bmi2); FORWARD_IF_ERROR(cSize, "ZSTD_compressLiterals failed"); assert(cSize <= dstCapacity); op += cSize; @@ -2026,98 +2932,23 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, assert(op <= oend); if (nbSeq==0) { /* Copy the old tables over as if we repeated them */ - memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse)); + ZSTD_memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse)); return (size_t)(op - ostart); } - - /* seqHead : flags for FSE encoding type */ - seqHead = op++; - assert(op <= oend); - - /* convert length/distances into codes */ - ZSTD_seqToCodes(seqStorePtr); - /* build CTable for Literal Lengths */ - { unsigned max = MaxLL; - size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ - DEBUGLOG(5, "Building LL table"); - nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode; - LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode, - count, max, mostFrequent, nbSeq, - LLFSELog, prevEntropy->fse.litlengthCTable, - ZSTDInternalConstants::LL_defaultNorm, ZSTDInternalConstants::LL_defaultNormLog, - ZSTD_defaultAllowed, strategy); - assert(set_basic < set_compressed && set_rle < set_compressed); - assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ - { size_t const countSize = ZSTD_buildCTable( - op, (size_t)(oend - op), - CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype, - count, max, llCodeTable, nbSeq, - ZSTDInternalConstants::LL_defaultNorm, ZSTDInternalConstants::LL_defaultNormLog, MaxLL, - prevEntropy->fse.litlengthCTable, - sizeof(prevEntropy->fse.litlengthCTable), - entropyWorkspace, entropyWkspSize); - FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed"); - if (LLtype == set_compressed) - lastNCount = op; - op += countSize; - assert(op <= oend); - } } - /* build CTable for Offsets */ - { unsigned max = MaxOff; - size_t const mostFrequent = HIST_countFast_wksp( - count, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ - /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ - ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; - DEBUGLOG(5, "Building OF table"); - nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode; - Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode, - count, max, mostFrequent, nbSeq, - OffFSELog, prevEntropy->fse.offcodeCTable, - ZSTDInternalConstants::OF_defaultNorm, ZSTDInternalConstants::OF_defaultNormLog, - defaultPolicy, strategy); - assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ - { size_t const countSize = ZSTD_buildCTable( - op, (size_t)(oend - op), - CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype, - count, max, ofCodeTable, nbSeq, - ZSTDInternalConstants::OF_defaultNorm, ZSTDInternalConstants::OF_defaultNormLog, DefaultMaxOff, - prevEntropy->fse.offcodeCTable, - sizeof(prevEntropy->fse.offcodeCTable), - entropyWorkspace, entropyWkspSize); - FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed"); - if (Offtype == set_compressed) - lastNCount = op; - op += countSize; - assert(op <= oend); - } } - /* build CTable for MatchLengths */ - { unsigned max = MaxML; - size_t const mostFrequent = HIST_countFast_wksp( - count, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ - DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op)); - nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode; - MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode, - count, max, mostFrequent, nbSeq, - MLFSELog, prevEntropy->fse.matchlengthCTable, - ZSTDInternalConstants::ML_defaultNorm, ZSTDInternalConstants::ML_defaultNormLog, - ZSTD_defaultAllowed, strategy); - assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ - { size_t const countSize = ZSTD_buildCTable( - op, (size_t)(oend - op), - CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype, - count, max, mlCodeTable, nbSeq, - ZSTDInternalConstants::ML_defaultNorm, ZSTDInternalConstants::ML_defaultNormLog, MaxML, - prevEntropy->fse.matchlengthCTable, - sizeof(prevEntropy->fse.matchlengthCTable), - entropyWorkspace, entropyWkspSize); - FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed"); - if (MLtype == set_compressed) - lastNCount = op; - op += countSize; - assert(op <= oend); - } } - - *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); + { BYTE* const seqHead = op++; + /* build stats for sequences */ + const ZSTD_symbolEncodingTypeStats_t stats = + ZSTD_buildSequencesStatistics(seqStorePtr, nbSeq, + &prevEntropy->fse, &nextEntropy->fse, + op, oend, + strategy, count, + entropyWorkspace, entropyWkspSize); + FORWARD_IF_ERROR(stats.size, "ZSTD_buildSequencesStatistics failed!"); + *seqHead = (BYTE)((stats.LLtype<<6) + (stats.Offtype<<4) + (stats.MLtype<<2)); + lastCountSize = stats.lastCountSize; + op += stats.size; + longOffsets = stats.longOffsets; + } { size_t const bitstreamSize = ZSTD_encodeSequences( op, (size_t)(oend - op), @@ -2137,9 +2968,9 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, * In this exceedingly rare case, we will simply emit an uncompressed * block, since it isn't worth optimizing. */ - if (lastNCount && (op - lastNCount) < 4) { - /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ - assert(op - lastNCount == 3); + if (lastCountSize && (lastCountSize + bitstreamSize) < 4) { + /* lastCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ + assert(lastCountSize + bitstreamSize == 3); DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by " "emitting an uncompressed block."); return 0; @@ -2151,16 +2982,17 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, } MEM_STATIC size_t -ZSTD_compressSequences(seqStore_t* seqStorePtr, - const ZSTD_entropyCTables_t* prevEntropy, - ZSTD_entropyCTables_t* nextEntropy, - const ZSTD_CCtx_params* cctxParams, - void* dst, size_t dstCapacity, - size_t srcSize, - void* entropyWorkspace, size_t entropyWkspSize, - int bmi2) -{ - size_t const cSize = ZSTD_compressSequences_internal( +ZSTD_entropyCompressSeqStore( + const seqStore_t* seqStorePtr, + const ZSTD_entropyCTables_t* prevEntropy, + ZSTD_entropyCTables_t* nextEntropy, + const ZSTD_CCtx_params* cctxParams, + void* dst, size_t dstCapacity, + size_t srcSize, + void* entropyWorkspace, size_t entropyWkspSize, + int bmi2) +{ + size_t const cSize = ZSTD_entropyCompressSeqStore_internal( seqStorePtr, prevEntropy, nextEntropy, cctxParams, dst, dstCapacity, entropyWorkspace, entropyWkspSize, bmi2); @@ -2168,60 +3000,108 @@ ZSTD_compressSequences(seqStore_t* seqStorePtr, /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block. * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block. */ - if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity)) + if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity)) { + DEBUGLOG(4, "not enough dstCapacity (%zu) for ZSTD_entropyCompressSeqStore_internal()=> do not compress block", dstCapacity); return 0; /* block not compressed */ - FORWARD_IF_ERROR(cSize, "ZSTD_compressSequences_internal failed"); + } + FORWARD_IF_ERROR(cSize, "ZSTD_entropyCompressSeqStore_internal failed"); /* Check compressibility */ { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy); if (cSize >= maxCSize) return 0; /* block not compressed */ } - + DEBUGLOG(5, "ZSTD_entropyCompressSeqStore() cSize: %zu", cSize); + /* libzstd decoder before > v1.5.4 is not compatible with compressed blocks of size ZSTD_BLOCKSIZE_MAX exactly. + * This restriction is indirectly already fulfilled by respecting ZSTD_minGain() condition above. + */ + assert(cSize < ZSTD_BLOCKSIZE_MAX); return cSize; } /* ZSTD_selectBlockCompressor() : * Not static, but internal use only (used by long distance matcher) * assumption : strat is a valid strategy */ -ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode) +ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_paramSwitch_e useRowMatchFinder, ZSTD_dictMode_e dictMode) { - static const ZSTD_blockCompressor blockCompressor[3][ZSTD_STRATEGY_MAX+1] = { + static const ZSTD_blockCompressor blockCompressor[4][ZSTD_STRATEGY_MAX+1] = { { ZSTD_compressBlock_fast /* default for 0 */, ZSTD_compressBlock_fast, - ZSTD_compressBlock_doubleFast, - ZSTD_compressBlock_greedy, - ZSTD_compressBlock_lazy, - ZSTD_compressBlock_lazy2, - ZSTD_compressBlock_btlazy2, - ZSTD_compressBlock_btopt, - ZSTD_compressBlock_btultra, - ZSTD_compressBlock_btultra2 }, + ZSTD_COMPRESSBLOCK_DOUBLEFAST, + ZSTD_COMPRESSBLOCK_GREEDY, + ZSTD_COMPRESSBLOCK_LAZY, + ZSTD_COMPRESSBLOCK_LAZY2, + ZSTD_COMPRESSBLOCK_BTLAZY2, + ZSTD_COMPRESSBLOCK_BTOPT, + ZSTD_COMPRESSBLOCK_BTULTRA, + ZSTD_COMPRESSBLOCK_BTULTRA2 + }, { ZSTD_compressBlock_fast_extDict /* default for 0 */, ZSTD_compressBlock_fast_extDict, - ZSTD_compressBlock_doubleFast_extDict, - ZSTD_compressBlock_greedy_extDict, - ZSTD_compressBlock_lazy_extDict, - ZSTD_compressBlock_lazy2_extDict, - ZSTD_compressBlock_btlazy2_extDict, - ZSTD_compressBlock_btopt_extDict, - ZSTD_compressBlock_btultra_extDict, - ZSTD_compressBlock_btultra_extDict }, + ZSTD_COMPRESSBLOCK_DOUBLEFAST_EXTDICT, + ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT, + ZSTD_COMPRESSBLOCK_LAZY_EXTDICT, + ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT, + ZSTD_COMPRESSBLOCK_BTLAZY2_EXTDICT, + ZSTD_COMPRESSBLOCK_BTOPT_EXTDICT, + ZSTD_COMPRESSBLOCK_BTULTRA_EXTDICT, + ZSTD_COMPRESSBLOCK_BTULTRA_EXTDICT + }, { ZSTD_compressBlock_fast_dictMatchState /* default for 0 */, ZSTD_compressBlock_fast_dictMatchState, - ZSTD_compressBlock_doubleFast_dictMatchState, - ZSTD_compressBlock_greedy_dictMatchState, - ZSTD_compressBlock_lazy_dictMatchState, - ZSTD_compressBlock_lazy2_dictMatchState, - ZSTD_compressBlock_btlazy2_dictMatchState, - ZSTD_compressBlock_btopt_dictMatchState, - ZSTD_compressBlock_btultra_dictMatchState, - ZSTD_compressBlock_btultra_dictMatchState } + ZSTD_COMPRESSBLOCK_DOUBLEFAST_DICTMATCHSTATE, + ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE, + ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE, + ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE, + ZSTD_COMPRESSBLOCK_BTLAZY2_DICTMATCHSTATE, + ZSTD_COMPRESSBLOCK_BTOPT_DICTMATCHSTATE, + ZSTD_COMPRESSBLOCK_BTULTRA_DICTMATCHSTATE, + ZSTD_COMPRESSBLOCK_BTULTRA_DICTMATCHSTATE + }, + { NULL /* default for 0 */, + NULL, + NULL, + ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH, + ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH, + ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH, + NULL, + NULL, + NULL, + NULL } }; ZSTD_blockCompressor selectedCompressor; ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1); assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat)); - selectedCompressor = blockCompressor[(int)dictMode][(int)strat]; + DEBUGLOG(4, "Selected block compressor: dictMode=%d strat=%d rowMatchfinder=%d", (int)dictMode, (int)strat, (int)useRowMatchFinder); + if (ZSTD_rowMatchFinderUsed(strat, useRowMatchFinder)) { + static const ZSTD_blockCompressor rowBasedBlockCompressors[4][3] = { + { + ZSTD_COMPRESSBLOCK_GREEDY_ROW, + ZSTD_COMPRESSBLOCK_LAZY_ROW, + ZSTD_COMPRESSBLOCK_LAZY2_ROW + }, + { + ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT_ROW, + ZSTD_COMPRESSBLOCK_LAZY_EXTDICT_ROW, + ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT_ROW + }, + { + ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE_ROW, + ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE_ROW, + ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE_ROW + }, + { + ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH_ROW, + ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH_ROW, + ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH_ROW + } + }; + DEBUGLOG(4, "Selecting a row-based matchfinder"); + assert(useRowMatchFinder != ZSTD_ps_auto); + selectedCompressor = rowBasedBlockCompressors[(int)dictMode][(int)strat - (int)ZSTD_greedy]; + } else { + selectedCompressor = blockCompressor[(int)dictMode][(int)strat]; + } assert(selectedCompressor != NULL); return selectedCompressor; } @@ -2229,7 +3109,7 @@ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMo static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr, const BYTE* anchor, size_t lastLLSize) { - memcpy(seqStorePtr->lit, anchor, lastLLSize); + ZSTD_memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } @@ -2237,7 +3117,73 @@ void ZSTD_resetSeqStore(seqStore_t* ssPtr) { ssPtr->lit = ssPtr->litStart; ssPtr->sequences = ssPtr->sequencesStart; - ssPtr->longLengthID = 0; + ssPtr->longLengthType = ZSTD_llt_none; +} + +/* ZSTD_postProcessSequenceProducerResult() : + * Validates and post-processes sequences obtained through the external matchfinder API: + * - Checks whether nbExternalSeqs represents an error condition. + * - Appends a block delimiter to outSeqs if one is not already present. + * See zstd.h for context regarding block delimiters. + * Returns the number of sequences after post-processing, or an error code. */ +static size_t ZSTD_postProcessSequenceProducerResult( + ZSTD_Sequence* outSeqs, size_t nbExternalSeqs, size_t outSeqsCapacity, size_t srcSize +) { + RETURN_ERROR_IF( + nbExternalSeqs > outSeqsCapacity, + sequenceProducer_failed, + "External sequence producer returned error code %lu", + (unsigned long)nbExternalSeqs + ); + + RETURN_ERROR_IF( + nbExternalSeqs == 0 && srcSize > 0, + sequenceProducer_failed, + "Got zero sequences from external sequence producer for a non-empty src buffer!" + ); + + if (srcSize == 0) { + ZSTD_memset(&outSeqs[0], 0, sizeof(ZSTD_Sequence)); + return 1; + } + + { + ZSTD_Sequence const lastSeq = outSeqs[nbExternalSeqs - 1]; + + /* We can return early if lastSeq is already a block delimiter. */ + if (lastSeq.offset == 0 && lastSeq.matchLength == 0) { + return nbExternalSeqs; + } + + /* This error condition is only possible if the external matchfinder + * produced an invalid parse, by definition of ZSTD_sequenceBound(). */ + RETURN_ERROR_IF( + nbExternalSeqs == outSeqsCapacity, + sequenceProducer_failed, + "nbExternalSeqs == outSeqsCapacity but lastSeq is not a block delimiter!" + ); + + /* lastSeq is not a block delimiter, so we need to append one. */ + ZSTD_memset(&outSeqs[nbExternalSeqs], 0, sizeof(ZSTD_Sequence)); + return nbExternalSeqs + 1; + } +} + +/* ZSTD_fastSequenceLengthSum() : + * Returns sum(litLen) + sum(matchLen) + lastLits for *seqBuf*. + * Similar to another function in zstd_compress.c (determine_blockSize), + * except it doesn't check for a block delimiter to end summation. + * Removing the early exit allows the compiler to auto-vectorize (https://godbolt.org/z/cY1cajz9P). + * This function can be deleted and replaced by determine_blockSize after we resolve issue #3456. */ +static size_t ZSTD_fastSequenceLengthSum(ZSTD_Sequence const* seqBuf, size_t seqBufSize) { + size_t matchLenSum, litLenSum, i; + matchLenSum = 0; + litLenSum = 0; + for (i = 0; i < seqBufSize; i++) { + litLenSum += seqBuf[i].litLength; + matchLenSum += seqBuf[i].matchLength; + } + return litLenSum + matchLenSum; } typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e; @@ -2249,8 +3195,14 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) assert(srcSize <= ZSTD_BLOCKSIZE_MAX); /* Assert that we have correctly flushed the ctx params into the ms's copy */ ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams); - if (srcSize < MIN_CBLOCK_SIZE+ZSTDInternalConstants::ZSTD_blockHeaderSize+1) { - ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch); + /* TODO: See 3090. We reduced MIN_CBLOCK_SIZE from 3 to 2 so to compensate we are adding + * additional 1. We need to revisit and change this logic to be more consistent */ + if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1+1) { + if (zc->appliedParams.cParams.strategy >= ZSTD_btopt) { + ZSTD_ldm_skipRawSeqStoreBytes(&zc->externSeqStore, srcSize); + } else { + ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch); + } return ZSTDbss_noCompress; /* don't even attempt compression below a certain srcSize */ } ZSTD_resetSeqStore(&(zc->seqStore)); @@ -2266,10 +3218,10 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) /* limited update after a very long match */ { const BYTE* const base = ms->window.base; const BYTE* const istart = (const BYTE*)src; - const U32 current = (U32)(istart-base); + const U32 curr = (U32)(istart-base); if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); /* ensure no overflow */ - if (current > ms->nextToUpdate + 384) - ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384)); + if (curr > ms->nextToUpdate + 384) + ms->nextToUpdate = curr - MIN(192, (U32)(curr - ms->nextToUpdate - 384)); } /* select and store sequences */ @@ -2280,16 +3232,34 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i]; } if (zc->externSeqStore.pos < zc->externSeqStore.size) { - assert(!zc->appliedParams.ldmParams.enableLdm); + assert(zc->appliedParams.ldmParams.enableLdm == ZSTD_ps_disable); + + /* External matchfinder + LDM is technically possible, just not implemented yet. + * We need to revisit soon and implement it. */ + RETURN_ERROR_IF( + ZSTD_hasExtSeqProd(&zc->appliedParams), + parameter_combination_unsupported, + "Long-distance matching with external sequence producer enabled is not currently supported." + ); + /* Updates ldmSeqStore.pos */ lastLLSize = ZSTD_ldm_blockCompress(&zc->externSeqStore, ms, &zc->seqStore, zc->blockState.nextCBlock->rep, + zc->appliedParams.useRowMatchFinder, src, srcSize); assert(zc->externSeqStore.pos <= zc->externSeqStore.size); - } else if (zc->appliedParams.ldmParams.enableLdm) { - rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0}; + } else if (zc->appliedParams.ldmParams.enableLdm == ZSTD_ps_enable) { + rawSeqStore_t ldmSeqStore = kNullRawSeqStore; + + /* External matchfinder + LDM is technically possible, just not implemented yet. + * We need to revisit soon and implement it. */ + RETURN_ERROR_IF( + ZSTD_hasExtSeqProd(&zc->appliedParams), + parameter_combination_unsupported, + "Long-distance matching with external sequence producer enabled is not currently supported." + ); ldmSeqStore.seq = zc->ldmSequences; ldmSeqStore.capacity = zc->maxNbLdmSequences; @@ -2302,10 +3272,78 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) ZSTD_ldm_blockCompress(&ldmSeqStore, ms, &zc->seqStore, zc->blockState.nextCBlock->rep, + zc->appliedParams.useRowMatchFinder, src, srcSize); assert(ldmSeqStore.pos == ldmSeqStore.size); - } else { /* not long range mode */ - ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode); + } else if (ZSTD_hasExtSeqProd(&zc->appliedParams)) { + assert( + zc->extSeqBufCapacity >= ZSTD_sequenceBound(srcSize) + ); + assert(zc->appliedParams.extSeqProdFunc != NULL); + + { U32 const windowSize = (U32)1 << zc->appliedParams.cParams.windowLog; + + size_t const nbExternalSeqs = (zc->appliedParams.extSeqProdFunc)( + zc->appliedParams.extSeqProdState, + zc->extSeqBuf, + zc->extSeqBufCapacity, + src, srcSize, + NULL, 0, /* dict and dictSize, currently not supported */ + zc->appliedParams.compressionLevel, + windowSize + ); + + size_t const nbPostProcessedSeqs = ZSTD_postProcessSequenceProducerResult( + zc->extSeqBuf, + nbExternalSeqs, + zc->extSeqBufCapacity, + srcSize + ); + + /* Return early if there is no error, since we don't need to worry about last literals */ + if (!ZSTD_isError(nbPostProcessedSeqs)) { + ZSTD_sequencePosition seqPos = {0,0,0}; + size_t const seqLenSum = ZSTD_fastSequenceLengthSum(zc->extSeqBuf, nbPostProcessedSeqs); + RETURN_ERROR_IF(seqLenSum > srcSize, externalSequences_invalid, "External sequences imply too large a block!"); + FORWARD_IF_ERROR( + ZSTD_copySequencesToSeqStoreExplicitBlockDelim( + zc, &seqPos, + zc->extSeqBuf, nbPostProcessedSeqs, + src, srcSize, + zc->appliedParams.searchForExternalRepcodes + ), + "Failed to copy external sequences to seqStore!" + ); + ms->ldmSeqStore = NULL; + DEBUGLOG(5, "Copied %lu sequences from external sequence producer to internal seqStore.", (unsigned long)nbExternalSeqs); + return ZSTDbss_compress; + } + + /* Propagate the error if fallback is disabled */ + if (!zc->appliedParams.enableMatchFinderFallback) { + return nbPostProcessedSeqs; + } + + /* Fallback to software matchfinder */ + { ZSTD_blockCompressor const blockCompressor = + ZSTD_selectBlockCompressor( + zc->appliedParams.cParams.strategy, + zc->appliedParams.useRowMatchFinder, + dictMode); + ms->ldmSeqStore = NULL; + DEBUGLOG( + 5, + "External sequence producer returned error code %lu. Falling back to internal parser.", + (unsigned long)nbExternalSeqs + ); + lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize); + } } + } else { /* not long range mode and no external matchfinder */ + ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor( + zc->appliedParams.cParams.strategy, + zc->appliedParams.useRowMatchFinder, + dictMode); + ms->ldmSeqStore = NULL; lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize); } { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize; @@ -2314,63 +3352,113 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) return ZSTDbss_compress; } -static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc) +static size_t ZSTD_copyBlockSequences(SeqCollector* seqCollector, const seqStore_t* seqStore, const U32 prevRepcodes[ZSTD_REP_NUM]) { - const seqStore_t* seqStore = ZSTD_getSeqStore(zc); - const seqDef* seqs = seqStore->sequencesStart; - size_t seqsSize = seqStore->sequences - seqs; - - ZSTD_Sequence* outSeqs = &zc->seqCollector.seqStart[zc->seqCollector.seqIndex]; - size_t i; size_t position; int repIdx; + const seqDef* inSeqs = seqStore->sequencesStart; + const size_t nbInSequences = seqStore->sequences - inSeqs; + const size_t nbInLiterals = (size_t)(seqStore->lit - seqStore->litStart); - assert(zc->seqCollector.seqIndex + 1 < zc->seqCollector.maxSequences); - for (i = 0, position = 0; i < seqsSize; ++i) { - outSeqs[i].offset = seqs[i].offset; - outSeqs[i].litLength = seqs[i].litLength; - outSeqs[i].matchLength = seqs[i].matchLength + MINMATCH; + ZSTD_Sequence* outSeqs = seqCollector->seqIndex == 0 ? seqCollector->seqStart : seqCollector->seqStart + seqCollector->seqIndex; + const size_t nbOutSequences = nbInSequences + 1; + size_t nbOutLiterals = 0; + repcodes_t repcodes; + size_t i; + /* Bounds check that we have enough space for every input sequence + * and the block delimiter + */ + assert(seqCollector->seqIndex <= seqCollector->maxSequences); + RETURN_ERROR_IF( + nbOutSequences > (size_t)(seqCollector->maxSequences - seqCollector->seqIndex), + dstSize_tooSmall, + "Not enough space to copy sequences"); + + ZSTD_memcpy(&repcodes, prevRepcodes, sizeof(repcodes)); + for (i = 0; i < nbInSequences; ++i) { + U32 rawOffset; + outSeqs[i].litLength = inSeqs[i].litLength; + outSeqs[i].matchLength = inSeqs[i].mlBase + MINMATCH; + outSeqs[i].rep = 0; + + /* Handle the possible single length >= 64K + * There can only be one because we add MINMATCH to every match length, + * and blocks are at most 128K. + */ if (i == seqStore->longLengthPos) { - if (seqStore->longLengthID == 1) { + if (seqStore->longLengthType == ZSTD_llt_literalLength) { outSeqs[i].litLength += 0x10000; - } else if (seqStore->longLengthID == 2) { + } else if (seqStore->longLengthType == ZSTD_llt_matchLength) { outSeqs[i].matchLength += 0x10000; } } - if (outSeqs[i].offset <= ZSTD_REP_NUM) { - outSeqs[i].rep = outSeqs[i].offset; - repIdx = (unsigned int)i - outSeqs[i].offset; - - if (outSeqs[i].litLength == 0) { - if (outSeqs[i].offset < 3) { - --repIdx; + /* Determine the raw offset given the offBase, which may be a repcode. */ + if (OFFBASE_IS_REPCODE(inSeqs[i].offBase)) { + const U32 repcode = OFFBASE_TO_REPCODE(inSeqs[i].offBase); + assert(repcode > 0); + outSeqs[i].rep = repcode; + if (outSeqs[i].litLength != 0) { + rawOffset = repcodes.rep[repcode - 1]; + } else { + if (repcode == 3) { + assert(repcodes.rep[0] > 1); + rawOffset = repcodes.rep[0] - 1; } else { - repIdx = (unsigned int)i - 1; + rawOffset = repcodes.rep[repcode]; } - ++outSeqs[i].rep; - } - assert(repIdx >= -3); - outSeqs[i].offset = repIdx >= 0 ? outSeqs[repIdx].offset : ZSTDInternalConstants::repStartValue[-repIdx - 1]; - if (outSeqs[i].rep == 4) { - --outSeqs[i].offset; } } else { - outSeqs[i].offset -= ZSTD_REP_NUM; + rawOffset = OFFBASE_TO_OFFSET(inSeqs[i].offBase); } + outSeqs[i].offset = rawOffset; - position += outSeqs[i].litLength; - outSeqs[i].matchPos = (unsigned int)position; - position += outSeqs[i].matchLength; + /* Update repcode history for the sequence */ + ZSTD_updateRep(repcodes.rep, + inSeqs[i].offBase, + inSeqs[i].litLength == 0); + + nbOutLiterals += outSeqs[i].litLength; + } + /* Insert last literals (if any exist) in the block as a sequence with ml == off == 0. + * If there are no last literals, then we'll emit (of: 0, ml: 0, ll: 0), which is a marker + * for the block boundary, according to the API. + */ + assert(nbInLiterals >= nbOutLiterals); + { + const size_t lastLLSize = nbInLiterals - nbOutLiterals; + outSeqs[nbInSequences].litLength = (U32)lastLLSize; + outSeqs[nbInSequences].matchLength = 0; + outSeqs[nbInSequences].offset = 0; + assert(nbOutSequences == nbInSequences + 1); } - zc->seqCollector.seqIndex += seqsSize; + seqCollector->seqIndex += nbOutSequences; + assert(seqCollector->seqIndex <= seqCollector->maxSequences); + + return 0; } -size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, - size_t outSeqsSize, const void* src, size_t srcSize) +size_t ZSTD_sequenceBound(size_t srcSize) { + const size_t maxNbSeq = (srcSize / ZSTD_MINMATCH_MIN) + 1; + const size_t maxNbDelims = (srcSize / ZSTD_BLOCKSIZE_MAX_MIN) + 1; + return maxNbSeq + maxNbDelims; +} + +size_t ZSTD_generateSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, + size_t outSeqsSize, const void* src, size_t srcSize) { const size_t dstCapacity = ZSTD_compressBound(srcSize); - void* dst = ZSTD_malloc(dstCapacity, ZSTDInternalConstants::ZSTD_defaultCMem); + void* dst = ZSTD_customMalloc(dstCapacity, ZSTD_defaultCMem); SeqCollector seqCollector; + { + int targetCBlockSize; + FORWARD_IF_ERROR(ZSTD_CCtx_getParameter(zc, ZSTD_c_targetCBlockSize, &targetCBlockSize), ""); + RETURN_ERROR_IF(targetCBlockSize != 0, parameter_unsupported, "targetCBlockSize != 0"); + } + { + int nbWorkers; + FORWARD_IF_ERROR(ZSTD_CCtx_getParameter(zc, ZSTD_c_nbWorkers, &nbWorkers), ""); + RETURN_ERROR_IF(nbWorkers != 0, parameter_unsupported, "nbWorkers != 0"); + } RETURN_ERROR_IF(dst == NULL, memory_allocation, "NULL pointer!"); @@ -2380,18 +3468,51 @@ size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, seqCollector.maxSequences = outSeqsSize; zc->seqCollector = seqCollector; - ZSTD_compress2(zc, dst, dstCapacity, src, srcSize); - ZSTD_free(dst, ZSTDInternalConstants::ZSTD_defaultCMem); + { + const size_t ret = ZSTD_compress2(zc, dst, dstCapacity, src, srcSize); + ZSTD_customFree(dst, ZSTD_defaultCMem); + FORWARD_IF_ERROR(ret, "ZSTD_compress2 failed"); + } + assert(zc->seqCollector.seqIndex <= ZSTD_sequenceBound(srcSize)); return zc->seqCollector.seqIndex; } -/* Returns true if the given block is a RLE block */ -static int ZSTD_isRLE(const BYTE *ip, size_t length) { +size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize) { + size_t in = 0; + size_t out = 0; + for (; in < seqsSize; ++in) { + if (sequences[in].offset == 0 && sequences[in].matchLength == 0) { + if (in != seqsSize - 1) { + sequences[in+1].litLength += sequences[in].litLength; + } + } else { + sequences[out] = sequences[in]; + ++out; + } + } + return out; +} + +/* Unrolled loop to read four size_ts of input at a time. Returns 1 if is RLE, 0 if not. */ +static int ZSTD_isRLE(const BYTE* src, size_t length) { + const BYTE* ip = src; + const BYTE value = ip[0]; + const size_t valueST = (size_t)((U64)value * 0x0101010101010101ULL); + const size_t unrollSize = sizeof(size_t) * 4; + const size_t unrollMask = unrollSize - 1; + const size_t prefixLength = length & unrollMask; size_t i; - if (length < 2) return 1; - for (i = 1; i < length; ++i) { - if (ip[0] != ip[i]) return 0; + if (length == 1) return 1; + /* Check if prefix is RLE first before using unrolled loop */ + if (prefixLength && ZSTD_count(ip+1, ip, ip+prefixLength) != prefixLength-1) { + return 0; } + for (i = prefixLength; i != length; i += unrollSize) { + size_t u; + for (u = 0; u < unrollSize; u += sizeof(size_t)) { + if (MEM_readST(ip + i + u) != valueST) { + return 0; + } } } return 1; } @@ -2407,81 +3528,856 @@ static int ZSTD_maybeRLE(seqStore_t const* seqStore) return nbSeqs < 4 && nbLits < 10; } -static void ZSTD_confirmRepcodesAndEntropyTables(ZSTD_CCtx* zc) +static void +ZSTD_blockState_confirmRepcodesAndEntropyTables(ZSTD_blockState_t* const bs) { - ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock; - zc->blockState.prevCBlock = zc->blockState.nextCBlock; - zc->blockState.nextCBlock = tmp; + ZSTD_compressedBlockState_t* const tmp = bs->prevCBlock; + bs->prevCBlock = bs->nextCBlock; + bs->nextCBlock = tmp; } -static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, U32 frame) +/* Writes the block header */ +static void +writeBlockHeader(void* op, size_t cSize, size_t blockSize, U32 lastBlock) { - /* This the upper bound for the length of an rle block. - * This isn't the actual upper bound. Finding the real threshold - * needs further investigation. - */ - const U32 rleMaxLength = 25; - size_t cSize; - const BYTE* ip = (const BYTE*)src; - BYTE* op = (BYTE*)dst; - DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", - (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, - (unsigned)zc->blockState.matchState.nextToUpdate); - - { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); - FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); - if (bss == ZSTDbss_noCompress) { cSize = 0; goto out; } - } + U32 const cBlockHeader = cSize == 1 ? + lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) : + lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); + MEM_writeLE24(op, cBlockHeader); + DEBUGLOG(3, "writeBlockHeader: cSize: %zu blockSize: %zu lastBlock: %u", cSize, blockSize, lastBlock); +} - if (zc->seqCollector.collectSequences) { - ZSTD_copyBlockSequences(zc); +/** ZSTD_buildBlockEntropyStats_literals() : + * Builds entropy for the literals. + * Stores literals block type (raw, rle, compressed, repeat) and + * huffman description table to hufMetadata. + * Requires ENTROPY_WORKSPACE_SIZE workspace + * @return : size of huffman description table, or an error code + */ +static size_t +ZSTD_buildBlockEntropyStats_literals(void* const src, size_t srcSize, + const ZSTD_hufCTables_t* prevHuf, + ZSTD_hufCTables_t* nextHuf, + ZSTD_hufCTablesMetadata_t* hufMetadata, + const int literalsCompressionIsDisabled, + void* workspace, size_t wkspSize, + int hufFlags) +{ + BYTE* const wkspStart = (BYTE*)workspace; + BYTE* const wkspEnd = wkspStart + wkspSize; + BYTE* const countWkspStart = wkspStart; + unsigned* const countWksp = (unsigned*)workspace; + const size_t countWkspSize = (HUF_SYMBOLVALUE_MAX + 1) * sizeof(unsigned); + BYTE* const nodeWksp = countWkspStart + countWkspSize; + const size_t nodeWkspSize = (size_t)(wkspEnd - nodeWksp); + unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX; + unsigned huffLog = LitHufLog; + HUF_repeat repeat = prevHuf->repeatMode; + DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_literals (srcSize=%zu)", srcSize); + + /* Prepare nextEntropy assuming reusing the existing table */ + ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + + if (literalsCompressionIsDisabled) { + DEBUGLOG(5, "set_basic - disabled"); + hufMetadata->hType = set_basic; return 0; } - /* encode sequences and literals */ - cSize = ZSTD_compressSequences(&zc->seqStore, - &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, - &zc->appliedParams, - dst, dstCapacity, - srcSize, - zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */, - zc->bmi2); + /* small ? don't even attempt compression (speed opt) */ +#ifndef COMPRESS_LITERALS_SIZE_MIN +# define COMPRESS_LITERALS_SIZE_MIN 63 /* heuristic */ +#endif + { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN; + if (srcSize <= minLitSize) { + DEBUGLOG(5, "set_basic - too small"); + hufMetadata->hType = set_basic; + return 0; + } } - if (frame && - /* We don't want to emit our first block as a RLE even if it qualifies because - * doing so will cause the decoder (cli only) to throw a "should consume all input error." - * This is only an issue for zstd <= v1.4.3 - */ - !zc->isFirstBlock && - cSize < rleMaxLength && - ZSTD_isRLE(ip, srcSize)) - { - cSize = 1; - op[0] = ip[0]; - } + /* Scan input and build symbol stats */ + { size_t const largest = + HIST_count_wksp (countWksp, &maxSymbolValue, + (const BYTE*)src, srcSize, + workspace, wkspSize); + FORWARD_IF_ERROR(largest, "HIST_count_wksp failed"); + if (largest == srcSize) { + /* only one literal symbol */ + DEBUGLOG(5, "set_rle"); + hufMetadata->hType = set_rle; + return 0; + } + if (largest <= (srcSize >> 7)+4) { + /* heuristic: likely not compressible */ + DEBUGLOG(5, "set_basic - no gain"); + hufMetadata->hType = set_basic; + return 0; + } } -out: - if (!ZSTD_isError(cSize) && cSize > 1) { - ZSTD_confirmRepcodesAndEntropyTables(zc); + /* Validate the previous Huffman table */ + if (repeat == HUF_repeat_check + && !HUF_validateCTable((HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue)) { + repeat = HUF_repeat_none; } - /* We check that dictionaries have offset codes available for the first - * block. After the first block, the offcode table might not have large - * enough codes to represent the offsets in the data. - */ - if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) - zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; - return cSize; + /* Build Huffman Tree */ + ZSTD_memset(nextHuf->CTable, 0, sizeof(nextHuf->CTable)); + huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue, nodeWksp, nodeWkspSize, nextHuf->CTable, countWksp, hufFlags); + assert(huffLog <= LitHufLog); + { size_t const maxBits = HUF_buildCTable_wksp((HUF_CElt*)nextHuf->CTable, countWksp, + maxSymbolValue, huffLog, + nodeWksp, nodeWkspSize); + FORWARD_IF_ERROR(maxBits, "HUF_buildCTable_wksp"); + huffLog = (U32)maxBits; + } + { /* Build and write the CTable */ + size_t const newCSize = HUF_estimateCompressedSize( + (HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue); + size_t const hSize = HUF_writeCTable_wksp( + hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer), + (HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog, + nodeWksp, nodeWkspSize); + /* Check against repeating the previous CTable */ + if (repeat != HUF_repeat_none) { + size_t const oldCSize = HUF_estimateCompressedSize( + (HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue); + if (oldCSize < srcSize && (oldCSize <= hSize + newCSize || hSize + 12 >= srcSize)) { + DEBUGLOG(5, "set_repeat - smaller"); + ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + hufMetadata->hType = set_repeat; + return 0; + } } + if (newCSize + hSize >= srcSize) { + DEBUGLOG(5, "set_basic - no gains"); + ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + hufMetadata->hType = set_basic; + return 0; + } + DEBUGLOG(5, "set_compressed (hSize=%u)", (U32)hSize); + hufMetadata->hType = set_compressed; + nextHuf->repeatMode = HUF_repeat_check; + return hSize; + } } -static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const size_t bss, U32 lastBlock) + +/* ZSTD_buildDummySequencesStatistics(): + * Returns a ZSTD_symbolEncodingTypeStats_t with all encoding types as set_basic, + * and updates nextEntropy to the appropriate repeatMode. + */ +static ZSTD_symbolEncodingTypeStats_t +ZSTD_buildDummySequencesStatistics(ZSTD_fseCTables_t* nextEntropy) { - DEBUGLOG(6, "Attempting ZSTD_compressSuperBlock()"); + ZSTD_symbolEncodingTypeStats_t stats = {set_basic, set_basic, set_basic, 0, 0, 0}; + nextEntropy->litlength_repeatMode = FSE_repeat_none; + nextEntropy->offcode_repeatMode = FSE_repeat_none; + nextEntropy->matchlength_repeatMode = FSE_repeat_none; + return stats; +} + +/** ZSTD_buildBlockEntropyStats_sequences() : + * Builds entropy for the sequences. + * Stores symbol compression modes and fse table to fseMetadata. + * Requires ENTROPY_WORKSPACE_SIZE wksp. + * @return : size of fse tables or error code */ +static size_t +ZSTD_buildBlockEntropyStats_sequences( + const seqStore_t* seqStorePtr, + const ZSTD_fseCTables_t* prevEntropy, + ZSTD_fseCTables_t* nextEntropy, + const ZSTD_CCtx_params* cctxParams, + ZSTD_fseCTablesMetadata_t* fseMetadata, + void* workspace, size_t wkspSize) +{ + ZSTD_strategy const strategy = cctxParams->cParams.strategy; + size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); + BYTE* const ostart = fseMetadata->fseTablesBuffer; + BYTE* const oend = ostart + sizeof(fseMetadata->fseTablesBuffer); + BYTE* op = ostart; + unsigned* countWorkspace = (unsigned*)workspace; + unsigned* entropyWorkspace = countWorkspace + (MaxSeq + 1); + size_t entropyWorkspaceSize = wkspSize - (MaxSeq + 1) * sizeof(*countWorkspace); + ZSTD_symbolEncodingTypeStats_t stats; + + DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_sequences (nbSeq=%zu)", nbSeq); + stats = nbSeq != 0 ? ZSTD_buildSequencesStatistics(seqStorePtr, nbSeq, + prevEntropy, nextEntropy, op, oend, + strategy, countWorkspace, + entropyWorkspace, entropyWorkspaceSize) + : ZSTD_buildDummySequencesStatistics(nextEntropy); + FORWARD_IF_ERROR(stats.size, "ZSTD_buildSequencesStatistics failed!"); + fseMetadata->llType = (symbolEncodingType_e) stats.LLtype; + fseMetadata->ofType = (symbolEncodingType_e) stats.Offtype; + fseMetadata->mlType = (symbolEncodingType_e) stats.MLtype; + fseMetadata->lastCountSize = stats.lastCountSize; + return stats.size; +} + + +/** ZSTD_buildBlockEntropyStats() : + * Builds entropy for the block. + * Requires workspace size ENTROPY_WORKSPACE_SIZE + * @return : 0 on success, or an error code + * Note : also employed in superblock + */ +size_t ZSTD_buildBlockEntropyStats( + const seqStore_t* seqStorePtr, + const ZSTD_entropyCTables_t* prevEntropy, + ZSTD_entropyCTables_t* nextEntropy, + const ZSTD_CCtx_params* cctxParams, + ZSTD_entropyCTablesMetadata_t* entropyMetadata, + void* workspace, size_t wkspSize) +{ + size_t const litSize = (size_t)(seqStorePtr->lit - seqStorePtr->litStart); + int const huf_useOptDepth = (cctxParams->cParams.strategy >= HUF_OPTIMAL_DEPTH_THRESHOLD); + int const hufFlags = huf_useOptDepth ? HUF_flags_optimalDepth : 0; + + entropyMetadata->hufMetadata.hufDesSize = + ZSTD_buildBlockEntropyStats_literals(seqStorePtr->litStart, litSize, + &prevEntropy->huf, &nextEntropy->huf, + &entropyMetadata->hufMetadata, + ZSTD_literalsCompressionIsDisabled(cctxParams), + workspace, wkspSize, hufFlags); + + FORWARD_IF_ERROR(entropyMetadata->hufMetadata.hufDesSize, "ZSTD_buildBlockEntropyStats_literals failed"); + entropyMetadata->fseMetadata.fseTablesSize = + ZSTD_buildBlockEntropyStats_sequences(seqStorePtr, + &prevEntropy->fse, &nextEntropy->fse, + cctxParams, + &entropyMetadata->fseMetadata, + workspace, wkspSize); + FORWARD_IF_ERROR(entropyMetadata->fseMetadata.fseTablesSize, "ZSTD_buildBlockEntropyStats_sequences failed"); + return 0; +} + +/* Returns the size estimate for the literals section (header + content) of a block */ +static size_t +ZSTD_estimateBlockSize_literal(const BYTE* literals, size_t litSize, + const ZSTD_hufCTables_t* huf, + const ZSTD_hufCTablesMetadata_t* hufMetadata, + void* workspace, size_t wkspSize, + int writeEntropy) +{ + unsigned* const countWksp = (unsigned*)workspace; + unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX; + size_t literalSectionHeaderSize = 3 + (litSize >= 1 KB) + (litSize >= 16 KB); + U32 singleStream = litSize < 256; + + if (hufMetadata->hType == set_basic) return litSize; + else if (hufMetadata->hType == set_rle) return 1; + else if (hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat) { + size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)literals, litSize, workspace, wkspSize); + if (ZSTD_isError(largest)) return litSize; + { size_t cLitSizeEstimate = HUF_estimateCompressedSize((const HUF_CElt*)huf->CTable, countWksp, maxSymbolValue); + if (writeEntropy) cLitSizeEstimate += hufMetadata->hufDesSize; + if (!singleStream) cLitSizeEstimate += 6; /* multi-stream huffman uses 6-byte jump table */ + return cLitSizeEstimate + literalSectionHeaderSize; + } } + assert(0); /* impossible */ + return 0; +} + +/* Returns the size estimate for the FSE-compressed symbols (of, ml, ll) of a block */ +static size_t +ZSTD_estimateBlockSize_symbolType(symbolEncodingType_e type, + const BYTE* codeTable, size_t nbSeq, unsigned maxCode, + const FSE_CTable* fseCTable, + const U8* additionalBits, + short const* defaultNorm, U32 defaultNormLog, U32 defaultMax, + void* workspace, size_t wkspSize) +{ + unsigned* const countWksp = (unsigned*)workspace; + const BYTE* ctp = codeTable; + const BYTE* const ctStart = ctp; + const BYTE* const ctEnd = ctStart + nbSeq; + size_t cSymbolTypeSizeEstimateInBits = 0; + unsigned max = maxCode; + + HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */ + if (type == set_basic) { + /* We selected this encoding type, so it must be valid. */ + assert(max <= defaultMax); + (void)defaultMax; + cSymbolTypeSizeEstimateInBits = ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max); + } else if (type == set_rle) { + cSymbolTypeSizeEstimateInBits = 0; + } else if (type == set_compressed || type == set_repeat) { + cSymbolTypeSizeEstimateInBits = ZSTD_fseBitCost(fseCTable, countWksp, max); + } + if (ZSTD_isError(cSymbolTypeSizeEstimateInBits)) { + return nbSeq * 10; + } + while (ctp < ctEnd) { + if (additionalBits) cSymbolTypeSizeEstimateInBits += additionalBits[*ctp]; + else cSymbolTypeSizeEstimateInBits += *ctp; /* for offset, offset code is also the number of additional bits */ + ctp++; + } + return cSymbolTypeSizeEstimateInBits >> 3; +} + +/* Returns the size estimate for the sequences section (header + content) of a block */ +static size_t +ZSTD_estimateBlockSize_sequences(const BYTE* ofCodeTable, + const BYTE* llCodeTable, + const BYTE* mlCodeTable, + size_t nbSeq, + const ZSTD_fseCTables_t* fseTables, + const ZSTD_fseCTablesMetadata_t* fseMetadata, + void* workspace, size_t wkspSize, + int writeEntropy) +{ + size_t sequencesSectionHeaderSize = 1 /* seqHead */ + 1 /* min seqSize size */ + (nbSeq >= 128) + (nbSeq >= LONGNBSEQ); + size_t cSeqSizeEstimate = 0; + cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, nbSeq, MaxOff, + fseTables->offcodeCTable, NULL, + OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, + workspace, wkspSize); + cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->llType, llCodeTable, nbSeq, MaxLL, + fseTables->litlengthCTable, LL_bits, + LL_defaultNorm, LL_defaultNormLog, MaxLL, + workspace, wkspSize); + cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, nbSeq, MaxML, + fseTables->matchlengthCTable, ML_bits, + ML_defaultNorm, ML_defaultNormLog, MaxML, + workspace, wkspSize); + if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize; + return cSeqSizeEstimate + sequencesSectionHeaderSize; +} + +/* Returns the size estimate for a given stream of literals, of, ll, ml */ +static size_t +ZSTD_estimateBlockSize(const BYTE* literals, size_t litSize, + const BYTE* ofCodeTable, + const BYTE* llCodeTable, + const BYTE* mlCodeTable, + size_t nbSeq, + const ZSTD_entropyCTables_t* entropy, + const ZSTD_entropyCTablesMetadata_t* entropyMetadata, + void* workspace, size_t wkspSize, + int writeLitEntropy, int writeSeqEntropy) +{ + size_t const literalsSize = ZSTD_estimateBlockSize_literal(literals, litSize, + &entropy->huf, &entropyMetadata->hufMetadata, + workspace, wkspSize, writeLitEntropy); + size_t const seqSize = ZSTD_estimateBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable, + nbSeq, &entropy->fse, &entropyMetadata->fseMetadata, + workspace, wkspSize, writeSeqEntropy); + return seqSize + literalsSize + ZSTD_blockHeaderSize; +} + +/* Builds entropy statistics and uses them for blocksize estimation. + * + * @return: estimated compressed size of the seqStore, or a zstd error. + */ +static size_t +ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(seqStore_t* seqStore, ZSTD_CCtx* zc) +{ + ZSTD_entropyCTablesMetadata_t* const entropyMetadata = &zc->blockSplitCtx.entropyMetadata; + DEBUGLOG(6, "ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize()"); + FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(seqStore, + &zc->blockState.prevCBlock->entropy, + &zc->blockState.nextCBlock->entropy, + &zc->appliedParams, + entropyMetadata, + zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE), ""); + return ZSTD_estimateBlockSize( + seqStore->litStart, (size_t)(seqStore->lit - seqStore->litStart), + seqStore->ofCode, seqStore->llCode, seqStore->mlCode, + (size_t)(seqStore->sequences - seqStore->sequencesStart), + &zc->blockState.nextCBlock->entropy, + entropyMetadata, + zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE, + (int)(entropyMetadata->hufMetadata.hType == set_compressed), 1); +} + +/* Returns literals bytes represented in a seqStore */ +static size_t ZSTD_countSeqStoreLiteralsBytes(const seqStore_t* const seqStore) +{ + size_t literalsBytes = 0; + size_t const nbSeqs = (size_t)(seqStore->sequences - seqStore->sequencesStart); + size_t i; + for (i = 0; i < nbSeqs; ++i) { + seqDef const seq = seqStore->sequencesStart[i]; + literalsBytes += seq.litLength; + if (i == seqStore->longLengthPos && seqStore->longLengthType == ZSTD_llt_literalLength) { + literalsBytes += 0x10000; + } } + return literalsBytes; +} + +/* Returns match bytes represented in a seqStore */ +static size_t ZSTD_countSeqStoreMatchBytes(const seqStore_t* const seqStore) +{ + size_t matchBytes = 0; + size_t const nbSeqs = (size_t)(seqStore->sequences - seqStore->sequencesStart); + size_t i; + for (i = 0; i < nbSeqs; ++i) { + seqDef seq = seqStore->sequencesStart[i]; + matchBytes += seq.mlBase + MINMATCH; + if (i == seqStore->longLengthPos && seqStore->longLengthType == ZSTD_llt_matchLength) { + matchBytes += 0x10000; + } } + return matchBytes; +} + +/* Derives the seqStore that is a chunk of the originalSeqStore from [startIdx, endIdx). + * Stores the result in resultSeqStore. + */ +static void ZSTD_deriveSeqStoreChunk(seqStore_t* resultSeqStore, + const seqStore_t* originalSeqStore, + size_t startIdx, size_t endIdx) +{ + *resultSeqStore = *originalSeqStore; + if (startIdx > 0) { + resultSeqStore->sequences = originalSeqStore->sequencesStart + startIdx; + resultSeqStore->litStart += ZSTD_countSeqStoreLiteralsBytes(resultSeqStore); + } + + /* Move longLengthPos into the correct position if necessary */ + if (originalSeqStore->longLengthType != ZSTD_llt_none) { + if (originalSeqStore->longLengthPos < startIdx || originalSeqStore->longLengthPos > endIdx) { + resultSeqStore->longLengthType = ZSTD_llt_none; + } else { + resultSeqStore->longLengthPos -= (U32)startIdx; + } + } + resultSeqStore->sequencesStart = originalSeqStore->sequencesStart + startIdx; + resultSeqStore->sequences = originalSeqStore->sequencesStart + endIdx; + if (endIdx == (size_t)(originalSeqStore->sequences - originalSeqStore->sequencesStart)) { + /* This accounts for possible last literals if the derived chunk reaches the end of the block */ + assert(resultSeqStore->lit == originalSeqStore->lit); + } else { + size_t const literalsBytes = ZSTD_countSeqStoreLiteralsBytes(resultSeqStore); + resultSeqStore->lit = resultSeqStore->litStart + literalsBytes; + } + resultSeqStore->llCode += startIdx; + resultSeqStore->mlCode += startIdx; + resultSeqStore->ofCode += startIdx; +} + +/** + * Returns the raw offset represented by the combination of offBase, ll0, and repcode history. + * offBase must represent a repcode in the numeric representation of ZSTD_storeSeq(). + */ +static U32 +ZSTD_resolveRepcodeToRawOffset(const U32 rep[ZSTD_REP_NUM], const U32 offBase, const U32 ll0) +{ + U32 const adjustedRepCode = OFFBASE_TO_REPCODE(offBase) - 1 + ll0; /* [ 0 - 3 ] */ + assert(OFFBASE_IS_REPCODE(offBase)); + if (adjustedRepCode == ZSTD_REP_NUM) { + assert(ll0); + /* litlength == 0 and offCode == 2 implies selection of first repcode - 1 + * This is only valid if it results in a valid offset value, aka > 0. + * Note : it may happen that `rep[0]==1` in exceptional circumstances. + * In which case this function will return 0, which is an invalid offset. + * It's not an issue though, since this value will be + * compared and discarded within ZSTD_seqStore_resolveOffCodes(). + */ + return rep[0] - 1; + } + return rep[adjustedRepCode]; +} + +/** + * ZSTD_seqStore_resolveOffCodes() reconciles any possible divergences in offset history that may arise + * due to emission of RLE/raw blocks that disturb the offset history, + * and replaces any repcodes within the seqStore that may be invalid. + * + * dRepcodes are updated as would be on the decompression side. + * cRepcodes are updated exactly in accordance with the seqStore. + * + * Note : this function assumes seq->offBase respects the following numbering scheme : + * 0 : invalid + * 1-3 : repcode 1-3 + * 4+ : real_offset+3 + */ +static void +ZSTD_seqStore_resolveOffCodes(repcodes_t* const dRepcodes, repcodes_t* const cRepcodes, + const seqStore_t* const seqStore, U32 const nbSeq) +{ + U32 idx = 0; + U32 const longLitLenIdx = seqStore->longLengthType == ZSTD_llt_literalLength ? seqStore->longLengthPos : nbSeq; + for (; idx < nbSeq; ++idx) { + seqDef* const seq = seqStore->sequencesStart + idx; + U32 const ll0 = (seq->litLength == 0) && (idx != longLitLenIdx); + U32 const offBase = seq->offBase; + assert(offBase > 0); + if (OFFBASE_IS_REPCODE(offBase)) { + U32 const dRawOffset = ZSTD_resolveRepcodeToRawOffset(dRepcodes->rep, offBase, ll0); + U32 const cRawOffset = ZSTD_resolveRepcodeToRawOffset(cRepcodes->rep, offBase, ll0); + /* Adjust simulated decompression repcode history if we come across a mismatch. Replace + * the repcode with the offset it actually references, determined by the compression + * repcode history. + */ + if (dRawOffset != cRawOffset) { + seq->offBase = OFFSET_TO_OFFBASE(cRawOffset); + } + } + /* Compression repcode history is always updated with values directly from the unmodified seqStore. + * Decompression repcode history may use modified seq->offset value taken from compression repcode history. + */ + ZSTD_updateRep(dRepcodes->rep, seq->offBase, ll0); + ZSTD_updateRep(cRepcodes->rep, offBase, ll0); + } +} + +/* ZSTD_compressSeqStore_singleBlock(): + * Compresses a seqStore into a block with a block header, into the buffer dst. + * + * Returns the total size of that block (including header) or a ZSTD error code. + */ +static size_t +ZSTD_compressSeqStore_singleBlock(ZSTD_CCtx* zc, + const seqStore_t* const seqStore, + repcodes_t* const dRep, repcodes_t* const cRep, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + U32 lastBlock, U32 isPartition) +{ + const U32 rleMaxLength = 25; + BYTE* op = (BYTE*)dst; + const BYTE* ip = (const BYTE*)src; + size_t cSize; + size_t cSeqsSize; + + /* In case of an RLE or raw block, the simulated decompression repcode history must be reset */ + repcodes_t const dRepOriginal = *dRep; + DEBUGLOG(5, "ZSTD_compressSeqStore_singleBlock"); + if (isPartition) + ZSTD_seqStore_resolveOffCodes(dRep, cRep, seqStore, (U32)(seqStore->sequences - seqStore->sequencesStart)); + + RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall, "Block header doesn't fit"); + cSeqsSize = ZSTD_entropyCompressSeqStore(seqStore, + &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, + &zc->appliedParams, + op + ZSTD_blockHeaderSize, dstCapacity - ZSTD_blockHeaderSize, + srcSize, + zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, + zc->bmi2); + FORWARD_IF_ERROR(cSeqsSize, "ZSTD_entropyCompressSeqStore failed!"); + + if (!zc->isFirstBlock && + cSeqsSize < rleMaxLength && + ZSTD_isRLE((BYTE const*)src, srcSize)) { + /* We don't want to emit our first block as a RLE even if it qualifies because + * doing so will cause the decoder (cli only) to throw a "should consume all input error." + * This is only an issue for zstd <= v1.4.3 + */ + cSeqsSize = 1; + } + + /* Sequence collection not supported when block splitting */ + if (zc->seqCollector.collectSequences) { + FORWARD_IF_ERROR(ZSTD_copyBlockSequences(&zc->seqCollector, seqStore, dRepOriginal.rep), "copyBlockSequences failed"); + ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); + return 0; + } + + if (cSeqsSize == 0) { + cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, srcSize, lastBlock); + FORWARD_IF_ERROR(cSize, "Nocompress block failed"); + DEBUGLOG(4, "Writing out nocompress block, size: %zu", cSize); + *dRep = dRepOriginal; /* reset simulated decompression repcode history */ + } else if (cSeqsSize == 1) { + cSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, srcSize, lastBlock); + FORWARD_IF_ERROR(cSize, "RLE compress block failed"); + DEBUGLOG(4, "Writing out RLE block, size: %zu", cSize); + *dRep = dRepOriginal; /* reset simulated decompression repcode history */ + } else { + ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); + writeBlockHeader(op, cSeqsSize, srcSize, lastBlock); + cSize = ZSTD_blockHeaderSize + cSeqsSize; + DEBUGLOG(4, "Writing out compressed block, size: %zu", cSize); + } + + if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) + zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; + + return cSize; +} + +/* Struct to keep track of where we are in our recursive calls. */ +typedef struct { + U32* splitLocations; /* Array of split indices */ + size_t idx; /* The current index within splitLocations being worked on */ +} seqStoreSplits; + +#define MIN_SEQUENCES_BLOCK_SPLITTING 300 + +/* Helper function to perform the recursive search for block splits. + * Estimates the cost of seqStore prior to split, and estimates the cost of splitting the sequences in half. + * If advantageous to split, then we recurse down the two sub-blocks. + * If not, or if an error occurred in estimation, then we do not recurse. + * + * Note: The recursion depth is capped by a heuristic minimum number of sequences, + * defined by MIN_SEQUENCES_BLOCK_SPLITTING. + * In theory, this means the absolute largest recursion depth is 10 == log2(maxNbSeqInBlock/MIN_SEQUENCES_BLOCK_SPLITTING). + * In practice, recursion depth usually doesn't go beyond 4. + * + * Furthermore, the number of splits is capped by ZSTD_MAX_NB_BLOCK_SPLITS. + * At ZSTD_MAX_NB_BLOCK_SPLITS == 196 with the current existing blockSize + * maximum of 128 KB, this value is actually impossible to reach. + */ +static void +ZSTD_deriveBlockSplitsHelper(seqStoreSplits* splits, size_t startIdx, size_t endIdx, + ZSTD_CCtx* zc, const seqStore_t* origSeqStore) +{ + seqStore_t* const fullSeqStoreChunk = &zc->blockSplitCtx.fullSeqStoreChunk; + seqStore_t* const firstHalfSeqStore = &zc->blockSplitCtx.firstHalfSeqStore; + seqStore_t* const secondHalfSeqStore = &zc->blockSplitCtx.secondHalfSeqStore; + size_t estimatedOriginalSize; + size_t estimatedFirstHalfSize; + size_t estimatedSecondHalfSize; + size_t midIdx = (startIdx + endIdx)/2; + + DEBUGLOG(5, "ZSTD_deriveBlockSplitsHelper: startIdx=%zu endIdx=%zu", startIdx, endIdx); + assert(endIdx >= startIdx); + if (endIdx - startIdx < MIN_SEQUENCES_BLOCK_SPLITTING || splits->idx >= ZSTD_MAX_NB_BLOCK_SPLITS) { + DEBUGLOG(6, "ZSTD_deriveBlockSplitsHelper: Too few sequences (%zu)", endIdx - startIdx); + return; + } + ZSTD_deriveSeqStoreChunk(fullSeqStoreChunk, origSeqStore, startIdx, endIdx); + ZSTD_deriveSeqStoreChunk(firstHalfSeqStore, origSeqStore, startIdx, midIdx); + ZSTD_deriveSeqStoreChunk(secondHalfSeqStore, origSeqStore, midIdx, endIdx); + estimatedOriginalSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(fullSeqStoreChunk, zc); + estimatedFirstHalfSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(firstHalfSeqStore, zc); + estimatedSecondHalfSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(secondHalfSeqStore, zc); + DEBUGLOG(5, "Estimated original block size: %zu -- First half split: %zu -- Second half split: %zu", + estimatedOriginalSize, estimatedFirstHalfSize, estimatedSecondHalfSize); + if (ZSTD_isError(estimatedOriginalSize) || ZSTD_isError(estimatedFirstHalfSize) || ZSTD_isError(estimatedSecondHalfSize)) { + return; + } + if (estimatedFirstHalfSize + estimatedSecondHalfSize < estimatedOriginalSize) { + DEBUGLOG(5, "split decided at seqNb:%zu", midIdx); + ZSTD_deriveBlockSplitsHelper(splits, startIdx, midIdx, zc, origSeqStore); + splits->splitLocations[splits->idx] = (U32)midIdx; + splits->idx++; + ZSTD_deriveBlockSplitsHelper(splits, midIdx, endIdx, zc, origSeqStore); + } +} + +/* Base recursive function. + * Populates a table with intra-block partition indices that can improve compression ratio. + * + * @return: number of splits made (which equals the size of the partition table - 1). + */ +static size_t ZSTD_deriveBlockSplits(ZSTD_CCtx* zc, U32 partitions[], U32 nbSeq) +{ + seqStoreSplits splits; + splits.splitLocations = partitions; + splits.idx = 0; + if (nbSeq <= 4) { + DEBUGLOG(5, "ZSTD_deriveBlockSplits: Too few sequences to split (%u <= 4)", nbSeq); + /* Refuse to try and split anything with less than 4 sequences */ + return 0; + } + ZSTD_deriveBlockSplitsHelper(&splits, 0, nbSeq, zc, &zc->seqStore); + splits.splitLocations[splits.idx] = nbSeq; + DEBUGLOG(5, "ZSTD_deriveBlockSplits: final nb partitions: %zu", splits.idx+1); + return splits.idx; +} + +/* ZSTD_compressBlock_splitBlock(): + * Attempts to split a given block into multiple blocks to improve compression ratio. + * + * Returns combined size of all blocks (which includes headers), or a ZSTD error code. + */ +static size_t +ZSTD_compressBlock_splitBlock_internal(ZSTD_CCtx* zc, + void* dst, size_t dstCapacity, + const void* src, size_t blockSize, + U32 lastBlock, U32 nbSeq) +{ + size_t cSize = 0; + const BYTE* ip = (const BYTE*)src; + BYTE* op = (BYTE*)dst; + size_t i = 0; + size_t srcBytesTotal = 0; + U32* const partitions = zc->blockSplitCtx.partitions; /* size == ZSTD_MAX_NB_BLOCK_SPLITS */ + seqStore_t* const nextSeqStore = &zc->blockSplitCtx.nextSeqStore; + seqStore_t* const currSeqStore = &zc->blockSplitCtx.currSeqStore; + size_t const numSplits = ZSTD_deriveBlockSplits(zc, partitions, nbSeq); + + /* If a block is split and some partitions are emitted as RLE/uncompressed, then repcode history + * may become invalid. In order to reconcile potentially invalid repcodes, we keep track of two + * separate repcode histories that simulate repcode history on compression and decompression side, + * and use the histories to determine whether we must replace a particular repcode with its raw offset. + * + * 1) cRep gets updated for each partition, regardless of whether the block was emitted as uncompressed + * or RLE. This allows us to retrieve the offset value that an invalid repcode references within + * a nocompress/RLE block. + * 2) dRep gets updated only for compressed partitions, and when a repcode gets replaced, will use + * the replacement offset value rather than the original repcode to update the repcode history. + * dRep also will be the final repcode history sent to the next block. + * + * See ZSTD_seqStore_resolveOffCodes() for more details. + */ + repcodes_t dRep; + repcodes_t cRep; + ZSTD_memcpy(dRep.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t)); + ZSTD_memcpy(cRep.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t)); + ZSTD_memset(nextSeqStore, 0, sizeof(seqStore_t)); + + DEBUGLOG(5, "ZSTD_compressBlock_splitBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", + (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, + (unsigned)zc->blockState.matchState.nextToUpdate); + + if (numSplits == 0) { + size_t cSizeSingleBlock = + ZSTD_compressSeqStore_singleBlock(zc, &zc->seqStore, + &dRep, &cRep, + op, dstCapacity, + ip, blockSize, + lastBlock, 0 /* isPartition */); + FORWARD_IF_ERROR(cSizeSingleBlock, "Compressing single block from splitBlock_internal() failed!"); + DEBUGLOG(5, "ZSTD_compressBlock_splitBlock_internal: No splits"); + assert(zc->blockSize <= ZSTD_BLOCKSIZE_MAX); + assert(cSizeSingleBlock <= zc->blockSize + ZSTD_blockHeaderSize); + return cSizeSingleBlock; + } + + ZSTD_deriveSeqStoreChunk(currSeqStore, &zc->seqStore, 0, partitions[0]); + for (i = 0; i <= numSplits; ++i) { + size_t cSizeChunk; + U32 const lastPartition = (i == numSplits); + U32 lastBlockEntireSrc = 0; + + size_t srcBytes = ZSTD_countSeqStoreLiteralsBytes(currSeqStore) + ZSTD_countSeqStoreMatchBytes(currSeqStore); + srcBytesTotal += srcBytes; + if (lastPartition) { + /* This is the final partition, need to account for possible last literals */ + srcBytes += blockSize - srcBytesTotal; + lastBlockEntireSrc = lastBlock; + } else { + ZSTD_deriveSeqStoreChunk(nextSeqStore, &zc->seqStore, partitions[i], partitions[i+1]); + } + + cSizeChunk = ZSTD_compressSeqStore_singleBlock(zc, currSeqStore, + &dRep, &cRep, + op, dstCapacity, + ip, srcBytes, + lastBlockEntireSrc, 1 /* isPartition */); + DEBUGLOG(5, "Estimated size: %zu vs %zu : actual size", + ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(currSeqStore, zc), cSizeChunk); + FORWARD_IF_ERROR(cSizeChunk, "Compressing chunk failed!"); + + ip += srcBytes; + op += cSizeChunk; + dstCapacity -= cSizeChunk; + cSize += cSizeChunk; + *currSeqStore = *nextSeqStore; + assert(cSizeChunk <= zc->blockSize + ZSTD_blockHeaderSize); + } + /* cRep and dRep may have diverged during the compression. + * If so, we use the dRep repcodes for the next block. + */ + ZSTD_memcpy(zc->blockState.prevCBlock->rep, dRep.rep, sizeof(repcodes_t)); + return cSize; +} + +static size_t +ZSTD_compressBlock_splitBlock(ZSTD_CCtx* zc, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, U32 lastBlock) +{ + U32 nbSeq; + size_t cSize; + DEBUGLOG(4, "ZSTD_compressBlock_splitBlock"); + assert(zc->appliedParams.useBlockSplitter == ZSTD_ps_enable); + + { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); + FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); + if (bss == ZSTDbss_noCompress) { + if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) + zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; + RETURN_ERROR_IF(zc->seqCollector.collectSequences, sequenceProducer_failed, "Uncompressible block"); + cSize = ZSTD_noCompressBlock(dst, dstCapacity, src, srcSize, lastBlock); + FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed"); + DEBUGLOG(4, "ZSTD_compressBlock_splitBlock: Nocompress block"); + return cSize; + } + nbSeq = (U32)(zc->seqStore.sequences - zc->seqStore.sequencesStart); + } + + cSize = ZSTD_compressBlock_splitBlock_internal(zc, dst, dstCapacity, src, srcSize, lastBlock, nbSeq); + FORWARD_IF_ERROR(cSize, "Splitting blocks failed!"); + return cSize; +} + +static size_t +ZSTD_compressBlock_internal(ZSTD_CCtx* zc, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, U32 frame) +{ + /* This is an estimated upper bound for the length of an rle block. + * This isn't the actual upper bound. + * Finding the real threshold needs further investigation. + */ + const U32 rleMaxLength = 25; + size_t cSize; + const BYTE* ip = (const BYTE*)src; + BYTE* op = (BYTE*)dst; + DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", + (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, + (unsigned)zc->blockState.matchState.nextToUpdate); + + { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); + FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); + if (bss == ZSTDbss_noCompress) { + RETURN_ERROR_IF(zc->seqCollector.collectSequences, sequenceProducer_failed, "Uncompressible block"); + cSize = 0; + goto out; + } + } + + if (zc->seqCollector.collectSequences) { + FORWARD_IF_ERROR(ZSTD_copyBlockSequences(&zc->seqCollector, ZSTD_getSeqStore(zc), zc->blockState.prevCBlock->rep), "copyBlockSequences failed"); + ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); + return 0; + } + + /* encode sequences and literals */ + cSize = ZSTD_entropyCompressSeqStore(&zc->seqStore, + &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, + &zc->appliedParams, + dst, dstCapacity, + srcSize, + zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, + zc->bmi2); + + if (frame && + /* We don't want to emit our first block as a RLE even if it qualifies because + * doing so will cause the decoder (cli only) to throw a "should consume all input error." + * This is only an issue for zstd <= v1.4.3 + */ + !zc->isFirstBlock && + cSize < rleMaxLength && + ZSTD_isRLE(ip, srcSize)) + { + cSize = 1; + op[0] = ip[0]; + } + +out: + if (!ZSTD_isError(cSize) && cSize > 1) { + ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); + } + /* We check that dictionaries have offset codes available for the first + * block. After the first block, the offcode table might not have large + * enough codes to represent the offsets in the data. + */ + if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) + zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; + + return cSize; +} + +static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const size_t bss, U32 lastBlock) +{ + DEBUGLOG(6, "Attempting ZSTD_compressSuperBlock()"); if (bss == ZSTDbss_compress) { if (/* We don't want to emit our first block as a RLE even if it qualifies because * doing so will cause the decoder (cli only) to throw a "should consume all input error." @@ -2511,18 +4407,19 @@ static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc, * * cSize >= blockBound(srcSize): We have expanded the block too much so * emit an uncompressed block. */ - { - size_t const cSize = ZSTD_compressSuperBlock(zc, dst, dstCapacity, src, srcSize, lastBlock); + { size_t const cSize = + ZSTD_compressSuperBlock(zc, dst, dstCapacity, src, srcSize, lastBlock); if (cSize != ERROR(dstSize_tooSmall)) { - size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, zc->appliedParams.cParams.strategy); + size_t const maxCSize = + srcSize - ZSTD_minGain(srcSize, zc->appliedParams.cParams.strategy); FORWARD_IF_ERROR(cSize, "ZSTD_compressSuperBlock failed"); - if (cSize != 0 && cSize < maxCSize + ZSTDInternalConstants::ZSTD_blockHeaderSize) { - ZSTD_confirmRepcodesAndEntropyTables(zc); + if (cSize != 0 && cSize < maxCSize + ZSTD_blockHeaderSize) { + ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); return cSize; } } } - } + } /* if (bss == ZSTDbss_compress)*/ DEBUGLOG(6, "Resorting to ZSTD_noCompressBlock()"); /* Superblock compression failed, attempt to emit a single no compress block. @@ -2557,9 +4454,9 @@ static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms, void const* ip, void const* iend) { - if (ZSTD_window_needOverflowCorrection(ms->window, iend)) { - U32 const maxDist = (U32)1 << params->cParams.windowLog; - U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy); + U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy); + U32 const maxDist = (U32)1 << params->cParams.windowLog; + if (ZSTD_window_needOverflowCorrection(ms->window, cycleLog, maxDist, ms->loadedDictEnd, ip, iend)) { U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip); ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); @@ -2580,9 +4477,9 @@ static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms, * All blocks will be terminated, all input will be consumed. * Function will issue an error if there is not enough `dstCapacity` to hold the compressed content. * Frame is supposed already started (header already produced) -* @return : compressed size, or an error code +* @return : compressed size, or an error code */ -static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, +static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastFrameChunk) @@ -2596,7 +4493,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX); - DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize); + DEBUGLOG(4, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize); if (cctx->appliedParams.fParams.checksumFlag && srcSize) XXH64_update(&cctx->xxhState, src, srcSize); @@ -2604,7 +4501,9 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, ZSTD_matchState_t* const ms = &cctx->blockState.matchState; U32 const lastBlock = lastFrameChunk & (blockSize >= remaining); - RETURN_ERROR_IF(dstCapacity < ZSTDInternalConstants::ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE, + /* TODO: See 3090. We reduced MIN_CBLOCK_SIZE from 3 to 2 so to compensate we are adding + * additional 1. We need to revisit and change this logic to be more consistent */ + RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE + 1, dstSize_tooSmall, "not enough space to store compressed block"); if (remaining < blockSize) blockSize = remaining; @@ -2612,6 +4511,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, ZSTD_overflowCorrectIfNeeded( ms, &cctx->workspace, &cctx->appliedParams, ip, ip + blockSize); ZSTD_checkDictValidity(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); + ZSTD_window_enforceMaxDist(&ms->window, ip, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); /* Ensure hash/chain table insertion resumes no sooner than lowlimit */ if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit; @@ -2621,10 +4521,14 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, cSize = ZSTD_compressBlock_targetCBlockSize(cctx, op, dstCapacity, ip, blockSize, lastBlock); FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize failed"); assert(cSize > 0); - assert(cSize <= blockSize + ZSTDInternalConstants::ZSTD_blockHeaderSize); + assert(cSize <= blockSize + ZSTD_blockHeaderSize); + } else if (ZSTD_blockSplitterEnabled(&cctx->appliedParams)) { + cSize = ZSTD_compressBlock_splitBlock(cctx, op, dstCapacity, ip, blockSize, lastBlock); + FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_splitBlock failed"); + assert(cSize > 0 || cctx->seqCollector.collectSequences == 1); } else { cSize = ZSTD_compressBlock_internal(cctx, - op+ZSTDInternalConstants::ZSTD_blockHeaderSize, dstCapacity-ZSTDInternalConstants::ZSTD_blockHeaderSize, + op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize, 1 /* frame */); FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_internal failed"); @@ -2636,9 +4540,9 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) : lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); MEM_writeLE24(op, cBlockHeader); - cSize += ZSTDInternalConstants::ZSTD_blockHeaderSize; + cSize += ZSTD_blockHeaderSize; } - } + } /* if (ZSTD_useTargetCBlockSize(&cctx->appliedParams))*/ ip += blockSize; @@ -2676,7 +4580,6 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, "dst buf is too small to fit worst-case frame header size."); DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u", !params->fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode); - if (params->format == ZSTD_f_zstd1) { MEM_writeLE32(dst, ZSTD_MAGICNUMBER); pos = 4; @@ -2685,7 +4588,9 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, if (!singleSegment) op[pos++] = windowLogByte; switch(dictIDSizeCode) { - default: assert(0); /* impossible */ + default: + assert(0); /* impossible */ + ZSTD_FALLTHROUGH; case 0 : break; case 1 : op[pos] = (BYTE)(dictID); pos++; break; case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break; @@ -2693,7 +4598,9 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, } switch(fcsCode) { - default: assert(0); /* impossible */ + default: + assert(0); /* impossible */ + ZSTD_FALLTHROUGH; case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break; case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break; case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break; @@ -2702,6 +4609,26 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, return pos; } +/* ZSTD_writeSkippableFrame_advanced() : + * Writes out a skippable frame with the specified magic number variant (16 are supported), + * from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15, and the desired source data. + * + * Returns the total number of bytes written, or a ZSTD error code. + */ +size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity, + const void* src, size_t srcSize, unsigned magicVariant) { + BYTE* op = (BYTE*)dst; + RETURN_ERROR_IF(dstCapacity < srcSize + ZSTD_SKIPPABLEHEADERSIZE /* Skippable frame overhead */, + dstSize_tooSmall, "Not enough room for skippable frame"); + RETURN_ERROR_IF(srcSize > (unsigned)0xFFFFFFFF, srcSize_wrong, "Src size too large for skippable frame"); + RETURN_ERROR_IF(magicVariant > 15, parameter_outOfBound, "Skippable frame magic number variant not supported"); + + MEM_writeLE32(op, (U32)(ZSTD_MAGIC_SKIPPABLE_START + magicVariant)); + MEM_writeLE32(op+4, (U32)srcSize); + ZSTD_memcpy(op+8, src, srcSize); + return srcSize + ZSTD_SKIPPABLEHEADERSIZE; +} + /* ZSTD_writeLastEmptyBlock() : * output an empty Block with end-of-frame mark to complete a frame * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h)) @@ -2709,26 +4636,23 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, */ size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity) { - RETURN_ERROR_IF(dstCapacity < ZSTDInternalConstants::ZSTD_blockHeaderSize, dstSize_tooSmall, + RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall, "dst buf is too small to write frame trailer empty block."); { U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */ MEM_writeLE24(dst, cBlockHeader24); - return ZSTDInternalConstants::ZSTD_blockHeaderSize; + return ZSTD_blockHeaderSize; } } -size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq) +void ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq) { - RETURN_ERROR_IF(cctx->stage != ZSTDcs_init, stage_wrong, - "wrong cctx stage"); - RETURN_ERROR_IF(cctx->appliedParams.ldmParams.enableLdm, - parameter_unsupported, - "incompatible with ldm"); + assert(cctx->stage == ZSTDcs_init); + assert(nbSeq == 0 || cctx->appliedParams.ldmParams.enableLdm != ZSTD_ps_enable); cctx->externSeqStore.seq = seq; cctx->externSeqStore.size = nbSeq; cctx->externSeqStore.capacity = nbSeq; cctx->externSeqStore.pos = 0; - return 0; + cctx->externSeqStore.posInSequence = 0; } @@ -2757,11 +4681,12 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, if (!srcSize) return fhSize; /* do not generate an empty block if no input */ - if (!ZSTD_window_update(&ms->window, src, srcSize)) { + if (!ZSTD_window_update(&ms->window, src, srcSize, ms->forceNonContiguous)) { + ms->forceNonContiguous = 0; ms->nextToUpdate = ms->window.dictLimit; } - if (cctx->appliedParams.ldmParams.enableLdm) { - ZSTD_window_update(&cctx->ldmState.window, src, srcSize); + if (cctx->appliedParams.ldmParams.enableLdm == ZSTD_ps_enable) { + ZSTD_window_update(&cctx->ldmState.window, src, srcSize, /* forceNonContiguous */ 0); } if (!frame) { @@ -2792,31 +4717,51 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, } } -size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) +size_t ZSTD_compressContinue_public(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (unsigned)srcSize); return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */); } +/* NOTE: Must just wrap ZSTD_compressContinue_public() */ +size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize) +{ + return ZSTD_compressContinue_public(cctx, dst, dstCapacity, src, srcSize); +} -size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) +static size_t ZSTD_getBlockSize_deprecated(const ZSTD_CCtx* cctx) { ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams; assert(!ZSTD_checkCParams(cParams)); - return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog); + return MIN(cctx->appliedParams.maxBlockSize, (size_t)1 << cParams.windowLog); } -size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) +/* NOTE: Must just wrap ZSTD_getBlockSize_deprecated() */ +size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) +{ + return ZSTD_getBlockSize_deprecated(cctx); +} + +/* NOTE: Must just wrap ZSTD_compressBlock_deprecated() */ +size_t ZSTD_compressBlock_deprecated(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_compressBlock: srcSize = %u", (unsigned)srcSize); - { size_t const blockSizeMax = ZSTD_getBlockSize(cctx); + { size_t const blockSizeMax = ZSTD_getBlockSize_deprecated(cctx); RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong, "input is larger than a block"); } return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */); } +/* NOTE: Must just wrap ZSTD_compressBlock_deprecated() */ +size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) +{ + return ZSTD_compressBlock_deprecated(cctx, dst, dstCapacity, src, srcSize); +} + /*! ZSTD_loadDictionaryContent() : * @return : 0, or an error code */ @@ -2825,63 +4770,133 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, ZSTD_cwksp* ws, ZSTD_CCtx_params const* params, const void* src, size_t srcSize, - ZSTD_dictTableLoadMethod_e dtlm) + ZSTD_dictTableLoadMethod_e dtlm, + ZSTD_tableFillPurpose_e tfp) { const BYTE* ip = (const BYTE*) src; const BYTE* const iend = ip + srcSize; + int const loadLdmDict = params->ldmParams.enableLdm == ZSTD_ps_enable && ls != NULL; - ZSTD_window_update(&ms->window, src, srcSize); - ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base); + /* Assert that the ms params match the params we're being given */ + ZSTD_assertEqualCParams(params->cParams, ms->cParams); - if (params->ldmParams.enableLdm && ls != NULL) { - ZSTD_window_update(&ls->window, src, srcSize); - ls->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ls->window.base); + { /* Ensure large dictionaries can't cause index overflow */ + + /* Allow the dictionary to set indices up to exactly ZSTD_CURRENT_MAX. + * Dictionaries right at the edge will immediately trigger overflow + * correction, but I don't want to insert extra constraints here. + */ + U32 maxDictSize = ZSTD_CURRENT_MAX - ZSTD_WINDOW_START_INDEX; + + int const CDictTaggedIndices = ZSTD_CDictIndicesAreTagged(¶ms->cParams); + if (CDictTaggedIndices && tfp == ZSTD_tfp_forCDict) { + /* Some dictionary matchfinders in zstd use "short cache", + * which treats the lower ZSTD_SHORT_CACHE_TAG_BITS of each + * CDict hashtable entry as a tag rather than as part of an index. + * When short cache is used, we need to truncate the dictionary + * so that its indices don't overlap with the tag. */ + U32 const shortCacheMaxDictSize = (1u << (32 - ZSTD_SHORT_CACHE_TAG_BITS)) - ZSTD_WINDOW_START_INDEX; + maxDictSize = MIN(maxDictSize, shortCacheMaxDictSize); + assert(!loadLdmDict); + } + + /* If the dictionary is too large, only load the suffix of the dictionary. */ + if (srcSize > maxDictSize) { + ip = iend - maxDictSize; + src = ip; + srcSize = maxDictSize; + } } - /* Assert that we the ms params match the params we're being given */ - ZSTD_assertEqualCParams(params->cParams, ms->cParams); + if (srcSize > ZSTD_CHUNKSIZE_MAX) { + /* We must have cleared our windows when our source is this large. */ + assert(ZSTD_window_isEmpty(ms->window)); + if (loadLdmDict) assert(ZSTD_window_isEmpty(ls->window)); + } + ZSTD_window_update(&ms->window, src, srcSize, /* forceNonContiguous */ 0); - if (srcSize <= HASH_READ_SIZE) return 0; + DEBUGLOG(4, "ZSTD_loadDictionaryContent(): useRowMatchFinder=%d", (int)params->useRowMatchFinder); - while (iend - ip > HASH_READ_SIZE) { - size_t const remaining = (size_t)(iend - ip); - size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX); - const BYTE* const ichunk = ip + chunk; + if (loadLdmDict) { /* Load the entire dict into LDM matchfinders. */ + ZSTD_window_update(&ls->window, src, srcSize, /* forceNonContiguous */ 0); + ls->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ls->window.base); + ZSTD_ldm_fillHashTable(ls, ip, iend, ¶ms->ldmParams); + } - ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, ichunk); + /* If the dict is larger than we can reasonably index in our tables, only load the suffix. */ + if (params->cParams.strategy < ZSTD_btultra) { + U32 maxDictSize = 8U << MIN(MAX(params->cParams.hashLog, params->cParams.chainLog), 28); + if (srcSize > maxDictSize) { + ip = iend - maxDictSize; + src = ip; + srcSize = maxDictSize; + } + } - if (params->ldmParams.enableLdm && ls != NULL) - ZSTD_ldm_fillHashTable(ls, (const BYTE*)src, (const BYTE*)src + srcSize, ¶ms->ldmParams); + ms->nextToUpdate = (U32)(ip - ms->window.base); + ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base); + ms->forceNonContiguous = params->deterministicRefPrefix; - switch(params->cParams.strategy) - { - case ZSTD_fast: - ZSTD_fillHashTable(ms, ichunk, dtlm); - break; - case ZSTD_dfast: - ZSTD_fillDoubleHashTable(ms, ichunk, dtlm); - break; + if (srcSize <= HASH_READ_SIZE) return 0; - case ZSTD_greedy: - case ZSTD_lazy: - case ZSTD_lazy2: - if (chunk >= HASH_READ_SIZE) - ZSTD_insertAndFindFirstIndex(ms, ichunk-HASH_READ_SIZE); - break; + ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, iend); - case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ - case ZSTD_btopt: - case ZSTD_btultra: - case ZSTD_btultra2: - if (chunk >= HASH_READ_SIZE) - ZSTD_updateTree(ms, ichunk-HASH_READ_SIZE, ichunk); - break; + switch(params->cParams.strategy) + { + case ZSTD_fast: + ZSTD_fillHashTable(ms, iend, dtlm, tfp); + break; + case ZSTD_dfast: +#ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR + ZSTD_fillDoubleHashTable(ms, iend, dtlm, tfp); +#else + assert(0); /* shouldn't be called: cparams should've been adjusted. */ +#endif + break; - default: - assert(0); /* not possible : not a valid strategy id */ + case ZSTD_greedy: + case ZSTD_lazy: + case ZSTD_lazy2: +#if !defined(ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR) + assert(srcSize >= HASH_READ_SIZE); + if (ms->dedicatedDictSearch) { + assert(ms->chainTable != NULL); + ZSTD_dedicatedDictSearch_lazy_loadDictionary(ms, iend-HASH_READ_SIZE); + } else { + assert(params->useRowMatchFinder != ZSTD_ps_auto); + if (params->useRowMatchFinder == ZSTD_ps_enable) { + size_t const tagTableSize = ((size_t)1 << params->cParams.hashLog); + ZSTD_memset(ms->tagTable, 0, tagTableSize); + ZSTD_row_update(ms, iend-HASH_READ_SIZE); + DEBUGLOG(4, "Using row-based hash table for lazy dict"); + } else { + ZSTD_insertAndFindFirstIndex(ms, iend-HASH_READ_SIZE); + DEBUGLOG(4, "Using chain-based hash table for lazy dict"); + } } +#else + assert(0); /* shouldn't be called: cparams should've been adjusted. */ +#endif + break; + + case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ + case ZSTD_btopt: + case ZSTD_btultra: + case ZSTD_btultra2: +#if !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR) + assert(srcSize >= HASH_READ_SIZE); + ZSTD_updateTree(ms, iend-HASH_READ_SIZE, iend); +#else + assert(0); /* shouldn't be called: cparams should've been adjusted. */ +#endif + break; - ip = ichunk; + default: + assert(0); /* not possible : not a valid strategy id */ } ms->nextToUpdate = (U32)(iend - ms->window.base); @@ -2890,22 +4905,28 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, /* Dictionaries that assign zero probability to symbols that show up causes problems - when FSE encoding. Refuse dictionaries that assign zero probability to symbols - that we may encounter during compression. - NOTE: This behavior is not standard and could be improved in the future. */ -static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) { + * when FSE encoding. Mark dictionaries with zero probability symbols as FSE_repeat_check + * and only dictionaries with 100% valid symbols can be assumed valid. + */ +static FSE_repeat ZSTD_dictNCountRepeat(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) +{ U32 s; - RETURN_ERROR_IF(dictMaxSymbolValue < maxSymbolValue, dictionary_corrupted, "dict fse tables don't have all symbols"); + if (dictMaxSymbolValue < maxSymbolValue) { + return FSE_repeat_check; + } for (s = 0; s <= maxSymbolValue; ++s) { - RETURN_ERROR_IF(normalizedCounter[s] == 0, dictionary_corrupted, "dict fse tables don't have all symbols"); + if (normalizedCounter[s] == 0) { + return FSE_repeat_check; + } } - return 0; + return FSE_repeat_valid; } size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, - short* offcodeNCount, unsigned* offcodeMaxValue, const void* const dict, size_t dictSize) { + short offcodeNCount[MaxOff+1]; + unsigned offcodeMaxValue = MaxOff; const BYTE* dictPtr = (const BYTE*)dict; /* skip magic num and dict ID */ const BYTE* const dictEnd = dictPtr + dictSize; dictPtr += 8; @@ -2918,25 +4939,24 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, /* We only set the loaded table as valid if it contains all non-zero * weights. Otherwise, we set it to check */ - if (!hasZeroWeights) + if (!hasZeroWeights && maxSymbolValue == 255) bs->entropy.huf.repeatMode = HUF_repeat_valid; RETURN_ERROR_IF(HUF_isError(hufHeaderSize), dictionary_corrupted, ""); - RETURN_ERROR_IF(maxSymbolValue < 255, dictionary_corrupted, ""); dictPtr += hufHeaderSize; } { unsigned offcodeLog; - size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); + size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, ""); RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, ""); - /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ /* fill all offset symbols to avoid garbage at end of table */ RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( bs->entropy.fse.offcodeCTable, offcodeNCount, MaxOff, offcodeLog, workspace, HUF_WORKSPACE_SIZE)), dictionary_corrupted, ""); + /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ dictPtr += offcodeHeaderSize; } @@ -2945,13 +4965,12 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, ""); RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, ""); - /* Every match length code must have non-zero probability */ - FORWARD_IF_ERROR( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML), ""); RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( bs->entropy.fse.matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, workspace, HUF_WORKSPACE_SIZE)), dictionary_corrupted, ""); + bs->entropy.fse.matchlength_repeatMode = ZSTD_dictNCountRepeat(matchlengthNCount, matchlengthMaxValue, MaxML); dictPtr += matchlengthHeaderSize; } @@ -2960,13 +4979,12 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, ""); RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, ""); - /* Every literal length code must have non-zero probability */ - FORWARD_IF_ERROR( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL), ""); RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( bs->entropy.fse.litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, workspace, HUF_WORKSPACE_SIZE)), dictionary_corrupted, ""); + bs->entropy.fse.litlength_repeatMode = ZSTD_dictNCountRepeat(litlengthNCount, litlengthMaxValue, MaxLL); dictPtr += litlengthHeaderSize; } @@ -2976,12 +4994,28 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, bs->rep[2] = MEM_readLE32(dictPtr+8); dictPtr += 12; + { size_t const dictContentSize = (size_t)(dictEnd - dictPtr); + U32 offcodeMax = MaxOff; + if (dictContentSize <= ((U32)-1) - 128 KB) { + U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */ + offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */ + } + /* All offset values <= dictContentSize + 128 KB must be representable for a valid table */ + bs->entropy.fse.offcode_repeatMode = ZSTD_dictNCountRepeat(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)); + + /* All repCodes must be <= dictContentSize and != 0 */ + { U32 u; + for (u=0; u<3; u++) { + RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, ""); + RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, ""); + } } } + return dictPtr - (const BYTE*)dict; } /* Dictionary format : * See : - * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format + * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#dictionary-format */ /*! ZSTD_loadZstdDictionary() : * @return : dictID, or an error code @@ -2994,46 +5028,28 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_CCtx_params const* params, const void* dict, size_t dictSize, ZSTD_dictTableLoadMethod_e dtlm, + ZSTD_tableFillPurpose_e tfp, void* workspace) { const BYTE* dictPtr = (const BYTE*)dict; const BYTE* const dictEnd = dictPtr + dictSize; - short offcodeNCount[MaxOff+1]; - unsigned offcodeMaxValue = MaxOff; size_t dictID; size_t eSize; - ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<= 8); assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY); dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr + 4 /* skip magic number */ ); - eSize = ZSTD_loadCEntropy(bs, workspace, offcodeNCount, &offcodeMaxValue, dict, dictSize); + eSize = ZSTD_loadCEntropy(bs, workspace, dict, dictSize); FORWARD_IF_ERROR(eSize, "ZSTD_loadCEntropy failed"); dictPtr += eSize; - { size_t const dictContentSize = (size_t)(dictEnd - dictPtr); - U32 offcodeMax = MaxOff; - if (dictContentSize <= ((U32)-1) - 128 KB) { - U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */ - offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */ - } - /* All offset values <= dictContentSize + 128 KB must be representable */ - FORWARD_IF_ERROR(ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)), ""); - /* All repCodes must be <= dictContentSize and != 0*/ - { U32 u; - for (u=0; u<3; u++) { - RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, ""); - RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, ""); - } } - - bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid; - bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid; - bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid; + { + size_t const dictContentSize = (size_t)(dictEnd - dictPtr); FORWARD_IF_ERROR(ZSTD_loadDictionaryContent( - ms, NULL, ws, params, dictPtr, dictContentSize, dtlm), ""); - return dictID; + ms, NULL, ws, params, dictPtr, dictContentSize, dtlm, tfp), ""); } + return dictID; } /** ZSTD_compress_insertDictionary() : @@ -3047,6 +5063,7 @@ ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, ZSTD_dictTableLoadMethod_e dtlm, + ZSTD_tableFillPurpose_e tfp, void* workspace) { DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize); @@ -3059,13 +5076,13 @@ ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, /* dict restricted modes */ if (dictContentType == ZSTD_dct_rawContent) - return ZSTD_loadDictionaryContent(ms, ls, ws, params, dict, dictSize, dtlm); + return ZSTD_loadDictionaryContent(ms, ls, ws, params, dict, dictSize, dtlm, tfp); if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) { if (dictContentType == ZSTD_dct_auto) { DEBUGLOG(4, "raw content dictionary detected"); return ZSTD_loadDictionaryContent( - ms, ls, ws, params, dict, dictSize, dtlm); + ms, ls, ws, params, dict, dictSize, dtlm, tfp); } RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, ""); assert(0); /* impossible */ @@ -3073,13 +5090,14 @@ ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, /* dict as full zstd dictionary */ return ZSTD_loadZstdDictionary( - bs, ms, ws, params, dict, dictSize, dtlm, workspace); + bs, ms, ws, params, dict, dictSize, dtlm, tfp, workspace); } #define ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF (128 KB) -#define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6) +#define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6ULL) /*! ZSTD_compressBegin_internal() : + * Assumption : either @dict OR @cdict (or none) is non-NULL, never both * @return : 0, or an error code */ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, @@ -3089,6 +5107,10 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params, U64 pledgedSrcSize, ZSTD_buffered_policy_e zbuff) { + size_t const dictContentSize = cdict ? cdict->dictContentSize : dictSize; +#if ZSTD_TRACE + cctx->traceCtx = (ZSTD_trace_compress_begin != NULL) ? ZSTD_trace_compress_begin(cctx) : 0; +#endif DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params->cParams.windowLog); /* params are supposed to be fully validated at this point */ assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); @@ -3103,21 +5125,23 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff); } - FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, *params, pledgedSrcSize, + FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, + dictContentSize, ZSTDcrp_makeClean, zbuff) , ""); { size_t const dictID = cdict ? ZSTD_compress_insertDictionary( cctx->blockState.prevCBlock, &cctx->blockState.matchState, &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, cdict->dictContent, - cdict->dictContentSize, dictContentType, dtlm, - cctx->entropyWorkspace) + cdict->dictContentSize, cdict->dictContentType, dtlm, + ZSTD_tfp_forCCtx, cctx->entropyWorkspace) : ZSTD_compress_insertDictionary( cctx->blockState.prevCBlock, &cctx->blockState.matchState, &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, dict, dictSize, - dictContentType, dtlm, cctx->entropyWorkspace); + dictContentType, dtlm, ZSTD_tfp_forCCtx, cctx->entropyWorkspace); FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed"); assert(dictID <= UINT_MAX); cctx->dictID = (U32)dictID; + cctx->dictContentSize = dictContentSize; } return 0; } @@ -3146,27 +5170,35 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize) { - ZSTD_CCtx_params const cctxParams = - ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, ¶ms); + ZSTD_CCtx_params cctxParams; + ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, ZSTD_NO_CLEVEL); return ZSTD_compressBegin_advanced_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL /*cdict*/, &cctxParams, pledgedSrcSize); } -size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) +static size_t +ZSTD_compressBegin_usingDict_deprecated(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize); - ZSTD_CCtx_params const cctxParams = - ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, ¶ms); + ZSTD_CCtx_params cctxParams; + { ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_noAttachDict); + ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel); + } DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize); return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered); } +size_t +ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) +{ + return ZSTD_compressBegin_usingDict_deprecated(cctx, dict, dictSize, compressionLevel); +} + size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel) { - return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel); + return ZSTD_compressBegin_usingDict_deprecated(cctx, NULL, 0, compressionLevel); } @@ -3177,14 +5209,13 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) { BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; - size_t fhSize = 0; DEBUGLOG(4, "ZSTD_writeEpilogue"); RETURN_ERROR_IF(cctx->stage == ZSTDcs_created, stage_wrong, "init missing"); /* special case : empty frame */ if (cctx->stage == ZSTDcs_init) { - fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 0, 0); + size_t fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 0, 0); FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed"); dstCapacity -= fhSize; op += fhSize; @@ -3194,10 +5225,11 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) if (cctx->stage != ZSTDcs_ending) { /* write one last empty block, make it the "last" block */ U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0; - RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for epilogue"); - MEM_writeLE32(op, cBlockHeader24); - op += ZSTDInternalConstants::ZSTD_blockHeaderSize; - dstCapacity -= ZSTDInternalConstants::ZSTD_blockHeaderSize; + ZSTD_STATIC_ASSERT(ZSTD_BLOCKHEADERSIZE == 3); + RETURN_ERROR_IF(dstCapacity<3, dstSize_tooSmall, "no room for epilogue"); + MEM_writeLE24(op, cBlockHeader24); + op += ZSTD_blockHeaderSize; + dstCapacity -= ZSTD_blockHeaderSize; } if (cctx->appliedParams.fParams.checksumFlag) { @@ -3212,9 +5244,33 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) return op-ostart; } -size_t ZSTD_compressEnd (ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) +void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize) +{ +#if ZSTD_TRACE + if (cctx->traceCtx && ZSTD_trace_compress_end != NULL) { + int const streaming = cctx->inBuffSize > 0 || cctx->outBuffSize > 0 || cctx->appliedParams.nbWorkers > 0; + ZSTD_Trace trace; + ZSTD_memset(&trace, 0, sizeof(trace)); + trace.version = ZSTD_VERSION_NUMBER; + trace.streaming = streaming; + trace.dictionaryID = cctx->dictID; + trace.dictionarySize = cctx->dictContentSize; + trace.uncompressedSize = cctx->consumedSrcSize; + trace.compressedSize = cctx->producedCSize + extraCSize; + trace.params = &cctx->appliedParams; + trace.cctx = cctx; + ZSTD_trace_compress_end(cctx->traceCtx, &trace); + } + cctx->traceCtx = 0; +#else + (void)cctx; + (void)extraCSize; +#endif +} + +size_t ZSTD_compressEnd_public(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize) { size_t endResult; size_t const cSize = ZSTD_compressContinue_internal(cctx, @@ -3234,24 +5290,16 @@ size_t ZSTD_compressEnd (ZSTD_CCtx* cctx, (unsigned)cctx->pledgedSrcSizePlusOne-1, (unsigned)cctx->consumedSrcSize); } + ZSTD_CCtx_trace(cctx, endResult); return cSize + endResult; } - -static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const void* dict,size_t dictSize, - const ZSTD_parameters* params) +/* NOTE: Must just wrap ZSTD_compressEnd_public() */ +size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize) { - ZSTD_CCtx_params const cctxParams = - ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params); - DEBUGLOG(4, "ZSTD_compress_internal"); - return ZSTD_compress_advanced_internal(cctx, - dst, dstCapacity, - src, srcSize, - dict, dictSize, - &cctxParams); + return ZSTD_compressEnd_public(cctx, dst, dstCapacity, src, srcSize); } size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, @@ -3262,11 +5310,12 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, { DEBUGLOG(4, "ZSTD_compress_advanced"); FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), ""); - return ZSTD_compress_internal(cctx, - dst, dstCapacity, - src, srcSize, - dict, dictSize, - ¶ms); + ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, ¶ms, ZSTD_NO_CLEVEL); + return ZSTD_compress_advanced_internal(cctx, + dst, dstCapacity, + src, srcSize, + dict, dictSize, + &cctx->simpleApiParams); } /* Internal */ @@ -3281,7 +5330,7 @@ size_t ZSTD_compress_advanced_internal( FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, params, srcSize, ZSTDb_not_buffered) , ""); - return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); + return ZSTD_compressEnd_public(cctx, dst, dstCapacity, src, srcSize); } size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, @@ -3290,11 +5339,13 @@ size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0); - ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, ¶ms); + { + ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0, ZSTD_cpm_noAttachDict); + assert(params.fParams.contentSizeFlag == 1); + ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, ¶ms, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT: compressionLevel); + } DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize); - assert(params.fParams.contentSizeFlag == 1); - return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctxParams); + return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctx->simpleApiParams); } size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, @@ -3312,10 +5363,17 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity, int compressionLevel) { size_t result; +#if ZSTD_COMPRESS_HEAPMODE + ZSTD_CCtx* cctx = ZSTD_createCCtx(); + RETURN_ERROR_IF(!cctx, memory_allocation, "ZSTD_createCCtx failed"); + result = ZSTD_compressCCtx(cctx, dst, dstCapacity, src, srcSize, compressionLevel); + ZSTD_freeCCtx(cctx); +#else ZSTD_CCtx ctxBody; - ZSTD_initCCtx(&ctxBody, ZSTDInternalConstants::ZSTD_defaultCMem); + ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem); result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel); ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */ +#endif return result; } @@ -3331,14 +5389,17 @@ size_t ZSTD_estimateCDictSize_advanced( DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict)); return ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) - + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) + /* enableDedicatedDictSearch == 1 ensures that CDict estimation will not be too small + * in case we are using DDS with row-hash. */ + + ZSTD_sizeof_matchState(&cParams, ZSTD_resolveRowMatchFinderMode(ZSTD_ps_auto, &cParams), + /* enableDedicatedDictSearch */ 1, /* forCCtx */ 0) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void *)))); } size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) { - ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize); + ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); } @@ -3356,20 +5417,22 @@ static size_t ZSTD_initCDict_internal( const void* dictBuffer, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType, - ZSTD_compressionParameters cParams) + ZSTD_CCtx_params params) { DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType); - assert(!ZSTD_checkCParams(cParams)); - cdict->matchState.cParams = cParams; + assert(!ZSTD_checkCParams(params.cParams)); + cdict->matchState.cParams = params.cParams; + cdict->matchState.dedicatedDictSearch = params.enableDedicatedDictSearch; if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) { cdict->dictContent = dictBuffer; } else { void *internalBuffer = ZSTD_cwksp_reserve_object(&cdict->workspace, ZSTD_cwksp_align(dictSize, sizeof(void*))); RETURN_ERROR_IF(!internalBuffer, memory_allocation, "NULL pointer!"); cdict->dictContent = internalBuffer; - memcpy(internalBuffer, dictBuffer, dictSize); + ZSTD_memcpy(internalBuffer, dictBuffer, dictSize); } cdict->dictContentSize = dictSize; + cdict->dictContentType = dictContentType; cdict->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cdict->workspace, HUF_WORKSPACE_SIZE); @@ -3379,22 +5442,20 @@ static size_t ZSTD_initCDict_internal( FORWARD_IF_ERROR(ZSTD_reset_matchState( &cdict->matchState, &cdict->workspace, - &cParams, + ¶ms.cParams, + params.useRowMatchFinder, ZSTDcrp_makeClean, ZSTDirp_reset, ZSTD_resetTarget_CDict), ""); /* (Maybe) load the dictionary * Skips loading the dictionary if it is < 8 bytes. */ - { ZSTD_CCtx_params params; - memset(¶ms, 0, sizeof(params)); - params.compressionLevel = ZSTD_CLEVEL_DEFAULT; + { params.compressionLevel = ZSTD_CLEVEL_DEFAULT; params.fParams.contentSizeFlag = 1; - params.cParams = cParams; { size_t const dictID = ZSTD_compress_insertDictionary( &cdict->cBlockState, &cdict->matchState, NULL, &cdict->workspace, ¶ms, cdict->dictContent, cdict->dictContentSize, - dictContentType, ZSTD_dtlm_full, cdict->entropyWorkspace); + dictContentType, ZSTD_dtlm_full, ZSTD_tfp_forCDict, cdict->entropyWorkspace); FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed"); assert(dictID <= (size_t)(U32)-1); cdict->dictID = (U32)dictID; @@ -3404,66 +5465,129 @@ static size_t ZSTD_initCDict_internal( return 0; } -ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, +static ZSTD_CDict* ZSTD_createCDict_advanced_internal(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType, - ZSTD_compressionParameters cParams, ZSTD_customMem customMem) + ZSTD_compressionParameters cParams, + ZSTD_paramSwitch_e useRowMatchFinder, + U32 enableDedicatedDictSearch, + ZSTD_customMem customMem) { - DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (unsigned)dictContentType); - if (!customMem.customAlloc ^ !customMem.customFree) return NULL; + if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; { size_t const workspaceSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) + - ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) + + ZSTD_sizeof_matchState(&cParams, useRowMatchFinder, enableDedicatedDictSearch, /* forCCtx */ 0) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*)))); - void* const workspace = ZSTD_malloc(workspaceSize, customMem); + void* const workspace = ZSTD_customMalloc(workspaceSize, customMem); ZSTD_cwksp ws; ZSTD_CDict* cdict; if (!workspace) { - ZSTD_free(workspace, customMem); + ZSTD_customFree(workspace, customMem); return NULL; } - ZSTD_cwksp_init(&ws, workspace, workspaceSize); + ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_dynamic_alloc); cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict)); assert(cdict != NULL); ZSTD_cwksp_move(&cdict->workspace, &ws); cdict->customMem = customMem; - cdict->compressionLevel = 0; /* signals advanced API usage */ + cdict->compressionLevel = ZSTD_NO_CLEVEL; /* signals advanced API usage */ + cdict->useRowMatchFinder = useRowMatchFinder; + return cdict; + } +} - if (ZSTD_isError( ZSTD_initCDict_internal(cdict, - dictBuffer, dictSize, - dictLoadMethod, dictContentType, - cParams) )) { - ZSTD_freeCDict(cdict); - return NULL; - } +ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_compressionParameters cParams, + ZSTD_customMem customMem) +{ + ZSTD_CCtx_params cctxParams; + ZSTD_memset(&cctxParams, 0, sizeof(cctxParams)); + ZSTD_CCtxParams_init(&cctxParams, 0); + cctxParams.cParams = cParams; + cctxParams.customMem = customMem; + return ZSTD_createCDict_advanced2( + dictBuffer, dictSize, + dictLoadMethod, dictContentType, + &cctxParams, customMem); +} + +ZSTD_CDict* ZSTD_createCDict_advanced2( + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + const ZSTD_CCtx_params* originalCctxParams, + ZSTD_customMem customMem) +{ + ZSTD_CCtx_params cctxParams = *originalCctxParams; + ZSTD_compressionParameters cParams; + ZSTD_CDict* cdict; - return cdict; + DEBUGLOG(3, "ZSTD_createCDict_advanced2, mode %u", (unsigned)dictContentType); + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; + + if (cctxParams.enableDedicatedDictSearch) { + cParams = ZSTD_dedicatedDictSearch_getCParams( + cctxParams.compressionLevel, dictSize); + ZSTD_overrideCParams(&cParams, &cctxParams.cParams); + } else { + cParams = ZSTD_getCParamsFromCCtxParams( + &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); } + + if (!ZSTD_dedicatedDictSearch_isSupported(&cParams)) { + /* Fall back to non-DDSS params */ + cctxParams.enableDedicatedDictSearch = 0; + cParams = ZSTD_getCParamsFromCCtxParams( + &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); + } + + DEBUGLOG(3, "ZSTD_createCDict_advanced2: DDS: %u", cctxParams.enableDedicatedDictSearch); + cctxParams.cParams = cParams; + cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams); + + cdict = ZSTD_createCDict_advanced_internal(dictSize, + dictLoadMethod, cctxParams.cParams, + cctxParams.useRowMatchFinder, cctxParams.enableDedicatedDictSearch, + customMem); + + if (!cdict || ZSTD_isError( ZSTD_initCDict_internal(cdict, + dict, dictSize, + dictLoadMethod, dictContentType, + cctxParams) )) { + ZSTD_freeCDict(cdict); + return NULL; + } + + return cdict; } ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize); - ZSTD_CDict* cdict = ZSTD_createCDict_advanced(dict, dictSize, + ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); + ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto, - cParams, ZSTDInternalConstants::ZSTD_defaultCMem); + cParams, ZSTD_defaultCMem); if (cdict) - cdict->compressionLevel = compressionLevel == 0 ? ZSTD_CLEVEL_DEFAULT : compressionLevel; + cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel; return cdict; } ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize); - return ZSTD_createCDict_advanced(dict, dictSize, + ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); + ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto, - cParams, ZSTDInternalConstants::ZSTD_defaultCMem); + cParams, ZSTD_defaultCMem); + if (cdict) + cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel; + return cdict; } size_t ZSTD_freeCDict(ZSTD_CDict* cdict) @@ -3473,7 +5597,7 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict) int cdictInWorkspace = ZSTD_cwksp_owns_buffer(&cdict->workspace, cdict); ZSTD_cwksp_free(&cdict->workspace, cMem); if (!cdictInWorkspace) { - ZSTD_free(cdict, cMem); + ZSTD_customFree(cdict, cMem); } return 0; } @@ -3499,19 +5623,22 @@ const ZSTD_CDict* ZSTD_initStaticCDict( ZSTD_dictContentType_e dictContentType, ZSTD_compressionParameters cParams) { - size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0); + ZSTD_paramSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(ZSTD_ps_auto, &cParams); + /* enableDedicatedDictSearch == 1 ensures matchstate is not too small in case this CDict will be used for DDS + row hash */ + size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 1, /* forCCtx */ 0); size_t const neededSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*)))) + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) + matchStateSize; ZSTD_CDict* cdict; + ZSTD_CCtx_params params; if ((size_t)workspace & 7) return NULL; /* 8-aligned */ { ZSTD_cwksp ws; - ZSTD_cwksp_init(&ws, workspace, workspaceSize); + ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc); cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict)); if (cdict == NULL) return NULL; ZSTD_cwksp_move(&cdict->workspace, &ws); @@ -3521,10 +5648,16 @@ const ZSTD_CDict* ZSTD_initStaticCDict( (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize)); if (workspaceSize < neededSize) return NULL; + ZSTD_CCtxParams_init(¶ms, 0); + params.cParams = cParams; + params.useRowMatchFinder = useRowMatchFinder; + cdict->useRowMatchFinder = useRowMatchFinder; + cdict->compressionLevel = ZSTD_NO_CLEVEL; + if (ZSTD_isError( ZSTD_initCDict_internal(cdict, dict, dictSize, dictLoadMethod, dictContentType, - cParams) )) + params) )) return NULL; return cdict; @@ -3536,59 +5669,101 @@ ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) return cdict->matchState.cParams; } -/* ZSTD_compressBegin_usingCDict_advanced() : - * cdict must be != NULL */ -size_t ZSTD_compressBegin_usingCDict_advanced( +/*! ZSTD_getDictID_fromCDict() : + * Provides the dictID of the dictionary loaded into `cdict`. + * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. + * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ +unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict) +{ + if (cdict==NULL) return 0; + return cdict->dictID; +} + +/* ZSTD_compressBegin_usingCDict_internal() : + * Implementation of various ZSTD_compressBegin_usingCDict* functions. + */ +static size_t ZSTD_compressBegin_usingCDict_internal( ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) { - DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced"); + ZSTD_CCtx_params cctxParams; + DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_internal"); RETURN_ERROR_IF(cdict==NULL, dictionary_wrong, "NULL pointer!"); - { ZSTD_CCtx_params params = cctx->requestedParams; + /* Initialize the cctxParams from the cdict */ + { + ZSTD_parameters params; + params.fParams = fParams; params.cParams = ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN - || cdict->compressionLevel == 0 ) - && (params.attachDictPref != ZSTD_dictForceLoad) ? + || cdict->compressionLevel == 0 ) ? ZSTD_getCParamsFromCDict(cdict) : ZSTD_getCParams(cdict->compressionLevel, pledgedSrcSize, cdict->dictContentSize); - /* Increase window log to fit the entire dictionary and source if the - * source size is known. Limit the increase to 19, which is the - * window log for compression level 1 with the largest source size. - */ - if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { - U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); - U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; - params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog); - } - params.fParams = fParams; - return ZSTD_compressBegin_internal(cctx, - NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, - cdict, - ¶ms, pledgedSrcSize, - ZSTDb_not_buffered); + ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, cdict->compressionLevel); } + /* Increase window log to fit the entire dictionary and source if the + * source size is known. Limit the increase to 19, which is the + * window log for compression level 1 with the largest source size. + */ + if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { + U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); + U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; + cctxParams.cParams.windowLog = MAX(cctxParams.cParams.windowLog, limitedSrcLog); + } + return ZSTD_compressBegin_internal(cctx, + NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, + cdict, + &cctxParams, pledgedSrcSize, + ZSTDb_not_buffered); +} + + +/* ZSTD_compressBegin_usingCDict_advanced() : + * This function is DEPRECATED. + * cdict must be != NULL */ +size_t ZSTD_compressBegin_usingCDict_advanced( + ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, + ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) +{ + return ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, pledgedSrcSize); } /* ZSTD_compressBegin_usingCDict() : - * pledgedSrcSize=0 means "unknown" - * if pledgedSrcSize>0, it will enable contentSizeFlag */ + * cdict must be != NULL */ +size_t ZSTD_compressBegin_usingCDict_deprecated(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) +{ + ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; + return ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); +} + size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) { - ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; - DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag); - return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); + return ZSTD_compressBegin_usingCDict_deprecated(cctx, cdict); +} + +/*! ZSTD_compress_usingCDict_internal(): + * Implementation of various ZSTD_compress_usingCDict* functions. + */ +static size_t ZSTD_compress_usingCDict_internal(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) +{ + FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, srcSize), ""); /* will check if cdict != NULL */ + return ZSTD_compressEnd_public(cctx, dst, dstCapacity, src, srcSize); } +/*! ZSTD_compress_usingCDict_advanced(): + * This function is DEPRECATED. + */ size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) { - FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize), ""); /* will check if cdict != NULL */ - return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); + return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); } /*! ZSTD_compress_usingCDict() : @@ -3602,7 +5777,7 @@ size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) { ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; - return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); + return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); } @@ -3614,7 +5789,7 @@ size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, ZSTD_CStream* ZSTD_createCStream(void) { DEBUGLOG(3, "ZSTD_createCStream"); - return ZSTD_createCStream_advanced(ZSTDInternalConstants::ZSTD_defaultCMem); + return ZSTD_createCStream_advanced(ZSTD_defaultCMem); } ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize) @@ -3640,35 +5815,15 @@ size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; } size_t ZSTD_CStreamOutSize(void) { - return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTDInternalConstants::ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; + return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; } -static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx, - const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType, - const ZSTD_CDict* const cdict, - ZSTD_CCtx_params params, unsigned long long const pledgedSrcSize) +static ZSTD_cParamMode_e ZSTD_getCParamMode(ZSTD_CDict const* cdict, ZSTD_CCtx_params const* params, U64 pledgedSrcSize) { - DEBUGLOG(4, "ZSTD_resetCStream_internal"); - /* Finalize the compression parameters */ - params.cParams = ZSTD_getCParamsFromCCtxParams(¶ms, pledgedSrcSize, dictSize); - /* params are supposed to be fully validated at this point */ - assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); - assert(!((dict) && (cdict))); /* either dict or cdict, not both */ - - FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, - dict, dictSize, dictContentType, ZSTD_dtlm_fast, - cdict, - ¶ms, pledgedSrcSize, - ZSTDb_buffered) , ""); - - cctx->inToCompress = 0; - cctx->inBuffPos = 0; - cctx->inBuffTarget = cctx->blockSize - + (cctx->blockSize == pledgedSrcSize); /* for small input: avoid automatic flush on reaching end of block, since it would require to add a 3-bytes null block to end frame */ - cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0; - cctx->streamStage = zcss_load; - cctx->frameEnded = 0; - return 0; /* ready to go */ + if (cdict != NULL && ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) + return ZSTD_cpm_attachDict; + else + return ZSTD_cpm_noAttachDict; } /* ZSTD_resetCStream(): @@ -3752,7 +5907,7 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , ""); - zcs->requestedParams = ZSTD_assignParamsToCCtxParams(&zcs->requestedParams, ¶ms); + ZSTD_CCtxParams_setZstdParams(&zcs->requestedParams, ¶ms); FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , ""); return 0; } @@ -3794,36 +5949,54 @@ size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) static size_t ZSTD_nextInputSizeHint(const ZSTD_CCtx* cctx) { - size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos; - if (hintInSize==0) hintInSize = cctx->blockSize; - return hintInSize; + if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { + return cctx->blockSize - cctx->stableIn_notConsumed; + } + assert(cctx->appliedParams.inBufferMode == ZSTD_bm_buffered); + { size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos; + if (hintInSize==0) hintInSize = cctx->blockSize; + return hintInSize; + } } /** ZSTD_compressStream_generic(): * internal function for all *compressStream*() variants - * non-static, because can be called from zstdmt_compress.c - * @return : hint size for next input */ + * @return : hint size for next input to complete ongoing block */ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input, ZSTD_EndDirective const flushMode) { - const char* const istart = (const char*)input->src; - const char* const iend = input->size != 0 ? istart + input->size : istart; - const char* ip = input->pos != 0 ? istart + input->pos : istart; - char* const ostart = (char*)output->dst; - char* const oend = output->size != 0 ? ostart + output->size : ostart; - char* op = output->pos != 0 ? ostart + output->pos : ostart; + const char* const istart = (assert(input != NULL), (const char*)input->src); + const char* const iend = (istart != NULL) ? istart + input->size : istart; + const char* ip = (istart != NULL) ? istart + input->pos : istart; + char* const ostart = (assert(output != NULL), (char*)output->dst); + char* const oend = (ostart != NULL) ? ostart + output->size : ostart; + char* op = (ostart != NULL) ? ostart + output->pos : ostart; U32 someMoreWork = 1; /* check expectations */ - DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (unsigned)flushMode); - assert(zcs->inBuff != NULL); - assert(zcs->inBuffSize > 0); - assert(zcs->outBuff != NULL); - assert(zcs->outBuffSize > 0); - assert(output->pos <= output->size); + DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%i, srcSize = %zu", (int)flushMode, input->size - input->pos); + assert(zcs != NULL); + if (zcs->appliedParams.inBufferMode == ZSTD_bm_stable) { + assert(input->pos >= zcs->stableIn_notConsumed); + input->pos -= zcs->stableIn_notConsumed; + if (ip) ip -= zcs->stableIn_notConsumed; + zcs->stableIn_notConsumed = 0; + } + if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) { + assert(zcs->inBuff != NULL); + assert(zcs->inBuffSize > 0); + } + if (zcs->appliedParams.outBufferMode == ZSTD_bm_buffered) { + assert(zcs->outBuff != NULL); + assert(zcs->outBuffSize > 0); + } + if (input->src == NULL) assert(input->size == 0); assert(input->pos <= input->size); + if (output->dst == NULL) assert(output->size == 0); + assert(output->pos <= output->size); + assert((U32)flushMode <= (U32)ZSTD_e_end); while (someMoreWork) { switch(zcs->streamStage) @@ -3833,10 +6006,11 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, case zcss_load: if ( (flushMode == ZSTD_e_end) - && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */ + && ( (size_t)(oend-op) >= ZSTD_compressBound(iend-ip) /* Enough output space */ + || zcs->appliedParams.outBufferMode == ZSTD_bm_stable) /* OR we are allowed to return dstSizeTooSmall */ && (zcs->inBuffPos == 0) ) { /* shortcut to compression pass directly into output buffer */ - size_t const cSize = ZSTD_compressEnd(zcs, + size_t const cSize = ZSTD_compressEnd_public(zcs, op, oend-op, ip, iend-ip); DEBUGLOG(4, "ZSTD_compressEnd : cSize=%u", (unsigned)cSize); FORWARD_IF_ERROR(cSize, "ZSTD_compressEnd failed"); @@ -3846,14 +6020,14 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); someMoreWork = 0; break; } - /* complete loading into inBuffer */ - { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; + /* complete loading into inBuffer in buffered mode */ + if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) { + size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; size_t const loaded = ZSTD_limitCopy( zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip); zcs->inBuffPos += loaded; - if (loaded != 0) - ip += loaded; + if (ip) ip += loaded; if ( (flushMode == ZSTD_e_continue) && (zcs->inBuffPos < zcs->inBuffTarget) ) { /* not enough input to fill full block : stop here */ @@ -3864,34 +6038,62 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, /* empty */ someMoreWork = 0; break; } + } else { + assert(zcs->appliedParams.inBufferMode == ZSTD_bm_stable); + if ( (flushMode == ZSTD_e_continue) + && ( (size_t)(iend - ip) < zcs->blockSize) ) { + /* can't compress a full block : stop here */ + zcs->stableIn_notConsumed = (size_t)(iend - ip); + ip = iend; /* pretend to have consumed input */ + someMoreWork = 0; break; + } + if ( (flushMode == ZSTD_e_flush) + && (ip == iend) ) { + /* empty */ + someMoreWork = 0; break; + } } /* compress current block (note : this stage cannot be stopped in the middle) */ DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode); - { void* cDst; + { int const inputBuffered = (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered); + void* cDst; size_t cSize; - size_t const iSize = zcs->inBuffPos - zcs->inToCompress; size_t oSize = oend-op; - unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend); - if (oSize >= ZSTD_compressBound(iSize)) + size_t const iSize = inputBuffered ? zcs->inBuffPos - zcs->inToCompress + : MIN((size_t)(iend - ip), zcs->blockSize); + if (oSize >= ZSTD_compressBound(iSize) || zcs->appliedParams.outBufferMode == ZSTD_bm_stable) cDst = op; /* compress into output buffer, to skip flush stage */ else cDst = zcs->outBuff, oSize = zcs->outBuffSize; - cSize = lastBlock ? - ZSTD_compressEnd(zcs, cDst, oSize, - zcs->inBuff + zcs->inToCompress, iSize) : - ZSTD_compressContinue(zcs, cDst, oSize, - zcs->inBuff + zcs->inToCompress, iSize); - FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed"); - zcs->frameEnded = lastBlock; - /* prepare next block */ - zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; - if (zcs->inBuffTarget > zcs->inBuffSize) - zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; - DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u", - (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize); - if (!lastBlock) - assert(zcs->inBuffTarget <= zcs->inBuffSize); - zcs->inToCompress = zcs->inBuffPos; + if (inputBuffered) { + unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend); + cSize = lastBlock ? + ZSTD_compressEnd_public(zcs, cDst, oSize, + zcs->inBuff + zcs->inToCompress, iSize) : + ZSTD_compressContinue_public(zcs, cDst, oSize, + zcs->inBuff + zcs->inToCompress, iSize); + FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed"); + zcs->frameEnded = lastBlock; + /* prepare next block */ + zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; + if (zcs->inBuffTarget > zcs->inBuffSize) + zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; + DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u", + (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize); + if (!lastBlock) + assert(zcs->inBuffTarget <= zcs->inBuffSize); + zcs->inToCompress = zcs->inBuffPos; + } else { /* !inputBuffered, hence ZSTD_bm_stable */ + unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip + iSize == iend); + cSize = lastBlock ? + ZSTD_compressEnd_public(zcs, cDst, oSize, ip, iSize) : + ZSTD_compressContinue_public(zcs, cDst, oSize, ip, iSize); + /* Consume the input prior to error checking to mirror buffered mode. */ + if (ip) ip += iSize; + FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed"); + zcs->frameEnded = lastBlock; + if (lastBlock) assert(ip == iend); + } if (cDst == op) { /* no need to flush */ op += cSize; if (zcs->frameEnded) { @@ -3905,9 +6107,10 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, zcs->outBuffFlushedSize = 0; zcs->streamStage = zcss_flush; /* pass-through to flush stage */ } - /* fall-through */ + ZSTD_FALLTHROUGH; case zcss_flush: DEBUGLOG(5, "flush stage"); + assert(zcs->appliedParams.outBufferMode == ZSTD_bm_buffered); { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize; size_t const flushed = ZSTD_limitCopy(op, (size_t)(oend-op), zcs->outBuff + zcs->outBuffFlushedSize, toFlush); @@ -3962,7 +6165,141 @@ size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuf return ZSTD_nextInputSizeHint_MTorST(zcs); } +/* After a compression call set the expected input/output buffer. + * This is validated at the start of the next compression call. + */ +static void +ZSTD_setBufferExpectations(ZSTD_CCtx* cctx, const ZSTD_outBuffer* output, const ZSTD_inBuffer* input) +{ + DEBUGLOG(5, "ZSTD_setBufferExpectations (for advanced stable in/out modes)"); + if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { + cctx->expectedInBuffer = *input; + } + if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) { + cctx->expectedOutBufferSize = output->size - output->pos; + } +} + +/* Validate that the input/output buffers match the expectations set by + * ZSTD_setBufferExpectations. + */ +static size_t ZSTD_checkBufferStability(ZSTD_CCtx const* cctx, + ZSTD_outBuffer const* output, + ZSTD_inBuffer const* input, + ZSTD_EndDirective endOp) +{ + if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { + ZSTD_inBuffer const expect = cctx->expectedInBuffer; + if (expect.src != input->src || expect.pos != input->pos) + RETURN_ERROR(stabilityCondition_notRespected, "ZSTD_c_stableInBuffer enabled but input differs!"); + } + (void)endOp; + if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) { + size_t const outBufferSize = output->size - output->pos; + if (cctx->expectedOutBufferSize != outBufferSize) + RETURN_ERROR(stabilityCondition_notRespected, "ZSTD_c_stableOutBuffer enabled but output size differs!"); + } + return 0; +} + +static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx, + ZSTD_EndDirective endOp, + size_t inSize) +{ + ZSTD_CCtx_params params = cctx->requestedParams; + ZSTD_prefixDict const prefixDict = cctx->prefixDict; + FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */ + ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ + assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ + if (cctx->cdict && !cctx->localDict.cdict) { + /* Let the cdict's compression level take priority over the requested params. + * But do not take the cdict's compression level if the "cdict" is actually a localDict + * generated from ZSTD_initLocalDict(). + */ + params.compressionLevel = cctx->cdict->compressionLevel; + } + DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage"); + if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = inSize + 1; /* auto-determine pledgedSrcSize */ + + { size_t const dictSize = prefixDict.dict + ? prefixDict.dictSize + : (cctx->cdict ? cctx->cdict->dictContentSize : 0); + ZSTD_cParamMode_e const mode = ZSTD_getCParamMode(cctx->cdict, ¶ms, cctx->pledgedSrcSizePlusOne - 1); + params.cParams = ZSTD_getCParamsFromCCtxParams( + ¶ms, cctx->pledgedSrcSizePlusOne-1, + dictSize, mode); + } + + params.useBlockSplitter = ZSTD_resolveBlockSplitterMode(params.useBlockSplitter, ¶ms.cParams); + params.ldmParams.enableLdm = ZSTD_resolveEnableLdm(params.ldmParams.enableLdm, ¶ms.cParams); + params.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params.useRowMatchFinder, ¶ms.cParams); + params.validateSequences = ZSTD_resolveExternalSequenceValidation(params.validateSequences); + params.maxBlockSize = ZSTD_resolveMaxBlockSize(params.maxBlockSize); + params.searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(params.searchForExternalRepcodes, params.compressionLevel); + +#ifdef ZSTD_MULTITHREAD + /* If external matchfinder is enabled, make sure to fail before checking job size (for consistency) */ + RETURN_ERROR_IF( + ZSTD_hasExtSeqProd(¶ms) && params.nbWorkers >= 1, + parameter_combination_unsupported, + "External sequence producer isn't supported with nbWorkers >= 1" + ); + + if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) { + params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */ + } + if (params.nbWorkers > 0) { +#if ZSTD_TRACE + cctx->traceCtx = (ZSTD_trace_compress_begin != NULL) ? ZSTD_trace_compress_begin(cctx) : 0; +#endif + /* mt context creation */ + if (cctx->mtctx == NULL) { + DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u", + params.nbWorkers); + cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem, cctx->pool); + RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation, "NULL pointer!"); + } + /* mt compression */ + DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers); + FORWARD_IF_ERROR( ZSTDMT_initCStream_internal( + cctx->mtctx, + prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, + cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) , ""); + cctx->dictID = cctx->cdict ? cctx->cdict->dictID : 0; + cctx->dictContentSize = cctx->cdict ? cctx->cdict->dictContentSize : prefixDict.dictSize; + cctx->consumedSrcSize = 0; + cctx->producedCSize = 0; + cctx->streamStage = zcss_load; + cctx->appliedParams = params; + } else +#endif /* ZSTD_MULTITHREAD */ + { U64 const pledgedSrcSize = cctx->pledgedSrcSizePlusOne - 1; + assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); + FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, + prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, ZSTD_dtlm_fast, + cctx->cdict, + ¶ms, pledgedSrcSize, + ZSTDb_buffered) , ""); + assert(cctx->appliedParams.nbWorkers == 0); + cctx->inToCompress = 0; + cctx->inBuffPos = 0; + if (cctx->appliedParams.inBufferMode == ZSTD_bm_buffered) { + /* for small input: avoid automatic flush on reaching end of block, since + * it would require to add a 3-bytes null block to end frame + */ + cctx->inBuffTarget = cctx->blockSize + (cctx->blockSize == pledgedSrcSize); + } else { + cctx->inBuffTarget = 0; + } + cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0; + cctx->streamStage = zcss_load; + cctx->frameEnded = 0; + } + return 0; +} +/* @return provides a minimum amount of data remaining to be flushed from internal buffers + */ size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input, @@ -3970,82 +6307,95 @@ size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, { DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp); /* check conditions */ - RETURN_ERROR_IF(output->pos > output->size, GENERIC, "invalid buffer"); - RETURN_ERROR_IF(input->pos > input->size, GENERIC, "invalid buffer"); - assert(cctx!=NULL); + RETURN_ERROR_IF(output->pos > output->size, dstSize_tooSmall, "invalid output buffer"); + RETURN_ERROR_IF(input->pos > input->size, srcSize_wrong, "invalid input buffer"); + RETURN_ERROR_IF((U32)endOp > (U32)ZSTD_e_end, parameter_outOfBound, "invalid endDirective"); + assert(cctx != NULL); /* transparent initialization stage */ if (cctx->streamStage == zcss_init) { - ZSTD_CCtx_params params = cctx->requestedParams; - ZSTD_prefixDict const prefixDict = cctx->prefixDict; - FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */ - memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ - assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ - DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage"); - if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */ - params.cParams = ZSTD_getCParamsFromCCtxParams( - &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); - - -#ifdef ZSTD_MULTITHREAD - if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) { - params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */ - } - if (params.nbWorkers > 0) { - /* mt context creation */ - if (cctx->mtctx == NULL) { - DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u", - params.nbWorkers); - cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem); - RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation, "NULL pointer!"); + size_t const inputSize = input->size - input->pos; /* no obligation to start from pos==0 */ + size_t const totalInputSize = inputSize + cctx->stableIn_notConsumed; + if ( (cctx->requestedParams.inBufferMode == ZSTD_bm_stable) /* input is presumed stable, across invocations */ + && (endOp == ZSTD_e_continue) /* no flush requested, more input to come */ + && (totalInputSize < ZSTD_BLOCKSIZE_MAX) ) { /* not even reached one block yet */ + if (cctx->stableIn_notConsumed) { /* not the first time */ + /* check stable source guarantees */ + RETURN_ERROR_IF(input->src != cctx->expectedInBuffer.src, stabilityCondition_notRespected, "stableInBuffer condition not respected: wrong src pointer"); + RETURN_ERROR_IF(input->pos != cctx->expectedInBuffer.size, stabilityCondition_notRespected, "stableInBuffer condition not respected: externally modified pos"); } - /* mt compression */ - DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers); - FORWARD_IF_ERROR( ZSTDMT_initCStream_internal( - cctx->mtctx, - prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, - cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) , ""); - cctx->streamStage = zcss_load; - cctx->appliedParams.nbWorkers = params.nbWorkers; - } else -#endif - { FORWARD_IF_ERROR( ZSTD_resetCStream_internal(cctx, - prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, - cctx->cdict, - params, cctx->pledgedSrcSizePlusOne-1) , ""); - assert(cctx->streamStage == zcss_load); - assert(cctx->appliedParams.nbWorkers == 0); - } } + /* pretend input was consumed, to give a sense forward progress */ + input->pos = input->size; + /* save stable inBuffer, for later control, and flush/end */ + cctx->expectedInBuffer = *input; + /* but actually input wasn't consumed, so keep track of position from where compression shall resume */ + cctx->stableIn_notConsumed += inputSize; + /* don't initialize yet, wait for the first block of flush() order, for better parameters adaptation */ + return ZSTD_FRAMEHEADERSIZE_MIN(cctx->requestedParams.format); /* at least some header to produce */ + } + FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, endOp, totalInputSize), "compressStream2 initialization failed"); + ZSTD_setBufferExpectations(cctx, output, input); /* Set initial buffer expectations now that we've initialized */ + } /* end of transparent initialization stage */ + FORWARD_IF_ERROR(ZSTD_checkBufferStability(cctx, output, input, endOp), "invalid buffers"); /* compression stage */ #ifdef ZSTD_MULTITHREAD if (cctx->appliedParams.nbWorkers > 0) { - int const forceMaxProgress = (endOp == ZSTD_e_flush || endOp == ZSTD_e_end); size_t flushMin; - assert(forceMaxProgress || endOp == ZSTD_e_continue /* Protection for a new flush type */); if (cctx->cParamsChanged) { ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams); cctx->cParamsChanged = 0; } - do { + if (cctx->stableIn_notConsumed) { + assert(cctx->appliedParams.inBufferMode == ZSTD_bm_stable); + /* some early data was skipped - make it available for consumption */ + assert(input->pos >= cctx->stableIn_notConsumed); + input->pos -= cctx->stableIn_notConsumed; + cctx->stableIn_notConsumed = 0; + } + for (;;) { + size_t const ipos = input->pos; + size_t const opos = output->pos; flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); + cctx->consumedSrcSize += (U64)(input->pos - ipos); + cctx->producedCSize += (U64)(output->pos - opos); if ( ZSTD_isError(flushMin) || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */ + if (flushMin == 0) + ZSTD_CCtx_trace(cctx, 0); ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); } FORWARD_IF_ERROR(flushMin, "ZSTDMT_compressStream_generic failed"); - } while (forceMaxProgress && flushMin != 0 && output->pos < output->size); + + if (endOp == ZSTD_e_continue) { + /* We only require some progress with ZSTD_e_continue, not maximal progress. + * We're done if we've consumed or produced any bytes, or either buffer is + * full. + */ + if (input->pos != ipos || output->pos != opos || input->pos == input->size || output->pos == output->size) + break; + } else { + assert(endOp == ZSTD_e_flush || endOp == ZSTD_e_end); + /* We require maximal progress. We're done when the flush is complete or the + * output buffer is full. + */ + if (flushMin == 0 || output->pos == output->size) + break; + } + } DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic"); /* Either we don't require maximum forward progress, we've finished the * flush, or we are out of output space. */ - assert(!forceMaxProgress || flushMin == 0 || output->pos == output->size); + assert(endOp == ZSTD_e_continue || flushMin == 0 || output->pos == output->size); + ZSTD_setBufferExpectations(cctx, output, input); return flushMin; } -#endif +#endif /* ZSTD_MULTITHREAD */ FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) , ""); DEBUGLOG(5, "completed ZSTD_compressStream2"); + ZSTD_setBufferExpectations(cctx, output, input); return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */ } @@ -4055,27 +6405,43 @@ size_t ZSTD_compressStream2_simpleArgs ( const void* src, size_t srcSize, size_t* srcPos, ZSTD_EndDirective endOp) { - ZSTD_outBuffer output = { dst, dstCapacity, *dstPos }; - ZSTD_inBuffer input = { src, srcSize, *srcPos }; + ZSTD_outBuffer output; + ZSTD_inBuffer input; + output.dst = dst; + output.size = dstCapacity; + output.pos = *dstPos; + input.src = src; + input.size = srcSize; + input.pos = *srcPos; /* ZSTD_compressStream2() will check validity of dstPos and srcPos */ - size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp); - *dstPos = output.pos; - *srcPos = input.pos; - return cErr; + { size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp); + *dstPos = output.pos; + *srcPos = input.pos; + return cErr; + } } size_t ZSTD_compress2(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { + ZSTD_bufferMode_e const originalInBufferMode = cctx->requestedParams.inBufferMode; + ZSTD_bufferMode_e const originalOutBufferMode = cctx->requestedParams.outBufferMode; DEBUGLOG(4, "ZSTD_compress2 (srcSize=%u)", (unsigned)srcSize); ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); + /* Enable stable input/output buffers. */ + cctx->requestedParams.inBufferMode = ZSTD_bm_stable; + cctx->requestedParams.outBufferMode = ZSTD_bm_stable; { size_t oPos = 0; size_t iPos = 0; size_t const result = ZSTD_compressStream2_simpleArgs(cctx, dst, dstCapacity, &oPos, src, srcSize, &iPos, ZSTD_e_end); + /* Reset to the original values. */ + cctx->requestedParams.inBufferMode = originalInBufferMode; + cctx->requestedParams.outBufferMode = originalOutBufferMode; + FORWARD_IF_ERROR(result, "ZSTD_compressStream2_simpleArgs failed"); if (result != 0) { /* compression not completed, due to lack of output space */ assert(oPos == dstCapacity); @@ -4086,22 +6452,512 @@ size_t ZSTD_compress2(ZSTD_CCtx* cctx, } } +/* ZSTD_validateSequence() : + * @offCode : is presumed to follow format required by ZSTD_storeSeq() + * @returns a ZSTD error code if sequence is not valid + */ +static size_t +ZSTD_validateSequence(U32 offCode, U32 matchLength, U32 minMatch, + size_t posInSrc, U32 windowLog, size_t dictSize, int useSequenceProducer) +{ + U32 const windowSize = 1u << windowLog; + /* posInSrc represents the amount of data the decoder would decode up to this point. + * As long as the amount of data decoded is less than or equal to window size, offsets may be + * larger than the total length of output decoded in order to reference the dict, even larger than + * window size. After output surpasses windowSize, we're limited to windowSize offsets again. + */ + size_t const offsetBound = posInSrc > windowSize ? (size_t)windowSize : posInSrc + (size_t)dictSize; + size_t const matchLenLowerBound = (minMatch == 3 || useSequenceProducer) ? 3 : 4; + RETURN_ERROR_IF(offCode > OFFSET_TO_OFFBASE(offsetBound), externalSequences_invalid, "Offset too large!"); + /* Validate maxNbSeq is large enough for the given matchLength and minMatch */ + RETURN_ERROR_IF(matchLength < matchLenLowerBound, externalSequences_invalid, "Matchlength too small for the minMatch"); + return 0; +} + +/* Returns an offset code, given a sequence's raw offset, the ongoing repcode array, and whether litLength == 0 */ +static U32 ZSTD_finalizeOffBase(U32 rawOffset, const U32 rep[ZSTD_REP_NUM], U32 ll0) +{ + U32 offBase = OFFSET_TO_OFFBASE(rawOffset); + + if (!ll0 && rawOffset == rep[0]) { + offBase = REPCODE1_TO_OFFBASE; + } else if (rawOffset == rep[1]) { + offBase = REPCODE_TO_OFFBASE(2 - ll0); + } else if (rawOffset == rep[2]) { + offBase = REPCODE_TO_OFFBASE(3 - ll0); + } else if (ll0 && rawOffset == rep[0] - 1) { + offBase = REPCODE3_TO_OFFBASE; + } + return offBase; +} + +size_t +ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx, + ZSTD_sequencePosition* seqPos, + const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, + const void* src, size_t blockSize, + ZSTD_paramSwitch_e externalRepSearch) +{ + U32 idx = seqPos->idx; + U32 const startIdx = idx; + BYTE const* ip = (BYTE const*)(src); + const BYTE* const iend = ip + blockSize; + repcodes_t updatedRepcodes; + U32 dictSize; + + DEBUGLOG(5, "ZSTD_copySequencesToSeqStoreExplicitBlockDelim (blockSize = %zu)", blockSize); + + if (cctx->cdict) { + dictSize = (U32)cctx->cdict->dictContentSize; + } else if (cctx->prefixDict.dict) { + dictSize = (U32)cctx->prefixDict.dictSize; + } else { + dictSize = 0; + } + ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t)); + for (; idx < inSeqsSize && (inSeqs[idx].matchLength != 0 || inSeqs[idx].offset != 0); ++idx) { + U32 const litLength = inSeqs[idx].litLength; + U32 const matchLength = inSeqs[idx].matchLength; + U32 offBase; + + if (externalRepSearch == ZSTD_ps_disable) { + offBase = OFFSET_TO_OFFBASE(inSeqs[idx].offset); + } else { + U32 const ll0 = (litLength == 0); + offBase = ZSTD_finalizeOffBase(inSeqs[idx].offset, updatedRepcodes.rep, ll0); + ZSTD_updateRep(updatedRepcodes.rep, offBase, ll0); + } + + DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength); + if (cctx->appliedParams.validateSequences) { + seqPos->posInSrc += litLength + matchLength; + FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc, + cctx->appliedParams.cParams.windowLog, dictSize, ZSTD_hasExtSeqProd(&cctx->appliedParams)), + "Sequence validation failed"); + } + RETURN_ERROR_IF(idx - seqPos->idx >= cctx->seqStore.maxNbSeq, externalSequences_invalid, + "Not enough memory allocated. Try adjusting ZSTD_c_minMatch."); + ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offBase, matchLength); + ip += matchLength + litLength; + } + + /* If we skipped repcode search while parsing, we need to update repcodes now */ + assert(externalRepSearch != ZSTD_ps_auto); + assert(idx >= startIdx); + if (externalRepSearch == ZSTD_ps_disable && idx != startIdx) { + U32* const rep = updatedRepcodes.rep; + U32 lastSeqIdx = idx - 1; /* index of last non-block-delimiter sequence */ + + if (lastSeqIdx >= startIdx + 2) { + rep[2] = inSeqs[lastSeqIdx - 2].offset; + rep[1] = inSeqs[lastSeqIdx - 1].offset; + rep[0] = inSeqs[lastSeqIdx].offset; + } else if (lastSeqIdx == startIdx + 1) { + rep[2] = rep[0]; + rep[1] = inSeqs[lastSeqIdx - 1].offset; + rep[0] = inSeqs[lastSeqIdx].offset; + } else { + assert(lastSeqIdx == startIdx); + rep[2] = rep[1]; + rep[1] = rep[0]; + rep[0] = inSeqs[lastSeqIdx].offset; + } + } + + ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t)); + + if (inSeqs[idx].litLength) { + DEBUGLOG(6, "Storing last literals of size: %u", inSeqs[idx].litLength); + ZSTD_storeLastLiterals(&cctx->seqStore, ip, inSeqs[idx].litLength); + ip += inSeqs[idx].litLength; + seqPos->posInSrc += inSeqs[idx].litLength; + } + RETURN_ERROR_IF(ip != iend, externalSequences_invalid, "Blocksize doesn't agree with block delimiter!"); + seqPos->idx = idx+1; + return 0; +} + +size_t +ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos, + const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, + const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch) +{ + U32 idx = seqPos->idx; + U32 startPosInSequence = seqPos->posInSequence; + U32 endPosInSequence = seqPos->posInSequence + (U32)blockSize; + size_t dictSize; + BYTE const* ip = (BYTE const*)(src); + BYTE const* iend = ip + blockSize; /* May be adjusted if we decide to process fewer than blockSize bytes */ + repcodes_t updatedRepcodes; + U32 bytesAdjustment = 0; + U32 finalMatchSplit = 0; + + /* TODO(embg) support fast parsing mode in noBlockDelim mode */ + (void)externalRepSearch; + + if (cctx->cdict) { + dictSize = cctx->cdict->dictContentSize; + } else if (cctx->prefixDict.dict) { + dictSize = cctx->prefixDict.dictSize; + } else { + dictSize = 0; + } + DEBUGLOG(5, "ZSTD_copySequencesToSeqStoreNoBlockDelim: idx: %u PIS: %u blockSize: %zu", idx, startPosInSequence, blockSize); + DEBUGLOG(5, "Start seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength); + ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t)); + while (endPosInSequence && idx < inSeqsSize && !finalMatchSplit) { + const ZSTD_Sequence currSeq = inSeqs[idx]; + U32 litLength = currSeq.litLength; + U32 matchLength = currSeq.matchLength; + U32 const rawOffset = currSeq.offset; + U32 offBase; + + /* Modify the sequence depending on where endPosInSequence lies */ + if (endPosInSequence >= currSeq.litLength + currSeq.matchLength) { + if (startPosInSequence >= litLength) { + startPosInSequence -= litLength; + litLength = 0; + matchLength -= startPosInSequence; + } else { + litLength -= startPosInSequence; + } + /* Move to the next sequence */ + endPosInSequence -= currSeq.litLength + currSeq.matchLength; + startPosInSequence = 0; + } else { + /* This is the final (partial) sequence we're adding from inSeqs, and endPosInSequence + does not reach the end of the match. So, we have to split the sequence */ + DEBUGLOG(6, "Require a split: diff: %u, idx: %u PIS: %u", + currSeq.litLength + currSeq.matchLength - endPosInSequence, idx, endPosInSequence); + if (endPosInSequence > litLength) { + U32 firstHalfMatchLength; + litLength = startPosInSequence >= litLength ? 0 : litLength - startPosInSequence; + firstHalfMatchLength = endPosInSequence - startPosInSequence - litLength; + if (matchLength > blockSize && firstHalfMatchLength >= cctx->appliedParams.cParams.minMatch) { + /* Only ever split the match if it is larger than the block size */ + U32 secondHalfMatchLength = currSeq.matchLength + currSeq.litLength - endPosInSequence; + if (secondHalfMatchLength < cctx->appliedParams.cParams.minMatch) { + /* Move the endPosInSequence backward so that it creates match of minMatch length */ + endPosInSequence -= cctx->appliedParams.cParams.minMatch - secondHalfMatchLength; + bytesAdjustment = cctx->appliedParams.cParams.minMatch - secondHalfMatchLength; + firstHalfMatchLength -= bytesAdjustment; + } + matchLength = firstHalfMatchLength; + /* Flag that we split the last match - after storing the sequence, exit the loop, + but keep the value of endPosInSequence */ + finalMatchSplit = 1; + } else { + /* Move the position in sequence backwards so that we don't split match, and break to store + * the last literals. We use the original currSeq.litLength as a marker for where endPosInSequence + * should go. We prefer to do this whenever it is not necessary to split the match, or if doing so + * would cause the first half of the match to be too small + */ + bytesAdjustment = endPosInSequence - currSeq.litLength; + endPosInSequence = currSeq.litLength; + break; + } + } else { + /* This sequence ends inside the literals, break to store the last literals */ + break; + } + } + /* Check if this offset can be represented with a repcode */ + { U32 const ll0 = (litLength == 0); + offBase = ZSTD_finalizeOffBase(rawOffset, updatedRepcodes.rep, ll0); + ZSTD_updateRep(updatedRepcodes.rep, offBase, ll0); + } + + if (cctx->appliedParams.validateSequences) { + seqPos->posInSrc += litLength + matchLength; + FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc, + cctx->appliedParams.cParams.windowLog, dictSize, ZSTD_hasExtSeqProd(&cctx->appliedParams)), + "Sequence validation failed"); + } + DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength); + RETURN_ERROR_IF(idx - seqPos->idx >= cctx->seqStore.maxNbSeq, externalSequences_invalid, + "Not enough memory allocated. Try adjusting ZSTD_c_minMatch."); + ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offBase, matchLength); + ip += matchLength + litLength; + if (!finalMatchSplit) + idx++; /* Next Sequence */ + } + DEBUGLOG(5, "Ending seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength); + assert(idx == inSeqsSize || endPosInSequence <= inSeqs[idx].litLength + inSeqs[idx].matchLength); + seqPos->idx = idx; + seqPos->posInSequence = endPosInSequence; + ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t)); + + iend -= bytesAdjustment; + if (ip != iend) { + /* Store any last literals */ + U32 lastLLSize = (U32)(iend - ip); + assert(ip <= iend); + DEBUGLOG(6, "Storing last literals of size: %u", lastLLSize); + ZSTD_storeLastLiterals(&cctx->seqStore, ip, lastLLSize); + seqPos->posInSrc += lastLLSize; + } + + return bytesAdjustment; +} + +typedef size_t (*ZSTD_sequenceCopier) (ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos, + const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, + const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch); +static ZSTD_sequenceCopier ZSTD_selectSequenceCopier(ZSTD_sequenceFormat_e mode) +{ + ZSTD_sequenceCopier sequenceCopier = NULL; + assert(ZSTD_cParam_withinBounds(ZSTD_c_blockDelimiters, mode)); + if (mode == ZSTD_sf_explicitBlockDelimiters) { + return ZSTD_copySequencesToSeqStoreExplicitBlockDelim; + } else if (mode == ZSTD_sf_noBlockDelimiters) { + return ZSTD_copySequencesToSeqStoreNoBlockDelim; + } + assert(sequenceCopier != NULL); + return sequenceCopier; +} + +/* Discover the size of next block by searching for the delimiter. + * Note that a block delimiter **must** exist in this mode, + * otherwise it's an input error. + * The block size retrieved will be later compared to ensure it remains within bounds */ +static size_t +blockSize_explicitDelimiter(const ZSTD_Sequence* inSeqs, size_t inSeqsSize, ZSTD_sequencePosition seqPos) +{ + int end = 0; + size_t blockSize = 0; + size_t spos = seqPos.idx; + DEBUGLOG(6, "blockSize_explicitDelimiter : seq %zu / %zu", spos, inSeqsSize); + assert(spos <= inSeqsSize); + while (spos < inSeqsSize) { + end = (inSeqs[spos].offset == 0); + blockSize += inSeqs[spos].litLength + inSeqs[spos].matchLength; + if (end) { + if (inSeqs[spos].matchLength != 0) + RETURN_ERROR(externalSequences_invalid, "delimiter format error : both matchlength and offset must be == 0"); + break; + } + spos++; + } + if (!end) + RETURN_ERROR(externalSequences_invalid, "Reached end of sequences without finding a block delimiter"); + return blockSize; +} + +/* More a "target" block size */ +static size_t blockSize_noDelimiter(size_t blockSize, size_t remaining) +{ + int const lastBlock = (remaining <= blockSize); + return lastBlock ? remaining : blockSize; +} + +static size_t determine_blockSize(ZSTD_sequenceFormat_e mode, + size_t blockSize, size_t remaining, + const ZSTD_Sequence* inSeqs, size_t inSeqsSize, ZSTD_sequencePosition seqPos) +{ + DEBUGLOG(6, "determine_blockSize : remainingSize = %zu", remaining); + if (mode == ZSTD_sf_noBlockDelimiters) + return blockSize_noDelimiter(blockSize, remaining); + { size_t const explicitBlockSize = blockSize_explicitDelimiter(inSeqs, inSeqsSize, seqPos); + FORWARD_IF_ERROR(explicitBlockSize, "Error while determining block size with explicit delimiters"); + if (explicitBlockSize > blockSize) + RETURN_ERROR(externalSequences_invalid, "sequences incorrectly define a too large block"); + if (explicitBlockSize > remaining) + RETURN_ERROR(externalSequences_invalid, "sequences define a frame longer than source"); + return explicitBlockSize; + } +} + +/* Compress, block-by-block, all of the sequences given. + * + * Returns the cumulative size of all compressed blocks (including their headers), + * otherwise a ZSTD error. + */ +static size_t +ZSTD_compressSequences_internal(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const ZSTD_Sequence* inSeqs, size_t inSeqsSize, + const void* src, size_t srcSize) +{ + size_t cSize = 0; + size_t remaining = srcSize; + ZSTD_sequencePosition seqPos = {0, 0, 0}; + + BYTE const* ip = (BYTE const*)src; + BYTE* op = (BYTE*)dst; + ZSTD_sequenceCopier const sequenceCopier = ZSTD_selectSequenceCopier(cctx->appliedParams.blockDelimiters); + + DEBUGLOG(4, "ZSTD_compressSequences_internal srcSize: %zu, inSeqsSize: %zu", srcSize, inSeqsSize); + /* Special case: empty frame */ + if (remaining == 0) { + U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1); + RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "No room for empty frame block header"); + MEM_writeLE32(op, cBlockHeader24); + op += ZSTD_blockHeaderSize; + dstCapacity -= ZSTD_blockHeaderSize; + cSize += ZSTD_blockHeaderSize; + } + + while (remaining) { + size_t compressedSeqsSize; + size_t cBlockSize; + size_t additionalByteAdjustment; + size_t blockSize = determine_blockSize(cctx->appliedParams.blockDelimiters, + cctx->blockSize, remaining, + inSeqs, inSeqsSize, seqPos); + U32 const lastBlock = (blockSize == remaining); + FORWARD_IF_ERROR(blockSize, "Error while trying to determine block size"); + assert(blockSize <= remaining); + ZSTD_resetSeqStore(&cctx->seqStore); + DEBUGLOG(5, "Working on new block. Blocksize: %zu (total:%zu)", blockSize, (ip - (const BYTE*)src) + blockSize); + + additionalByteAdjustment = sequenceCopier(cctx, &seqPos, inSeqs, inSeqsSize, ip, blockSize, cctx->appliedParams.searchForExternalRepcodes); + FORWARD_IF_ERROR(additionalByteAdjustment, "Bad sequence copy"); + blockSize -= additionalByteAdjustment; + + /* If blocks are too small, emit as a nocompress block */ + /* TODO: See 3090. We reduced MIN_CBLOCK_SIZE from 3 to 2 so to compensate we are adding + * additional 1. We need to revisit and change this logic to be more consistent */ + if (blockSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1+1) { + cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); + FORWARD_IF_ERROR(cBlockSize, "Nocompress block failed"); + DEBUGLOG(5, "Block too small, writing out nocompress block: cSize: %zu", cBlockSize); + cSize += cBlockSize; + ip += blockSize; + op += cBlockSize; + remaining -= blockSize; + dstCapacity -= cBlockSize; + continue; + } + + RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall, "not enough dstCapacity to write a new compressed block"); + compressedSeqsSize = ZSTD_entropyCompressSeqStore(&cctx->seqStore, + &cctx->blockState.prevCBlock->entropy, &cctx->blockState.nextCBlock->entropy, + &cctx->appliedParams, + op + ZSTD_blockHeaderSize /* Leave space for block header */, dstCapacity - ZSTD_blockHeaderSize, + blockSize, + cctx->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, + cctx->bmi2); + FORWARD_IF_ERROR(compressedSeqsSize, "Compressing sequences of block failed"); + DEBUGLOG(5, "Compressed sequences size: %zu", compressedSeqsSize); + + if (!cctx->isFirstBlock && + ZSTD_maybeRLE(&cctx->seqStore) && + ZSTD_isRLE(ip, blockSize)) { + /* We don't want to emit our first block as a RLE even if it qualifies because + * doing so will cause the decoder (cli only) to throw a "should consume all input error." + * This is only an issue for zstd <= v1.4.3 + */ + compressedSeqsSize = 1; + } + + if (compressedSeqsSize == 0) { + /* ZSTD_noCompressBlock writes the block header as well */ + cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); + FORWARD_IF_ERROR(cBlockSize, "ZSTD_noCompressBlock failed"); + DEBUGLOG(5, "Writing out nocompress block, size: %zu", cBlockSize); + } else if (compressedSeqsSize == 1) { + cBlockSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, blockSize, lastBlock); + FORWARD_IF_ERROR(cBlockSize, "ZSTD_rleCompressBlock failed"); + DEBUGLOG(5, "Writing out RLE block, size: %zu", cBlockSize); + } else { + U32 cBlockHeader; + /* Error checking and repcodes update */ + ZSTD_blockState_confirmRepcodesAndEntropyTables(&cctx->blockState); + if (cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) + cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; + + /* Write block header into beginning of block*/ + cBlockHeader = lastBlock + (((U32)bt_compressed)<<1) + (U32)(compressedSeqsSize << 3); + MEM_writeLE24(op, cBlockHeader); + cBlockSize = ZSTD_blockHeaderSize + compressedSeqsSize; + DEBUGLOG(5, "Writing out compressed block, size: %zu", cBlockSize); + } + + cSize += cBlockSize; + + if (lastBlock) { + break; + } else { + ip += blockSize; + op += cBlockSize; + remaining -= blockSize; + dstCapacity -= cBlockSize; + cctx->isFirstBlock = 0; + } + DEBUGLOG(5, "cSize running total: %zu (remaining dstCapacity=%zu)", cSize, dstCapacity); + } + + DEBUGLOG(4, "cSize final total: %zu", cSize); + return cSize; +} + +size_t ZSTD_compressSequences(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const ZSTD_Sequence* inSeqs, size_t inSeqsSize, + const void* src, size_t srcSize) +{ + BYTE* op = (BYTE*)dst; + size_t cSize = 0; + size_t compressedBlocksSize = 0; + size_t frameHeaderSize = 0; + + /* Transparent initialization stage, same as compressStream2() */ + DEBUGLOG(4, "ZSTD_compressSequences (dstCapacity=%zu)", dstCapacity); + assert(cctx != NULL); + FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, ZSTD_e_end, srcSize), "CCtx initialization failed"); + /* Begin writing output, starting with frame header */ + frameHeaderSize = ZSTD_writeFrameHeader(op, dstCapacity, &cctx->appliedParams, srcSize, cctx->dictID); + op += frameHeaderSize; + dstCapacity -= frameHeaderSize; + cSize += frameHeaderSize; + if (cctx->appliedParams.fParams.checksumFlag && srcSize) { + XXH64_update(&cctx->xxhState, src, srcSize); + } + /* cSize includes block header size and compressed sequences size */ + compressedBlocksSize = ZSTD_compressSequences_internal(cctx, + op, dstCapacity, + inSeqs, inSeqsSize, + src, srcSize); + FORWARD_IF_ERROR(compressedBlocksSize, "Compressing blocks failed!"); + cSize += compressedBlocksSize; + dstCapacity -= compressedBlocksSize; + + if (cctx->appliedParams.fParams.checksumFlag) { + U32 const checksum = (U32) XXH64_digest(&cctx->xxhState); + RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum"); + DEBUGLOG(4, "Write checksum : %08X", (unsigned)checksum); + MEM_writeLE32((char*)dst + cSize, checksum); + cSize += 4; + } + + DEBUGLOG(4, "Final compressed size: %zu", cSize); + return cSize; +} + /*====== Finalize ======*/ +static ZSTD_inBuffer inBuffer_forEndFlush(const ZSTD_CStream* zcs) +{ + const ZSTD_inBuffer nullInput = { NULL, 0, 0 }; + const int stableInput = (zcs->appliedParams.inBufferMode == ZSTD_bm_stable); + return stableInput ? zcs->expectedInBuffer : nullInput; +} + /*! ZSTD_flushStream() : * @return : amount of data remaining to flush */ size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) { - ZSTD_inBuffer input = { NULL, 0, 0 }; + ZSTD_inBuffer input = inBuffer_forEndFlush(zcs); + input.size = input.pos; /* do not ingest more input during flush */ return ZSTD_compressStream2(zcs, output, &input, ZSTD_e_flush); } size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) { - ZSTD_inBuffer input = { NULL, 0, 0 }; + ZSTD_inBuffer input = inBuffer_forEndFlush(zcs); size_t const remainingToFlush = ZSTD_compressStream2(zcs, output, &input, ZSTD_e_end); - FORWARD_IF_ERROR( remainingToFlush , "ZSTD_compressStream2 failed"); + FORWARD_IF_ERROR(remainingToFlush , "ZSTD_compressStream2(,,ZSTD_e_end) failed"); if (zcs->appliedParams.nbWorkers > 0) return remainingToFlush; /* minimal estimation */ /* single thread mode : attempt to calculate remaining to flush more precisely */ { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE; @@ -4112,139 +6968,121 @@ size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) } } +} // namespace duckdb_zstd /*-===== Pre-defined compression levels =====-*/ +#include "zstd/compress/clevels.h" + +namespace duckdb_zstd { -#define ZSTD_MAX_CLEVEL 22 int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; } +int ZSTD_defaultCLevel(void) { return ZSTD_CLEVEL_DEFAULT; } -static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { -{ /* "default" - for any srcSize > 256 KB */ - /* W, C, H, S, L, TL, strat */ - { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */ - { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */ - { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */ - { 21, 16, 17, 1, 5, 0, ZSTD_dfast }, /* level 3 */ - { 21, 18, 18, 1, 5, 0, ZSTD_dfast }, /* level 4 */ - { 21, 18, 19, 2, 5, 2, ZSTD_greedy }, /* level 5 */ - { 21, 19, 19, 3, 5, 4, ZSTD_greedy }, /* level 6 */ - { 21, 19, 19, 3, 5, 8, ZSTD_lazy }, /* level 7 */ - { 21, 19, 19, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */ - { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */ - { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */ - { 22, 21, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */ - { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */ - { 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 13 */ - { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */ - { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */ - { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */ - { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */ - { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */ - { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */ - { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */ - { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */ - { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */ -}, -{ /* for srcSize <= 256 KB */ - /* W, C, H, S, L, T, strat */ - { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ - { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */ - { 18, 14, 14, 1, 5, 0, ZSTD_dfast }, /* level 2 */ - { 18, 16, 16, 1, 4, 0, ZSTD_dfast }, /* level 3 */ - { 18, 16, 17, 2, 5, 2, ZSTD_greedy }, /* level 4.*/ - { 18, 18, 18, 3, 5, 2, ZSTD_greedy }, /* level 5.*/ - { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/ - { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */ - { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ - { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ - { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ - { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/ - { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/ - { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */ - { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ - { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/ - { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/ - { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/ - { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/ - { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ - { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/ - { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/ - { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/ -}, -{ /* for srcSize <= 128 KB */ - /* W, C, H, S, L, T, strat */ - { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ - { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */ - { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */ - { 17, 15, 16, 2, 5, 0, ZSTD_dfast }, /* level 3 */ - { 17, 17, 17, 2, 4, 0, ZSTD_dfast }, /* level 4 */ - { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */ - { 17, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ - { 17, 17, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */ - { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ - { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ - { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ - { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */ - { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */ - { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/ - { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ - { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/ - { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/ - { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/ - { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/ - { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/ - { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/ - { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ - { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/ -}, -{ /* for srcSize <= 16 KB */ - /* W, C, H, S, L, T, strat */ - { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ - { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */ - { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */ - { 14, 14, 15, 2, 4, 0, ZSTD_dfast }, /* level 3 */ - { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */ - { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/ - { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */ - { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */ - { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/ - { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/ - { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/ - { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/ - { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/ - { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/ - { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/ - { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/ - { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/ - { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/ - { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/ - { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ - { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/ - { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ - { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/ -}, -}; +static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(int const compressionLevel, size_t const dictSize) +{ + ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, 0, dictSize, ZSTD_cpm_createCDict); + switch (cParams.strategy) { + case ZSTD_fast: + case ZSTD_dfast: + break; + case ZSTD_greedy: + case ZSTD_lazy: + case ZSTD_lazy2: + cParams.hashLog += ZSTD_LAZY_DDSS_BUCKET_LOG; + break; + case ZSTD_btlazy2: + case ZSTD_btopt: + case ZSTD_btultra: + case ZSTD_btultra2: + break; + } + return cParams; +} + +static int ZSTD_dedicatedDictSearch_isSupported( + ZSTD_compressionParameters const* cParams) +{ + return (cParams->strategy >= ZSTD_greedy) + && (cParams->strategy <= ZSTD_lazy2) + && (cParams->hashLog > cParams->chainLog) + && (cParams->chainLog <= 24); +} + +/** + * Reverses the adjustment applied to cparams when enabling dedicated dict + * search. This is used to recover the params set to be used in the working + * context. (Otherwise, those tables would also grow.) + */ +static void ZSTD_dedicatedDictSearch_revertCParams( + ZSTD_compressionParameters* cParams) { + switch (cParams->strategy) { + case ZSTD_fast: + case ZSTD_dfast: + break; + case ZSTD_greedy: + case ZSTD_lazy: + case ZSTD_lazy2: + cParams->hashLog -= ZSTD_LAZY_DDSS_BUCKET_LOG; + if (cParams->hashLog < ZSTD_HASHLOG_MIN) { + cParams->hashLog = ZSTD_HASHLOG_MIN; + } + break; + case ZSTD_btlazy2: + case ZSTD_btopt: + case ZSTD_btultra: + case ZSTD_btultra2: + break; + } +} + +static U64 ZSTD_getCParamRowSize(U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) +{ + switch (mode) { + case ZSTD_cpm_unknown: + case ZSTD_cpm_noAttachDict: + case ZSTD_cpm_createCDict: + break; + case ZSTD_cpm_attachDict: + dictSize = 0; + break; + default: + assert(0); + break; + } + { int const unknown = srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN; + size_t const addedSize = unknown && dictSize > 0 ? 500 : 0; + return unknown && dictSize == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : srcSizeHint+dictSize+addedSize; + } +} /*! ZSTD_getCParams_internal() : * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. * Note: srcSizeHint 0 means 0, use ZSTD_CONTENTSIZE_UNKNOWN for unknown. - * Use dictSize == 0 for unknown or unused. */ -static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) + * Use dictSize == 0 for unknown or unused. + * Note: `mode` controls how we treat the `dictSize`. See docs for `ZSTD_cParamMode_e`. */ +static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) { - int const unknown = srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN; - size_t const addedSize = unknown && dictSize > 0 ? 500 : 0; - U64 const rSize = unknown && dictSize == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : srcSizeHint+dictSize+addedSize; + U64 const rSize = ZSTD_getCParamRowSize(srcSizeHint, dictSize, mode); U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); - int row = compressionLevel; + int row; DEBUGLOG(5, "ZSTD_getCParams_internal (cLevel=%i)", compressionLevel); + + /* row */ if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ - if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */ - if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL; + else if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */ + else if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL; + else row = compressionLevel; + { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row]; - if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */ + DEBUGLOG(5, "ZSTD_getCParams_internal selected tableID: %u row: %u strat: %u", tableID, row, (U32)cp.strategy); + /* acceleration factor */ + if (compressionLevel < 0) { + int const clampedCompressionLevel = MAX(ZSTD_minCLevel(), compressionLevel); + cp.targetLength = (unsigned)(-clampedCompressionLevel); + } /* refine parameters based on srcSize & dictSize */ - return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); + return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize, mode, ZSTD_ps_auto); } } @@ -4254,18 +7092,18 @@ static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN; - return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize); + return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown); } /*! ZSTD_getParams() : * same idea as ZSTD_getCParams() * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`). * Fields of `ZSTD_frameParameters` are set to default values */ -static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { +static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) { ZSTD_parameters params; - ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize); + ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, mode); DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel); - memset(¶ms, 0, sizeof(params)); + ZSTD_memset(¶ms, 0, sizeof(params)); params.cParams = cParams; params.fParams.contentSizeFlag = 1; return params; @@ -4277,7 +7115,33 @@ static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned lo * Fields of `ZSTD_frameParameters` are set to default values */ ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN; - return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize); + return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown); +} + +void ZSTD_registerSequenceProducer( + ZSTD_CCtx* zc, + void* extSeqProdState, + ZSTD_sequenceProducer_F extSeqProdFunc +) { + assert(zc != NULL); + ZSTD_CCtxParams_registerSequenceProducer( + &zc->requestedParams, extSeqProdState, extSeqProdFunc + ); +} + +void ZSTD_CCtxParams_registerSequenceProducer( + ZSTD_CCtx_params* params, + void* extSeqProdState, + ZSTD_sequenceProducer_F extSeqProdFunc +) { + assert(params != NULL); + if (extSeqProdFunc != NULL) { + params->extSeqProdFunc = extSeqProdFunc; + params->extSeqProdState = extSeqProdState; + } else { + params->extSeqProdFunc = NULL; + params->extSeqProdState = NULL; + } } -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/compress/zstd_compress_literals.cpp b/src/duckdb/third_party/zstd/compress/zstd_compress_literals.cpp index ab9dfb459..b68340da7 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_compress_literals.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_compress_literals.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,11 +14,36 @@ #include "zstd/compress/zstd_compress_literals.h" namespace duckdb_zstd { + +/* ************************************************************** +* Debug Traces +****************************************************************/ +#if DEBUGLEVEL >= 2 + +static size_t showHexa(const void* src, size_t srcSize) +{ + const BYTE* const ip = (const BYTE*)src; + size_t u; + for (u=0; u31) + (srcSize>4095); + DEBUGLOG(5, "ZSTD_noCompressLiterals: srcSize=%zu, dstCapacity=%zu", srcSize, dstCapacity); + RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall, ""); switch(flSize) @@ -36,17 +61,31 @@ size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, assert(0); } - memcpy(ostart + flSize, src, srcSize); - DEBUGLOG(5, "Raw literals: %u -> %u", (U32)srcSize, (U32)(srcSize + flSize)); + ZSTD_memcpy(ostart + flSize, src, srcSize); + DEBUGLOG(5, "Raw (uncompressed) literals: %u -> %u", (U32)srcSize, (U32)(srcSize + flSize)); return srcSize + flSize; } +static int allBytesIdentical(const void* src, size_t srcSize) +{ + assert(srcSize >= 1); + assert(src != NULL); + { const BYTE b = ((const BYTE*)src)[0]; + size_t p; + for (p=1; p31) + (srcSize>4095); - (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */ + assert(dstCapacity >= 4); (void)dstCapacity; + assert(allBytesIdentical(src, srcSize)); switch(flSize) { @@ -64,68 +103,103 @@ size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* } ostart[flSize] = *(const BYTE*)src; - DEBUGLOG(5, "RLE literals: %u -> %u", (U32)srcSize, (U32)flSize + 1); + DEBUGLOG(5, "RLE : Repeated Literal (%02X: %u times) -> %u bytes encoded", ((const BYTE*)src)[0], (U32)srcSize, (U32)flSize + 1); return flSize+1; } -size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, - ZSTD_hufCTables_t* nextHuf, - ZSTD_strategy strategy, int disableLiteralCompression, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - void* entropyWorkspace, size_t entropyWorkspaceSize, - const int bmi2) +/* ZSTD_minLiteralsToCompress() : + * returns minimal amount of literals + * for literal compression to even be attempted. + * Minimum is made tighter as compression strategy increases. + */ +static size_t +ZSTD_minLiteralsToCompress(ZSTD_strategy strategy, HUF_repeat huf_repeat) +{ + assert((int)strategy >= 0); + assert((int)strategy <= 9); + /* btultra2 : min 8 bytes; + * then 2x larger for each successive compression strategy + * max threshold 64 bytes */ + { int const shift = MIN(9-(int)strategy, 3); + size_t const mintc = (huf_repeat == HUF_repeat_valid) ? 6 : (size_t)8 << shift; + DEBUGLOG(7, "minLiteralsToCompress = %zu", mintc); + return mintc; + } +} + +size_t ZSTD_compressLiterals ( + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + void* entropyWorkspace, size_t entropyWorkspaceSize, + const ZSTD_hufCTables_t* prevHuf, + ZSTD_hufCTables_t* nextHuf, + ZSTD_strategy strategy, + int disableLiteralCompression, + int suspectUncompressible, + int bmi2) { - size_t const minGain = ZSTD_minGain(srcSize, strategy); size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); BYTE* const ostart = (BYTE*)dst; U32 singleStream = srcSize < 256; symbolEncodingType_e hType = set_compressed; size_t cLitSize; - DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i srcSize=%u)", - disableLiteralCompression, (U32)srcSize); + DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i, srcSize=%u, dstCapacity=%zu)", + disableLiteralCompression, (U32)srcSize, dstCapacity); + + DEBUGLOG(6, "Completed literals listing (%zu bytes)", showHexa(src, srcSize)); /* Prepare nextEntropy assuming reusing the existing table */ - memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); if (disableLiteralCompression) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); - /* small ? don't even attempt compression (speed opt) */ -# define COMPRESS_LITERALS_SIZE_MIN 63 - { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN; - if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); - } + /* if too small, don't even attempt compression (speed opt) */ + if (srcSize < ZSTD_minLiteralsToCompress(strategy, prevHuf->repeatMode)) + return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); RETURN_ERROR_IF(dstCapacity < lhSize+1, dstSize_tooSmall, "not enough space for compression"); { HUF_repeat repeat = prevHuf->repeatMode; - int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0; + int const flags = 0 + | (bmi2 ? HUF_flags_bmi2 : 0) + | (strategy < ZSTD_lazy && srcSize <= 1024 ? HUF_flags_preferRepeat : 0) + | (strategy >= HUF_OPTIMAL_DEPTH_THRESHOLD ? HUF_flags_optimalDepth : 0) + | (suspectUncompressible ? HUF_flags_suspectUncompressible : 0); + + typedef size_t (*huf_compress_f)(void*, size_t, const void*, size_t, unsigned, unsigned, void*, size_t, HUF_CElt*, HUF_repeat*, int); + huf_compress_f huf_compress; if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1; - cLitSize = singleStream ? - HUF_compress1X_repeat( - ostart+lhSize, dstCapacity-lhSize, src, srcSize, - HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize, - (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2) : - HUF_compress4X_repeat( - ostart+lhSize, dstCapacity-lhSize, src, srcSize, - HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize, - (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2); + huf_compress = singleStream ? HUF_compress1X_repeat : HUF_compress4X_repeat; + cLitSize = huf_compress(ostart+lhSize, dstCapacity-lhSize, + src, srcSize, + HUF_SYMBOLVALUE_MAX, LitHufLog, + entropyWorkspace, entropyWorkspaceSize, + (HUF_CElt*)nextHuf->CTable, + &repeat, flags); + DEBUGLOG(5, "%zu literals compressed into %zu bytes (before header)", srcSize, cLitSize); if (repeat != HUF_repeat_none) { /* reused the existing table */ - DEBUGLOG(5, "Reusing previous huffman table"); + DEBUGLOG(5, "reusing statistics from previous huffman block"); hType = set_repeat; } } - if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) { - memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); - return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); - } + { size_t const minGain = ZSTD_minGain(srcSize, strategy); + if ((cLitSize==0) || (cLitSize >= srcSize - minGain) || ERR_isError(cLitSize)) { + ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); + } } if (cLitSize==1) { - memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); - return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); - } + /* A return value of 1 signals that the alphabet consists of a single symbol. + * However, in some rare circumstances, it could be the compressed size (a single byte). + * For that outcome to have a chance to happen, it's necessary that `srcSize < 8`. + * (it's also necessary to not generate statistics). + * Therefore, in such a case, actively check that all bytes are identical. */ + if ((srcSize >= 8) || allBytesIdentical(src, srcSize)) { + ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); + } } if (hType == set_compressed) { /* using a newly constructed table */ @@ -136,16 +210,19 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, switch(lhSize) { case 3: /* 2 - 2 - 10 - 10 */ - { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14); + if (!singleStream) assert(srcSize >= MIN_LITERALS_FOR_4_STREAMS); + { U32 const lhc = hType + ((U32)(!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14); MEM_writeLE24(ostart, lhc); break; } case 4: /* 2 - 2 - 14 - 14 */ + assert(srcSize >= MIN_LITERALS_FOR_4_STREAMS); { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18); MEM_writeLE32(ostart, lhc); break; } case 5: /* 2 - 2 - 18 - 18 */ + assert(srcSize >= MIN_LITERALS_FOR_4_STREAMS); { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22); MEM_writeLE32(ostart, lhc); ostart[4] = (BYTE)(cLitSize >> 10); @@ -158,4 +235,4 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, return lhSize+cLitSize; } -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/compress/zstd_compress_sequences.cpp b/src/duckdb/third_party/zstd/compress/zstd_compress_sequences.cpp index e1cc14597..0ab822622 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_compress_sequences.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_compress_sequences.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,6 +14,7 @@ #include "zstd/compress/zstd_compress_sequences.h" namespace duckdb_zstd { + /** * -log2(x / 256) lookup table for x in [0, 256). * If x == 0: Return 0 @@ -51,6 +52,19 @@ static unsigned ZSTD_getFSEMaxSymbolValue(FSE_CTable const* ctable) { return maxSymbolValue; } +/** + * Returns true if we should use ncount=-1 else we should + * use ncount=1 for low probability symbols instead. + */ +static unsigned ZSTD_useLowProbCount(size_t const nbSeq) +{ + /* Heuristic: This should cover most blocks <= 16K and + * start to fade out after 16K to about 32K depending on + * compressibility. + */ + return nbSeq >= 2048; +} + /** * Returns the cost in bytes of encoding the normalized count header. * Returns an error if any of the helper functions return an error. @@ -61,7 +75,7 @@ static size_t ZSTD_NCountCost(unsigned const* count, unsigned const max, BYTE wksp[FSE_NCOUNTBOUND]; S16 norm[MaxSeq + 1]; const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max); - FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq, max), ""); + FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq, max, ZSTD_useLowProbCount(nbSeq)), ""); return FSE_writeNCount(wksp, sizeof(wksp), norm, max, tableLog); } @@ -73,6 +87,8 @@ static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t { unsigned cost = 0; unsigned s; + + assert(total > 0); for (s = 0; s <= max; ++s) { unsigned norm = (unsigned)((256 * count[s]) / total); if (count[s] != 0 && norm == 0) @@ -152,7 +168,7 @@ ZSTD_selectEncodingType( if (mostFrequent == nbSeq) { *repeatMode = FSE_repeat_none; if (isDefaultAllowed && nbSeq <= 2) { - /* Prefer set_basic over set_rle when there are 2 or less symbols, + /* Prefer set_basic over set_rle when there are 2 or fewer symbols, * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol. * If basic encoding isn't possible, always choose RLE. */ @@ -220,6 +236,11 @@ ZSTD_selectEncodingType( return set_compressed; } +typedef struct { + S16 norm[MaxSeq + 1]; + U32 wksp[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(MaxSeq, MaxFSELog)]; +} ZSTD_BuildCTableWksp; + size_t ZSTD_buildCTable(void* dst, size_t dstCapacity, FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type, @@ -240,13 +261,13 @@ ZSTD_buildCTable(void* dst, size_t dstCapacity, *op = codeTable[0]; return 1; case set_repeat: - memcpy(nextCTable, prevCTable, prevCTableSize); + ZSTD_memcpy(nextCTable, prevCTable, prevCTableSize); return 0; case set_basic: FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, entropyWorkspace, entropyWorkspaceSize), ""); /* note : could be pre-calculated */ return 0; case set_compressed: { - S16 norm[MaxSeq + 1]; + ZSTD_BuildCTableWksp* wksp = (ZSTD_BuildCTableWksp*)entropyWorkspace; size_t nbSeq_1 = nbSeq; const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max); if (count[codeTable[nbSeq-1]] > 1) { @@ -254,10 +275,13 @@ ZSTD_buildCTable(void* dst, size_t dstCapacity, nbSeq_1--; } assert(nbSeq_1 > 1); - FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max), ""); - { size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */ + assert(entropyWorkspaceSize >= sizeof(ZSTD_BuildCTableWksp)); + (void)entropyWorkspaceSize; + FORWARD_IF_ERROR(FSE_normalizeCount(wksp->norm, tableLog, count, nbSeq_1, max, ZSTD_useLowProbCount(nbSeq_1)), "FSE_normalizeCount failed"); + assert(oend >= op); + { size_t const NCountSize = FSE_writeNCount(op, (size_t)(oend - op), wksp->norm, max, tableLog); /* overflow protected */ FORWARD_IF_ERROR(NCountSize, "FSE_writeNCount failed"); - FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, entropyWorkspace, entropyWorkspaceSize), ""); + FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, wksp->norm, max, tableLog, wksp->wksp, sizeof(wksp->wksp)), "FSE_buildCTable_wksp failed"); return NCountSize; } } @@ -289,21 +313,21 @@ ZSTD_encodeSequences_body( FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]); FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]); FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]); - BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, ZSTDInternalConstants::LL_bits[llCodeTable[nbSeq-1]]); + BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]); if (MEM_32bits()) BIT_flushBits(&blockStream); - BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ZSTDInternalConstants::ML_bits[mlCodeTable[nbSeq-1]]); + BIT_addBits(&blockStream, sequences[nbSeq-1].mlBase, ML_bits[mlCodeTable[nbSeq-1]]); if (MEM_32bits()) BIT_flushBits(&blockStream); if (longOffsets) { U32 const ofBits = ofCodeTable[nbSeq-1]; unsigned const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); if (extraBits) { - BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits); + BIT_addBits(&blockStream, sequences[nbSeq-1].offBase, extraBits); BIT_flushBits(&blockStream); } - BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits, + BIT_addBits(&blockStream, sequences[nbSeq-1].offBase >> extraBits, ofBits - extraBits); } else { - BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]); + BIT_addBits(&blockStream, sequences[nbSeq-1].offBase, ofCodeTable[nbSeq-1]); } BIT_flushBits(&blockStream); @@ -312,13 +336,13 @@ ZSTD_encodeSequences_body( BYTE const llCode = llCodeTable[n]; BYTE const ofCode = ofCodeTable[n]; BYTE const mlCode = mlCodeTable[n]; - U32 const llBits = ZSTDInternalConstants::LL_bits[llCode]; + U32 const llBits = LL_bits[llCode]; U32 const ofBits = ofCode; - U32 const mlBits = ZSTDInternalConstants::ML_bits[mlCode]; + U32 const mlBits = ML_bits[mlCode]; DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u", (unsigned)sequences[n].litLength, - (unsigned)sequences[n].matchLength + MINMATCH, - (unsigned)sequences[n].offset); + (unsigned)sequences[n].mlBase + MINMATCH, + (unsigned)sequences[n].offBase); /* 32b*/ /* 64b*/ /* (7)*/ /* (7)*/ FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */ @@ -329,18 +353,18 @@ ZSTD_encodeSequences_body( BIT_flushBits(&blockStream); /* (7)*/ BIT_addBits(&blockStream, sequences[n].litLength, llBits); if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream); - BIT_addBits(&blockStream, sequences[n].matchLength, mlBits); + BIT_addBits(&blockStream, sequences[n].mlBase, mlBits); if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream); if (longOffsets) { unsigned const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); if (extraBits) { - BIT_addBits(&blockStream, sequences[n].offset, extraBits); + BIT_addBits(&blockStream, sequences[n].offBase, extraBits); BIT_flushBits(&blockStream); /* (7)*/ } - BIT_addBits(&blockStream, sequences[n].offset >> extraBits, + BIT_addBits(&blockStream, sequences[n].offBase >> extraBits, ofBits - extraBits); /* 31 */ } else { - BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */ + BIT_addBits(&blockStream, sequences[n].offBase, ofBits); /* 31 */ } BIT_flushBits(&blockStream); /* (7)*/ DEBUGLOG(7, "remaining space : %i", (int)(blockStream.endPtr - blockStream.ptr)); @@ -377,7 +401,7 @@ ZSTD_encodeSequences_default( #if DYNAMIC_BMI2 -static TARGET_ATTRIBUTE("bmi2") size_t +static BMI2_TARGET_ATTRIBUTE size_t ZSTD_encodeSequences_bmi2( void* dst, size_t dstCapacity, FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, @@ -419,4 +443,4 @@ size_t ZSTD_encodeSequences( sequences, nbSeq, longOffsets); } -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/compress/zstd_compress_superblock.cpp b/src/duckdb/third_party/zstd/compress/zstd_compress_superblock.cpp index 559a3a0cd..1ad0d3aa0 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_compress_superblock.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_compress_superblock.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,288 +15,11 @@ #include "zstd/common/zstd_internal.h" /* ZSTD_getSequenceLength */ #include "zstd/compress/hist.h" /* HIST_countFast_wksp */ -#include "zstd/compress/zstd_compress_internal.h" +#include "zstd/compress/zstd_compress_internal.h" /* ZSTD_[huf|fse|entropy]CTablesMetadata_t */ #include "zstd/compress/zstd_compress_sequences.h" #include "zstd/compress/zstd_compress_literals.h" namespace duckdb_zstd { -/*-************************************* -* Superblock entropy buffer structs -***************************************/ -/** ZSTD_hufCTablesMetadata_t : - * Stores Literals Block Type for a super-block in hType, and - * huffman tree description in hufDesBuffer. - * hufDesSize refers to the size of huffman tree description in bytes. - * This metadata is populated in ZSTD_buildSuperBlockEntropy_literal() */ -typedef struct { - symbolEncodingType_e hType; - BYTE hufDesBuffer[500]; /* TODO give name to this value */ - size_t hufDesSize; -} ZSTD_hufCTablesMetadata_t; - -/** ZSTD_fseCTablesMetadata_t : - * Stores symbol compression modes for a super-block in {ll, ol, ml}Type, and - * fse tables in fseTablesBuffer. - * fseTablesSize refers to the size of fse tables in bytes. - * This metadata is populated in ZSTD_buildSuperBlockEntropy_sequences() */ -typedef struct { - symbolEncodingType_e llType; - symbolEncodingType_e ofType; - symbolEncodingType_e mlType; - BYTE fseTablesBuffer[500]; /* TODO give name to this value */ - size_t fseTablesSize; - size_t lastCountSize; /* This is to account for bug in 1.3.4. More detail in ZSTD_compressSubBlock_sequences() */ -} ZSTD_fseCTablesMetadata_t; - -typedef struct { - ZSTD_hufCTablesMetadata_t hufMetadata; - ZSTD_fseCTablesMetadata_t fseMetadata; -} ZSTD_entropyCTablesMetadata_t; - - -/** ZSTD_buildSuperBlockEntropy_literal() : - * Builds entropy for the super-block literals. - * Stores literals block type (raw, rle, compressed, repeat) and - * huffman description table to hufMetadata. - * @return : size of huffman description table or error code */ -static size_t ZSTD_buildSuperBlockEntropy_literal(void* const src, size_t srcSize, - const ZSTD_hufCTables_t* prevHuf, - ZSTD_hufCTables_t* nextHuf, - ZSTD_hufCTablesMetadata_t* hufMetadata, - const int disableLiteralsCompression, - void* workspace, size_t wkspSize) -{ - BYTE* const wkspStart = (BYTE*)workspace; - BYTE* const wkspEnd = wkspStart + wkspSize; - BYTE* const countWkspStart = wkspStart; - unsigned* const countWksp = (unsigned*)workspace; - const size_t countWkspSize = (HUF_SYMBOLVALUE_MAX + 1) * sizeof(unsigned); - BYTE* const nodeWksp = countWkspStart + countWkspSize; - const size_t nodeWkspSize = wkspEnd-nodeWksp; - unsigned maxSymbolValue = 255; - unsigned huffLog = HUF_TABLELOG_DEFAULT; - HUF_repeat repeat = prevHuf->repeatMode; - - DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy_literal (srcSize=%zu)", srcSize); - - /* Prepare nextEntropy assuming reusing the existing table */ - memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); - - if (disableLiteralsCompression) { - DEBUGLOG(5, "set_basic - disabled"); - hufMetadata->hType = set_basic; - return 0; - } - - /* small ? don't even attempt compression (speed opt) */ -# define COMPRESS_LITERALS_SIZE_MIN 63 - { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN; - if (srcSize <= minLitSize) { - DEBUGLOG(5, "set_basic - too small"); - hufMetadata->hType = set_basic; - return 0; - } - } - - /* Scan input and build symbol stats */ - { size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)src, srcSize, workspace, wkspSize); - FORWARD_IF_ERROR(largest, "HIST_count_wksp failed"); - if (largest == srcSize) { - DEBUGLOG(5, "set_rle"); - hufMetadata->hType = set_rle; - return 0; - } - if (largest <= (srcSize >> 7)+4) { - DEBUGLOG(5, "set_basic - no gain"); - hufMetadata->hType = set_basic; - return 0; - } - } - - /* Validate the previous Huffman table */ - if (repeat == HUF_repeat_check && !HUF_validateCTable((HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue)) { - repeat = HUF_repeat_none; - } - - /* Build Huffman Tree */ - memset(nextHuf->CTable, 0, sizeof(nextHuf->CTable)); - huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue); - { size_t const maxBits = HUF_buildCTable_wksp((HUF_CElt*)nextHuf->CTable, countWksp, - maxSymbolValue, huffLog, - nodeWksp, nodeWkspSize); - FORWARD_IF_ERROR(maxBits, "HUF_buildCTable_wksp"); - huffLog = (U32)maxBits; - { /* Build and write the CTable */ - size_t const newCSize = HUF_estimateCompressedSize( - (HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue); - size_t const hSize = HUF_writeCTable( - hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer), - (HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog); - /* Check against repeating the previous CTable */ - if (repeat != HUF_repeat_none) { - size_t const oldCSize = HUF_estimateCompressedSize( - (HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue); - if (oldCSize < srcSize && (oldCSize <= hSize + newCSize || hSize + 12 >= srcSize)) { - DEBUGLOG(5, "set_repeat - smaller"); - memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); - hufMetadata->hType = set_repeat; - return 0; - } - } - if (newCSize + hSize >= srcSize) { - DEBUGLOG(5, "set_basic - no gains"); - memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); - hufMetadata->hType = set_basic; - return 0; - } - DEBUGLOG(5, "set_compressed (hSize=%u)", (U32)hSize); - hufMetadata->hType = set_compressed; - nextHuf->repeatMode = HUF_repeat_check; - return hSize; - } - } -} - -/** ZSTD_buildSuperBlockEntropy_sequences() : - * Builds entropy for the super-block sequences. - * Stores symbol compression modes and fse table to fseMetadata. - * @return : size of fse tables or error code */ -static size_t ZSTD_buildSuperBlockEntropy_sequences(seqStore_t* seqStorePtr, - const ZSTD_fseCTables_t* prevEntropy, - ZSTD_fseCTables_t* nextEntropy, - const ZSTD_CCtx_params* cctxParams, - ZSTD_fseCTablesMetadata_t* fseMetadata, - void* workspace, size_t wkspSize) -{ - BYTE* const wkspStart = (BYTE*)workspace; - BYTE* const wkspEnd = wkspStart + wkspSize; - BYTE* const countWkspStart = wkspStart; - unsigned* const countWksp = (unsigned*)workspace; - const size_t countWkspSize = (MaxSeq + 1) * sizeof(unsigned); - BYTE* const cTableWksp = countWkspStart + countWkspSize; - const size_t cTableWkspSize = wkspEnd-cTableWksp; - ZSTD_strategy const strategy = cctxParams->cParams.strategy; - FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable; - FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable; - FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable; - const BYTE* const ofCodeTable = seqStorePtr->ofCode; - const BYTE* const llCodeTable = seqStorePtr->llCode; - const BYTE* const mlCodeTable = seqStorePtr->mlCode; - size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart; - BYTE* const ostart = fseMetadata->fseTablesBuffer; - BYTE* const oend = ostart + sizeof(fseMetadata->fseTablesBuffer); - BYTE* op = ostart; - - assert(cTableWkspSize >= (1 << MaxFSELog) * sizeof(FSE_FUNCTION_TYPE)); - DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy_sequences (nbSeq=%zu)", nbSeq); - memset(workspace, 0, wkspSize); - - fseMetadata->lastCountSize = 0; - /* convert length/distances into codes */ - ZSTD_seqToCodes(seqStorePtr); - /* build CTable for Literal Lengths */ - { U32 LLtype; - unsigned max = MaxLL; - size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, llCodeTable, nbSeq, workspace, wkspSize); /* can't fail */ - DEBUGLOG(5, "Building LL table"); - nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode; - LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode, - countWksp, max, mostFrequent, nbSeq, - LLFSELog, prevEntropy->litlengthCTable, - ZSTDInternalConstants::LL_defaultNorm, ZSTDInternalConstants::LL_defaultNormLog, - ZSTD_defaultAllowed, strategy); - assert(set_basic < set_compressed && set_rle < set_compressed); - assert(!(LLtype < set_compressed && nextEntropy->litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ - { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype, - countWksp, max, llCodeTable, nbSeq, ZSTDInternalConstants::LL_defaultNorm, ZSTDInternalConstants::LL_defaultNormLog, MaxLL, - prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable), - cTableWksp, cTableWkspSize); - FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed"); - if (LLtype == set_compressed) - fseMetadata->lastCountSize = countSize; - op += countSize; - fseMetadata->llType = (symbolEncodingType_e) LLtype; - } } - /* build CTable for Offsets */ - { U32 Offtype; - unsigned max = MaxOff; - size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, ofCodeTable, nbSeq, workspace, wkspSize); /* can't fail */ - /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ - ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; - DEBUGLOG(5, "Building OF table"); - nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode; - Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode, - countWksp, max, mostFrequent, nbSeq, - OffFSELog, prevEntropy->offcodeCTable, - ZSTDInternalConstants::OF_defaultNorm, ZSTDInternalConstants::OF_defaultNormLog, - defaultPolicy, strategy); - assert(!(Offtype < set_compressed && nextEntropy->offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ - { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype, - countWksp, max, ofCodeTable, nbSeq, ZSTDInternalConstants::OF_defaultNorm, ZSTDInternalConstants::OF_defaultNormLog, DefaultMaxOff, - prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable), - cTableWksp, cTableWkspSize); - FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed"); - if (Offtype == set_compressed) - fseMetadata->lastCountSize = countSize; - op += countSize; - fseMetadata->ofType = (symbolEncodingType_e) Offtype; - } } - /* build CTable for MatchLengths */ - { U32 MLtype; - unsigned max = MaxML; - size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, mlCodeTable, nbSeq, workspace, wkspSize); /* can't fail */ - DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op)); - nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode; - MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode, - countWksp, max, mostFrequent, nbSeq, - MLFSELog, prevEntropy->matchlengthCTable, - ZSTDInternalConstants::ML_defaultNorm, ZSTDInternalConstants::ML_defaultNormLog, - ZSTD_defaultAllowed, strategy); - assert(!(MLtype < set_compressed && nextEntropy->matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ - { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype, - countWksp, max, mlCodeTable, nbSeq, ZSTDInternalConstants::ML_defaultNorm, ZSTDInternalConstants::ML_defaultNormLog, MaxML, - prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable), - cTableWksp, cTableWkspSize); - FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed"); - if (MLtype == set_compressed) - fseMetadata->lastCountSize = countSize; - op += countSize; - fseMetadata->mlType = (symbolEncodingType_e) MLtype; - } } - assert((size_t) (op-ostart) <= sizeof(fseMetadata->fseTablesBuffer)); - return op-ostart; -} - - -/** ZSTD_buildSuperBlockEntropy() : - * Builds entropy for the super-block. - * @return : 0 on success or error code */ -static size_t -ZSTD_buildSuperBlockEntropy(seqStore_t* seqStorePtr, - const ZSTD_entropyCTables_t* prevEntropy, - ZSTD_entropyCTables_t* nextEntropy, - const ZSTD_CCtx_params* cctxParams, - ZSTD_entropyCTablesMetadata_t* entropyMetadata, - void* workspace, size_t wkspSize) -{ - size_t const litSize = seqStorePtr->lit - seqStorePtr->litStart; - DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy"); - entropyMetadata->hufMetadata.hufDesSize = - ZSTD_buildSuperBlockEntropy_literal(seqStorePtr->litStart, litSize, - &prevEntropy->huf, &nextEntropy->huf, - &entropyMetadata->hufMetadata, - ZSTD_disableLiteralsCompression(cctxParams), - workspace, wkspSize); - FORWARD_IF_ERROR(entropyMetadata->hufMetadata.hufDesSize, "ZSTD_buildSuperBlockEntropy_literal failed"); - entropyMetadata->fseMetadata.fseTablesSize = - ZSTD_buildSuperBlockEntropy_sequences(seqStorePtr, - &prevEntropy->fse, &nextEntropy->fse, - cctxParams, - &entropyMetadata->fseMetadata, - workspace, wkspSize); - FORWARD_IF_ERROR(entropyMetadata->fseMetadata.fseTablesSize, "ZSTD_buildSuperBlockEntropy_sequences failed"); - return 0; -} /** ZSTD_compressSubBlock_literal() : * Compresses literals section for a sub-block. @@ -305,7 +28,7 @@ ZSTD_buildSuperBlockEntropy(seqStore_t* seqStorePtr, * before we know the table size + compressed size, so we have a bound on the * table size. If we guessed incorrectly, we fall back to uncompressed literals. * - * We write the header when writeEntropy=1 and set entropyWrriten=1 when we succeeded + * We write the header when writeEntropy=1 and set entropyWritten=1 when we succeeded * in writing the header, otherwise it is set to 0. * * hufMetadata->hType has literals block type info. @@ -315,13 +38,14 @@ ZSTD_buildSuperBlockEntropy(seqStore_t* seqStorePtr, * If it is set_compressed, first sub-block's literals section will be Treeless_Literals_Block * and the following sub-blocks' literals sections will be Treeless_Literals_Block. * @return : compressed size of literals section of a sub-block - * Or 0 if it unable to compress. + * Or 0 if unable to compress. * Or error code */ -static size_t ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable, - const ZSTD_hufCTablesMetadata_t* hufMetadata, - const BYTE* literals, size_t litSize, - void* dst, size_t dstSize, - const int bmi2, int writeEntropy, int* entropyWritten) +static size_t +ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable, + const ZSTD_hufCTablesMetadata_t* hufMetadata, + const BYTE* literals, size_t litSize, + void* dst, size_t dstSize, + const int bmi2, int writeEntropy, int* entropyWritten) { size_t const header = writeEntropy ? 200 : 0; size_t const lhSize = 3 + (litSize >= (1 KB - header)) + (litSize >= (16 KB - header)); @@ -332,8 +56,6 @@ static size_t ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable, symbolEncodingType_e hType = writeEntropy ? hufMetadata->hType : set_repeat; size_t cLitSize = 0; - (void)bmi2; /* TODO bmi2... */ - DEBUGLOG(5, "ZSTD_compressSubBlock_literal (litSize=%zu, lhSize=%zu, writeEntropy=%d)", litSize, lhSize, writeEntropy); *entropyWritten = 0; @@ -349,15 +71,15 @@ static size_t ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable, assert(hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat); if (writeEntropy && hufMetadata->hType == set_compressed) { - memcpy(op, hufMetadata->hufDesBuffer, hufMetadata->hufDesSize); + ZSTD_memcpy(op, hufMetadata->hufDesBuffer, hufMetadata->hufDesSize); op += hufMetadata->hufDesSize; cLitSize += hufMetadata->hufDesSize; DEBUGLOG(5, "ZSTD_compressSubBlock_literal (hSize=%zu)", hufMetadata->hufDesSize); } - /* TODO bmi2 */ - { const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, oend-op, literals, litSize, hufTable) - : HUF_compress4X_usingCTable(op, oend-op, literals, litSize, hufTable); + { int const flags = bmi2 ? HUF_flags_bmi2 : 0; + const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, (size_t)(oend-op), literals, litSize, hufTable, flags) + : HUF_compress4X_usingCTable(op, (size_t)(oend-op), literals, litSize, hufTable, flags); op += cSize; cLitSize += cSize; if (cSize == 0 || ERR_isError(cSize)) { @@ -382,7 +104,7 @@ static size_t ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable, switch(lhSize) { case 3: /* 2 - 2 - 10 - 10 */ - { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14); + { U32 const lhc = hType + ((U32)(!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14); MEM_writeLE24(ostart, lhc); break; } @@ -402,19 +124,30 @@ static size_t ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable, } *entropyWritten = 1; DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)litSize, (U32)(op-ostart)); - return op-ostart; + return (size_t)(op-ostart); } -static size_t ZSTD_seqDecompressedSize(seqStore_t const* seqStore, const seqDef* sequences, size_t nbSeq, size_t litSize, int lastSequence) { - const seqDef* const sstart = sequences; - const seqDef* const send = sequences + nbSeq; - const seqDef* sp = sstart; +static size_t +ZSTD_seqDecompressedSize(seqStore_t const* seqStore, + const seqDef* sequences, size_t nbSeqs, + size_t litSize, int lastSubBlock) +{ size_t matchLengthSum = 0; - while (send-sp > 0) { - ZSTD_sequenceLength const seqLen = ZSTD_getSequenceLength(seqStore, sp); + size_t litLengthSum = 0; + size_t n; + for (n=0; ncParams.windowLog > STREAM_ACCUMULATOR_MIN; BYTE* const ostart = (BYTE*)dst; @@ -448,14 +182,14 @@ static size_t ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables /* Sequences Header */ RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/, dstSize_tooSmall, ""); - if (nbSeq < 0x7F) + if (nbSeq < 128) *op++ = (BYTE)nbSeq; else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2; else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3; if (nbSeq==0) { - return op - ostart; + return (size_t)(op - ostart); } /* seqHead : flags for FSE encoding type */ @@ -469,7 +203,7 @@ static size_t ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables const U32 MLtype = fseMetadata->mlType; DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (fseTablesSize=%zu)", fseMetadata->fseTablesSize); *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); - memcpy(op, fseMetadata->fseTablesBuffer, fseMetadata->fseTablesSize); + ZSTD_memcpy(op, fseMetadata->fseTablesBuffer, fseMetadata->fseTablesSize); op += fseMetadata->fseTablesSize; } else { const U32 repeat = set_repeat; @@ -477,7 +211,7 @@ static size_t ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables } { size_t const bitstreamSize = ZSTD_encodeSequences( - op, oend - op, + op, (size_t)(oend - op), fseTables->matchlengthCTable, mlCode, fseTables->offcodeCTable, ofCode, fseTables->litlengthCTable, llCode, @@ -521,7 +255,7 @@ static size_t ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables #endif *entropyWritten = 1; - return op - ostart; + return (size_t)(op - ostart); } /** ZSTD_compressSubBlock() : @@ -542,12 +276,13 @@ static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy, { BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + dstCapacity; - BYTE* op = ostart + ZSTDInternalConstants::ZSTD_blockHeaderSize; + BYTE* op = ostart + ZSTD_blockHeaderSize; DEBUGLOG(5, "ZSTD_compressSubBlock (litSize=%zu, nbSeq=%zu, writeLitEntropy=%d, writeSeqEntropy=%d, lastBlock=%d)", litSize, nbSeq, writeLitEntropy, writeSeqEntropy, lastBlock); { size_t cLitSize = ZSTD_compressSubBlock_literal((const HUF_CElt*)entropy->huf.CTable, &entropyMetadata->hufMetadata, literals, litSize, - op, oend-op, bmi2, writeLitEntropy, litEntropyWritten); + op, (size_t)(oend-op), + bmi2, writeLitEntropy, litEntropyWritten); FORWARD_IF_ERROR(cLitSize, "ZSTD_compressSubBlock_literal failed"); if (cLitSize == 0) return 0; op += cLitSize; @@ -557,18 +292,18 @@ static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy, sequences, nbSeq, llCode, mlCode, ofCode, cctxParams, - op, oend-op, + op, (size_t)(oend-op), bmi2, writeSeqEntropy, seqEntropyWritten); FORWARD_IF_ERROR(cSeqSize, "ZSTD_compressSubBlock_sequences failed"); if (cSeqSize == 0) return 0; op += cSeqSize; } /* Write block header */ - { size_t cSize = (op-ostart)-ZSTDInternalConstants::ZSTD_blockHeaderSize; + { size_t cSize = (size_t)(op-ostart) - ZSTD_blockHeaderSize; U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); MEM_writeLE24(ostart, cBlockHeader24); } - return op-ostart; + return (size_t)(op-ostart); } static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t litSize, @@ -597,8 +332,8 @@ static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t lit static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type, const BYTE* codeTable, unsigned maxCode, size_t nbSeq, const FSE_CTable* fseCTable, - const U32* additionalBits, - short const* defaultNorm, U32 defaultNormLog, + const U8* additionalBits, + short const* defaultNorm, U32 defaultNormLog, U32 defaultMax, void* workspace, size_t wkspSize) { unsigned* const countWksp = (unsigned*)workspace; @@ -610,7 +345,11 @@ static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type, HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */ if (type == set_basic) { - cSymbolTypeSizeEstimateInBits = ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max); + /* We selected this encoding type, so it must be valid. */ + assert(max <= defaultMax); + cSymbolTypeSizeEstimateInBits = max <= defaultMax + ? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max) + : ERROR(GENERIC); } else if (type == set_rle) { cSymbolTypeSizeEstimateInBits = 0; } else if (type == set_compressed || type == set_repeat) { @@ -634,25 +373,30 @@ static size_t ZSTD_estimateSubBlockSize_sequences(const BYTE* ofCodeTable, void* workspace, size_t wkspSize, int writeEntropy) { - size_t sequencesSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */ + size_t const sequencesSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */ size_t cSeqSizeEstimate = 0; + if (nbSeq == 0) return sequencesSectionHeaderSize; cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, MaxOff, nbSeq, fseTables->offcodeCTable, NULL, - ZSTDInternalConstants::OF_defaultNorm, ZSTDInternalConstants::OF_defaultNormLog, + OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, workspace, wkspSize); cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->llType, llCodeTable, MaxLL, - nbSeq, fseTables->litlengthCTable, ZSTDInternalConstants::LL_bits, - ZSTDInternalConstants::LL_defaultNorm, ZSTDInternalConstants::LL_defaultNormLog, + nbSeq, fseTables->litlengthCTable, LL_bits, + LL_defaultNorm, LL_defaultNormLog, MaxLL, workspace, wkspSize); cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, MaxML, - nbSeq, fseTables->matchlengthCTable, ZSTDInternalConstants::ML_bits, - ZSTDInternalConstants::ML_defaultNorm, ZSTDInternalConstants::ML_defaultNormLog, + nbSeq, fseTables->matchlengthCTable, ML_bits, + ML_defaultNorm, ML_defaultNormLog, MaxML, workspace, wkspSize); if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize; return cSeqSizeEstimate + sequencesSectionHeaderSize; } -static size_t ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize, +typedef struct { + size_t estLitSize; + size_t estBlockSize; +} EstimatedBlockSize; +static EstimatedBlockSize ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize, const BYTE* ofCodeTable, const BYTE* llCodeTable, const BYTE* mlCodeTable, @@ -660,15 +404,17 @@ static size_t ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize, const ZSTD_entropyCTables_t* entropy, const ZSTD_entropyCTablesMetadata_t* entropyMetadata, void* workspace, size_t wkspSize, - int writeLitEntropy, int writeSeqEntropy) { - size_t cSizeEstimate = 0; - cSizeEstimate += ZSTD_estimateSubBlockSize_literal(literals, litSize, - &entropy->huf, &entropyMetadata->hufMetadata, - workspace, wkspSize, writeLitEntropy); - cSizeEstimate += ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable, + int writeLitEntropy, int writeSeqEntropy) +{ + EstimatedBlockSize ebs; + ebs.estLitSize = ZSTD_estimateSubBlockSize_literal(literals, litSize, + &entropy->huf, &entropyMetadata->hufMetadata, + workspace, wkspSize, writeLitEntropy); + ebs.estBlockSize = ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable, nbSeq, &entropy->fse, &entropyMetadata->fseMetadata, workspace, wkspSize, writeSeqEntropy); - return cSizeEstimate + ZSTDInternalConstants::ZSTD_blockHeaderSize; + ebs.estBlockSize += ebs.estLitSize + ZSTD_blockHeaderSize; + return ebs; } static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMetadata) @@ -682,13 +428,56 @@ static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMe return 0; } +static size_t countLiterals(seqStore_t const* seqStore, const seqDef* sp, size_t seqCount) +{ + size_t n, total = 0; + assert(sp != NULL); + for (n=0; n %zu bytes", seqCount, (const void*)sp, total); + return total; +} + +#define BYTESCALE 256 + +static size_t sizeBlockSequences(const seqDef* sp, size_t nbSeqs, + size_t targetBudget, size_t avgLitCost, size_t avgSeqCost, + int firstSubBlock) +{ + size_t n, budget = 0, inSize=0; + /* entropy headers */ + size_t const headerSize = (size_t)firstSubBlock * 120 * BYTESCALE; /* generous estimate */ + assert(firstSubBlock==0 || firstSubBlock==1); + budget += headerSize; + + /* first sequence => at least one sequence*/ + budget += sp[0].litLength * avgLitCost + avgSeqCost; + if (budget > targetBudget) return 1; + inSize = sp[0].litLength + (sp[0].mlBase+MINMATCH); + + /* loop over sequences */ + for (n=1; n targetBudget) + /* though continue to expand until the sub-block is deemed compressible */ + && (budget < inSize * BYTESCALE) ) + break; + } + + return n; +} + /** ZSTD_compressSubBlock_multi() : * Breaks super-block into multiple sub-blocks and compresses them. - * Entropy will be written to the first block. - * The following blocks will use repeat mode to compress. - * All sub-blocks are compressed blocks (no raw or rle blocks). - * @return : compressed size of the super block (which is multiple ZSTD blocks) - * Or 0 if it failed to compress. */ + * Entropy will be written into the first block. + * The following blocks use repeat_mode to compress. + * Sub-blocks are all compressed, except the last one when beneficial. + * @return : compressed size of the super block (which features multiple ZSTD blocks) + * or 0 if it failed to compress. */ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr, const ZSTD_compressedBlockState_t* prevCBlock, ZSTD_compressedBlockState_t* nextCBlock, @@ -701,10 +490,12 @@ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr, { const seqDef* const sstart = seqStorePtr->sequencesStart; const seqDef* const send = seqStorePtr->sequences; - const seqDef* sp = sstart; + const seqDef* sp = sstart; /* tracks progresses within seqStorePtr->sequences */ + size_t const nbSeqs = (size_t)(send - sstart); const BYTE* const lstart = seqStorePtr->litStart; const BYTE* const lend = seqStorePtr->lit; const BYTE* lp = lstart; + size_t const nbLiterals = (size_t)(lend - lstart); BYTE const* ip = (BYTE const*)src; BYTE const* const iend = ip + srcSize; BYTE* const ostart = (BYTE*)dst; @@ -713,120 +504,179 @@ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr, const BYTE* llCodePtr = seqStorePtr->llCode; const BYTE* mlCodePtr = seqStorePtr->mlCode; const BYTE* ofCodePtr = seqStorePtr->ofCode; - size_t targetCBlockSize = cctxParams->targetCBlockSize; - size_t litSize, seqCount; - int writeLitEntropy = entropyMetadata->hufMetadata.hType == set_compressed; + size_t const minTarget = ZSTD_TARGETCBLOCKSIZE_MIN; /* enforce minimum size, to reduce undesirable side effects */ + size_t const targetCBlockSize = MAX(minTarget, cctxParams->targetCBlockSize); + int writeLitEntropy = (entropyMetadata->hufMetadata.hType == set_compressed); int writeSeqEntropy = 1; - int lastSequence = 0; - - DEBUGLOG(5, "ZSTD_compressSubBlock_multi (litSize=%u, nbSeq=%u)", - (unsigned)(lend-lp), (unsigned)(send-sstart)); - - litSize = 0; - seqCount = 0; - do { - size_t cBlockSizeEstimate = 0; - if (sstart == send) { - lastSequence = 1; - } else { - const seqDef* const sequence = sp + seqCount; - lastSequence = sequence == send - 1; - litSize += ZSTD_getSequenceLength(seqStorePtr, sequence).litLength; - seqCount++; - } - if (lastSequence) { - assert(lp <= lend); - assert(litSize <= (size_t)(lend - lp)); - litSize = (size_t)(lend - lp); + + DEBUGLOG(5, "ZSTD_compressSubBlock_multi (srcSize=%u, litSize=%u, nbSeq=%u)", + (unsigned)srcSize, (unsigned)(lend-lstart), (unsigned)(send-sstart)); + + /* let's start by a general estimation for the full block */ + if (nbSeqs > 0) { + EstimatedBlockSize const ebs = + ZSTD_estimateSubBlockSize(lp, nbLiterals, + ofCodePtr, llCodePtr, mlCodePtr, nbSeqs, + &nextCBlock->entropy, entropyMetadata, + workspace, wkspSize, + writeLitEntropy, writeSeqEntropy); + /* quick estimation */ + size_t const avgLitCost = nbLiterals ? (ebs.estLitSize * BYTESCALE) / nbLiterals : BYTESCALE; + size_t const avgSeqCost = ((ebs.estBlockSize - ebs.estLitSize) * BYTESCALE) / nbSeqs; + const size_t nbSubBlocks = MAX((ebs.estBlockSize + (targetCBlockSize/2)) / targetCBlockSize, 1); + size_t n, avgBlockBudget, blockBudgetSupp=0; + avgBlockBudget = (ebs.estBlockSize * BYTESCALE) / nbSubBlocks; + DEBUGLOG(5, "estimated fullblock size=%u bytes ; avgLitCost=%.2f ; avgSeqCost=%.2f ; targetCBlockSize=%u, nbSubBlocks=%u ; avgBlockBudget=%.0f bytes", + (unsigned)ebs.estBlockSize, (double)avgLitCost/BYTESCALE, (double)avgSeqCost/BYTESCALE, + (unsigned)targetCBlockSize, (unsigned)nbSubBlocks, (double)avgBlockBudget/BYTESCALE); + /* simplification: if estimates states that the full superblock doesn't compress, just bail out immediately + * this will result in the production of a single uncompressed block covering @srcSize.*/ + if (ebs.estBlockSize > srcSize) return 0; + + /* compress and write sub-blocks */ + assert(nbSubBlocks>0); + for (n=0; n < nbSubBlocks-1; n++) { + /* determine nb of sequences for current sub-block + nbLiterals from next sequence */ + size_t const seqCount = sizeBlockSequences(sp, (size_t)(send-sp), + avgBlockBudget + blockBudgetSupp, avgLitCost, avgSeqCost, n==0); + /* if reached last sequence : break to last sub-block (simplification) */ + assert(seqCount <= (size_t)(send-sp)); + if (sp + seqCount == send) break; + assert(seqCount > 0); + /* compress sub-block */ + { int litEntropyWritten = 0; + int seqEntropyWritten = 0; + size_t litSize = countLiterals(seqStorePtr, sp, seqCount); + const size_t decompressedSize = + ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, 0); + size_t const cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata, + sp, seqCount, + lp, litSize, + llCodePtr, mlCodePtr, ofCodePtr, + cctxParams, + op, (size_t)(oend-op), + bmi2, writeLitEntropy, writeSeqEntropy, + &litEntropyWritten, &seqEntropyWritten, + 0); + FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed"); + + /* check compressibility, update state components */ + if (cSize > 0 && cSize < decompressedSize) { + DEBUGLOG(5, "Committed sub-block compressing %u bytes => %u bytes", + (unsigned)decompressedSize, (unsigned)cSize); + assert(ip + decompressedSize <= iend); + ip += decompressedSize; + lp += litSize; + op += cSize; + llCodePtr += seqCount; + mlCodePtr += seqCount; + ofCodePtr += seqCount; + /* Entropy only needs to be written once */ + if (litEntropyWritten) { + writeLitEntropy = 0; + } + if (seqEntropyWritten) { + writeSeqEntropy = 0; + } + sp += seqCount; + blockBudgetSupp = 0; + } } + /* otherwise : do not compress yet, coalesce current sub-block with following one */ } - /* I think there is an optimization opportunity here. - * Calling ZSTD_estimateSubBlockSize for every sequence can be wasteful - * since it recalculates estimate from scratch. - * For example, it would recount literal distribution and symbol codes everytime. - */ - cBlockSizeEstimate = ZSTD_estimateSubBlockSize(lp, litSize, ofCodePtr, llCodePtr, mlCodePtr, seqCount, - &nextCBlock->entropy, entropyMetadata, - workspace, wkspSize, writeLitEntropy, writeSeqEntropy); - if (cBlockSizeEstimate > targetCBlockSize || lastSequence) { - int litEntropyWritten = 0; - int seqEntropyWritten = 0; - const size_t decompressedSize = ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, lastSequence); - const size_t cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata, - sp, seqCount, - lp, litSize, - llCodePtr, mlCodePtr, ofCodePtr, - cctxParams, - op, oend-op, - bmi2, writeLitEntropy, writeSeqEntropy, - &litEntropyWritten, &seqEntropyWritten, - lastBlock && lastSequence); - FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed"); - if (cSize > 0 && cSize < decompressedSize) { - DEBUGLOG(5, "Committed the sub-block"); - assert(ip + decompressedSize <= iend); - ip += decompressedSize; - sp += seqCount; - lp += litSize; - op += cSize; - llCodePtr += seqCount; - mlCodePtr += seqCount; - ofCodePtr += seqCount; - litSize = 0; - seqCount = 0; - /* Entropy only needs to be written once */ - if (litEntropyWritten) { - writeLitEntropy = 0; - } - if (seqEntropyWritten) { - writeSeqEntropy = 0; - } + } /* if (nbSeqs > 0) */ + + /* write last block */ + DEBUGLOG(5, "Generate last sub-block: %u sequences remaining", (unsigned)(send - sp)); + { int litEntropyWritten = 0; + int seqEntropyWritten = 0; + size_t litSize = (size_t)(lend - lp); + size_t seqCount = (size_t)(send - sp); + const size_t decompressedSize = + ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, 1); + size_t const cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata, + sp, seqCount, + lp, litSize, + llCodePtr, mlCodePtr, ofCodePtr, + cctxParams, + op, (size_t)(oend-op), + bmi2, writeLitEntropy, writeSeqEntropy, + &litEntropyWritten, &seqEntropyWritten, + lastBlock); + FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed"); + + /* update pointers, the nb of literals borrowed from next sequence must be preserved */ + if (cSize > 0 && cSize < decompressedSize) { + DEBUGLOG(5, "Last sub-block compressed %u bytes => %u bytes", + (unsigned)decompressedSize, (unsigned)cSize); + assert(ip + decompressedSize <= iend); + ip += decompressedSize; + lp += litSize; + op += cSize; + llCodePtr += seqCount; + mlCodePtr += seqCount; + ofCodePtr += seqCount; + /* Entropy only needs to be written once */ + if (litEntropyWritten) { + writeLitEntropy = 0; + } + if (seqEntropyWritten) { + writeSeqEntropy = 0; } + sp += seqCount; } - } while (!lastSequence); + } + + if (writeLitEntropy) { - DEBUGLOG(5, "ZSTD_compressSubBlock_multi has literal entropy tables unwritten"); - memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf)); + DEBUGLOG(5, "Literal entropy tables were never written"); + ZSTD_memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf)); } if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) { /* If we haven't written our entropy tables, then we've violated our contract and * must emit an uncompressed block. */ - DEBUGLOG(5, "ZSTD_compressSubBlock_multi has sequence entropy tables unwritten"); + DEBUGLOG(5, "Sequence entropy tables were never written => cancel, emit an uncompressed block"); return 0; } + if (ip < iend) { - size_t const cSize = ZSTD_noCompressBlock(op, oend - op, ip, iend - ip, lastBlock); - DEBUGLOG(5, "ZSTD_compressSubBlock_multi last sub-block uncompressed, %zu bytes", (size_t)(iend - ip)); + /* some data left : last part of the block sent uncompressed */ + size_t const rSize = (size_t)((iend - ip)); + size_t const cSize = ZSTD_noCompressBlock(op, (size_t)(oend - op), ip, rSize, lastBlock); + DEBUGLOG(5, "Generate last uncompressed sub-block of %u bytes", (unsigned)(rSize)); FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed"); assert(cSize != 0); op += cSize; /* We have to regenerate the repcodes because we've skipped some sequences */ if (sp < send) { - seqDef const* seq; + const seqDef* seq; repcodes_t rep; - memcpy(&rep, prevCBlock->rep, sizeof(rep)); + ZSTD_memcpy(&rep, prevCBlock->rep, sizeof(rep)); for (seq = sstart; seq < sp; ++seq) { - rep = ZSTD_updateRep(rep.rep, seq->offset - 1, ZSTD_getSequenceLength(seqStorePtr, seq).litLength == 0); + ZSTD_updateRep(rep.rep, seq->offBase, ZSTD_getSequenceLength(seqStorePtr, seq).litLength == 0); } - memcpy(nextCBlock->rep, &rep, sizeof(rep)); + ZSTD_memcpy(nextCBlock->rep, &rep, sizeof(rep)); } } - DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed"); - return op-ostart; + + DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed all subBlocks: total compressed size = %u", + (unsigned)(op-ostart)); + return (size_t)(op-ostart); } size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, - void const* src, size_t srcSize, - unsigned lastBlock) { + const void* src, size_t srcSize, + unsigned lastBlock) +{ ZSTD_entropyCTablesMetadata_t entropyMetadata; - FORWARD_IF_ERROR(ZSTD_buildSuperBlockEntropy(&zc->seqStore, + FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(&zc->seqStore, &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, &zc->appliedParams, &entropyMetadata, - zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */), ""); + zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */), ""); return ZSTD_compressSubBlock_multi(&zc->seqStore, zc->blockState.prevCBlock, @@ -836,7 +686,7 @@ size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc, dst, dstCapacity, src, srcSize, zc->bmi2, lastBlock, - zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */); + zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */); } -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/compress/zstd_double_fast.cpp b/src/duckdb/third_party/zstd/compress/zstd_double_fast.cpp index ecc1cdb77..d791b724b 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_double_fast.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_double_fast.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -13,7 +13,49 @@ namespace duckdb_zstd { -void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, +#ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR + +static +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +void ZSTD_fillDoubleHashTableForCDict(ZSTD_matchState_t* ms, + void const* end, ZSTD_dictTableLoadMethod_e dtlm) +{ + const ZSTD_compressionParameters* const cParams = &ms->cParams; + U32* const hashLarge = ms->hashTable; + U32 const hBitsL = cParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; + U32 const mls = cParams->minMatch; + U32* const hashSmall = ms->chainTable; + U32 const hBitsS = cParams->chainLog + ZSTD_SHORT_CACHE_TAG_BITS; + const BYTE* const base = ms->window.base; + const BYTE* ip = base + ms->nextToUpdate; + const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; + const U32 fastHashFillStep = 3; + + /* Always insert every fastHashFillStep position into the hash tables. + * Insert the other positions into the large hash table if their entry + * is empty. + */ + for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) { + U32 const curr = (U32)(ip - base); + U32 i; + for (i = 0; i < fastHashFillStep; ++i) { + size_t const smHashAndTag = ZSTD_hashPtr(ip + i, hBitsS, mls); + size_t const lgHashAndTag = ZSTD_hashPtr(ip + i, hBitsL, 8); + if (i == 0) { + ZSTD_writeTaggedIndex(hashSmall, smHashAndTag, curr + i); + } + if (i == 0 || hashLarge[lgHashAndTag >> ZSTD_SHORT_CACHE_TAG_BITS] == 0) { + ZSTD_writeTaggedIndex(hashLarge, lgHashAndTag, curr + i); + } + /* Only load extra positions for ZSTD_dtlm_full */ + if (dtlm == ZSTD_dtlm_fast) + break; + } } +} + +static +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +void ZSTD_fillDoubleHashTableForCCtx(ZSTD_matchState_t* ms, void const* end, ZSTD_dictTableLoadMethod_e dtlm) { const ZSTD_compressionParameters* const cParams = &ms->cParams; @@ -32,27 +74,251 @@ void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, * is empty. */ for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) { - U32 const current = (U32)(ip - base); + U32 const curr = (U32)(ip - base); U32 i; for (i = 0; i < fastHashFillStep; ++i) { size_t const smHash = ZSTD_hashPtr(ip + i, hBitsS, mls); size_t const lgHash = ZSTD_hashPtr(ip + i, hBitsL, 8); if (i == 0) - hashSmall[smHash] = current + i; + hashSmall[smHash] = curr + i; if (i == 0 || hashLarge[lgHash] == 0) - hashLarge[lgHash] = current + i; + hashLarge[lgHash] = curr + i; /* Only load extra positions for ZSTD_dtlm_full */ if (dtlm == ZSTD_dtlm_fast) break; - } } + } } +} + +void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, + const void* const end, + ZSTD_dictTableLoadMethod_e dtlm, + ZSTD_tableFillPurpose_e tfp) +{ + if (tfp == ZSTD_tfp_forCDict) { + ZSTD_fillDoubleHashTableForCDict(ms, end, dtlm); + } else { + ZSTD_fillDoubleHashTableForCCtx(ms, end, dtlm); + } +} + + +FORCE_INLINE_TEMPLATE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +size_t ZSTD_compressBlock_doubleFast_noDict_generic( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize, U32 const mls /* template */) +{ + ZSTD_compressionParameters const* cParams = &ms->cParams; + U32* const hashLong = ms->hashTable; + const U32 hBitsL = cParams->hashLog; + U32* const hashSmall = ms->chainTable; + const U32 hBitsS = cParams->chainLog; + const BYTE* const base = ms->window.base; + const BYTE* const istart = (const BYTE*)src; + const BYTE* anchor = istart; + const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); + /* presumes that, if there is a dictionary, it must be using Attach mode */ + const U32 prefixLowestIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog); + const BYTE* const prefixLowest = base + prefixLowestIndex; + const BYTE* const iend = istart + srcSize; + const BYTE* const ilimit = iend - HASH_READ_SIZE; + U32 offset_1=rep[0], offset_2=rep[1]; + U32 offsetSaved1 = 0, offsetSaved2 = 0; + + size_t mLength; + U32 offset; + U32 curr; + + /* how many positions to search before increasing step size */ + const size_t kStepIncr = 1 << kSearchStrength; + /* the position at which to increment the step size if no match is found */ + const BYTE* nextStep; + size_t step; /* the current step size */ + + size_t hl0; /* the long hash at ip */ + size_t hl1; /* the long hash at ip1 */ + + U32 idxl0; /* the long match index for ip */ + U32 idxl1; /* the long match index for ip1 */ + + const BYTE* matchl0; /* the long match for ip */ + const BYTE* matchs0; /* the short match for ip */ + const BYTE* matchl1; /* the long match for ip1 */ + + const BYTE* ip = istart; /* the current position */ + const BYTE* ip1; /* the next position */ + + DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_noDict_generic"); + + /* init */ + ip += ((ip - prefixLowest) == 0); + { + U32 const current = (U32)(ip - base); + U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog); + U32 const maxRep = current - windowLow; + if (offset_2 > maxRep) offsetSaved2 = offset_2, offset_2 = 0; + if (offset_1 > maxRep) offsetSaved1 = offset_1, offset_1 = 0; + } + + /* Outer Loop: one iteration per match found and stored */ + while (1) { + step = 1; + nextStep = ip + kStepIncr; + ip1 = ip + step; + + if (ip1 > ilimit) { + goto _cleanup; + } + + hl0 = ZSTD_hashPtr(ip, hBitsL, 8); + idxl0 = hashLong[hl0]; + matchl0 = base + idxl0; + + /* Inner Loop: one iteration per search / position */ + do { + const size_t hs0 = ZSTD_hashPtr(ip, hBitsS, mls); + const U32 idxs0 = hashSmall[hs0]; + curr = (U32)(ip-base); + matchs0 = base + idxs0; + + hashLong[hl0] = hashSmall[hs0] = curr; /* update hash tables */ + + /* check noDict repcode */ + if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { + mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4; + ip++; + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength); + goto _match_stored; + } + + hl1 = ZSTD_hashPtr(ip1, hBitsL, 8); + + if (idxl0 > prefixLowestIndex) { + /* check prefix long match */ + if (MEM_read64(matchl0) == MEM_read64(ip)) { + mLength = ZSTD_count(ip+8, matchl0+8, iend) + 8; + offset = (U32)(ip-matchl0); + while (((ip>anchor) & (matchl0>prefixLowest)) && (ip[-1] == matchl0[-1])) { ip--; matchl0--; mLength++; } /* catch up */ + goto _match_found; + } + } + + idxl1 = hashLong[hl1]; + matchl1 = base + idxl1; + + if (idxs0 > prefixLowestIndex) { + /* check prefix short match */ + if (MEM_read32(matchs0) == MEM_read32(ip)) { + goto _search_next_long; + } + } + + if (ip1 >= nextStep) { + PREFETCH_L1(ip1 + 64); + PREFETCH_L1(ip1 + 128); + step++; + nextStep += kStepIncr; + } + ip = ip1; + ip1 += step; + + hl0 = hl1; + idxl0 = idxl1; + matchl0 = matchl1; + #if defined(__aarch64__) + PREFETCH_L1(ip+256); + #endif + } while (ip1 <= ilimit); + +_cleanup: + /* If offset_1 started invalid (offsetSaved1 != 0) and became valid (offset_1 != 0), + * rotate saved offsets. See comment in ZSTD_compressBlock_fast_noDict for more context. */ + offsetSaved2 = ((offsetSaved1 != 0) && (offset_1 != 0)) ? offsetSaved1 : offsetSaved2; + + /* save reps for next block */ + rep[0] = offset_1 ? offset_1 : offsetSaved1; + rep[1] = offset_2 ? offset_2 : offsetSaved2; + + /* Return the last literals size */ + return (size_t)(iend - anchor); + +_search_next_long: + + /* check prefix long +1 match */ + if (idxl1 > prefixLowestIndex) { + if (MEM_read64(matchl1) == MEM_read64(ip1)) { + ip = ip1; + mLength = ZSTD_count(ip+8, matchl1+8, iend) + 8; + offset = (U32)(ip-matchl1); + while (((ip>anchor) & (matchl1>prefixLowest)) && (ip[-1] == matchl1[-1])) { ip--; matchl1--; mLength++; } /* catch up */ + goto _match_found; + } + } + + /* if no long +1 match, explore the short match we found */ + mLength = ZSTD_count(ip+4, matchs0+4, iend) + 4; + offset = (U32)(ip - matchs0); + while (((ip>anchor) & (matchs0>prefixLowest)) && (ip[-1] == matchs0[-1])) { ip--; matchs0--; mLength++; } /* catch up */ + + /* fall-through */ + +_match_found: /* requires ip, offset, mLength */ + offset_2 = offset_1; + offset_1 = offset; + + if (step < 4) { + /* It is unsafe to write this value back to the hashtable when ip1 is + * greater than or equal to the new ip we will have after we're done + * processing this match. Rather than perform that test directly + * (ip1 >= ip + mLength), which costs speed in practice, we do a simpler + * more predictable test. The minmatch even if we take a short match is + * 4 bytes, so as long as step, the distance between ip and ip1 + * (initially) is less than 4, we know ip1 < new ip. */ + hashLong[hl1] = (U32)(ip1 - base); + } + + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); + +_match_stored: + /* match found */ + ip += mLength; + anchor = ip; + + if (ip <= ilimit) { + /* Complementary insertion */ + /* done after iLimit test, as candidates could be > iend-8 */ + { U32 const indexToInsert = curr+2; + hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert; + hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base); + hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert; + hashSmall[ZSTD_hashPtr(ip-1, hBitsS, mls)] = (U32)(ip-1-base); + } + + /* check immediate repcode */ + while ( (ip <= ilimit) + && ( (offset_2>0) + & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) { + /* store sequence */ + size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; + U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */ + hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base); + hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base); + ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, rLength); + ip += rLength; + anchor = ip; + continue; /* faster when present ... (?) */ + } + } + } } FORCE_INLINE_TEMPLATE -size_t ZSTD_compressBlock_doubleFast_generic( +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize, - U32 const mls /* template */, ZSTD_dictMode_e const dictMode) + U32 const mls /* template */) { ZSTD_compressionParameters const* cParams = &ms->cParams; U32* const hashLong = ms->hashTable; @@ -70,57 +336,39 @@ size_t ZSTD_compressBlock_doubleFast_generic( const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; U32 offset_1=rep[0], offset_2=rep[1]; - U32 offsetSaved = 0; const ZSTD_matchState_t* const dms = ms->dictMatchState; - const ZSTD_compressionParameters* const dictCParams = - dictMode == ZSTD_dictMatchState ? - &dms->cParams : NULL; - const U32* const dictHashLong = dictMode == ZSTD_dictMatchState ? - dms->hashTable : NULL; - const U32* const dictHashSmall = dictMode == ZSTD_dictMatchState ? - dms->chainTable : NULL; - const U32 dictStartIndex = dictMode == ZSTD_dictMatchState ? - dms->window.dictLimit : 0; - const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ? - dms->window.base : NULL; - const BYTE* const dictStart = dictMode == ZSTD_dictMatchState ? - dictBase + dictStartIndex : NULL; - const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ? - dms->window.nextSrc : NULL; - const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ? - prefixLowestIndex - (U32)(dictEnd - dictBase) : - 0; - const U32 dictHBitsL = dictMode == ZSTD_dictMatchState ? - dictCParams->hashLog : hBitsL; - const U32 dictHBitsS = dictMode == ZSTD_dictMatchState ? - dictCParams->chainLog : hBitsS; + const ZSTD_compressionParameters* const dictCParams = &dms->cParams; + const U32* const dictHashLong = dms->hashTable; + const U32* const dictHashSmall = dms->chainTable; + const U32 dictStartIndex = dms->window.dictLimit; + const BYTE* const dictBase = dms->window.base; + const BYTE* const dictStart = dictBase + dictStartIndex; + const BYTE* const dictEnd = dms->window.nextSrc; + const U32 dictIndexDelta = prefixLowestIndex - (U32)(dictEnd - dictBase); + const U32 dictHBitsL = dictCParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; + const U32 dictHBitsS = dictCParams->chainLog + ZSTD_SHORT_CACHE_TAG_BITS; const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictStart)); - DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_generic"); - - assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState); + DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_dictMatchState_generic"); /* if a dictionary is attached, it must be within window range */ - if (dictMode == ZSTD_dictMatchState) { - assert(ms->window.dictLimit + (1U << cParams->windowLog) >= endIndex); + assert(ms->window.dictLimit + (1U << cParams->windowLog) >= endIndex); + + if (ms->prefetchCDictTables) { + size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32); + size_t const chainTableBytes = (((size_t)1) << dictCParams->chainLog) * sizeof(U32); + PREFETCH_AREA(dictHashLong, hashTableBytes); + PREFETCH_AREA(dictHashSmall, chainTableBytes); } /* init */ ip += (dictAndPrefixLength == 0); - if (dictMode == ZSTD_noDict) { - U32 const current = (U32)(ip - base); - U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog); - U32 const maxRep = current - windowLow; - if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0; - if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0; - } - if (dictMode == ZSTD_dictMatchState) { - /* dictMatchState repCode checks don't currently handle repCode == 0 - * disabling. */ - assert(offset_1 <= dictAndPrefixLength); - assert(offset_2 <= dictAndPrefixLength); - } + + /* dictMatchState repCode checks don't currently handle repCode == 0 + * disabling. */ + assert(offset_1 <= dictAndPrefixLength); + assert(offset_2 <= dictAndPrefixLength); /* Main Search Loop */ while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ @@ -128,37 +376,30 @@ size_t ZSTD_compressBlock_doubleFast_generic( U32 offset; size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8); size_t const h = ZSTD_hashPtr(ip, hBitsS, mls); - size_t const dictHL = ZSTD_hashPtr(ip, dictHBitsL, 8); - size_t const dictHS = ZSTD_hashPtr(ip, dictHBitsS, mls); - U32 const current = (U32)(ip-base); + size_t const dictHashAndTagL = ZSTD_hashPtr(ip, dictHBitsL, 8); + size_t const dictHashAndTagS = ZSTD_hashPtr(ip, dictHBitsS, mls); + U32 const dictMatchIndexAndTagL = dictHashLong[dictHashAndTagL >> ZSTD_SHORT_CACHE_TAG_BITS]; + U32 const dictMatchIndexAndTagS = dictHashSmall[dictHashAndTagS >> ZSTD_SHORT_CACHE_TAG_BITS]; + int const dictTagsMatchL = ZSTD_comparePackedTags(dictMatchIndexAndTagL, dictHashAndTagL); + int const dictTagsMatchS = ZSTD_comparePackedTags(dictMatchIndexAndTagS, dictHashAndTagS); + U32 const curr = (U32)(ip-base); U32 const matchIndexL = hashLong[h2]; U32 matchIndexS = hashSmall[h]; const BYTE* matchLong = base + matchIndexL; const BYTE* match = base + matchIndexS; - const U32 repIndex = current + 1 - offset_1; - const BYTE* repMatch = (dictMode == ZSTD_dictMatchState - && repIndex < prefixLowestIndex) ? + const U32 repIndex = curr + 1 - offset_1; + const BYTE* repMatch = (repIndex < prefixLowestIndex) ? dictBase + (repIndex - dictIndexDelta) : base + repIndex; - hashLong[h2] = hashSmall[h] = current; /* update hash tables */ + hashLong[h2] = hashSmall[h] = curr; /* update hash tables */ - /* check dictMatchState repcode */ - if (dictMode == ZSTD_dictMatchState - && ((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */) + /* check repcode */ + if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */) && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; ip++; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH); - goto _match_stored; - } - - /* check noDict repcode */ - if ( dictMode == ZSTD_noDict - && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) { - mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4; - ip++; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength); goto _match_stored; } @@ -170,15 +411,15 @@ size_t ZSTD_compressBlock_doubleFast_generic( while (((ip>anchor) & (matchLong>prefixLowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */ goto _match_found; } - } else if (dictMode == ZSTD_dictMatchState) { + } else if (dictTagsMatchL) { /* check dictMatchState long match */ - U32 const dictMatchIndexL = dictHashLong[dictHL]; + U32 const dictMatchIndexL = dictMatchIndexAndTagL >> ZSTD_SHORT_CACHE_TAG_BITS; const BYTE* dictMatchL = dictBase + dictMatchIndexL; assert(dictMatchL < dictEnd); if (dictMatchL > dictStart && MEM_read64(dictMatchL) == MEM_read64(ip)) { mLength = ZSTD_count_2segments(ip+8, dictMatchL+8, iend, dictEnd, prefixLowest) + 8; - offset = (U32)(current - dictMatchIndexL - dictIndexDelta); + offset = (U32)(curr - dictMatchIndexL - dictIndexDelta); while (((ip>anchor) & (dictMatchL>dictStart)) && (ip[-1] == dictMatchL[-1])) { ip--; dictMatchL--; mLength++; } /* catch up */ goto _match_found; } } @@ -188,9 +429,9 @@ size_t ZSTD_compressBlock_doubleFast_generic( if (MEM_read32(match) == MEM_read32(ip)) { goto _search_next_long; } - } else if (dictMode == ZSTD_dictMatchState) { + } else if (dictTagsMatchS) { /* check dictMatchState short match */ - U32 const dictMatchIndexS = dictHashSmall[dictHS]; + U32 const dictMatchIndexS = dictMatchIndexAndTagS >> ZSTD_SHORT_CACHE_TAG_BITS; match = dictBase + dictMatchIndexS; matchIndexS = dictMatchIndexS + dictIndexDelta; @@ -205,12 +446,13 @@ size_t ZSTD_compressBlock_doubleFast_generic( continue; _search_next_long: - { size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8); - size_t const dictHLNext = ZSTD_hashPtr(ip+1, dictHBitsL, 8); + size_t const dictHashAndTagL3 = ZSTD_hashPtr(ip+1, dictHBitsL, 8); U32 const matchIndexL3 = hashLong[hl3]; + U32 const dictMatchIndexAndTagL3 = dictHashLong[dictHashAndTagL3 >> ZSTD_SHORT_CACHE_TAG_BITS]; + int const dictTagsMatchL3 = ZSTD_comparePackedTags(dictMatchIndexAndTagL3, dictHashAndTagL3); const BYTE* matchL3 = base + matchIndexL3; - hashLong[hl3] = current + 1; + hashLong[hl3] = curr + 1; /* check prefix long +1 match */ if (matchIndexL3 > prefixLowestIndex) { @@ -221,23 +463,23 @@ size_t ZSTD_compressBlock_doubleFast_generic( while (((ip>anchor) & (matchL3>prefixLowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */ goto _match_found; } - } else if (dictMode == ZSTD_dictMatchState) { + } else if (dictTagsMatchL3) { /* check dict long +1 match */ - U32 const dictMatchIndexL3 = dictHashLong[dictHLNext]; + U32 const dictMatchIndexL3 = dictMatchIndexAndTagL3 >> ZSTD_SHORT_CACHE_TAG_BITS; const BYTE* dictMatchL3 = dictBase + dictMatchIndexL3; assert(dictMatchL3 < dictEnd); if (dictMatchL3 > dictStart && MEM_read64(dictMatchL3) == MEM_read64(ip+1)) { mLength = ZSTD_count_2segments(ip+1+8, dictMatchL3+8, iend, dictEnd, prefixLowest) + 8; ip++; - offset = (U32)(current + 1 - dictMatchIndexL3 - dictIndexDelta); + offset = (U32)(curr + 1 - dictMatchIndexL3 - dictIndexDelta); while (((ip>anchor) & (dictMatchL3>dictStart)) && (ip[-1] == dictMatchL3[-1])) { ip--; dictMatchL3--; mLength++; } /* catch up */ goto _match_found; } } } /* if no long +1 match, explore the short match we found */ - if (dictMode == ZSTD_dictMatchState && matchIndexS < prefixLowestIndex) { + if (matchIndexS < prefixLowestIndex) { mLength = ZSTD_count_2segments(ip+4, match+4, iend, dictEnd, prefixLowest) + 4; - offset = (U32)(current - matchIndexS); + offset = (U32)(curr - matchIndexS); while (((ip>anchor) & (match>dictStart)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ } else { mLength = ZSTD_count(ip+4, match+4, iend) + 4; @@ -245,13 +487,11 @@ size_t ZSTD_compressBlock_doubleFast_generic( while (((ip>anchor) & (match>prefixLowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ } - /* fall-through */ - _match_found: offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); _match_stored: /* match found */ @@ -261,7 +501,7 @@ size_t ZSTD_compressBlock_doubleFast_generic( if (ip <= ilimit) { /* Complementary insertion */ /* done after iLimit test, as candidates could be > iend-8 */ - { U32 const indexToInsert = current+2; + { U32 const indexToInsert = curr+2; hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert; hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base); hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert; @@ -269,53 +509,55 @@ size_t ZSTD_compressBlock_doubleFast_generic( } /* check immediate repcode */ - if (dictMode == ZSTD_dictMatchState) { - while (ip <= ilimit) { - U32 const current2 = (U32)(ip-base); - U32 const repIndex2 = current2 - offset_2; - const BYTE* repMatch2 = dictMode == ZSTD_dictMatchState - && repIndex2 < prefixLowestIndex ? - dictBase + repIndex2 - dictIndexDelta : - base + repIndex2; - if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */) - && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { - const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend; - size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4; - U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH); - hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2; - hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2; - ip += repLength2; - anchor = ip; - continue; - } - break; - } } - - if (dictMode == ZSTD_noDict) { - while ( (ip <= ilimit) - && ( (offset_2>0) - & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) { - /* store sequence */ - size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; - U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */ - hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base); - hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base); - ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, rLength-MINMATCH); - ip += rLength; + while (ip <= ilimit) { + U32 const current2 = (U32)(ip-base); + U32 const repIndex2 = current2 - offset_2; + const BYTE* repMatch2 = repIndex2 < prefixLowestIndex ? + dictBase + repIndex2 - dictIndexDelta : + base + repIndex2; + if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */) + && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { + const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend; + size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4; + U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ + ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, repLength2); + hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2; + hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2; + ip += repLength2; anchor = ip; - continue; /* faster when present ... (?) */ - } } } + continue; + } + break; + } + } } /* while (ip < ilimit) */ /* save reps for next block */ - rep[0] = offset_1 ? offset_1 : offsetSaved; - rep[1] = offset_2 ? offset_2 : offsetSaved; + rep[0] = offset_1; + rep[1] = offset_2; /* Return the last literals size */ return (size_t)(iend - anchor); } +#define ZSTD_GEN_DFAST_FN(dictMode, mls) \ + static size_t ZSTD_compressBlock_doubleFast_##dictMode##_##mls( \ + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], \ + void const* src, size_t srcSize) \ + { \ + return ZSTD_compressBlock_doubleFast_##dictMode##_generic(ms, seqStore, rep, src, srcSize, mls); \ + } + +ZSTD_GEN_DFAST_FN(noDict, 4) +ZSTD_GEN_DFAST_FN(noDict, 5) +ZSTD_GEN_DFAST_FN(noDict, 6) +ZSTD_GEN_DFAST_FN(noDict, 7) + +ZSTD_GEN_DFAST_FN(dictMatchState, 4) +ZSTD_GEN_DFAST_FN(dictMatchState, 5) +ZSTD_GEN_DFAST_FN(dictMatchState, 6) +ZSTD_GEN_DFAST_FN(dictMatchState, 7) + size_t ZSTD_compressBlock_doubleFast( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -326,13 +568,13 @@ size_t ZSTD_compressBlock_doubleFast( { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_noDict); + return ZSTD_compressBlock_doubleFast_noDict_4(ms, seqStore, rep, src, srcSize); case 5 : - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_noDict); + return ZSTD_compressBlock_doubleFast_noDict_5(ms, seqStore, rep, src, srcSize); case 6 : - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_noDict); + return ZSTD_compressBlock_doubleFast_noDict_6(ms, seqStore, rep, src, srcSize); case 7 : - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_noDict); + return ZSTD_compressBlock_doubleFast_noDict_7(ms, seqStore, rep, src, srcSize); } } @@ -346,18 +588,20 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState( { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_dictMatchState); + return ZSTD_compressBlock_doubleFast_dictMatchState_4(ms, seqStore, rep, src, srcSize); case 5 : - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_dictMatchState); + return ZSTD_compressBlock_doubleFast_dictMatchState_5(ms, seqStore, rep, src, srcSize); case 6 : - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_dictMatchState); + return ZSTD_compressBlock_doubleFast_dictMatchState_6(ms, seqStore, rep, src, srcSize); case 7 : - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_dictMatchState); + return ZSTD_compressBlock_doubleFast_dictMatchState_7(ms, seqStore, rep, src, srcSize); } } -static size_t ZSTD_compressBlock_doubleFast_extDict_generic( +static +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +size_t ZSTD_compressBlock_doubleFast_extDict_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize, U32 const mls /* template */) @@ -388,7 +632,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( /* if extDict is invalidated due to maxDistance, switch to "regular" variant */ if (prefixStartIndex == dictStartIndex) - return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, mls, ZSTD_noDict); + return ZSTD_compressBlock_doubleFast(ms, seqStore, rep, src, srcSize); /* Search Loop */ while (ip < ilimit) { /* < instead of <=, because (ip+1) */ @@ -402,31 +646,31 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( const BYTE* const matchLongBase = matchLongIndex < prefixStartIndex ? dictBase : base; const BYTE* matchLong = matchLongBase + matchLongIndex; - const U32 current = (U32)(ip-base); - const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */ + const U32 curr = (U32)(ip-base); + const U32 repIndex = curr + 1 - offset_1; /* offset_1 expected <= curr +1 */ const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; size_t mLength; - hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */ + hashSmall[hSmall] = hashLong[hLong] = curr; /* update hash table */ if ((((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex doesn't overlap dict + prefix */ - & (repIndex > dictStartIndex)) + & (offset_1 <= curr+1 - dictStartIndex)) /* note: we are searching at curr+1 */ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; ip++; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength); } else { if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) { const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend; const BYTE* const lowMatchPtr = matchLongIndex < prefixStartIndex ? dictStart : prefixStart; U32 offset; mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, prefixStart) + 8; - offset = current - matchLongIndex; + offset = curr - matchLongIndex; while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */ offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); } else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) { size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8); @@ -434,24 +678,24 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( const BYTE* const match3Base = matchIndex3 < prefixStartIndex ? dictBase : base; const BYTE* match3 = match3Base + matchIndex3; U32 offset; - hashLong[h3] = current + 1; + hashLong[h3] = curr + 1; if ( (matchIndex3 > dictStartIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) { const BYTE* const matchEnd = matchIndex3 < prefixStartIndex ? dictEnd : iend; const BYTE* const lowMatchPtr = matchIndex3 < prefixStartIndex ? dictStart : prefixStart; mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, prefixStart) + 8; ip++; - offset = current+1 - matchIndex3; + offset = curr+1 - matchIndex3; while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */ } else { const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend; const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart; mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4; - offset = current - matchIndex; + offset = curr - matchIndex; while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ } offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); } else { ip += ((ip-anchor) >> kSearchStrength) + 1; @@ -465,7 +709,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( if (ip <= ilimit) { /* Complementary insertion */ /* done after iLimit test, as candidates could be > iend-8 */ - { U32 const indexToInsert = current+2; + { U32 const indexToInsert = curr+2; hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert; hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base); hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert; @@ -478,12 +722,12 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( U32 const repIndex2 = current2 - offset_2; const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2; if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) /* intentional overflow : ensure repIndex2 doesn't overlap dict + prefix */ - & (repIndex2 > dictStartIndex)) + & (offset_2 <= current2 - dictStartIndex)) && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH); + ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, repLength2); hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2; hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2; ip += repLength2; @@ -501,6 +745,10 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic( return (size_t)(iend - anchor); } +ZSTD_GEN_DFAST_FN(extDict, 4) +ZSTD_GEN_DFAST_FN(extDict, 5) +ZSTD_GEN_DFAST_FN(extDict, 6) +ZSTD_GEN_DFAST_FN(extDict, 7) size_t ZSTD_compressBlock_doubleFast_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -511,14 +759,16 @@ size_t ZSTD_compressBlock_doubleFast_extDict( { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 4); + return ZSTD_compressBlock_doubleFast_extDict_4(ms, seqStore, rep, src, srcSize); case 5 : - return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 5); + return ZSTD_compressBlock_doubleFast_extDict_5(ms, seqStore, rep, src, srcSize); case 6 : - return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 6); + return ZSTD_compressBlock_doubleFast_extDict_6(ms, seqStore, rep, src, srcSize); case 7 : - return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 7); + return ZSTD_compressBlock_doubleFast_extDict_7(ms, seqStore, rep, src, srcSize); } } -} +#endif /* ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR */ + +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/compress/zstd_fast.cpp b/src/duckdb/third_party/zstd/compress/zstd_fast.cpp index 31da71d85..f45c4d8e1 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_fast.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_fast.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -13,7 +13,46 @@ namespace duckdb_zstd { -void ZSTD_fillHashTable(ZSTD_matchState_t* ms, +static +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +void ZSTD_fillHashTableForCDict(ZSTD_matchState_t* ms, + const void* const end, + ZSTD_dictTableLoadMethod_e dtlm) +{ + const ZSTD_compressionParameters* const cParams = &ms->cParams; + U32* const hashTable = ms->hashTable; + U32 const hBits = cParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; + U32 const mls = cParams->minMatch; + const BYTE* const base = ms->window.base; + const BYTE* ip = base + ms->nextToUpdate; + const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; + const U32 fastHashFillStep = 3; + + /* Currently, we always use ZSTD_dtlm_full for filling CDict tables. + * Feel free to remove this assert if there's a good reason! */ + assert(dtlm == ZSTD_dtlm_full); + + /* Always insert every fastHashFillStep position into the hash table. + * Insert the other positions if their hash entry is empty. + */ + for ( ; ip + fastHashFillStep < iend + 2; ip += fastHashFillStep) { + U32 const curr = (U32)(ip - base); + { size_t const hashAndTag = ZSTD_hashPtr(ip, hBits, mls); + ZSTD_writeTaggedIndex(hashTable, hashAndTag, curr); } + + if (dtlm == ZSTD_dtlm_fast) continue; + /* Only load extra positions for ZSTD_dtlm_full */ + { U32 p; + for (p = 1; p < fastHashFillStep; ++p) { + size_t const hashAndTag = ZSTD_hashPtr(ip + p, hBits, mls); + if (hashTable[hashAndTag >> ZSTD_SHORT_CACHE_TAG_BITS] == 0) { /* not yet filled */ + ZSTD_writeTaggedIndex(hashTable, hashAndTag, curr + p); + } } } } +} + +static +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +void ZSTD_fillHashTableForCCtx(ZSTD_matchState_t* ms, const void* const end, ZSTD_dictTableLoadMethod_e dtlm) { @@ -26,163 +65,366 @@ void ZSTD_fillHashTable(ZSTD_matchState_t* ms, const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; const U32 fastHashFillStep = 3; + /* Currently, we always use ZSTD_dtlm_fast for filling CCtx tables. + * Feel free to remove this assert if there's a good reason! */ + assert(dtlm == ZSTD_dtlm_fast); + /* Always insert every fastHashFillStep position into the hash table. * Insert the other positions if their hash entry is empty. */ for ( ; ip + fastHashFillStep < iend + 2; ip += fastHashFillStep) { - U32 const current = (U32)(ip - base); + U32 const curr = (U32)(ip - base); size_t const hash0 = ZSTD_hashPtr(ip, hBits, mls); - hashTable[hash0] = current; + hashTable[hash0] = curr; if (dtlm == ZSTD_dtlm_fast) continue; /* Only load extra positions for ZSTD_dtlm_full */ { U32 p; for (p = 1; p < fastHashFillStep; ++p) { size_t const hash = ZSTD_hashPtr(ip + p, hBits, mls); if (hashTable[hash] == 0) { /* not yet filled */ - hashTable[hash] = current + p; + hashTable[hash] = curr + p; } } } } } +void ZSTD_fillHashTable(ZSTD_matchState_t* ms, + const void* const end, + ZSTD_dictTableLoadMethod_e dtlm, + ZSTD_tableFillPurpose_e tfp) +{ + if (tfp == ZSTD_tfp_forCDict) { + ZSTD_fillHashTableForCDict(ms, end, dtlm); + } else { + ZSTD_fillHashTableForCCtx(ms, end, dtlm); + } +} + -FORCE_INLINE_TEMPLATE size_t -ZSTD_compressBlock_fast_generic( +/** + * If you squint hard enough (and ignore repcodes), the search operation at any + * given position is broken into 4 stages: + * + * 1. Hash (map position to hash value via input read) + * 2. Lookup (map hash val to index via hashtable read) + * 3. Load (map index to value at that position via input read) + * 4. Compare + * + * Each of these steps involves a memory read at an address which is computed + * from the previous step. This means these steps must be sequenced and their + * latencies are cumulative. + * + * Rather than do 1->2->3->4 sequentially for a single position before moving + * onto the next, this implementation interleaves these operations across the + * next few positions: + * + * R = Repcode Read & Compare + * H = Hash + * T = Table Lookup + * M = Match Read & Compare + * + * Pos | Time --> + * ----+------------------- + * N | ... M + * N+1 | ... TM + * N+2 | R H T M + * N+3 | H TM + * N+4 | R H T M + * N+5 | H ... + * N+6 | R ... + * + * This is very much analogous to the pipelining of execution in a CPU. And just + * like a CPU, we have to dump the pipeline when we find a match (i.e., take a + * branch). + * + * When this happens, we throw away our current state, and do the following prep + * to re-enter the loop: + * + * Pos | Time --> + * ----+------------------- + * N | H T + * N+1 | H + * + * This is also the work we do at the beginning to enter the loop initially. + */ +FORCE_INLINE_TEMPLATE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +size_t ZSTD_compressBlock_fast_noDict_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize, - U32 const mls) + U32 const mls, U32 const hasStep) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32* const hashTable = ms->hashTable; U32 const hlog = cParams->hashLog; /* support stepSize of 0 */ - size_t const stepSize = cParams->targetLength + !(cParams->targetLength) + 1; + size_t const stepSize = hasStep ? (cParams->targetLength + !(cParams->targetLength) + 1) : 2; const BYTE* const base = ms->window.base; const BYTE* const istart = (const BYTE*)src; - /* We check ip0 (ip + 0) and ip1 (ip + 1) each loop */ - const BYTE* ip0 = istart; - const BYTE* ip1; - const BYTE* anchor = istart; const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); const U32 prefixStartIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog); const BYTE* const prefixStart = base + prefixStartIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; - U32 offset_1=rep[0], offset_2=rep[1]; - U32 offsetSaved = 0; - /* init */ + const BYTE* anchor = istart; + const BYTE* ip0 = istart; + const BYTE* ip1; + const BYTE* ip2; + const BYTE* ip3; + U32 current0; + + U32 rep_offset1 = rep[0]; + U32 rep_offset2 = rep[1]; + U32 offsetSaved1 = 0, offsetSaved2 = 0; + + size_t hash0; /* hash for ip0 */ + size_t hash1; /* hash for ip1 */ + U32 idx; /* match idx for ip0 */ + U32 mval; /* src value at match idx */ + + U32 offcode; + const BYTE* match0; + size_t mLength; + + /* ip0 and ip1 are always adjacent. The targetLength skipping and + * uncompressibility acceleration is applied to every other position, + * matching the behavior of #1562. step therefore represents the gap + * between pairs of positions, from ip0 to ip2 or ip1 to ip3. */ + size_t step; + const BYTE* nextStep; + const size_t kStepIncr = (1 << (kSearchStrength - 1)); + DEBUGLOG(5, "ZSTD_compressBlock_fast_generic"); ip0 += (ip0 == prefixStart); + { U32 const curr = (U32)(ip0 - base); + U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, curr, cParams->windowLog); + U32 const maxRep = curr - windowLow; + if (rep_offset2 > maxRep) offsetSaved2 = rep_offset2, rep_offset2 = 0; + if (rep_offset1 > maxRep) offsetSaved1 = rep_offset1, rep_offset1 = 0; + } + + /* start each op */ +_start: /* Requires: ip0 */ + + step = stepSize; + nextStep = ip0 + kStepIncr; + + /* calculate positions, ip0 - anchor == 0, so we skip step calc */ ip1 = ip0 + 1; - { U32 const current = (U32)(ip0 - base); - U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog); - U32 const maxRep = current - windowLow; - if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0; - if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0; + ip2 = ip0 + step; + ip3 = ip2 + 1; + + if (ip3 >= ilimit) { + goto _cleanup; } - /* Main Search Loop */ -#ifdef __INTEL_COMPILER - /* From intel 'The vector pragma indicates that the loop should be - * vectorized if it is legal to do so'. Can be used together with - * #pragma ivdep (but have opted to exclude that because intel - * warns against using it).*/ - #pragma vector always -#endif - while (ip1 < ilimit) { /* < instead of <=, because check at ip0+2 */ - size_t mLength; - BYTE const* ip2 = ip0 + 2; - size_t const h0 = ZSTD_hashPtr(ip0, hlog, mls); - U32 const val0 = MEM_read32(ip0); - size_t const h1 = ZSTD_hashPtr(ip1, hlog, mls); - U32 const val1 = MEM_read32(ip1); - U32 const current0 = (U32)(ip0-base); - U32 const current1 = (U32)(ip1-base); - U32 const matchIndex0 = hashTable[h0]; - U32 const matchIndex1 = hashTable[h1]; - BYTE const* repMatch = ip2 - offset_1; - const BYTE* match0 = base + matchIndex0; - const BYTE* match1 = base + matchIndex1; - U32 offcode; - -#if defined(__aarch64__) - PREFETCH_L1(ip0+256); -#endif - - hashTable[h0] = current0; /* update hash table */ - hashTable[h1] = current1; /* update hash table */ - - assert(ip0 + 1 == ip1); - - if ((offset_1 > 0) & (MEM_read32(repMatch) == MEM_read32(ip2))) { - mLength = (ip2[-1] == repMatch[-1]) ? 1 : 0; - ip0 = ip2 - mLength; - match0 = repMatch - mLength; + hash0 = ZSTD_hashPtr(ip0, hlog, mls); + hash1 = ZSTD_hashPtr(ip1, hlog, mls); + + idx = hashTable[hash0]; + + do { + /* load repcode match for ip[2]*/ + const U32 rval = MEM_read32(ip2 - rep_offset1); + + /* write back hash table entry */ + current0 = (U32)(ip0 - base); + hashTable[hash0] = current0; + + /* check repcode at ip[2] */ + if ((MEM_read32(ip2) == rval) & (rep_offset1 > 0)) { + ip0 = ip2; + match0 = ip0 - rep_offset1; + mLength = ip0[-1] == match0[-1]; + ip0 -= mLength; + match0 -= mLength; + offcode = REPCODE1_TO_OFFBASE; mLength += 4; - offcode = 0; + + /* First write next hash table entry; we've already calculated it. + * This write is known to be safe because the ip1 is before the + * repcode (ip2). */ + hashTable[hash1] = (U32)(ip1 - base); + goto _match; } - if ((matchIndex0 > prefixStartIndex) && MEM_read32(match0) == val0) { - /* found a regular match */ - goto _offset; + + /* load match for ip[0] */ + if (idx >= prefixStartIndex) { + mval = MEM_read32(base + idx); + } else { + mval = MEM_read32(ip0) ^ 1; /* guaranteed to not match. */ } - if ((matchIndex1 > prefixStartIndex) && MEM_read32(match1) == val1) { - /* found a regular match after one literal */ - ip0 = ip1; - match0 = match1; + + /* check match at ip[0] */ + if (MEM_read32(ip0) == mval) { + /* found a match! */ + + /* First write next hash table entry; we've already calculated it. + * This write is known to be safe because the ip1 == ip0 + 1, so + * we know we will resume searching after ip1 */ + hashTable[hash1] = (U32)(ip1 - base); + goto _offset; } - { size_t const step = ((size_t)(ip0-anchor) >> (kSearchStrength - 1)) + stepSize; - assert(step >= 2); - ip0 += step; - ip1 += step; - continue; + + /* lookup ip[1] */ + idx = hashTable[hash1]; + + /* hash ip[2] */ + hash0 = hash1; + hash1 = ZSTD_hashPtr(ip2, hlog, mls); + + /* advance to next positions */ + ip0 = ip1; + ip1 = ip2; + ip2 = ip3; + + /* write back hash table entry */ + current0 = (U32)(ip0 - base); + hashTable[hash0] = current0; + + /* load match for ip[0] */ + if (idx >= prefixStartIndex) { + mval = MEM_read32(base + idx); + } else { + mval = MEM_read32(ip0) ^ 1; /* guaranteed to not match. */ } -_offset: /* Requires: ip0, match0 */ - /* Compute the offset code */ - offset_2 = offset_1; - offset_1 = (U32)(ip0-match0); - offcode = offset_1 + ZSTD_REP_MOVE; - mLength = 4; - /* Count the backwards match length */ - while (((ip0>anchor) & (match0>prefixStart)) - && (ip0[-1] == match0[-1])) { ip0--; match0--; mLength++; } /* catch up */ -_match: /* Requires: ip0, match0, offcode */ - /* Count the forward length */ - mLength += ZSTD_count(ip0+mLength, match0+mLength, iend); - ZSTD_storeSeq(seqStore, (size_t)(ip0-anchor), anchor, iend, offcode, mLength-MINMATCH); - /* match found */ - ip0 += mLength; - anchor = ip0; + /* check match at ip[0] */ + if (MEM_read32(ip0) == mval) { + /* found a match! */ + + /* first write next hash table entry; we've already calculated it */ + if (step <= 4) { + /* We need to avoid writing an index into the hash table >= the + * position at which we will pick up our searching after we've + * taken this match. + * + * The minimum possible match has length 4, so the earliest ip0 + * can be after we take this match will be the current ip0 + 4. + * ip1 is ip0 + step - 1. If ip1 is >= ip0 + 4, we can't safely + * write this position. + */ + hashTable[hash1] = (U32)(ip1 - base); + } - if (ip0 <= ilimit) { - /* Fill Table */ - assert(base+current0+2 > istart); /* check base overflow */ - hashTable[ZSTD_hashPtr(base+current0+2, hlog, mls)] = current0+2; /* here because current+2 could be > iend-8 */ - hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); + goto _offset; + } - if (offset_2 > 0) { /* offset_2==0 means offset_2 is invalidated */ - while ( (ip0 <= ilimit) && (MEM_read32(ip0) == MEM_read32(ip0 - offset_2)) ) { - /* store sequence */ - size_t const rLength = ZSTD_count(ip0+4, ip0+4-offset_2, iend) + 4; - { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */ - hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = (U32)(ip0-base); - ip0 += rLength; - ZSTD_storeSeq(seqStore, 0 /*litLen*/, anchor, iend, 0 /*offCode*/, rLength-MINMATCH); - anchor = ip0; - continue; /* faster when present (confirmed on gcc-8) ... (?) */ - } } } - ip1 = ip0 + 1; - } + /* lookup ip[1] */ + idx = hashTable[hash1]; + + /* hash ip[2] */ + hash0 = hash1; + hash1 = ZSTD_hashPtr(ip2, hlog, mls); + + /* advance to next positions */ + ip0 = ip1; + ip1 = ip2; + ip2 = ip0 + step; + ip3 = ip1 + step; + + /* calculate step */ + if (ip2 >= nextStep) { + step++; + PREFETCH_L1(ip1 + 64); + PREFETCH_L1(ip1 + 128); + nextStep += kStepIncr; + } + } while (ip3 < ilimit); + +_cleanup: + /* Note that there are probably still a couple positions we could search. + * However, it seems to be a meaningful performance hit to try to search + * them. So let's not. */ + + /* When the repcodes are outside of the prefix, we set them to zero before the loop. + * When the offsets are still zero, we need to restore them after the block to have a correct + * repcode history. If only one offset was invalid, it is easy. The tricky case is when both + * offsets were invalid. We need to figure out which offset to refill with. + * - If both offsets are zero they are in the same order. + * - If both offsets are non-zero, we won't restore the offsets from `offsetSaved[12]`. + * - If only one is zero, we need to decide which offset to restore. + * - If rep_offset1 is non-zero, then rep_offset2 must be offsetSaved1. + * - It is impossible for rep_offset2 to be non-zero. + * + * So if rep_offset1 started invalid (offsetSaved1 != 0) and became valid (rep_offset1 != 0), then + * set rep[0] = rep_offset1 and rep[1] = offsetSaved1. + */ + offsetSaved2 = ((offsetSaved1 != 0) && (rep_offset1 != 0)) ? offsetSaved1 : offsetSaved2; /* save reps for next block */ - rep[0] = offset_1 ? offset_1 : offsetSaved; - rep[1] = offset_2 ? offset_2 : offsetSaved; + rep[0] = rep_offset1 ? rep_offset1 : offsetSaved1; + rep[1] = rep_offset2 ? rep_offset2 : offsetSaved2; /* Return the last literals size */ return (size_t)(iend - anchor); + +_offset: /* Requires: ip0, idx */ + + /* Compute the offset code. */ + match0 = base + idx; + rep_offset2 = rep_offset1; + rep_offset1 = (U32)(ip0-match0); + offcode = OFFSET_TO_OFFBASE(rep_offset1); + mLength = 4; + + /* Count the backwards match length. */ + while (((ip0>anchor) & (match0>prefixStart)) && (ip0[-1] == match0[-1])) { + ip0--; + match0--; + mLength++; + } + +_match: /* Requires: ip0, match0, offcode */ + + /* Count the forward length. */ + mLength += ZSTD_count(ip0 + mLength, match0 + mLength, iend); + + ZSTD_storeSeq(seqStore, (size_t)(ip0 - anchor), anchor, iend, offcode, mLength); + + ip0 += mLength; + anchor = ip0; + + /* Fill table and check for immediate repcode. */ + if (ip0 <= ilimit) { + /* Fill Table */ + assert(base+current0+2 > istart); /* check base overflow */ + hashTable[ZSTD_hashPtr(base+current0+2, hlog, mls)] = current0+2; /* here because current+2 could be > iend-8 */ + hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); + + if (rep_offset2 > 0) { /* rep_offset2==0 means rep_offset2 is invalidated */ + while ( (ip0 <= ilimit) && (MEM_read32(ip0) == MEM_read32(ip0 - rep_offset2)) ) { + /* store sequence */ + size_t const rLength = ZSTD_count(ip0+4, ip0+4-rep_offset2, iend) + 4; + { U32 const tmpOff = rep_offset2; rep_offset2 = rep_offset1; rep_offset1 = tmpOff; } /* swap rep_offset2 <=> rep_offset1 */ + hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = (U32)(ip0-base); + ip0 += rLength; + ZSTD_storeSeq(seqStore, 0 /*litLen*/, anchor, iend, REPCODE1_TO_OFFBASE, rLength); + anchor = ip0; + continue; /* faster when present (confirmed on gcc-8) ... (?) */ + } } } + + goto _start; } +#define ZSTD_GEN_FAST_FN(dictMode, mls, step) \ + static size_t ZSTD_compressBlock_fast_##dictMode##_##mls##_##step( \ + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], \ + void const* src, size_t srcSize) \ + { \ + return ZSTD_compressBlock_fast_##dictMode##_generic(ms, seqStore, rep, src, srcSize, mls, step); \ + } + +ZSTD_GEN_FAST_FN(noDict, 4, 1) +ZSTD_GEN_FAST_FN(noDict, 5, 1) +ZSTD_GEN_FAST_FN(noDict, 6, 1) +ZSTD_GEN_FAST_FN(noDict, 7, 1) + +ZSTD_GEN_FAST_FN(noDict, 4, 0) +ZSTD_GEN_FAST_FN(noDict, 5, 0) +ZSTD_GEN_FAST_FN(noDict, 6, 0) +ZSTD_GEN_FAST_FN(noDict, 7, 0) size_t ZSTD_compressBlock_fast( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -190,24 +432,41 @@ size_t ZSTD_compressBlock_fast( { U32 const mls = ms->cParams.minMatch; assert(ms->dictMatchState == NULL); - switch(mls) - { - default: /* includes case 3 */ - case 4 : - return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 4); - case 5 : - return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 5); - case 6 : - return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 6); - case 7 : - return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 7); + if (ms->cParams.targetLength > 1) { + switch(mls) + { + default: /* includes case 3 */ + case 4 : + return ZSTD_compressBlock_fast_noDict_4_1(ms, seqStore, rep, src, srcSize); + case 5 : + return ZSTD_compressBlock_fast_noDict_5_1(ms, seqStore, rep, src, srcSize); + case 6 : + return ZSTD_compressBlock_fast_noDict_6_1(ms, seqStore, rep, src, srcSize); + case 7 : + return ZSTD_compressBlock_fast_noDict_7_1(ms, seqStore, rep, src, srcSize); + } + } else { + switch(mls) + { + default: /* includes case 3 */ + case 4 : + return ZSTD_compressBlock_fast_noDict_4_0(ms, seqStore, rep, src, srcSize); + case 5 : + return ZSTD_compressBlock_fast_noDict_5_0(ms, seqStore, rep, src, srcSize); + case 6 : + return ZSTD_compressBlock_fast_noDict_6_0(ms, seqStore, rep, src, srcSize); + case 7 : + return ZSTD_compressBlock_fast_noDict_7_0(ms, seqStore, rep, src, srcSize); + } + } } FORCE_INLINE_TEMPLATE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR size_t ZSTD_compressBlock_fast_dictMatchState_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize, U32 const mls) + void const* src, size_t srcSize, U32 const mls, U32 const hasStep) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32* const hashTable = ms->hashTable; @@ -216,14 +475,14 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic( U32 const stepSize = cParams->targetLength + !(cParams->targetLength); const BYTE* const base = ms->window.base; const BYTE* const istart = (const BYTE*)src; - const BYTE* ip = istart; + const BYTE* ip0 = istart; + const BYTE* ip1 = ip0 + stepSize; /* we assert below that stepSize >= 1 */ const BYTE* anchor = istart; const U32 prefixStartIndex = ms->window.dictLimit; const BYTE* const prefixStart = base + prefixStartIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; U32 offset_1=rep[0], offset_2=rep[1]; - U32 offsetSaved = 0; const ZSTD_matchState_t* const dms = ms->dictMatchState; const ZSTD_compressionParameters* const dictCParams = &dms->cParams ; @@ -233,125 +492,182 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic( const BYTE* const dictStart = dictBase + dictStartIndex; const BYTE* const dictEnd = dms->window.nextSrc; const U32 dictIndexDelta = prefixStartIndex - (U32)(dictEnd - dictBase); - const U32 dictAndPrefixLength = (U32)(ip - prefixStart + dictEnd - dictStart); - const U32 dictHLog = dictCParams->hashLog; + const U32 dictAndPrefixLength = (U32)(istart - prefixStart + dictEnd - dictStart); + const U32 dictHBits = dictCParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; /* if a dictionary is still attached, it necessarily means that * it is within window size. So we just check it. */ const U32 maxDistance = 1U << cParams->windowLog; - const U32 endIndex = (U32)((size_t)(ip - base) + srcSize); + const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); assert(endIndex - prefixStartIndex <= maxDistance); (void)maxDistance; (void)endIndex; /* these variables are not used when assert() is disabled */ - /* ensure there will be no no underflow + (void)hasStep; /* not currently specialized on whether it's accelerated */ + + /* ensure there will be no underflow * when translating a dict index into a local index */ assert(prefixStartIndex >= (U32)(dictEnd - dictBase)); + if (ms->prefetchCDictTables) { + size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32); + PREFETCH_AREA(dictHashTable, hashTableBytes); + } + /* init */ DEBUGLOG(5, "ZSTD_compressBlock_fast_dictMatchState_generic"); - ip += (dictAndPrefixLength == 0); + ip0 += (dictAndPrefixLength == 0); /* dictMatchState repCode checks don't currently handle repCode == 0 * disabling. */ assert(offset_1 <= dictAndPrefixLength); assert(offset_2 <= dictAndPrefixLength); - /* Main Search Loop */ - while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ + /* Outer search loop */ + assert(stepSize >= 1); + while (ip1 <= ilimit) { /* repcode check at (ip0 + 1) is safe because ip0 < ip1 */ size_t mLength; - size_t const h = ZSTD_hashPtr(ip, hlog, mls); - U32 const current = (U32)(ip-base); - U32 const matchIndex = hashTable[h]; - const BYTE* match = base + matchIndex; - const U32 repIndex = current + 1 - offset_1; - const BYTE* repMatch = (repIndex < prefixStartIndex) ? - dictBase + (repIndex - dictIndexDelta) : - base + repIndex; - hashTable[h] = current; /* update hash table */ - - if ( ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */ - && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { - const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; - mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; - ip++; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH); - } else if ( (matchIndex <= prefixStartIndex) ) { - size_t const dictHash = ZSTD_hashPtr(ip, dictHLog, mls); - U32 const dictMatchIndex = dictHashTable[dictHash]; - const BYTE* dictMatch = dictBase + dictMatchIndex; - if (dictMatchIndex <= dictStartIndex || - MEM_read32(dictMatch) != MEM_read32(ip)) { - assert(stepSize >= 1); - ip += ((ip-anchor) >> kSearchStrength) + stepSize; - continue; - } else { - /* found a dict match */ - U32 const offset = (U32)(current-dictMatchIndex-dictIndexDelta); - mLength = ZSTD_count_2segments(ip+4, dictMatch+4, iend, dictEnd, prefixStart) + 4; - while (((ip>anchor) & (dictMatch>dictStart)) - && (ip[-1] == dictMatch[-1])) { - ip--; dictMatch--; mLength++; + size_t hash0 = ZSTD_hashPtr(ip0, hlog, mls); + + size_t const dictHashAndTag0 = ZSTD_hashPtr(ip0, dictHBits, mls); + U32 dictMatchIndexAndTag = dictHashTable[dictHashAndTag0 >> ZSTD_SHORT_CACHE_TAG_BITS]; + int dictTagsMatch = ZSTD_comparePackedTags(dictMatchIndexAndTag, dictHashAndTag0); + + U32 matchIndex = hashTable[hash0]; + U32 curr = (U32)(ip0 - base); + size_t step = stepSize; + const size_t kStepIncr = 1 << kSearchStrength; + const BYTE* nextStep = ip0 + kStepIncr; + + /* Inner search loop */ + while (1) { + const BYTE* match = base + matchIndex; + const U32 repIndex = curr + 1 - offset_1; + const BYTE* repMatch = (repIndex < prefixStartIndex) ? + dictBase + (repIndex - dictIndexDelta) : + base + repIndex; + const size_t hash1 = ZSTD_hashPtr(ip1, hlog, mls); + size_t const dictHashAndTag1 = ZSTD_hashPtr(ip1, dictHBits, mls); + hashTable[hash0] = curr; /* update hash table */ + + if (((U32) ((prefixStartIndex - 1) - repIndex) >= + 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */ + && (MEM_read32(repMatch) == MEM_read32(ip0 + 1))) { + const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; + mLength = ZSTD_count_2segments(ip0 + 1 + 4, repMatch + 4, iend, repMatchEnd, prefixStart) + 4; + ip0++; + ZSTD_storeSeq(seqStore, (size_t) (ip0 - anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength); + break; + } + + if (dictTagsMatch) { + /* Found a possible dict match */ + const U32 dictMatchIndex = dictMatchIndexAndTag >> ZSTD_SHORT_CACHE_TAG_BITS; + const BYTE* dictMatch = dictBase + dictMatchIndex; + if (dictMatchIndex > dictStartIndex && + MEM_read32(dictMatch) == MEM_read32(ip0)) { + /* To replicate extDict parse behavior, we only use dict matches when the normal matchIndex is invalid */ + if (matchIndex <= prefixStartIndex) { + U32 const offset = (U32) (curr - dictMatchIndex - dictIndexDelta); + mLength = ZSTD_count_2segments(ip0 + 4, dictMatch + 4, iend, dictEnd, prefixStart) + 4; + while (((ip0 > anchor) & (dictMatch > dictStart)) + && (ip0[-1] == dictMatch[-1])) { + ip0--; + dictMatch--; + mLength++; + } /* catch up */ + offset_2 = offset_1; + offset_1 = offset; + ZSTD_storeSeq(seqStore, (size_t) (ip0 - anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); + break; + } + } + } + + if (matchIndex > prefixStartIndex && MEM_read32(match) == MEM_read32(ip0)) { + /* found a regular match */ + U32 const offset = (U32) (ip0 - match); + mLength = ZSTD_count(ip0 + 4, match + 4, iend) + 4; + while (((ip0 > anchor) & (match > prefixStart)) + && (ip0[-1] == match[-1])) { + ip0--; + match--; + mLength++; } /* catch up */ offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + ZSTD_storeSeq(seqStore, (size_t) (ip0 - anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); + break; } - } else if (MEM_read32(match) != MEM_read32(ip)) { - /* it's not a match, and we're not going to check the dictionary */ - assert(stepSize >= 1); - ip += ((ip-anchor) >> kSearchStrength) + stepSize; - continue; - } else { - /* found a regular match */ - U32 const offset = (U32)(ip-match); - mLength = ZSTD_count(ip+4, match+4, iend) + 4; - while (((ip>anchor) & (match>prefixStart)) - && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ - offset_2 = offset_1; - offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); - } + + /* Prepare for next iteration */ + dictMatchIndexAndTag = dictHashTable[dictHashAndTag1 >> ZSTD_SHORT_CACHE_TAG_BITS]; + dictTagsMatch = ZSTD_comparePackedTags(dictMatchIndexAndTag, dictHashAndTag1); + matchIndex = hashTable[hash1]; + + if (ip1 >= nextStep) { + step++; + nextStep += kStepIncr; + } + ip0 = ip1; + ip1 = ip1 + step; + if (ip1 > ilimit) goto _cleanup; + + curr = (U32)(ip0 - base); + hash0 = hash1; + } /* end inner search loop */ /* match found */ - ip += mLength; - anchor = ip; + assert(mLength); + ip0 += mLength; + anchor = ip0; - if (ip <= ilimit) { + if (ip0 <= ilimit) { /* Fill Table */ - assert(base+current+2 > istart); /* check base overflow */ - hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2; /* here because current+2 could be > iend-8 */ - hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base); + assert(base+curr+2 > istart); /* check base overflow */ + hashTable[ZSTD_hashPtr(base+curr+2, hlog, mls)] = curr+2; /* here because curr+2 could be > iend-8 */ + hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); /* check immediate repcode */ - while (ip <= ilimit) { - U32 const current2 = (U32)(ip-base); + while (ip0 <= ilimit) { + U32 const current2 = (U32)(ip0-base); U32 const repIndex2 = current2 - offset_2; const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase - dictIndexDelta + repIndex2 : base + repIndex2; if ( ((U32)((prefixStartIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */) - && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { + && (MEM_read32(repMatch2) == MEM_read32(ip0))) { const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; - size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; + size_t const repLength2 = ZSTD_count_2segments(ip0+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH); - hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2; - ip += repLength2; - anchor = ip; + ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, repLength2); + hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = current2; + ip0 += repLength2; + anchor = ip0; continue; } break; } } + + /* Prepare for next iteration */ + assert(ip0 == anchor); + ip1 = ip0 + stepSize; } +_cleanup: /* save reps for next block */ - rep[0] = offset_1 ? offset_1 : offsetSaved; - rep[1] = offset_2 ? offset_2 : offsetSaved; + rep[0] = offset_1; + rep[1] = offset_2; /* Return the last literals size */ return (size_t)(iend - anchor); } + +ZSTD_GEN_FAST_FN(dictMatchState, 4, 0) +ZSTD_GEN_FAST_FN(dictMatchState, 5, 0) +ZSTD_GEN_FAST_FN(dictMatchState, 6, 0) +ZSTD_GEN_FAST_FN(dictMatchState, 7, 0) + size_t ZSTD_compressBlock_fast_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) @@ -362,30 +678,31 @@ size_t ZSTD_compressBlock_fast_dictMatchState( { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 4); + return ZSTD_compressBlock_fast_dictMatchState_4_0(ms, seqStore, rep, src, srcSize); case 5 : - return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 5); + return ZSTD_compressBlock_fast_dictMatchState_5_0(ms, seqStore, rep, src, srcSize); case 6 : - return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 6); + return ZSTD_compressBlock_fast_dictMatchState_6_0(ms, seqStore, rep, src, srcSize); case 7 : - return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 7); + return ZSTD_compressBlock_fast_dictMatchState_7_0(ms, seqStore, rep, src, srcSize); } } -static size_t ZSTD_compressBlock_fast_extDict_generic( +static +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +size_t ZSTD_compressBlock_fast_extDict_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize, U32 const mls) + void const* src, size_t srcSize, U32 const mls, U32 const hasStep) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32* const hashTable = ms->hashTable; U32 const hlog = cParams->hashLog; /* support stepSize of 0 */ - U32 const stepSize = cParams->targetLength + !(cParams->targetLength); + size_t const stepSize = cParams->targetLength + !(cParams->targetLength) + 1; const BYTE* const base = ms->window.base; const BYTE* const dictBase = ms->window.dictBase; const BYTE* const istart = (const BYTE*)src; - const BYTE* ip = istart; const BYTE* anchor = istart; const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); const U32 lowLimit = ZSTD_getLowestMatchIndex(ms, endIndex, cParams->windowLog); @@ -398,102 +715,258 @@ static size_t ZSTD_compressBlock_fast_extDict_generic( const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - 8; U32 offset_1=rep[0], offset_2=rep[1]; + U32 offsetSaved1 = 0, offsetSaved2 = 0; + + const BYTE* ip0 = istart; + const BYTE* ip1; + const BYTE* ip2; + const BYTE* ip3; + U32 current0; + + + size_t hash0; /* hash for ip0 */ + size_t hash1; /* hash for ip1 */ + U32 idx; /* match idx for ip0 */ + const BYTE* idxBase; /* base pointer for idx */ + + U32 offcode; + const BYTE* match0; + size_t mLength; + const BYTE* matchEnd = 0; /* initialize to avoid warning, assert != 0 later */ + + size_t step; + const BYTE* nextStep; + const size_t kStepIncr = (1 << (kSearchStrength - 1)); + + (void)hasStep; /* not currently specialized on whether it's accelerated */ DEBUGLOG(5, "ZSTD_compressBlock_fast_extDict_generic (offset_1=%u)", offset_1); /* switch to "regular" variant if extDict is invalidated due to maxDistance */ if (prefixStartIndex == dictStartIndex) - return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, mls); - - /* Search Loop */ - while (ip < ilimit) { /* < instead of <=, because (ip+1) */ - const size_t h = ZSTD_hashPtr(ip, hlog, mls); - const U32 matchIndex = hashTable[h]; - const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base; - const BYTE* match = matchBase + matchIndex; - const U32 current = (U32)(ip-base); - const U32 repIndex = current + 1 - offset_1; - const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base; - const BYTE* const repMatch = repBase + repIndex; - hashTable[h] = current; /* update hash table */ - DEBUGLOG(7, "offset_1 = %u , current = %u", offset_1, current); - assert(offset_1 <= current +1); /* check repIndex */ - - if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex)) - && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { - const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; - size_t const rLength = ZSTD_count_2segments(ip+1 +4, repMatch +4, iend, repMatchEnd, prefixStart) + 4; - ip++; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, rLength-MINMATCH); - ip += rLength; - anchor = ip; - } else { - if ( (matchIndex < dictStartIndex) || - (MEM_read32(match) != MEM_read32(ip)) ) { - assert(stepSize >= 1); - ip += ((ip-anchor) >> kSearchStrength) + stepSize; - continue; + return ZSTD_compressBlock_fast(ms, seqStore, rep, src, srcSize); + + { U32 const curr = (U32)(ip0 - base); + U32 const maxRep = curr - dictStartIndex; + if (offset_2 >= maxRep) offsetSaved2 = offset_2, offset_2 = 0; + if (offset_1 >= maxRep) offsetSaved1 = offset_1, offset_1 = 0; + } + + /* start each op */ +_start: /* Requires: ip0 */ + + step = stepSize; + nextStep = ip0 + kStepIncr; + + /* calculate positions, ip0 - anchor == 0, so we skip step calc */ + ip1 = ip0 + 1; + ip2 = ip0 + step; + ip3 = ip2 + 1; + + if (ip3 >= ilimit) { + goto _cleanup; + } + + hash0 = ZSTD_hashPtr(ip0, hlog, mls); + hash1 = ZSTD_hashPtr(ip1, hlog, mls); + + idx = hashTable[hash0]; + idxBase = idx < prefixStartIndex ? dictBase : base; + + do { + { /* load repcode match for ip[2] */ + U32 const current2 = (U32)(ip2 - base); + U32 const repIndex = current2 - offset_1; + const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base; + U32 rval; + if ( ((U32)(prefixStartIndex - repIndex) >= 4) /* intentional underflow */ + & (offset_1 > 0) ) { + rval = MEM_read32(repBase + repIndex); + } else { + rval = MEM_read32(ip2) ^ 1; /* guaranteed to not match. */ } - { const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend; - const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart; - U32 const offset = current - matchIndex; - size_t mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4; - while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ - offset_2 = offset_1; offset_1 = offset; /* update offset history */ - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); - ip += mLength; - anchor = ip; + + /* write back hash table entry */ + current0 = (U32)(ip0 - base); + hashTable[hash0] = current0; + + /* check repcode at ip[2] */ + if (MEM_read32(ip2) == rval) { + ip0 = ip2; + match0 = repBase + repIndex; + matchEnd = repIndex < prefixStartIndex ? dictEnd : iend; + assert((match0 != prefixStart) & (match0 != dictStart)); + mLength = ip0[-1] == match0[-1]; + ip0 -= mLength; + match0 -= mLength; + offcode = REPCODE1_TO_OFFBASE; + mLength += 4; + goto _match; } } - if (ip <= ilimit) { - /* Fill Table */ - hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2; - hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base); - /* check immediate repcode */ - while (ip <= ilimit) { - U32 const current2 = (U32)(ip-base); - U32 const repIndex2 = current2 - offset_2; - const BYTE* const repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2; - if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (repIndex2 > dictStartIndex)) /* intentional overflow */ - && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { - const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; - size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; - { U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; } /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0 /*litlen*/, anchor, iend, 0 /*offcode*/, repLength2-MINMATCH); - hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2; - ip += repLength2; - anchor = ip; - continue; - } - break; - } } } + { /* load match for ip[0] */ + U32 const mval = idx >= dictStartIndex ? + MEM_read32(idxBase + idx) : + MEM_read32(ip0) ^ 1; /* guaranteed not to match */ + + /* check match at ip[0] */ + if (MEM_read32(ip0) == mval) { + /* found a match! */ + goto _offset; + } } + + /* lookup ip[1] */ + idx = hashTable[hash1]; + idxBase = idx < prefixStartIndex ? dictBase : base; + + /* hash ip[2] */ + hash0 = hash1; + hash1 = ZSTD_hashPtr(ip2, hlog, mls); + + /* advance to next positions */ + ip0 = ip1; + ip1 = ip2; + ip2 = ip3; + + /* write back hash table entry */ + current0 = (U32)(ip0 - base); + hashTable[hash0] = current0; + + { /* load match for ip[0] */ + U32 const mval = idx >= dictStartIndex ? + MEM_read32(idxBase + idx) : + MEM_read32(ip0) ^ 1; /* guaranteed not to match */ + + /* check match at ip[0] */ + if (MEM_read32(ip0) == mval) { + /* found a match! */ + goto _offset; + } } + + /* lookup ip[1] */ + idx = hashTable[hash1]; + idxBase = idx < prefixStartIndex ? dictBase : base; + + /* hash ip[2] */ + hash0 = hash1; + hash1 = ZSTD_hashPtr(ip2, hlog, mls); + + /* advance to next positions */ + ip0 = ip1; + ip1 = ip2; + ip2 = ip0 + step; + ip3 = ip1 + step; + + /* calculate step */ + if (ip2 >= nextStep) { + step++; + PREFETCH_L1(ip1 + 64); + PREFETCH_L1(ip1 + 128); + nextStep += kStepIncr; + } + } while (ip3 < ilimit); + +_cleanup: + /* Note that there are probably still a couple positions we could search. + * However, it seems to be a meaningful performance hit to try to search + * them. So let's not. */ + + /* If offset_1 started invalid (offsetSaved1 != 0) and became valid (offset_1 != 0), + * rotate saved offsets. See comment in ZSTD_compressBlock_fast_noDict for more context. */ + offsetSaved2 = ((offsetSaved1 != 0) && (offset_1 != 0)) ? offsetSaved1 : offsetSaved2; /* save reps for next block */ - rep[0] = offset_1; - rep[1] = offset_2; + rep[0] = offset_1 ? offset_1 : offsetSaved1; + rep[1] = offset_2 ? offset_2 : offsetSaved2; /* Return the last literals size */ return (size_t)(iend - anchor); + +_offset: /* Requires: ip0, idx, idxBase */ + + /* Compute the offset code. */ + { U32 const offset = current0 - idx; + const BYTE* const lowMatchPtr = idx < prefixStartIndex ? dictStart : prefixStart; + matchEnd = idx < prefixStartIndex ? dictEnd : iend; + match0 = idxBase + idx; + offset_2 = offset_1; + offset_1 = offset; + offcode = OFFSET_TO_OFFBASE(offset); + mLength = 4; + + /* Count the backwards match length. */ + while (((ip0>anchor) & (match0>lowMatchPtr)) && (ip0[-1] == match0[-1])) { + ip0--; + match0--; + mLength++; + } } + +_match: /* Requires: ip0, match0, offcode, matchEnd */ + + /* Count the forward length. */ + assert(matchEnd != 0); + mLength += ZSTD_count_2segments(ip0 + mLength, match0 + mLength, iend, matchEnd, prefixStart); + + ZSTD_storeSeq(seqStore, (size_t)(ip0 - anchor), anchor, iend, offcode, mLength); + + ip0 += mLength; + anchor = ip0; + + /* write next hash table entry */ + if (ip1 < ip0) { + hashTable[hash1] = (U32)(ip1 - base); + } + + /* Fill table and check for immediate repcode. */ + if (ip0 <= ilimit) { + /* Fill Table */ + assert(base+current0+2 > istart); /* check base overflow */ + hashTable[ZSTD_hashPtr(base+current0+2, hlog, mls)] = current0+2; /* here because current+2 could be > iend-8 */ + hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); + + while (ip0 <= ilimit) { + U32 const repIndex2 = (U32)(ip0-base) - offset_2; + const BYTE* const repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2; + if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (offset_2 > 0)) /* intentional underflow */ + && (MEM_read32(repMatch2) == MEM_read32(ip0)) ) { + const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; + size_t const repLength2 = ZSTD_count_2segments(ip0+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; + { U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; } /* swap offset_2 <=> offset_1 */ + ZSTD_storeSeq(seqStore, 0 /*litlen*/, anchor, iend, REPCODE1_TO_OFFBASE, repLength2); + hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = (U32)(ip0-base); + ip0 += repLength2; + anchor = ip0; + continue; + } + break; + } } + + goto _start; } +ZSTD_GEN_FAST_FN(extDict, 4, 0) +ZSTD_GEN_FAST_FN(extDict, 5, 0) +ZSTD_GEN_FAST_FN(extDict, 6, 0) +ZSTD_GEN_FAST_FN(extDict, 7, 0) size_t ZSTD_compressBlock_fast_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { U32 const mls = ms->cParams.minMatch; + assert(ms->dictMatchState == NULL); switch(mls) { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 4); + return ZSTD_compressBlock_fast_extDict_4_0(ms, seqStore, rep, src, srcSize); case 5 : - return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 5); + return ZSTD_compressBlock_fast_extDict_5_0(ms, seqStore, rep, src, srcSize); case 6 : - return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 6); + return ZSTD_compressBlock_fast_extDict_6_0(ms, seqStore, rep, src, srcSize); case 7 : - return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 7); + return ZSTD_compressBlock_fast_extDict_7_0(ms, seqStore, rep, src, srcSize); } } -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/compress/zstd_lazy.cpp b/src/duckdb/third_party/zstd/compress/zstd_lazy.cpp index af2d3b703..1e9152823 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_lazy.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_lazy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -10,16 +10,25 @@ #include "zstd/compress/zstd_compress_internal.h" #include "zstd/compress/zstd_lazy.h" +#include "zstd/common/bits.h" /* ZSTD_countTrailingZeros64 */ + +namespace duckdb_zstd { + +#if !defined(ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) + +#define kLazySkippingStep 8 /*-************************************* * Binary Tree search ***************************************/ -namespace duckdb_zstd { - -static void -ZSTD_updateDUBT(ZSTD_matchState_t* ms, +static +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +void ZSTD_updateDUBT(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend, U32 mls) { @@ -60,11 +69,12 @@ ZSTD_updateDUBT(ZSTD_matchState_t* ms, /** ZSTD_insertDUBT1() : * sort one already inserted but unsorted position - * assumption : current >= btlow == (current - btmask) + * assumption : curr >= btlow == (curr - btmask) * doesn't fail */ -static void -ZSTD_insertDUBT1(ZSTD_matchState_t* ms, - U32 current, const BYTE* inputEnd, +static +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +void ZSTD_insertDUBT1(const ZSTD_matchState_t* ms, + U32 curr, const BYTE* inputEnd, U32 nbCompares, U32 btLow, const ZSTD_dictMode_e dictMode) { @@ -76,41 +86,41 @@ ZSTD_insertDUBT1(ZSTD_matchState_t* ms, const BYTE* const base = ms->window.base; const BYTE* const dictBase = ms->window.dictBase; const U32 dictLimit = ms->window.dictLimit; - const BYTE* const ip = (current>=dictLimit) ? base + current : dictBase + current; - const BYTE* const iend = (current>=dictLimit) ? inputEnd : dictBase + dictLimit; + const BYTE* const ip = (curr>=dictLimit) ? base + curr : dictBase + curr; + const BYTE* const iend = (curr>=dictLimit) ? inputEnd : dictBase + dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* match; - U32* smallerPtr = bt + 2*(current&btMask); + U32* smallerPtr = bt + 2*(curr&btMask); U32* largerPtr = smallerPtr + 1; U32 matchIndex = *smallerPtr; /* this candidate is unsorted : next sorted candidate is reached through *smallerPtr, while *largerPtr contains previous unsorted candidate (which is already saved and can be overwritten) */ U32 dummy32; /* to be nullified at the end */ U32 const windowValid = ms->window.lowLimit; U32 const maxDistance = 1U << cParams->windowLog; - U32 const windowLow = (current - windowValid > maxDistance) ? current - maxDistance : windowValid; + U32 const windowLow = (curr - windowValid > maxDistance) ? curr - maxDistance : windowValid; DEBUGLOG(8, "ZSTD_insertDUBT1(%u) (dictLimit=%u, lowLimit=%u)", - current, dictLimit, windowLow); - assert(current >= btLow); + curr, dictLimit, windowLow); + assert(curr >= btLow); assert(ip < iend); /* condition for ZSTD_count */ - while (nbCompares-- && (matchIndex > windowLow)) { + for (; nbCompares && (matchIndex > windowLow); --nbCompares) { U32* const nextPtr = bt + 2*(matchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ - assert(matchIndex < current); + assert(matchIndex < curr); /* note : all candidates are now supposed sorted, * but it's still possible to have nextPtr[1] == ZSTD_DUBT_UNSORTED_MARK * when a real index has the same value as ZSTD_DUBT_UNSORTED_MARK */ if ( (dictMode != ZSTD_extDict) || (matchIndex+matchLength >= dictLimit) /* both in current segment*/ - || (current < dictLimit) /* both in extDict */) { + || (curr < dictLimit) /* both in extDict */) { const BYTE* const mBase = ( (dictMode != ZSTD_extDict) || (matchIndex+matchLength >= dictLimit)) ? base : dictBase; assert( (matchIndex+matchLength >= dictLimit) /* might be wrong if extDict is incorrectly set to 0 */ - || (current < dictLimit) ); + || (curr < dictLimit) ); match = mBase + matchIndex; matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend); } else { @@ -121,7 +131,7 @@ ZSTD_insertDUBT1(ZSTD_matchState_t* ms, } DEBUGLOG(8, "ZSTD_insertDUBT1: comparing %u with %u : found %u common bytes ", - current, matchIndex, (U32)matchLength); + curr, matchIndex, (U32)matchLength); if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */ break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */ @@ -151,9 +161,10 @@ ZSTD_insertDUBT1(ZSTD_matchState_t* ms, } -static size_t -ZSTD_DUBT_findBetterDictMatch ( - ZSTD_matchState_t* ms, +static +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +size_t ZSTD_DUBT_findBetterDictMatch ( + const ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iend, size_t* offsetPtr, size_t bestLength, @@ -170,7 +181,7 @@ ZSTD_DUBT_findBetterDictMatch ( const BYTE* const base = ms->window.base; const BYTE* const prefixStart = base + ms->window.dictLimit; - U32 const current = (U32)(ip-base); + U32 const curr = (U32)(ip-base); const BYTE* const dictBase = dms->window.base; const BYTE* const dictEnd = dms->window.nextSrc; U32 const dictHighLimit = (U32)(dms->window.nextSrc - dms->window.base); @@ -187,7 +198,7 @@ ZSTD_DUBT_findBetterDictMatch ( (void)dictMode; assert(dictMode == ZSTD_dictMatchState); - while (nbCompares-- && (dictMatchIndex > dictLowLimit)) { + for (; nbCompares && (dictMatchIndex > dictLowLimit); --nbCompares) { U32* const nextPtr = dictBt + 2*(dictMatchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ const BYTE* match = dictBase + dictMatchIndex; @@ -197,10 +208,10 @@ ZSTD_DUBT_findBetterDictMatch ( if (matchLength > bestLength) { U32 matchIndex = dictMatchIndex + dictIndexDelta; - if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) { + if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(curr-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) { DEBUGLOG(9, "ZSTD_DUBT_findBetterDictMatch(%u) : found better match length %u -> %u and offsetCode %u -> %u (dictMatchIndex %u, matchIndex %u)", - current, (U32)bestLength, (U32)matchLength, (U32)*offsetPtr, ZSTD_REP_MOVE + current - matchIndex, dictMatchIndex, matchIndex); - bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex; + curr, (U32)bestLength, (U32)matchLength, (U32)*offsetPtr, OFFSET_TO_OFFBASE(curr - matchIndex), dictMatchIndex, matchIndex); + bestLength = matchLength, *offsetPtr = OFFSET_TO_OFFBASE(curr - matchIndex); } if (ip+matchLength == iend) { /* reached end of input : ip[matchLength] is not valid, no way to know if it's larger or smaller than match */ break; /* drop, to guarantee consistency (miss a little bit of compression) */ @@ -220,19 +231,20 @@ ZSTD_DUBT_findBetterDictMatch ( } if (bestLength >= MINMATCH) { - U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex; + U32 const mIndex = curr - (U32)OFFBASE_TO_OFFSET(*offsetPtr); (void)mIndex; DEBUGLOG(8, "ZSTD_DUBT_findBetterDictMatch(%u) : found match of length %u and offsetCode %u (pos %u)", - current, (U32)bestLength, (U32)*offsetPtr, mIndex); + curr, (U32)bestLength, (U32)*offsetPtr, mIndex); } return bestLength; } -static size_t -ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, +static +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +size_t ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iend, - size_t* offsetPtr, + size_t* offBasePtr, U32 const mls, const ZSTD_dictMode_e dictMode) { @@ -243,13 +255,13 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, U32 matchIndex = hashTable[h]; const BYTE* const base = ms->window.base; - U32 const current = (U32)(ip-base); - U32 const windowLow = ZSTD_getLowestMatchIndex(ms, current, cParams->windowLog); + U32 const curr = (U32)(ip-base); + U32 const windowLow = ZSTD_getLowestMatchIndex(ms, curr, cParams->windowLog); U32* const bt = ms->chainTable; U32 const btLog = cParams->chainLog - 1; U32 const btMask = (1 << btLog) - 1; - U32 const btLow = (btMask >= current) ? 0 : current - btMask; + U32 const btLow = (btMask >= curr) ? 0 : curr - btMask; U32 const unsortLimit = MAX(btLow, windowLow); U32* nextCandidate = bt + 2*(matchIndex&btMask); @@ -258,8 +270,9 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, U32 nbCandidates = nbCompares; U32 previousCandidate = 0; - DEBUGLOG(7, "ZSTD_DUBT_findBestMatch (%u) ", current); + DEBUGLOG(7, "ZSTD_DUBT_findBestMatch (%u) ", curr); assert(ip <= iend-8); /* required for h calculation */ + assert(dictMode != ZSTD_dedicatedDictSearch); /* reach end of unsorted candidates list */ while ( (matchIndex > unsortLimit) @@ -301,16 +314,16 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, const U32 dictLimit = ms->window.dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; - U32* smallerPtr = bt + 2*(current&btMask); - U32* largerPtr = bt + 2*(current&btMask) + 1; - U32 matchEndIdx = current + 8 + 1; + U32* smallerPtr = bt + 2*(curr&btMask); + U32* largerPtr = bt + 2*(curr&btMask) + 1; + U32 matchEndIdx = curr + 8 + 1; U32 dummy32; /* to be nullified at the end */ size_t bestLength = 0; matchIndex = hashTable[h]; - hashTable[h] = current; /* Update Hash Table */ + hashTable[h] = curr; /* Update Hash Table */ - while (nbCompares-- && (matchIndex > windowLow)) { + for (; nbCompares && (matchIndex > windowLow); --nbCompares) { U32* const nextPtr = bt + 2*(matchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ const BYTE* match; @@ -328,8 +341,8 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, if (matchLength > bestLength) { if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; - if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) - bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex; + if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(curr - matchIndex + 1) - ZSTD_highbit32((U32)*offBasePtr)) ) + bestLength = matchLength, *offBasePtr = OFFSET_TO_OFFBASE(curr - matchIndex); if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */ if (dictMode == ZSTD_dictMatchState) { nbCompares = 0; /* in addition to avoiding checking any @@ -358,19 +371,20 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, *smallerPtr = *largerPtr = 0; + assert(nbCompares <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */ if (dictMode == ZSTD_dictMatchState && nbCompares) { bestLength = ZSTD_DUBT_findBetterDictMatch( ms, ip, iend, - offsetPtr, bestLength, nbCompares, + offBasePtr, bestLength, nbCompares, mls, dictMode); } - assert(matchEndIdx > current+8); /* ensure nextToUpdate is increased */ + assert(matchEndIdx > curr+8); /* ensure nextToUpdate is increased */ ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */ if (bestLength >= MINMATCH) { - U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex; + U32 const mIndex = curr - (U32)OFFBASE_TO_OFFSET(*offBasePtr); (void)mIndex; DEBUGLOG(8, "ZSTD_DUBT_findBestMatch(%u) : found match of length %u and offsetCode %u (pos %u)", - current, (U32)bestLength, (U32)*offsetPtr, mIndex); + curr, (U32)bestLength, (U32)*offBasePtr, mIndex); } return bestLength; } @@ -378,69 +392,236 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, /** ZSTD_BtFindBestMatch() : Tree updater, providing best match */ -FORCE_INLINE_TEMPLATE size_t -ZSTD_BtFindBestMatch( ZSTD_matchState_t* ms, +FORCE_INLINE_TEMPLATE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +size_t ZSTD_BtFindBestMatch( ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iLimit, - size_t* offsetPtr, + size_t* offBasePtr, const U32 mls /* template */, const ZSTD_dictMode_e dictMode) { DEBUGLOG(7, "ZSTD_BtFindBestMatch"); if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */ ZSTD_updateDUBT(ms, ip, iLimit, mls); - return ZSTD_DUBT_findBestMatch(ms, ip, iLimit, offsetPtr, mls, dictMode); + return ZSTD_DUBT_findBestMatch(ms, ip, iLimit, offBasePtr, mls, dictMode); } +/*********************************** +* Dedicated dict search +***********************************/ -static size_t -ZSTD_BtFindBestMatch_selectMLS ( ZSTD_matchState_t* ms, - const BYTE* ip, const BYTE* const iLimit, - size_t* offsetPtr) +void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const BYTE* const ip) { - switch(ms->cParams.minMatch) + const BYTE* const base = ms->window.base; + U32 const target = (U32)(ip - base); + U32* const hashTable = ms->hashTable; + U32* const chainTable = ms->chainTable; + U32 const chainSize = 1 << ms->cParams.chainLog; + U32 idx = ms->nextToUpdate; + U32 const minChain = chainSize < target - idx ? target - chainSize : idx; + U32 const bucketSize = 1 << ZSTD_LAZY_DDSS_BUCKET_LOG; + U32 const cacheSize = bucketSize - 1; + U32 const chainAttempts = (1 << ms->cParams.searchLog) - cacheSize; + U32 const chainLimit = chainAttempts > 255 ? 255 : chainAttempts; + + /* We know the hashtable is oversized by a factor of `bucketSize`. + * We are going to temporarily pretend `bucketSize == 1`, keeping only a + * single entry. We will use the rest of the space to construct a temporary + * chaintable. + */ + U32 const hashLog = ms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG; + U32* const tmpHashTable = hashTable; + U32* const tmpChainTable = hashTable + ((size_t)1 << hashLog); + U32 const tmpChainSize = (U32)((1 << ZSTD_LAZY_DDSS_BUCKET_LOG) - 1) << hashLog; + U32 const tmpMinChain = tmpChainSize < target ? target - tmpChainSize : idx; + U32 hashIdx; + + assert(ms->cParams.chainLog <= 24); + assert(ms->cParams.hashLog > ms->cParams.chainLog); + assert(idx != 0); + assert(tmpMinChain <= minChain); + + /* fill conventional hash table and conventional chain table */ + for ( ; idx < target; idx++) { + U32 const h = (U32)ZSTD_hashPtr(base + idx, hashLog, ms->cParams.minMatch); + if (idx >= tmpMinChain) { + tmpChainTable[idx - tmpMinChain] = hashTable[h]; + } + tmpHashTable[h] = idx; + } + + /* sort chains into ddss chain table */ { - default : /* includes case 3 */ - case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict); - case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict); - case 7 : - case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict); + U32 chainPos = 0; + for (hashIdx = 0; hashIdx < (1U << hashLog); hashIdx++) { + U32 count; + U32 countBeyondMinChain = 0; + U32 i = tmpHashTable[hashIdx]; + for (count = 0; i >= tmpMinChain && count < cacheSize; count++) { + /* skip through the chain to the first position that won't be + * in the hash cache bucket */ + if (i < minChain) { + countBeyondMinChain++; + } + i = tmpChainTable[i - tmpMinChain]; + } + if (count == cacheSize) { + for (count = 0; count < chainLimit;) { + if (i < minChain) { + if (!i || ++countBeyondMinChain > cacheSize) { + /* only allow pulling `cacheSize` number of entries + * into the cache or chainTable beyond `minChain`, + * to replace the entries pulled out of the + * chainTable into the cache. This lets us reach + * back further without increasing the total number + * of entries in the chainTable, guaranteeing the + * DDSS chain table will fit into the space + * allocated for the regular one. */ + break; + } + } + chainTable[chainPos++] = i; + count++; + if (i < tmpMinChain) { + break; + } + i = tmpChainTable[i - tmpMinChain]; + } + } else { + count = 0; + } + if (count) { + tmpHashTable[hashIdx] = ((chainPos - count) << 8) + count; + } else { + tmpHashTable[hashIdx] = 0; + } + } + assert(chainPos <= chainSize); /* I believe this is guaranteed... */ + } + + /* move chain pointers into the last entry of each hash bucket */ + for (hashIdx = (1 << hashLog); hashIdx; ) { + U32 const bucketIdx = --hashIdx << ZSTD_LAZY_DDSS_BUCKET_LOG; + U32 const chainPackedPointer = tmpHashTable[hashIdx]; + U32 i; + for (i = 0; i < cacheSize; i++) { + hashTable[bucketIdx + i] = 0; + } + hashTable[bucketIdx + bucketSize - 1] = chainPackedPointer; + } + + /* fill the buckets of the hash table */ + for (idx = ms->nextToUpdate; idx < target; idx++) { + U32 const h = (U32)ZSTD_hashPtr(base + idx, hashLog, ms->cParams.minMatch) + << ZSTD_LAZY_DDSS_BUCKET_LOG; + U32 i; + /* Shift hash cache down 1. */ + for (i = cacheSize - 1; i; i--) + hashTable[h + i] = hashTable[h + i - 1]; + hashTable[h] = idx; } + + ms->nextToUpdate = target; } +/* Returns the longest match length found in the dedicated dict search structure. + * If none are longer than the argument ml, then ml will be returned. + */ +FORCE_INLINE_TEMPLATE +size_t ZSTD_dedicatedDictSearch_lazy_search(size_t* offsetPtr, size_t ml, U32 nbAttempts, + const ZSTD_matchState_t* const dms, + const BYTE* const ip, const BYTE* const iLimit, + const BYTE* const prefixStart, const U32 curr, + const U32 dictLimit, const size_t ddsIdx) { + const U32 ddsLowestIndex = dms->window.dictLimit; + const BYTE* const ddsBase = dms->window.base; + const BYTE* const ddsEnd = dms->window.nextSrc; + const U32 ddsSize = (U32)(ddsEnd - ddsBase); + const U32 ddsIndexDelta = dictLimit - ddsSize; + const U32 bucketSize = (1 << ZSTD_LAZY_DDSS_BUCKET_LOG); + const U32 bucketLimit = nbAttempts < bucketSize - 1 ? nbAttempts : bucketSize - 1; + U32 ddsAttempt; + U32 matchIndex; + + for (ddsAttempt = 0; ddsAttempt < bucketSize - 1; ddsAttempt++) { + PREFETCH_L1(ddsBase + dms->hashTable[ddsIdx + ddsAttempt]); + } -static size_t ZSTD_BtFindBestMatch_dictMatchState_selectMLS ( - ZSTD_matchState_t* ms, - const BYTE* ip, const BYTE* const iLimit, - size_t* offsetPtr) -{ - switch(ms->cParams.minMatch) { - default : /* includes case 3 */ - case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState); - case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState); - case 7 : - case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState); + U32 const chainPackedPointer = dms->hashTable[ddsIdx + bucketSize - 1]; + U32 const chainIndex = chainPackedPointer >> 8; + + PREFETCH_L1(&dms->chainTable[chainIndex]); } -} + for (ddsAttempt = 0; ddsAttempt < bucketLimit; ddsAttempt++) { + size_t currentMl=0; + const BYTE* match; + matchIndex = dms->hashTable[ddsIdx + ddsAttempt]; + match = ddsBase + matchIndex; + + if (!matchIndex) { + return ml; + } + + /* guaranteed by table construction */ + (void)ddsLowestIndex; + assert(matchIndex >= ddsLowestIndex); + assert(match+4 <= ddsEnd); + if (MEM_read32(match) == MEM_read32(ip)) { + /* assumption : matchIndex <= dictLimit-4 (by table construction) */ + currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, ddsEnd, prefixStart) + 4; + } + + /* save best solution */ + if (currentMl > ml) { + ml = currentMl; + *offsetPtr = OFFSET_TO_OFFBASE(curr - (matchIndex + ddsIndexDelta)); + if (ip+currentMl == iLimit) { + /* best possible, avoids read overflow on next attempt */ + return ml; + } + } + } -static size_t ZSTD_BtFindBestMatch_extDict_selectMLS ( - ZSTD_matchState_t* ms, - const BYTE* ip, const BYTE* const iLimit, - size_t* offsetPtr) -{ - switch(ms->cParams.minMatch) { - default : /* includes case 3 */ - case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict); - case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict); - case 7 : - case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict); + U32 const chainPackedPointer = dms->hashTable[ddsIdx + bucketSize - 1]; + U32 chainIndex = chainPackedPointer >> 8; + U32 const chainLength = chainPackedPointer & 0xFF; + U32 const chainAttempts = nbAttempts - ddsAttempt; + U32 const chainLimit = chainAttempts > chainLength ? chainLength : chainAttempts; + U32 chainAttempt; + + for (chainAttempt = 0 ; chainAttempt < chainLimit; chainAttempt++) { + PREFETCH_L1(ddsBase + dms->chainTable[chainIndex + chainAttempt]); + } + + for (chainAttempt = 0 ; chainAttempt < chainLimit; chainAttempt++, chainIndex++) { + size_t currentMl=0; + const BYTE* match; + matchIndex = dms->chainTable[chainIndex]; + match = ddsBase + matchIndex; + + /* guaranteed by table construction */ + assert(matchIndex >= ddsLowestIndex); + assert(match+4 <= ddsEnd); + if (MEM_read32(match) == MEM_read32(ip)) { + /* assumption : matchIndex <= dictLimit-4 (by table construction) */ + currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, ddsEnd, prefixStart) + 4; + } + + /* save best solution */ + if (currentMl > ml) { + ml = currentMl; + *offsetPtr = OFFSET_TO_OFFBASE(curr - (matchIndex + ddsIndexDelta)); + if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ + } + } } + return ml; } - /* ********************************* * Hash Chain ***********************************/ @@ -448,10 +629,12 @@ static size_t ZSTD_BtFindBestMatch_extDict_selectMLS ( /* Update chains up to ip (excluded) Assumption : always within prefix (i.e. not within extDict) */ -static U32 ZSTD_insertAndFindFirstIndex_internal( +FORCE_INLINE_TEMPLATE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +U32 ZSTD_insertAndFindFirstIndex_internal( ZSTD_matchState_t* ms, const ZSTD_compressionParameters* const cParams, - const BYTE* ip, U32 const mls) + const BYTE* ip, U32 const mls, U32 const lazySkipping) { U32* const hashTable = ms->hashTable; const U32 hashLog = cParams->hashLog; @@ -466,6 +649,9 @@ static U32 ZSTD_insertAndFindFirstIndex_internal( NEXT_IN_CHAIN(idx, chainMask) = hashTable[h]; hashTable[h] = idx; idx++; + /* Stop inserting every position when in the lazy skipping mode. */ + if (lazySkipping) + break; } ms->nextToUpdate = target; @@ -474,13 +660,13 @@ static U32 ZSTD_insertAndFindFirstIndex_internal( U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip) { const ZSTD_compressionParameters* const cParams = &ms->cParams; - return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch); + return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch, /* lazySkipping*/ 0); } - /* inlining is important to hardwire a hot branch (template emulation) */ FORCE_INLINE_TEMPLATE -size_t ZSTD_HcFindBestMatch_generic ( +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +size_t ZSTD_HcFindBestMatch( ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iLimit, size_t* offsetPtr, @@ -495,25 +681,39 @@ size_t ZSTD_HcFindBestMatch_generic ( const U32 dictLimit = ms->window.dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; - const U32 current = (U32)(ip-base); + const U32 curr = (U32)(ip-base); const U32 maxDistance = 1U << cParams->windowLog; const U32 lowestValid = ms->window.lowLimit; - const U32 withinMaxDistance = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid; + const U32 withinMaxDistance = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; const U32 isDictionary = (ms->loadedDictEnd != 0); const U32 lowLimit = isDictionary ? lowestValid : withinMaxDistance; - const U32 minChain = current > chainSize ? current - chainSize : 0; + const U32 minChain = curr > chainSize ? curr - chainSize : 0; U32 nbAttempts = 1U << cParams->searchLog; size_t ml=4-1; + const ZSTD_matchState_t* const dms = ms->dictMatchState; + const U32 ddsHashLog = dictMode == ZSTD_dedicatedDictSearch + ? dms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG : 0; + const size_t ddsIdx = dictMode == ZSTD_dedicatedDictSearch + ? ZSTD_hashPtr(ip, ddsHashLog, mls) << ZSTD_LAZY_DDSS_BUCKET_LOG : 0; + + U32 matchIndex; + + if (dictMode == ZSTD_dedicatedDictSearch) { + const U32* entry = &dms->hashTable[ddsIdx]; + PREFETCH_L1(entry); + } + /* HC4 match finder */ - U32 matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls); + matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls, ms->lazySkipping); - for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) { + for ( ; (matchIndex>=lowLimit) & (nbAttempts>0) ; nbAttempts--) { size_t currentMl=0; if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) { const BYTE* const match = base + matchIndex; assert(matchIndex >= dictLimit); /* ensures this is true if dictMode != ZSTD_extDict */ - if (match[ml] == ip[ml]) /* potentially better */ + /* read 4B starting from (match + ml + 1 - sizeof(U32)) */ + if (MEM_read32(match + ml - 3) == MEM_read32(ip + ml - 3)) /* potentially better */ currentMl = ZSTD_count(ip, match, iLimit); } else { const BYTE* const match = dictBase + matchIndex; @@ -525,7 +725,7 @@ size_t ZSTD_HcFindBestMatch_generic ( /* save best solution */ if (currentMl > ml) { ml = currentMl; - *offsetPtr = current - matchIndex + ZSTD_REP_MOVE; + *offsetPtr = OFFSET_TO_OFFBASE(curr - matchIndex); if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ } @@ -533,8 +733,11 @@ size_t ZSTD_HcFindBestMatch_generic ( matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask); } - if (dictMode == ZSTD_dictMatchState) { - const ZSTD_matchState_t* const dms = ms->dictMatchState; + assert(nbAttempts <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */ + if (dictMode == ZSTD_dedicatedDictSearch) { + ml = ZSTD_dedicatedDictSearch_lazy_search(offsetPtr, ml, nbAttempts, dms, + ip, iLimit, prefixStart, curr, dictLimit, ddsIdx); + } else if (dictMode == ZSTD_dictMatchState) { const U32* const dmsChainTable = dms->chainTable; const U32 dmsChainSize = (1 << dms->cParams.chainLog); const U32 dmsChainMask = dmsChainSize - 1; @@ -547,7 +750,7 @@ size_t ZSTD_HcFindBestMatch_generic ( matchIndex = dms->hashTable[ZSTD_hashPtr(ip, dms->cParams.hashLog, mls)]; - for ( ; (matchIndex>dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) { + for ( ; (matchIndex>=dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) { size_t currentMl=0; const BYTE* const match = dmsBase + matchIndex; assert(match+4 <= dmsEnd); @@ -557,11 +760,13 @@ size_t ZSTD_HcFindBestMatch_generic ( /* save best solution */ if (currentMl > ml) { ml = currentMl; - *offsetPtr = current - (matchIndex + dmsIndexDelta) + ZSTD_REP_MOVE; + assert(curr > matchIndex + dmsIndexDelta); + *offsetPtr = OFFSET_TO_OFFBASE(curr - (matchIndex + dmsIndexDelta)); if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ } if (matchIndex <= dmsMinChain) break; + matchIndex = dmsChainTable[matchIndex & dmsChainMask]; } } @@ -569,62 +774,748 @@ size_t ZSTD_HcFindBestMatch_generic ( return ml; } +/* ********************************* +* (SIMD) Row-based matchfinder +***********************************/ +/* Constants for row-based hash */ +#define ZSTD_ROW_HASH_TAG_MASK ((1u << ZSTD_ROW_HASH_TAG_BITS) - 1) +#define ZSTD_ROW_HASH_MAX_ENTRIES 64 /* absolute maximum number of entries per row, for all configurations */ -FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS ( - ZSTD_matchState_t* ms, - const BYTE* ip, const BYTE* const iLimit, - size_t* offsetPtr) +#define ZSTD_ROW_HASH_CACHE_MASK (ZSTD_ROW_HASH_CACHE_SIZE - 1) + +typedef U64 ZSTD_VecMask; /* Clarifies when we are interacting with a U64 representing a mask of matches */ + +/* ZSTD_VecMask_next(): + * Starting from the LSB, returns the idx of the next non-zero bit. + * Basically counting the nb of trailing zeroes. + */ +MEM_STATIC U32 ZSTD_VecMask_next(ZSTD_VecMask val) { + return ZSTD_countTrailingZeros64(val); +} + +/* ZSTD_row_nextIndex(): + * Returns the next index to insert at within a tagTable row, and updates the "head" + * value to reflect the update. Essentially cycles backwards from [1, {entries per row}) + */ +FORCE_INLINE_TEMPLATE U32 ZSTD_row_nextIndex(BYTE* const tagRow, U32 const rowMask) { + U32 next = (*tagRow-1) & rowMask; + next += (next == 0) ? rowMask : 0; /* skip first position */ + *tagRow = (BYTE)next; + return next; +} + +/* ZSTD_isAligned(): + * Checks that a pointer is aligned to "align" bytes which must be a power of 2. + */ +MEM_STATIC int ZSTD_isAligned(void const* ptr, size_t align) { + assert((align & (align - 1)) == 0); + return (((size_t)ptr) & (align - 1)) == 0; +} + +/* ZSTD_row_prefetch(): + * Performs prefetching for the hashTable and tagTable at a given row. + */ +FORCE_INLINE_TEMPLATE void ZSTD_row_prefetch(U32 const* hashTable, BYTE const* tagTable, U32 const relRow, U32 const rowLog) { + PREFETCH_L1(hashTable + relRow); + if (rowLog >= 5) { + PREFETCH_L1(hashTable + relRow + 16); + /* Note: prefetching more of the hash table does not appear to be beneficial for 128-entry rows */ + } + PREFETCH_L1(tagTable + relRow); + if (rowLog == 6) { + PREFETCH_L1(tagTable + relRow + 32); + } + assert(rowLog == 4 || rowLog == 5 || rowLog == 6); + assert(ZSTD_isAligned(hashTable + relRow, 64)); /* prefetched hash row always 64-byte aligned */ + assert(ZSTD_isAligned(tagTable + relRow, (size_t)1 << rowLog)); /* prefetched tagRow sits on correct multiple of bytes (32,64,128) */ +} + +/* ZSTD_row_fillHashCache(): + * Fill up the hash cache starting at idx, prefetching up to ZSTD_ROW_HASH_CACHE_SIZE entries, + * but not beyond iLimit. + */ +FORCE_INLINE_TEMPLATE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +void ZSTD_row_fillHashCache(ZSTD_matchState_t* ms, const BYTE* base, + U32 const rowLog, U32 const mls, + U32 idx, const BYTE* const iLimit) { - switch(ms->cParams.minMatch) - { - default : /* includes case 3 */ - case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict); - case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict); - case 7 : - case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict); + U32 const* const hashTable = ms->hashTable; + BYTE const* const tagTable = ms->tagTable; + U32 const hashLog = ms->rowHashLog; + U32 const maxElemsToPrefetch = (base + idx) > iLimit ? 0 : (U32)(iLimit - (base + idx) + 1); + U32 const lim = idx + MIN(ZSTD_ROW_HASH_CACHE_SIZE, maxElemsToPrefetch); + + for (; idx < lim; ++idx) { + U32 const hash = (U32)ZSTD_hashPtrSalted(base + idx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, ms->hashSalt); + U32 const row = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; + ZSTD_row_prefetch(hashTable, tagTable, row, rowLog); + ms->hashCache[idx & ZSTD_ROW_HASH_CACHE_MASK] = hash; } + + DEBUGLOG(6, "ZSTD_row_fillHashCache(): [%u %u %u %u %u %u %u %u]", ms->hashCache[0], ms->hashCache[1], + ms->hashCache[2], ms->hashCache[3], ms->hashCache[4], + ms->hashCache[5], ms->hashCache[6], ms->hashCache[7]); } +/* ZSTD_row_nextCachedHash(): + * Returns the hash of base + idx, and replaces the hash in the hash cache with the byte at + * base + idx + ZSTD_ROW_HASH_CACHE_SIZE. Also prefetches the appropriate rows from hashTable and tagTable. + */ +FORCE_INLINE_TEMPLATE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +U32 ZSTD_row_nextCachedHash(U32* cache, U32 const* hashTable, + BYTE const* tagTable, BYTE const* base, + U32 idx, U32 const hashLog, + U32 const rowLog, U32 const mls, + U64 const hashSalt) +{ + U32 const newHash = (U32)ZSTD_hashPtrSalted(base+idx+ZSTD_ROW_HASH_CACHE_SIZE, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, hashSalt); + U32 const row = (newHash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; + ZSTD_row_prefetch(hashTable, tagTable, row, rowLog); + { U32 const hash = cache[idx & ZSTD_ROW_HASH_CACHE_MASK]; + cache[idx & ZSTD_ROW_HASH_CACHE_MASK] = newHash; + return hash; + } +} -static size_t ZSTD_HcFindBestMatch_dictMatchState_selectMLS ( - ZSTD_matchState_t* ms, - const BYTE* ip, const BYTE* const iLimit, - size_t* offsetPtr) +/* ZSTD_row_update_internalImpl(): + * Updates the hash table with positions starting from updateStartIdx until updateEndIdx. + */ +FORCE_INLINE_TEMPLATE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +void ZSTD_row_update_internalImpl(ZSTD_matchState_t* ms, + U32 updateStartIdx, U32 const updateEndIdx, + U32 const mls, U32 const rowLog, + U32 const rowMask, U32 const useCache) { - switch(ms->cParams.minMatch) - { - default : /* includes case 3 */ - case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState); - case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState); - case 7 : - case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState); + U32* const hashTable = ms->hashTable; + BYTE* const tagTable = ms->tagTable; + U32 const hashLog = ms->rowHashLog; + const BYTE* const base = ms->window.base; + + DEBUGLOG(6, "ZSTD_row_update_internalImpl(): updateStartIdx=%u, updateEndIdx=%u", updateStartIdx, updateEndIdx); + for (; updateStartIdx < updateEndIdx; ++updateStartIdx) { + U32 const hash = useCache ? ZSTD_row_nextCachedHash(ms->hashCache, hashTable, tagTable, base, updateStartIdx, hashLog, rowLog, mls, ms->hashSalt) + : (U32)ZSTD_hashPtrSalted(base + updateStartIdx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, ms->hashSalt); + U32 const relRow = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; + U32* const row = hashTable + relRow; + BYTE* tagRow = tagTable + relRow; + U32 const pos = ZSTD_row_nextIndex(tagRow, rowMask); + + assert(hash == ZSTD_hashPtrSalted(base + updateStartIdx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, ms->hashSalt)); + tagRow[pos] = hash & ZSTD_ROW_HASH_TAG_MASK; + row[pos] = updateStartIdx; } } +/* ZSTD_row_update_internal(): + * Inserts the byte at ip into the appropriate position in the hash table, and updates ms->nextToUpdate. + * Skips sections of long matches as is necessary. + */ +FORCE_INLINE_TEMPLATE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +void ZSTD_row_update_internal(ZSTD_matchState_t* ms, const BYTE* ip, + U32 const mls, U32 const rowLog, + U32 const rowMask, U32 const useCache) +{ + U32 idx = ms->nextToUpdate; + const BYTE* const base = ms->window.base; + const U32 target = (U32)(ip - base); + const U32 kSkipThreshold = 384; + const U32 kMaxMatchStartPositionsToUpdate = 96; + const U32 kMaxMatchEndPositionsToUpdate = 32; + + if (useCache) { + /* Only skip positions when using hash cache, i.e. + * if we are loading a dict, don't skip anything. + * If we decide to skip, then we only update a set number + * of positions at the beginning and end of the match. + */ + if (UNLIKELY(target - idx > kSkipThreshold)) { + U32 const bound = idx + kMaxMatchStartPositionsToUpdate; + ZSTD_row_update_internalImpl(ms, idx, bound, mls, rowLog, rowMask, useCache); + idx = target - kMaxMatchEndPositionsToUpdate; + ZSTD_row_fillHashCache(ms, base, rowLog, mls, idx, ip+1); + } + } + assert(target >= idx); + ZSTD_row_update_internalImpl(ms, idx, target, mls, rowLog, rowMask, useCache); + ms->nextToUpdate = target; +} + +/* ZSTD_row_update(): + * External wrapper for ZSTD_row_update_internal(). Used for filling the hashtable during dictionary + * processing. + */ +void ZSTD_row_update(ZSTD_matchState_t* const ms, const BYTE* ip) { + const U32 rowLog = BOUNDED(4, ms->cParams.searchLog, 6); + const U32 rowMask = (1u << rowLog) - 1; + const U32 mls = MIN(ms->cParams.minMatch, 6 /* mls caps out at 6 */); + + DEBUGLOG(5, "ZSTD_row_update(), rowLog=%u", rowLog); + ZSTD_row_update_internal(ms, ip, mls, rowLog, rowMask, 0 /* don't use cache */); +} + +/* Returns the mask width of bits group of which will be set to 1. Given not all + * architectures have easy movemask instruction, this helps to iterate over + * groups of bits easier and faster. + */ +FORCE_INLINE_TEMPLATE U32 +ZSTD_row_matchMaskGroupWidth(const U32 rowEntries) +{ + assert((rowEntries == 16) || (rowEntries == 32) || rowEntries == 64); + assert(rowEntries <= ZSTD_ROW_HASH_MAX_ENTRIES); + (void)rowEntries; +#if defined(ZSTD_ARCH_ARM_NEON) + /* NEON path only works for little endian */ + if (!MEM_isLittleEndian()) { + return 1; + } + if (rowEntries == 16) { + return 4; + } + if (rowEntries == 32) { + return 2; + } + if (rowEntries == 64) { + return 1; + } +#endif + return 1; +} -FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS ( +#if defined(ZSTD_ARCH_X86_SSE2) +FORCE_INLINE_TEMPLATE ZSTD_VecMask +ZSTD_row_getSSEMask(int nbChunks, const BYTE* const src, const BYTE tag, const U32 head) +{ + const __m128i comparisonMask = _mm_set1_epi8((char)tag); + int matches[4] = {0}; + int i; + assert(nbChunks == 1 || nbChunks == 2 || nbChunks == 4); + for (i=0; i> chunkSize; + do { + size_t chunk = MEM_readST(&src[i]); + chunk ^= splatChar; + chunk = (((chunk | x80) - x01) | chunk) & x80; + matches <<= chunkSize; + matches |= (chunk * extractMagic) >> shiftAmount; + i -= chunkSize; + } while (i >= 0); + } else { /* big endian: reverse bits during extraction */ + const size_t msb = xFF ^ (xFF >> 1); + const size_t extractMagic = (msb / 0x1FF) | msb; + do { + size_t chunk = MEM_readST(&src[i]); + chunk ^= splatChar; + chunk = (((chunk | x80) - x01) | chunk) & x80; + matches <<= chunkSize; + matches |= ((chunk >> 7) * extractMagic) >> shiftAmount; + i -= chunkSize; + } while (i >= 0); + } + matches = ~matches; + if (rowEntries == 16) { + return ZSTD_rotateRight_U16((U16)matches, headGrouped); + } else if (rowEntries == 32) { + return ZSTD_rotateRight_U32((U32)matches, headGrouped); + } else { + return ZSTD_rotateRight_U64((U64)matches, headGrouped); + } + } +#endif +} + +/* The high-level approach of the SIMD row based match finder is as follows: + * - Figure out where to insert the new entry: + * - Generate a hash for current input posistion and split it into a one byte of tag and `rowHashLog` bits of index. + * - The hash is salted by a value that changes on every contex reset, so when the same table is used + * we will avoid collisions that would otherwise slow us down by intorducing phantom matches. + * - The hashTable is effectively split into groups or "rows" of 15 or 31 entries of U32, and the index determines + * which row to insert into. + * - Determine the correct position within the row to insert the entry into. Each row of 15 or 31 can + * be considered as a circular buffer with a "head" index that resides in the tagTable (overall 16 or 32 bytes + * per row). + * - Use SIMD to efficiently compare the tags in the tagTable to the 1-byte tag calculated for the position and + * generate a bitfield that we can cycle through to check the collisions in the hash table. + * - Pick the longest match. + * - Insert the tag into the equivalent row and position in the tagTable. + */ +FORCE_INLINE_TEMPLATE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +size_t ZSTD_RowFindBestMatch( ZSTD_matchState_t* ms, - const BYTE* ip, const BYTE* const iLimit, - size_t* offsetPtr) + const BYTE* const ip, const BYTE* const iLimit, + size_t* offsetPtr, + const U32 mls, const ZSTD_dictMode_e dictMode, + const U32 rowLog) { - switch(ms->cParams.minMatch) - { - default : /* includes case 3 */ - case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict); - case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict); - case 7 : - case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict); + U32* const hashTable = ms->hashTable; + BYTE* const tagTable = ms->tagTable; + U32* const hashCache = ms->hashCache; + const U32 hashLog = ms->rowHashLog; + const ZSTD_compressionParameters* const cParams = &ms->cParams; + const BYTE* const base = ms->window.base; + const BYTE* const dictBase = ms->window.dictBase; + const U32 dictLimit = ms->window.dictLimit; + const BYTE* const prefixStart = base + dictLimit; + const BYTE* const dictEnd = dictBase + dictLimit; + const U32 curr = (U32)(ip-base); + const U32 maxDistance = 1U << cParams->windowLog; + const U32 lowestValid = ms->window.lowLimit; + const U32 withinMaxDistance = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; + const U32 isDictionary = (ms->loadedDictEnd != 0); + const U32 lowLimit = isDictionary ? lowestValid : withinMaxDistance; + const U32 rowEntries = (1U << rowLog); + const U32 rowMask = rowEntries - 1; + const U32 cappedSearchLog = MIN(cParams->searchLog, rowLog); /* nb of searches is capped at nb entries per row */ + const U32 groupWidth = ZSTD_row_matchMaskGroupWidth(rowEntries); + const U64 hashSalt = ms->hashSalt; + U32 nbAttempts = 1U << cappedSearchLog; + size_t ml=4-1; + U32 hash; + + /* DMS/DDS variables that may be referenced laster */ + const ZSTD_matchState_t* const dms = ms->dictMatchState; + + /* Initialize the following variables to satisfy static analyzer */ + size_t ddsIdx = 0; + U32 ddsExtraAttempts = 0; /* cctx hash tables are limited in searches, but allow extra searches into DDS */ + U32 dmsTag = 0; + U32* dmsRow = NULL; + BYTE* dmsTagRow = NULL; + + if (dictMode == ZSTD_dedicatedDictSearch) { + const U32 ddsHashLog = dms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG; + { /* Prefetch DDS hashtable entry */ + ddsIdx = ZSTD_hashPtr(ip, ddsHashLog, mls) << ZSTD_LAZY_DDSS_BUCKET_LOG; + PREFETCH_L1(&dms->hashTable[ddsIdx]); + } + ddsExtraAttempts = cParams->searchLog > rowLog ? 1U << (cParams->searchLog - rowLog) : 0; } + + if (dictMode == ZSTD_dictMatchState) { + /* Prefetch DMS rows */ + U32* const dmsHashTable = dms->hashTable; + BYTE* const dmsTagTable = dms->tagTable; + U32 const dmsHash = (U32)ZSTD_hashPtr(ip, dms->rowHashLog + ZSTD_ROW_HASH_TAG_BITS, mls); + U32 const dmsRelRow = (dmsHash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; + dmsTag = dmsHash & ZSTD_ROW_HASH_TAG_MASK; + dmsTagRow = (BYTE*)(dmsTagTable + dmsRelRow); + dmsRow = dmsHashTable + dmsRelRow; + ZSTD_row_prefetch(dmsHashTable, dmsTagTable, dmsRelRow, rowLog); + } + + /* Update the hashTable and tagTable up to (but not including) ip */ + if (!ms->lazySkipping) { + ZSTD_row_update_internal(ms, ip, mls, rowLog, rowMask, 1 /* useCache */); + hash = ZSTD_row_nextCachedHash(hashCache, hashTable, tagTable, base, curr, hashLog, rowLog, mls, hashSalt); + } else { + /* Stop inserting every position when in the lazy skipping mode. + * The hash cache is also not kept up to date in this mode. + */ + hash = (U32)ZSTD_hashPtrSalted(ip, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, hashSalt); + ms->nextToUpdate = curr; + } + ms->hashSaltEntropy += hash; /* collect salt entropy */ + + { /* Get the hash for ip, compute the appropriate row */ + U32 const relRow = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; + U32 const tag = hash & ZSTD_ROW_HASH_TAG_MASK; + U32* const row = hashTable + relRow; + BYTE* tagRow = (BYTE*)(tagTable + relRow); + U32 const headGrouped = (*tagRow & rowMask) * groupWidth; + U32 matchBuffer[ZSTD_ROW_HASH_MAX_ENTRIES]; + size_t numMatches = 0; + size_t currMatch = 0; + ZSTD_VecMask matches = ZSTD_row_getMatchMask(tagRow, (BYTE)tag, headGrouped, rowEntries); + + /* Cycle through the matches and prefetch */ + for (; (matches > 0) && (nbAttempts > 0); matches &= (matches - 1)) { + U32 const matchPos = ((headGrouped + ZSTD_VecMask_next(matches)) / groupWidth) & rowMask; + U32 const matchIndex = row[matchPos]; + if(matchPos == 0) continue; + assert(numMatches < rowEntries); + if (matchIndex < lowLimit) + break; + if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) { + PREFETCH_L1(base + matchIndex); + } else { + PREFETCH_L1(dictBase + matchIndex); + } + matchBuffer[numMatches++] = matchIndex; + --nbAttempts; + } + + /* Speed opt: insert current byte into hashtable too. This allows us to avoid one iteration of the loop + in ZSTD_row_update_internal() at the next search. */ + { + U32 const pos = ZSTD_row_nextIndex(tagRow, rowMask); + tagRow[pos] = (BYTE)tag; + row[pos] = ms->nextToUpdate++; + } + + /* Return the longest match */ + for (; currMatch < numMatches; ++currMatch) { + U32 const matchIndex = matchBuffer[currMatch]; + size_t currentMl=0; + assert(matchIndex < curr); + assert(matchIndex >= lowLimit); + + if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) { + const BYTE* const match = base + matchIndex; + assert(matchIndex >= dictLimit); /* ensures this is true if dictMode != ZSTD_extDict */ + /* read 4B starting from (match + ml + 1 - sizeof(U32)) */ + if (MEM_read32(match + ml - 3) == MEM_read32(ip + ml - 3)) /* potentially better */ + currentMl = ZSTD_count(ip, match, iLimit); + } else { + const BYTE* const match = dictBase + matchIndex; + assert(match+4 <= dictEnd); + if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */ + currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4; + } + + /* Save best solution */ + if (currentMl > ml) { + ml = currentMl; + *offsetPtr = OFFSET_TO_OFFBASE(curr - matchIndex); + if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ + } + } + } + + assert(nbAttempts <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */ + if (dictMode == ZSTD_dedicatedDictSearch) { + ml = ZSTD_dedicatedDictSearch_lazy_search(offsetPtr, ml, nbAttempts + ddsExtraAttempts, dms, + ip, iLimit, prefixStart, curr, dictLimit, ddsIdx); + } else if (dictMode == ZSTD_dictMatchState) { + /* TODO: Measure and potentially add prefetching to DMS */ + const U32 dmsLowestIndex = dms->window.dictLimit; + const BYTE* const dmsBase = dms->window.base; + const BYTE* const dmsEnd = dms->window.nextSrc; + const U32 dmsSize = (U32)(dmsEnd - dmsBase); + const U32 dmsIndexDelta = dictLimit - dmsSize; + + { U32 const headGrouped = (*dmsTagRow & rowMask) * groupWidth; + U32 matchBuffer[ZSTD_ROW_HASH_MAX_ENTRIES]; + size_t numMatches = 0; + size_t currMatch = 0; + ZSTD_VecMask matches = ZSTD_row_getMatchMask(dmsTagRow, (BYTE)dmsTag, headGrouped, rowEntries); + + for (; (matches > 0) && (nbAttempts > 0); matches &= (matches - 1)) { + U32 const matchPos = ((headGrouped + ZSTD_VecMask_next(matches)) / groupWidth) & rowMask; + U32 const matchIndex = dmsRow[matchPos]; + if(matchPos == 0) continue; + if (matchIndex < dmsLowestIndex) + break; + PREFETCH_L1(dmsBase + matchIndex); + matchBuffer[numMatches++] = matchIndex; + --nbAttempts; + } + + /* Return the longest match */ + for (; currMatch < numMatches; ++currMatch) { + U32 const matchIndex = matchBuffer[currMatch]; + size_t currentMl=0; + assert(matchIndex >= dmsLowestIndex); + assert(matchIndex < curr); + + { const BYTE* const match = dmsBase + matchIndex; + assert(match+4 <= dmsEnd); + if (MEM_read32(match) == MEM_read32(ip)) + currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dmsEnd, prefixStart) + 4; + } + + if (currentMl > ml) { + ml = currentMl; + assert(curr > matchIndex + dmsIndexDelta); + *offsetPtr = OFFSET_TO_OFFBASE(curr - (matchIndex + dmsIndexDelta)); + if (ip+currentMl == iLimit) break; + } + } + } + } + return ml; } +/** + * Generate search functions templated on (dictMode, mls, rowLog). + * These functions are outlined for code size & compilation time. + * ZSTD_searchMax() dispatches to the correct implementation function. + * + * TODO: The start of the search function involves loading and calculating a + * bunch of constants from the ZSTD_matchState_t. These computations could be + * done in an initialization function, and saved somewhere in the match state. + * Then we could pass a pointer to the saved state instead of the match state, + * and avoid duplicate computations. + * + * TODO: Move the match re-winding into searchMax. This improves compression + * ratio, and unlocks further simplifications with the next TODO. + * + * TODO: Try moving the repcode search into searchMax. After the re-winding + * and repcode search are in searchMax, there is no more logic in the match + * finder loop that requires knowledge about the dictMode. So we should be + * able to avoid force inlining it, and we can join the extDict loop with + * the single segment loop. It should go in searchMax instead of its own + * function to avoid having multiple virtual function calls per search. + */ + +#define ZSTD_BT_SEARCH_FN(dictMode, mls) ZSTD_BtFindBestMatch_##dictMode##_##mls +#define ZSTD_HC_SEARCH_FN(dictMode, mls) ZSTD_HcFindBestMatch_##dictMode##_##mls +#define ZSTD_ROW_SEARCH_FN(dictMode, mls, rowLog) ZSTD_RowFindBestMatch_##dictMode##_##mls##_##rowLog + +#define ZSTD_SEARCH_FN_ATTRS FORCE_NOINLINE + +#define GEN_ZSTD_BT_SEARCH_FN(dictMode, mls) \ + ZSTD_SEARCH_FN_ATTRS size_t ZSTD_BT_SEARCH_FN(dictMode, mls)( \ + ZSTD_matchState_t* ms, \ + const BYTE* ip, const BYTE* const iLimit, \ + size_t* offBasePtr) \ + { \ + assert(MAX(4, MIN(6, ms->cParams.minMatch)) == mls); \ + return ZSTD_BtFindBestMatch(ms, ip, iLimit, offBasePtr, mls, ZSTD_##dictMode); \ + } \ + +#define GEN_ZSTD_HC_SEARCH_FN(dictMode, mls) \ + ZSTD_SEARCH_FN_ATTRS size_t ZSTD_HC_SEARCH_FN(dictMode, mls)( \ + ZSTD_matchState_t* ms, \ + const BYTE* ip, const BYTE* const iLimit, \ + size_t* offsetPtr) \ + { \ + assert(MAX(4, MIN(6, ms->cParams.minMatch)) == mls); \ + return ZSTD_HcFindBestMatch(ms, ip, iLimit, offsetPtr, mls, ZSTD_##dictMode); \ + } \ + +#define GEN_ZSTD_ROW_SEARCH_FN(dictMode, mls, rowLog) \ + ZSTD_SEARCH_FN_ATTRS size_t ZSTD_ROW_SEARCH_FN(dictMode, mls, rowLog)( \ + ZSTD_matchState_t* ms, \ + const BYTE* ip, const BYTE* const iLimit, \ + size_t* offsetPtr) \ + { \ + assert(MAX(4, MIN(6, ms->cParams.minMatch)) == mls); \ + assert(MAX(4, MIN(6, ms->cParams.searchLog)) == rowLog); \ + return ZSTD_RowFindBestMatch(ms, ip, iLimit, offsetPtr, mls, ZSTD_##dictMode, rowLog); \ + } \ + +#define ZSTD_FOR_EACH_ROWLOG(X, dictMode, mls) \ + X(dictMode, mls, 4) \ + X(dictMode, mls, 5) \ + X(dictMode, mls, 6) + +#define ZSTD_FOR_EACH_MLS_ROWLOG(X, dictMode) \ + ZSTD_FOR_EACH_ROWLOG(X, dictMode, 4) \ + ZSTD_FOR_EACH_ROWLOG(X, dictMode, 5) \ + ZSTD_FOR_EACH_ROWLOG(X, dictMode, 6) + +#define ZSTD_FOR_EACH_MLS(X, dictMode) \ + X(dictMode, 4) \ + X(dictMode, 5) \ + X(dictMode, 6) + +#define ZSTD_FOR_EACH_DICT_MODE(X, ...) \ + X(__VA_ARGS__, noDict) \ + X(__VA_ARGS__, extDict) \ + X(__VA_ARGS__, dictMatchState) \ + X(__VA_ARGS__, dedicatedDictSearch) + +/* Generate row search fns for each combination of (dictMode, mls, rowLog) */ +ZSTD_FOR_EACH_DICT_MODE(ZSTD_FOR_EACH_MLS_ROWLOG, GEN_ZSTD_ROW_SEARCH_FN) +/* Generate binary Tree search fns for each combination of (dictMode, mls) */ +ZSTD_FOR_EACH_DICT_MODE(ZSTD_FOR_EACH_MLS, GEN_ZSTD_BT_SEARCH_FN) +/* Generate hash chain search fns for each combination of (dictMode, mls) */ +ZSTD_FOR_EACH_DICT_MODE(ZSTD_FOR_EACH_MLS, GEN_ZSTD_HC_SEARCH_FN) + +typedef enum { search_hashChain=0, search_binaryTree=1, search_rowHash=2 } searchMethod_e; + +#define GEN_ZSTD_CALL_BT_SEARCH_FN(dictMode, mls) \ + case mls: \ + return ZSTD_BT_SEARCH_FN(dictMode, mls)(ms, ip, iend, offsetPtr); +#define GEN_ZSTD_CALL_HC_SEARCH_FN(dictMode, mls) \ + case mls: \ + return ZSTD_HC_SEARCH_FN(dictMode, mls)(ms, ip, iend, offsetPtr); +#define GEN_ZSTD_CALL_ROW_SEARCH_FN(dictMode, mls, rowLog) \ + case rowLog: \ + return ZSTD_ROW_SEARCH_FN(dictMode, mls, rowLog)(ms, ip, iend, offsetPtr); + +#define ZSTD_SWITCH_MLS(X, dictMode) \ + switch (mls) { \ + ZSTD_FOR_EACH_MLS(X, dictMode) \ + } + +#define ZSTD_SWITCH_ROWLOG(dictMode, mls) \ + case mls: \ + switch (rowLog) { \ + ZSTD_FOR_EACH_ROWLOG(GEN_ZSTD_CALL_ROW_SEARCH_FN, dictMode, mls) \ + } \ + ZSTD_UNREACHABLE; \ + break; + +#define ZSTD_SWITCH_SEARCH_METHOD(dictMode) \ + switch (searchMethod) { \ + case search_hashChain: \ + ZSTD_SWITCH_MLS(GEN_ZSTD_CALL_HC_SEARCH_FN, dictMode) \ + break; \ + case search_binaryTree: \ + ZSTD_SWITCH_MLS(GEN_ZSTD_CALL_BT_SEARCH_FN, dictMode) \ + break; \ + case search_rowHash: \ + ZSTD_SWITCH_MLS(ZSTD_SWITCH_ROWLOG, dictMode) \ + break; \ + } \ + ZSTD_UNREACHABLE; + +/** + * Searches for the longest match at @p ip. + * Dispatches to the correct implementation function based on the + * (searchMethod, dictMode, mls, rowLog). We use switch statements + * here instead of using an indirect function call through a function + * pointer because after Spectre and Meltdown mitigations, indirect + * function calls can be very costly, especially in the kernel. + * + * NOTE: dictMode and searchMethod should be templated, so those switch + * statements should be optimized out. Only the mls & rowLog switches + * should be left. + * + * @param ms The match state. + * @param ip The position to search at. + * @param iend The end of the input data. + * @param[out] offsetPtr Stores the match offset into this pointer. + * @param mls The minimum search length, in the range [4, 6]. + * @param rowLog The row log (if applicable), in the range [4, 6]. + * @param searchMethod The search method to use (templated). + * @param dictMode The dictMode (templated). + * + * @returns The length of the longest match found, or < mls if no match is found. + * If a match is found its offset is stored in @p offsetPtr. + */ +FORCE_INLINE_TEMPLATE size_t ZSTD_searchMax( + ZSTD_matchState_t* ms, + const BYTE* ip, + const BYTE* iend, + size_t* offsetPtr, + U32 const mls, + U32 const rowLog, + searchMethod_e const searchMethod, + ZSTD_dictMode_e const dictMode) +{ + if (dictMode == ZSTD_noDict) { + ZSTD_SWITCH_SEARCH_METHOD(noDict) + } else if (dictMode == ZSTD_extDict) { + ZSTD_SWITCH_SEARCH_METHOD(extDict) + } else if (dictMode == ZSTD_dictMatchState) { + ZSTD_SWITCH_SEARCH_METHOD(dictMatchState) + } else if (dictMode == ZSTD_dedicatedDictSearch) { + ZSTD_SWITCH_SEARCH_METHOD(dedicatedDictSearch) + } + ZSTD_UNREACHABLE; + return 0; +} + /* ******************************* * Common parser - lazy strategy *********************************/ -typedef enum { search_hashChain, search_binaryTree } searchMethod_e; -FORCE_INLINE_TEMPLATE size_t -ZSTD_compressBlock_lazy_generic( +FORCE_INLINE_TEMPLATE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +size_t ZSTD_compressBlock_lazy_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize, @@ -635,53 +1526,52 @@ ZSTD_compressBlock_lazy_generic( const BYTE* ip = istart; const BYTE* anchor = istart; const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = iend - 8; + const BYTE* const ilimit = (searchMethod == search_rowHash) ? iend - 8 - ZSTD_ROW_HASH_CACHE_SIZE : iend - 8; const BYTE* const base = ms->window.base; const U32 prefixLowestIndex = ms->window.dictLimit; const BYTE* const prefixLowest = base + prefixLowestIndex; + const U32 mls = BOUNDED(4, ms->cParams.minMatch, 6); + const U32 rowLog = BOUNDED(4, ms->cParams.searchLog, 6); - typedef size_t (*searchMax_f)( - ZSTD_matchState_t* ms, - const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr); - searchMax_f const searchMax = dictMode == ZSTD_dictMatchState ? - (searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_dictMatchState_selectMLS - : ZSTD_HcFindBestMatch_dictMatchState_selectMLS) : - (searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_selectMLS - : ZSTD_HcFindBestMatch_selectMLS); - U32 offset_1 = rep[0], offset_2 = rep[1], savedOffset=0; + U32 offset_1 = rep[0], offset_2 = rep[1]; + U32 offsetSaved1 = 0, offsetSaved2 = 0; + const int isDMS = dictMode == ZSTD_dictMatchState; + const int isDDS = dictMode == ZSTD_dedicatedDictSearch; + const int isDxS = isDMS || isDDS; const ZSTD_matchState_t* const dms = ms->dictMatchState; - const U32 dictLowestIndex = dictMode == ZSTD_dictMatchState ? - dms->window.dictLimit : 0; - const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ? - dms->window.base : NULL; - const BYTE* const dictLowest = dictMode == ZSTD_dictMatchState ? - dictBase + dictLowestIndex : NULL; - const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ? - dms->window.nextSrc : NULL; - const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ? + const U32 dictLowestIndex = isDxS ? dms->window.dictLimit : 0; + const BYTE* const dictBase = isDxS ? dms->window.base : NULL; + const BYTE* const dictLowest = isDxS ? dictBase + dictLowestIndex : NULL; + const BYTE* const dictEnd = isDxS ? dms->window.nextSrc : NULL; + const U32 dictIndexDelta = isDxS ? prefixLowestIndex - (U32)(dictEnd - dictBase) : 0; const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictLowest)); - DEBUGLOG(5, "ZSTD_compressBlock_lazy_generic (dictMode=%u)", (U32)dictMode); - - /* init */ + DEBUGLOG(5, "ZSTD_compressBlock_lazy_generic (dictMode=%u) (searchFunc=%u)", (U32)dictMode, (U32)searchMethod); ip += (dictAndPrefixLength == 0); if (dictMode == ZSTD_noDict) { - U32 const current = (U32)(ip - base); - U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, ms->cParams.windowLog); - U32 const maxRep = current - windowLow; - if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0; - if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0; + U32 const curr = (U32)(ip - base); + U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, curr, ms->cParams.windowLog); + U32 const maxRep = curr - windowLow; + if (offset_2 > maxRep) offsetSaved2 = offset_2, offset_2 = 0; + if (offset_1 > maxRep) offsetSaved1 = offset_1, offset_1 = 0; } - if (dictMode == ZSTD_dictMatchState) { + if (isDxS) { /* dictMatchState repCode checks don't currently handle repCode == 0 * disabling. */ assert(offset_1 <= dictAndPrefixLength); assert(offset_2 <= dictAndPrefixLength); } + /* Reset the lazy skipping state */ + ms->lazySkipping = 0; + + if (searchMethod == search_rowHash) { + ZSTD_row_fillHashCache(ms, base, rowLog, mls, ms->nextToUpdate, ilimit); + } + /* Match Loop */ #if defined(__GNUC__) && defined(__x86_64__) /* I've measured random a 5% speed loss on levels 5 & 6 (greedy) when the @@ -691,13 +1581,14 @@ ZSTD_compressBlock_lazy_generic( #endif while (ip < ilimit) { size_t matchLength=0; - size_t offset=0; + size_t offBase = REPCODE1_TO_OFFBASE; const BYTE* start=ip+1; + DEBUGLOG(7, "search baseline (depth 0)"); /* check repCode */ - if (dictMode == ZSTD_dictMatchState) { + if (isDxS) { const U32 repIndex = (U32)(ip - base) + 1 - offset_1; - const BYTE* repMatch = (dictMode == ZSTD_dictMatchState + const BYTE* repMatch = ((dictMode == ZSTD_dictMatchState || dictMode == ZSTD_dedicatedDictSearch) && repIndex < prefixLowestIndex) ? dictBase + (repIndex - dictIndexDelta) : base + repIndex; @@ -715,30 +1606,40 @@ ZSTD_compressBlock_lazy_generic( } /* first search (depth 0) */ - { size_t offsetFound = 999999999; - size_t const ml2 = searchMax(ms, ip, iend, &offsetFound); + { size_t offbaseFound = 999999999; + size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &offbaseFound, mls, rowLog, searchMethod, dictMode); if (ml2 > matchLength) - matchLength = ml2, start = ip, offset=offsetFound; + matchLength = ml2, start = ip, offBase = offbaseFound; } if (matchLength < 4) { - ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */ + size_t const step = ((size_t)(ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */; + ip += step; + /* Enter the lazy skipping mode once we are skipping more than 8 bytes at a time. + * In this mode we stop inserting every position into our tables, and only insert + * positions that we search, which is one in step positions. + * The exact cutoff is flexible, I've just chosen a number that is reasonably high, + * so we minimize the compression ratio loss in "normal" scenarios. This mode gets + * triggered once we've gone 2KB without finding any matches. + */ + ms->lazySkipping = step > kLazySkippingStep; continue; } /* let's try to find a better solution */ if (depth>=1) while (ip0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { + && (offBase) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4; int const gain2 = (int)(mlRep * 3); - int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1); + int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offBase) + 1); if ((mlRep >= 4) && (gain2 > gain1)) - matchLength = mlRep, offset = 0, start = ip; + matchLength = mlRep, offBase = REPCODE1_TO_OFFBASE, start = ip; } - if (dictMode == ZSTD_dictMatchState) { + if (isDxS) { const U32 repIndex = (U32)(ip - base) - offset_1; const BYTE* repMatch = repIndex < prefixLowestIndex ? dictBase + (repIndex - dictIndexDelta) : @@ -748,32 +1649,33 @@ ZSTD_compressBlock_lazy_generic( const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; int const gain2 = (int)(mlRep * 3); - int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1); + int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offBase) + 1); if ((mlRep >= 4) && (gain2 > gain1)) - matchLength = mlRep, offset = 0, start = ip; + matchLength = mlRep, offBase = REPCODE1_TO_OFFBASE, start = ip; } } - { size_t offset2=999999999; - size_t const ml2 = searchMax(ms, ip, iend, &offset2); - int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4); + { size_t ofbCandidate=999999999; + size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &ofbCandidate, mls, rowLog, searchMethod, dictMode); + int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)ofbCandidate)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 4); if ((ml2 >= 4) && (gain2 > gain1)) { - matchLength = ml2, offset = offset2, start = ip; + matchLength = ml2, offBase = ofbCandidate, start = ip; continue; /* search a better one */ } } /* let's find an even better one */ if ((depth==2) && (ip0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { + && (offBase) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4; int const gain2 = (int)(mlRep * 4); - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1); + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 1); if ((mlRep >= 4) && (gain2 > gain1)) - matchLength = mlRep, offset = 0, start = ip; + matchLength = mlRep, offBase = REPCODE1_TO_OFFBASE, start = ip; } - if (dictMode == ZSTD_dictMatchState) { + if (isDxS) { const U32 repIndex = (U32)(ip - base) - offset_1; const BYTE* repMatch = repIndex < prefixLowestIndex ? dictBase + (repIndex - dictIndexDelta) : @@ -783,64 +1685,69 @@ ZSTD_compressBlock_lazy_generic( const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; int const gain2 = (int)(mlRep * 4); - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1); + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 1); if ((mlRep >= 4) && (gain2 > gain1)) - matchLength = mlRep, offset = 0, start = ip; + matchLength = mlRep, offBase = REPCODE1_TO_OFFBASE, start = ip; } } - { size_t offset2=999999999; - size_t const ml2 = searchMax(ms, ip, iend, &offset2); - int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7); + { size_t ofbCandidate=999999999; + size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &ofbCandidate, mls, rowLog, searchMethod, dictMode); + int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)ofbCandidate)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 7); if ((ml2 >= 4) && (gain2 > gain1)) { - matchLength = ml2, offset = offset2, start = ip; + matchLength = ml2, offBase = ofbCandidate, start = ip; continue; } } } break; /* nothing found : store previous solution */ } /* NOTE: - * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior. - * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which - * overflows the pointer, which is undefined behavior. + * Pay attention that `start[-value]` can lead to strange undefined behavior + * notably if `value` is unsigned, resulting in a large positive `-value`. */ /* catch up */ - if (offset) { + if (OFFBASE_IS_OFFSET(offBase)) { if (dictMode == ZSTD_noDict) { - while ( ((start > anchor) & (start - (offset-ZSTD_REP_MOVE) > prefixLowest)) - && (start[-1] == (start-(offset-ZSTD_REP_MOVE))[-1]) ) /* only search for offset within prefix */ + while ( ((start > anchor) & (start - OFFBASE_TO_OFFSET(offBase) > prefixLowest)) + && (start[-1] == (start-OFFBASE_TO_OFFSET(offBase))[-1]) ) /* only search for offset within prefix */ { start--; matchLength++; } } - if (dictMode == ZSTD_dictMatchState) { - U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE)); + if (isDxS) { + U32 const matchIndex = (U32)((size_t)(start-base) - OFFBASE_TO_OFFSET(offBase)); const BYTE* match = (matchIndex < prefixLowestIndex) ? dictBase + matchIndex - dictIndexDelta : base + matchIndex; const BYTE* const mStart = (matchIndex < prefixLowestIndex) ? dictLowest : prefixLowest; while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */ } - offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE); + offset_2 = offset_1; offset_1 = (U32)OFFBASE_TO_OFFSET(offBase); } /* store sequence */ _storeSequence: - { size_t const litLength = start - anchor; - ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offset, matchLength-MINMATCH); + { size_t const litLength = (size_t)(start - anchor); + ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offBase, matchLength); anchor = ip = start + matchLength; } + if (ms->lazySkipping) { + /* We've found a match, disable lazy skipping mode, and refill the hash cache. */ + if (searchMethod == search_rowHash) { + ZSTD_row_fillHashCache(ms, base, rowLog, mls, ms->nextToUpdate, ilimit); + } + ms->lazySkipping = 0; + } /* check immediate repcode */ - if (dictMode == ZSTD_dictMatchState) { + if (isDxS) { while (ip <= ilimit) { U32 const current2 = (U32)(ip-base); U32 const repIndex = current2 - offset_2; - const BYTE* repMatch = dictMode == ZSTD_dictMatchState - && repIndex < prefixLowestIndex ? + const BYTE* repMatch = repIndex < prefixLowestIndex ? dictBase - dictIndexDelta + repIndex : base + repIndex; if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex) >= 3 /* intentional overflow */) && (MEM_read32(repMatch) == MEM_read32(ip)) ) { const BYTE* const repEnd2 = repIndex < prefixLowestIndex ? dictEnd : iend; matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd2, prefixLowest) + 4; - offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH); + offBase = offset_2; offset_2 = offset_1; offset_1 = (U32)offBase; /* swap offset_2 <=> offset_1 */ + ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, matchLength); ip += matchLength; anchor = ip; continue; @@ -854,36 +1761,72 @@ ZSTD_compressBlock_lazy_generic( && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { /* store sequence */ matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; - offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH); + offBase = offset_2; offset_2 = offset_1; offset_1 = (U32)offBase; /* swap repcodes */ + ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, matchLength); ip += matchLength; anchor = ip; continue; /* faster when present ... (?) */ } } } - /* Save reps for next block */ - rep[0] = offset_1 ? offset_1 : savedOffset; - rep[1] = offset_2 ? offset_2 : savedOffset; + /* If offset_1 started invalid (offsetSaved1 != 0) and became valid (offset_1 != 0), + * rotate saved offsets. See comment in ZSTD_compressBlock_fast_noDict for more context. */ + offsetSaved2 = ((offsetSaved1 != 0) && (offset_1 != 0)) ? offsetSaved1 : offsetSaved2; + + /* save reps for next block */ + rep[0] = offset_1 ? offset_1 : offsetSaved1; + rep[1] = offset_2 ? offset_2 : offsetSaved2; /* Return the last literals size */ return (size_t)(iend - anchor); } +#endif /* build exclusions */ -size_t ZSTD_compressBlock_btlazy2( +#ifndef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR +size_t ZSTD_compressBlock_greedy( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_noDict); + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_noDict); } -size_t ZSTD_compressBlock_lazy2( +size_t ZSTD_compressBlock_greedy_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_noDict); + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_dictMatchState); +} + +size_t ZSTD_compressBlock_greedy_dedicatedDictSearch( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_dedicatedDictSearch); } +size_t ZSTD_compressBlock_greedy_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_noDict); +} + +size_t ZSTD_compressBlock_greedy_dictMatchState_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_dictMatchState); +} + +size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_dedicatedDictSearch); +} +#endif + +#ifndef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR size_t ZSTD_compressBlock_lazy( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) @@ -891,18 +1834,48 @@ size_t ZSTD_compressBlock_lazy( return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_noDict); } -size_t ZSTD_compressBlock_greedy( +size_t ZSTD_compressBlock_lazy_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_noDict); + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_dictMatchState); } -size_t ZSTD_compressBlock_btlazy2_dictMatchState( +size_t ZSTD_compressBlock_lazy_dedicatedDictSearch( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_dictMatchState); + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_dedicatedDictSearch); +} + +size_t ZSTD_compressBlock_lazy_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_noDict); +} + +size_t ZSTD_compressBlock_lazy_dictMatchState_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_dictMatchState); +} + +size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_dedicatedDictSearch); +} +#endif + +#ifndef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR +size_t ZSTD_compressBlock_lazy2( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_noDict); } size_t ZSTD_compressBlock_lazy2_dictMatchState( @@ -912,22 +1885,57 @@ size_t ZSTD_compressBlock_lazy2_dictMatchState( return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_dictMatchState); } -size_t ZSTD_compressBlock_lazy_dictMatchState( +size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_dictMatchState); + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_dedicatedDictSearch); } -size_t ZSTD_compressBlock_greedy_dictMatchState( +size_t ZSTD_compressBlock_lazy2_row( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_dictMatchState); + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_noDict); +} + +size_t ZSTD_compressBlock_lazy2_dictMatchState_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_dictMatchState); +} + +size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_dedicatedDictSearch); } +#endif +#ifndef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR +size_t ZSTD_compressBlock_btlazy2( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_noDict); +} +size_t ZSTD_compressBlock_btlazy2_dictMatchState( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_dictMatchState); +} +#endif + +#if !defined(ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) FORCE_INLINE_TEMPLATE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR size_t ZSTD_compressBlock_lazy_extDict_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -938,7 +1946,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( const BYTE* ip = istart; const BYTE* anchor = istart; const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = iend - 8; + const BYTE* const ilimit = searchMethod == search_rowHash ? iend - 8 - ZSTD_ROW_HASH_CACHE_SIZE : iend - 8; const BYTE* const base = ms->window.base; const U32 dictLimit = ms->window.dictLimit; const BYTE* const prefixStart = base + dictLimit; @@ -946,18 +1954,21 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const dictStart = dictBase + ms->window.lowLimit; const U32 windowLog = ms->cParams.windowLog; - - typedef size_t (*searchMax_f)( - ZSTD_matchState_t* ms, - const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr); - searchMax_f searchMax = searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_extDict_selectMLS : ZSTD_HcFindBestMatch_extDict_selectMLS; + const U32 mls = BOUNDED(4, ms->cParams.minMatch, 6); + const U32 rowLog = BOUNDED(4, ms->cParams.searchLog, 6); U32 offset_1 = rep[0], offset_2 = rep[1]; - DEBUGLOG(5, "ZSTD_compressBlock_lazy_extDict_generic"); + DEBUGLOG(5, "ZSTD_compressBlock_lazy_extDict_generic (searchFunc=%u)", (U32)searchMethod); + + /* Reset the lazy skipping state */ + ms->lazySkipping = 0; /* init */ ip += (ip == prefixStart); + if (searchMethod == search_rowHash) { + ZSTD_row_fillHashCache(ms, base, rowLog, mls, ms->nextToUpdate, ilimit); + } /* Match Loop */ #if defined(__GNUC__) && defined(__x86_64__) @@ -968,16 +1979,17 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( #endif while (ip < ilimit) { size_t matchLength=0; - size_t offset=0; + size_t offBase = REPCODE1_TO_OFFBASE; const BYTE* start=ip+1; - U32 current = (U32)(ip-base); + U32 curr = (U32)(ip-base); /* check repCode */ - { const U32 windowLow = ZSTD_getLowestMatchIndex(ms, current+1, windowLog); - const U32 repIndex = (U32)(current+1 - offset_1); + { const U32 windowLow = ZSTD_getLowestMatchIndex(ms, curr+1, windowLog); + const U32 repIndex = (U32)(curr+1 - offset_1); const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; - if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */ + if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ + & (offset_1 <= curr+1 - windowLow) ) /* note: we are searching at curr+1 */ if (MEM_read32(ip+1) == MEM_read32(repMatch)) { /* repcode detected we should take it */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; @@ -986,14 +1998,23 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( } } /* first search (depth 0) */ - { size_t offsetFound = 999999999; - size_t const ml2 = searchMax(ms, ip, iend, &offsetFound); + { size_t ofbCandidate = 999999999; + size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &ofbCandidate, mls, rowLog, searchMethod, ZSTD_extDict); if (ml2 > matchLength) - matchLength = ml2, start = ip, offset=offsetFound; + matchLength = ml2, start = ip, offBase = ofbCandidate; } - if (matchLength < 4) { - ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */ + if (matchLength < 4) { + size_t const step = ((size_t)(ip-anchor) >> kSearchStrength); + ip += step + 1; /* jump faster over incompressible sections */ + /* Enter the lazy skipping mode once we are skipping more than 8 bytes at a time. + * In this mode we stop inserting every position into our tables, and only insert + * positions that we search, which is one in step positions. + * The exact cutoff is flexible, I've just chosen a number that is reasonably high, + * so we minimize the compression ratio loss in "normal" scenarios. This mode gets + * triggered once we've gone 2KB without finding any matches. + */ + ms->lazySkipping = step > kLazySkippingStep; continue; } @@ -1001,82 +2022,91 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( if (depth>=1) while (ip= 3) & (repIndex > windowLow)) /* intentional overflow */ + if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow : do not test positions overlapping 2 memory segments */ + & (offset_1 <= curr - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */ if (MEM_read32(ip) == MEM_read32(repMatch)) { /* repcode detected */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4; int const gain2 = (int)(repLength * 3); - int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1); + int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offBase) + 1); if ((repLength >= 4) && (gain2 > gain1)) - matchLength = repLength, offset = 0, start = ip; + matchLength = repLength, offBase = REPCODE1_TO_OFFBASE, start = ip; } } /* search match, depth 1 */ - { size_t offset2=999999999; - size_t const ml2 = searchMax(ms, ip, iend, &offset2); - int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4); + { size_t ofbCandidate = 999999999; + size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &ofbCandidate, mls, rowLog, searchMethod, ZSTD_extDict); + int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)ofbCandidate)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 4); if ((ml2 >= 4) && (gain2 > gain1)) { - matchLength = ml2, offset = offset2, start = ip; + matchLength = ml2, offBase = ofbCandidate, start = ip; continue; /* search a better one */ } } /* let's find an even better one */ if ((depth==2) && (ip= 3) & (repIndex > windowLow)) /* intentional overflow */ + if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow : do not test positions overlapping 2 memory segments */ + & (offset_1 <= curr - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */ if (MEM_read32(ip) == MEM_read32(repMatch)) { /* repcode detected */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4; int const gain2 = (int)(repLength * 4); - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1); + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 1); if ((repLength >= 4) && (gain2 > gain1)) - matchLength = repLength, offset = 0, start = ip; + matchLength = repLength, offBase = REPCODE1_TO_OFFBASE, start = ip; } } /* search match, depth 2 */ - { size_t offset2=999999999; - size_t const ml2 = searchMax(ms, ip, iend, &offset2); - int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7); + { size_t ofbCandidate = 999999999; + size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &ofbCandidate, mls, rowLog, searchMethod, ZSTD_extDict); + int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)ofbCandidate)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 7); if ((ml2 >= 4) && (gain2 > gain1)) { - matchLength = ml2, offset = offset2, start = ip; + matchLength = ml2, offBase = ofbCandidate, start = ip; continue; } } } break; /* nothing found : store previous solution */ } /* catch up */ - if (offset) { - U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE)); + if (OFFBASE_IS_OFFSET(offBase)) { + U32 const matchIndex = (U32)((size_t)(start-base) - OFFBASE_TO_OFFSET(offBase)); const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex; const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart; while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */ - offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE); + offset_2 = offset_1; offset_1 = (U32)OFFBASE_TO_OFFSET(offBase); } /* store sequence */ _storeSequence: - { size_t const litLength = start - anchor; - ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offset, matchLength-MINMATCH); + { size_t const litLength = (size_t)(start - anchor); + ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offBase, matchLength); anchor = ip = start + matchLength; } + if (ms->lazySkipping) { + /* We've found a match, disable lazy skipping mode, and refill the hash cache. */ + if (searchMethod == search_rowHash) { + ZSTD_row_fillHashCache(ms, base, rowLog, mls, ms->nextToUpdate, ilimit); + } + ms->lazySkipping = 0; + } /* check immediate repcode */ while (ip <= ilimit) { @@ -1085,13 +2115,14 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( const U32 repIndex = repCurrent - offset_2; const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; - if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */ + if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow : do not test positions overlapping 2 memory segments */ + & (offset_2 <= repCurrent - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */ if (MEM_read32(ip) == MEM_read32(repMatch)) { /* repcode detected we should take it */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4; - offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH); + offBase = offset_2; offset_2 = offset_1; offset_1 = (U32)offBase; /* swap offset history */ + ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, matchLength); ip += matchLength; anchor = ip; continue; /* faster when present ... (?) */ @@ -1106,8 +2137,9 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( /* Return the last literals size */ return (size_t)(iend - anchor); } +#endif /* build exclusions */ - +#ifndef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR size_t ZSTD_compressBlock_greedy_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) @@ -1115,6 +2147,15 @@ size_t ZSTD_compressBlock_greedy_extDict( return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0); } +size_t ZSTD_compressBlock_greedy_extDict_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0); +} +#endif + +#ifndef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR size_t ZSTD_compressBlock_lazy_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) @@ -1123,6 +2164,16 @@ size_t ZSTD_compressBlock_lazy_extDict( return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1); } +size_t ZSTD_compressBlock_lazy_extDict_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) + +{ + return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1); +} +#endif + +#ifndef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR size_t ZSTD_compressBlock_lazy2_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) @@ -1131,6 +2182,15 @@ size_t ZSTD_compressBlock_lazy2_extDict( return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2); } +size_t ZSTD_compressBlock_lazy2_extDict_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize) +{ + return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2); +} +#endif + +#ifndef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR size_t ZSTD_compressBlock_btlazy2_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) @@ -1138,5 +2198,6 @@ size_t ZSTD_compressBlock_btlazy2_extDict( { return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2); } +#endif -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/compress/zstd_ldm.cpp b/src/duckdb/third_party/zstd/compress/zstd_ldm.cpp index ee2480bfb..a83bf7415 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_ldm.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_ldm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,16 +11,130 @@ #include "zstd/compress/zstd_ldm.h" #include "zstd/common/debug.h" +#include "zstd/common/xxhash.hpp" +#include "zstd/common/xxhash_static.hpp" #include "zstd/compress/zstd_fast.h" /* ZSTD_fillHashTable() */ #include "zstd/compress/zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */ +#include "zstd/compress/zstd_ldm_geartab.h" #define LDM_BUCKET_SIZE_LOG 3 #define LDM_MIN_MATCH_LENGTH 64 #define LDM_HASH_RLOG 7 -#define LDM_HASH_CHAR_OFFSET 10 namespace duckdb_zstd { +typedef struct { + U64 rolling; + U64 stopMask; +} ldmRollingHashState_t; + +/** ZSTD_ldm_gear_init(): + * + * Initializes the rolling hash state such that it will honor the + * settings in params. */ +static void ZSTD_ldm_gear_init(ldmRollingHashState_t* state, ldmParams_t const* params) +{ + unsigned maxBitsInMask = MIN(params->minMatchLength, 64); + unsigned hashRateLog = params->hashRateLog; + + state->rolling = ~(U32)0; + + /* The choice of the splitting criterion is subject to two conditions: + * 1. it has to trigger on average every 2^(hashRateLog) bytes; + * 2. ideally, it has to depend on a window of minMatchLength bytes. + * + * In the gear hash algorithm, bit n depends on the last n bytes; + * so in order to obtain a good quality splitting criterion it is + * preferable to use bits with high weight. + * + * To match condition 1 we use a mask with hashRateLog bits set + * and, because of the previous remark, we make sure these bits + * have the highest possible weight while still respecting + * condition 2. + */ + if (hashRateLog > 0 && hashRateLog <= maxBitsInMask) { + state->stopMask = (((U64)1 << hashRateLog) - 1) << (maxBitsInMask - hashRateLog); + } else { + /* In this degenerate case we simply honor the hash rate. */ + state->stopMask = ((U64)1 << hashRateLog) - 1; + } +} + +/** ZSTD_ldm_gear_reset() + * Feeds [data, data + minMatchLength) into the hash without registering any + * splits. This effectively resets the hash state. This is used when skipping + * over data, either at the beginning of a block, or skipping sections. + */ +static void ZSTD_ldm_gear_reset(ldmRollingHashState_t* state, + BYTE const* data, size_t minMatchLength) +{ + U64 hash = state->rolling; + size_t n = 0; + +#define GEAR_ITER_ONCE() do { \ + hash = (hash << 1) + ZSTD_ldm_gearTab[data[n] & 0xff]; \ + n += 1; \ + } while (0) + while (n + 3 < minMatchLength) { + GEAR_ITER_ONCE(); + GEAR_ITER_ONCE(); + GEAR_ITER_ONCE(); + GEAR_ITER_ONCE(); + } + while (n < minMatchLength) { + GEAR_ITER_ONCE(); + } +#undef GEAR_ITER_ONCE +} + +/** ZSTD_ldm_gear_feed(): + * + * Registers in the splits array all the split points found in the first + * size bytes following the data pointer. This function terminates when + * either all the data has been processed or LDM_BATCH_SIZE splits are + * present in the splits array. + * + * Precondition: The splits array must not be full. + * Returns: The number of bytes processed. */ +static size_t ZSTD_ldm_gear_feed(ldmRollingHashState_t* state, + BYTE const* data, size_t size, + size_t* splits, unsigned* numSplits) +{ + size_t n; + U64 hash, mask; + + hash = state->rolling; + mask = state->stopMask; + n = 0; + +#define GEAR_ITER_ONCE() do { \ + hash = (hash << 1) + ZSTD_ldm_gearTab[data[n] & 0xff]; \ + n += 1; \ + if (UNLIKELY((hash & mask) == 0)) { \ + splits[*numSplits] = n; \ + *numSplits += 1; \ + if (*numSplits == LDM_BATCH_SIZE) \ + goto done; \ + } \ + } while (0) + + while (n + 3 < size) { + GEAR_ITER_ONCE(); + GEAR_ITER_ONCE(); + GEAR_ITER_ONCE(); + GEAR_ITER_ONCE(); + } + while (n < size) { + GEAR_ITER_ONCE(); + } + +#undef GEAR_ITER_ONCE + +done: + state->rolling = hash; + return n; +} + void ZSTD_ldm_adjustParameters(ldmParams_t* params, ZSTD_compressionParameters const* cParams) { @@ -29,13 +143,6 @@ void ZSTD_ldm_adjustParameters(ldmParams_t* params, DEBUGLOG(4, "ZSTD_ldm_adjustParameters"); if (!params->bucketSizeLog) params->bucketSizeLog = LDM_BUCKET_SIZE_LOG; if (!params->minMatchLength) params->minMatchLength = LDM_MIN_MATCH_LENGTH; - if (cParams->strategy >= ZSTD_btopt) { - /* Get out of the way of the optimal parser */ - U32 const minMatch = MAX(cParams->targetLength, params->minMatchLength); - assert(minMatch >= ZSTD_LDM_MINMATCH_MIN); - assert(minMatch <= ZSTD_LDM_MINMATCH_MAX); - params->minMatchLength = minMatch; - } if (params->hashLog == 0) { params->hashLog = MAX(ZSTD_HASHLOG_MIN, params->windowLog - LDM_HASH_RLOG); assert(params->hashLog <= ZSTD_HASHLOG_MAX); @@ -55,47 +162,12 @@ size_t ZSTD_ldm_getTableSize(ldmParams_t params) size_t const ldmBucketSize = ((size_t)1) << (params.hashLog - ldmBucketSizeLog); size_t const totalSize = ZSTD_cwksp_alloc_size(ldmBucketSize) + ZSTD_cwksp_alloc_size(ldmHSize * sizeof(ldmEntry_t)); - return params.enableLdm ? totalSize : 0; + return params.enableLdm == ZSTD_ps_enable ? totalSize : 0; } size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize) { - return params.enableLdm ? (maxChunkSize / params.minMatchLength) : 0; -} - -/** ZSTD_ldm_getSmallHash() : - * numBits should be <= 32 - * If numBits==0, returns 0. - * @return : the most significant numBits of value. */ -static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits) -{ - assert(numBits <= 32); - return numBits == 0 ? 0 : (U32)(value >> (64 - numBits)); -} - -/** ZSTD_ldm_getChecksum() : - * numBitsToDiscard should be <= 32 - * @return : the next most significant 32 bits after numBitsToDiscard */ -static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard) -{ - assert(numBitsToDiscard <= 32); - return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF; -} - -/** ZSTD_ldm_getTag() ; - * Given the hash, returns the most significant numTagBits bits - * after (32 + hbits) bits. - * - * If there are not enough bits remaining, return the last - * numTagBits bits. */ -static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits) -{ - assert(numTagBits < 32 && hbits <= 32); - if (32 - hbits < numTagBits) { - return hash & (((U32)1 << numTagBits) - 1); - } else { - return (hash >> (32 - hbits - numTagBits)) & (((U32)1 << numTagBits) - 1); - } + return params.enableLdm == ZSTD_ps_enable ? (maxChunkSize / params.minMatchLength) : 0; } /** ZSTD_ldm_getBucket() : @@ -112,38 +184,12 @@ static void ZSTD_ldm_insertEntry(ldmState_t* ldmState, size_t const hash, const ldmEntry_t entry, ldmParams_t const ldmParams) { - BYTE* const bucketOffsets = ldmState->bucketOffsets; - *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry; - bucketOffsets[hash]++; - bucketOffsets[hash] &= ((U32)1 << ldmParams.bucketSizeLog) - 1; -} + BYTE* const pOffset = ldmState->bucketOffsets + hash; + unsigned const offset = *pOffset; + + *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + offset) = entry; + *pOffset = (BYTE)((offset + 1) & ((1u << ldmParams.bucketSizeLog) - 1)); -/** ZSTD_ldm_makeEntryAndInsertByTag() : - * - * Gets the small hash, checksum, and tag from the rollingHash. - * - * If the tag matches (1 << ldmParams.hashRateLog)-1, then - * creates an ldmEntry from the offset, and inserts it into the hash table. - * - * hBits is the length of the small hash, which is the most significant hBits - * of rollingHash. The checksum is the next 32 most significant bits, followed - * by ldmParams.hashRateLog bits that make up the tag. */ -static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState, - U64 const rollingHash, - U32 const hBits, - U32 const offset, - ldmParams_t const ldmParams) -{ - U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashRateLog); - U32 const tagMask = ((U32)1 << ldmParams.hashRateLog) - 1; - if (tag == tagMask) { - U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits); - U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); - ldmEntry_t entry; - entry.offset = offset; - entry.checksum = checksum; - ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams); - } } /** ZSTD_ldm_countBackwardsMatch() : @@ -152,10 +198,10 @@ static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState, * We count only bytes where pMatch >= pBase and pIn >= pAnchor. */ static size_t ZSTD_ldm_countBackwardsMatch( const BYTE* pIn, const BYTE* pAnchor, - const BYTE* pMatch, const BYTE* pBase) + const BYTE* pMatch, const BYTE* pMatchBase) { size_t matchLength = 0; - while (pIn > pAnchor && pMatch > pBase && pIn[-1] == pMatch[-1]) { + while (pIn > pAnchor && pMatch > pMatchBase && pIn[-1] == pMatch[-1]) { pIn--; pMatch--; matchLength++; @@ -163,6 +209,27 @@ static size_t ZSTD_ldm_countBackwardsMatch( return matchLength; } +/** ZSTD_ldm_countBackwardsMatch_2segments() : + * Returns the number of bytes that match backwards from pMatch, + * even with the backwards match spanning 2 different segments. + * + * On reaching `pMatchBase`, start counting from mEnd */ +static size_t ZSTD_ldm_countBackwardsMatch_2segments( + const BYTE* pIn, const BYTE* pAnchor, + const BYTE* pMatch, const BYTE* pMatchBase, + const BYTE* pExtDictStart, const BYTE* pExtDictEnd) +{ + size_t matchLength = ZSTD_ldm_countBackwardsMatch(pIn, pAnchor, pMatch, pMatchBase); + if (pMatch - matchLength != pMatchBase || pMatchBase == pExtDictStart) { + /* If backwards match is entirely in the extDict or prefix, immediately return */ + return matchLength; + } + DEBUGLOG(7, "ZSTD_ldm_countBackwardsMatch_2segments: found 2-parts backwards match (length in prefix==%zu)", matchLength); + matchLength += ZSTD_ldm_countBackwardsMatch(pIn - matchLength, pAnchor, pExtDictEnd, pExtDictStart); + DEBUGLOG(7, "final backwards match length = %zu", matchLength); + return matchLength; +} + /** ZSTD_ldm_fillFastTables() : * * Fills the relevant tables for the ZSTD_fast and ZSTD_dfast strategies. @@ -178,11 +245,15 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms, switch(ms->cParams.strategy) { case ZSTD_fast: - ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast); + ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast, ZSTD_tfp_forCCtx); break; case ZSTD_dfast: - ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast); +#ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR + ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast, ZSTD_tfp_forCCtx); +#else + assert(0); /* shouldn't be called: cparams should've been adjusted. */ +#endif break; case ZSTD_greedy: @@ -200,43 +271,42 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms, return 0; } -/** ZSTD_ldm_fillLdmHashTable() : - * - * Fills hashTable from (lastHashed + 1) to iend (non-inclusive). - * lastHash is the rolling hash that corresponds to lastHashed. - * - * Returns the rolling hash corresponding to position iend-1. */ -static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state, - U64 lastHash, const BYTE* lastHashed, - const BYTE* iend, const BYTE* base, - U32 hBits, ldmParams_t const ldmParams) -{ - U64 rollingHash = lastHash; - const BYTE* cur = lastHashed + 1; - - while (cur < iend) { - rollingHash = ZSTD_rollingHash_rotate(rollingHash, cur[-1], - cur[ldmParams.minMatchLength-1], - state->hashPower); - ZSTD_ldm_makeEntryAndInsertByTag(state, - rollingHash, hBits, - (U32)(cur - base), ldmParams); - ++cur; - } - return rollingHash; -} - void ZSTD_ldm_fillHashTable( - ldmState_t* state, const BYTE* ip, + ldmState_t* ldmState, const BYTE* ip, const BYTE* iend, ldmParams_t const* params) { + U32 const minMatchLength = params->minMatchLength; + U32 const hBits = params->hashLog - params->bucketSizeLog; + BYTE const* const base = ldmState->window.base; + BYTE const* const istart = ip; + ldmRollingHashState_t hashState; + size_t* const splits = ldmState->splitIndices; + unsigned numSplits; + DEBUGLOG(5, "ZSTD_ldm_fillHashTable"); - if ((size_t)(iend - ip) >= params->minMatchLength) { - U64 startingHash = ZSTD_rollingHash_compute(ip, params->minMatchLength); - ZSTD_ldm_fillLdmHashTable( - state, startingHash, ip, iend - params->minMatchLength, state->window.base, - params->hashLog - params->bucketSizeLog, - *params); + + ZSTD_ldm_gear_init(&hashState, params); + while (ip < iend) { + size_t hashed; + unsigned n; + + numSplits = 0; + hashed = ZSTD_ldm_gear_feed(&hashState, ip, iend - ip, splits, &numSplits); + + for (n = 0; n < numSplits; n++) { + if (ip + splits[n] >= istart + minMatchLength) { + BYTE const* const split = ip + splits[n] - minMatchLength; + U64 const xxhash = XXH64(split, minMatchLength, 0); + U32 const hash = (U32)(xxhash & (((U32)1 << hBits) - 1)); + ldmEntry_t entry; + + entry.offset = (U32)(split - base); + entry.checksum = (U32)(xxhash >> 32); + ZSTD_ldm_insertEntry(ldmState, hash, entry, *params); + } + } + + ip += hashed; } } @@ -248,25 +318,24 @@ void ZSTD_ldm_fillHashTable( * (after a long match, only update tables a limited amount). */ static void ZSTD_ldm_limitTableUpdate(ZSTD_matchState_t* ms, const BYTE* anchor) { - U32 const current = (U32)(anchor - ms->window.base); - if (current > ms->nextToUpdate + 1024) { + U32 const curr = (U32)(anchor - ms->window.base); + if (curr > ms->nextToUpdate + 1024) { ms->nextToUpdate = - current - MIN(512, current - ms->nextToUpdate - 1024); + curr - MIN(512, curr - ms->nextToUpdate - 1024); } } -static size_t ZSTD_ldm_generateSequences_internal( +static +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +size_t ZSTD_ldm_generateSequences_internal( ldmState_t* ldmState, rawSeqStore_t* rawSeqStore, ldmParams_t const* params, void const* src, size_t srcSize) { /* LDM parameters */ int const extDict = ZSTD_window_hasExtDict(ldmState->window); U32 const minMatchLength = params->minMatchLength; - U64 const hashPower = ldmState->hashPower; + U32 const entsPerBucket = 1U << params->bucketSizeLog; U32 const hBits = params->hashLog - params->bucketSizeLog; - U32 const ldmBucketSize = 1U << params->bucketSizeLog; - U32 const hashRateLog = params->hashRateLog; - U32 const ldmTagMask = (1U << params->hashRateLog) - 1; /* Prefix and extDict parameters */ U32 const dictLimit = ldmState->window.dictLimit; U32 const lowestIndex = extDict ? ldmState->window.lowLimit : dictLimit; @@ -278,45 +347,69 @@ static size_t ZSTD_ldm_generateSequences_internal( /* Input bounds */ BYTE const* const istart = (BYTE const*)src; BYTE const* const iend = istart + srcSize; - BYTE const* const ilimit = iend - MAX(minMatchLength, HASH_READ_SIZE); + BYTE const* const ilimit = iend - HASH_READ_SIZE; /* Input positions */ BYTE const* anchor = istart; BYTE const* ip = istart; - /* Rolling hash */ - BYTE const* lastHashed = NULL; - U64 rollingHash = 0; - - while (ip <= ilimit) { - size_t mLength; - U32 const current = (U32)(ip - base); - size_t forwardMatchLength = 0, backwardMatchLength = 0; - ldmEntry_t* bestEntry = NULL; - if (ip != istart) { - rollingHash = ZSTD_rollingHash_rotate(rollingHash, lastHashed[0], - lastHashed[minMatchLength], - hashPower); - } else { - rollingHash = ZSTD_rollingHash_compute(ip, minMatchLength); + /* Rolling hash state */ + ldmRollingHashState_t hashState; + /* Arrays for staged-processing */ + size_t* const splits = ldmState->splitIndices; + ldmMatchCandidate_t* const candidates = ldmState->matchCandidates; + unsigned numSplits; + + if (srcSize < minMatchLength) + return iend - anchor; + + /* Initialize the rolling hash state with the first minMatchLength bytes */ + ZSTD_ldm_gear_init(&hashState, params); + ZSTD_ldm_gear_reset(&hashState, ip, minMatchLength); + ip += minMatchLength; + + while (ip < ilimit) { + size_t hashed; + unsigned n; + + numSplits = 0; + hashed = ZSTD_ldm_gear_feed(&hashState, ip, ilimit - ip, + splits, &numSplits); + + for (n = 0; n < numSplits; n++) { + BYTE const* const split = ip + splits[n] - minMatchLength; + U64 const xxhash = XXH64(split, minMatchLength, 0); + U32 const hash = (U32)(xxhash & (((U32)1 << hBits) - 1)); + + candidates[n].split = split; + candidates[n].hash = hash; + candidates[n].checksum = (U32)(xxhash >> 32); + candidates[n].bucket = ZSTD_ldm_getBucket(ldmState, hash, *params); + PREFETCH_L1(candidates[n].bucket); } - lastHashed = ip; - /* Do not insert and do not look for a match */ - if (ZSTD_ldm_getTag(rollingHash, hBits, hashRateLog) != ldmTagMask) { - ip++; - continue; - } + for (n = 0; n < numSplits; n++) { + size_t forwardMatchLength = 0, backwardMatchLength = 0, + bestMatchLength = 0, mLength; + U32 offset; + BYTE const* const split = candidates[n].split; + U32 const checksum = candidates[n].checksum; + U32 const hash = candidates[n].hash; + ldmEntry_t* const bucket = candidates[n].bucket; + ldmEntry_t const* cur; + ldmEntry_t const* bestEntry = NULL; + ldmEntry_t newEntry; + + newEntry.offset = (U32)(split - base); + newEntry.checksum = checksum; + + /* If a split point would generate a sequence overlapping with + * the previous one, we merely register it in the hash table and + * move on */ + if (split < anchor) { + ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params); + continue; + } - /* Get the best entry and compute the match lengths */ - { - ldmEntry_t* const bucket = - ZSTD_ldm_getBucket(ldmState, - ZSTD_ldm_getSmallHash(rollingHash, hBits), - *params); - ldmEntry_t* cur; - size_t bestMatchLength = 0; - U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); - - for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) { + for (cur = bucket; cur < bucket + entsPerBucket; cur++) { size_t curForwardMatchLength, curBackwardMatchLength, curTotalMatchLength; if (cur->checksum != checksum || cur->offset <= lowestIndex) { @@ -330,30 +423,23 @@ static size_t ZSTD_ldm_generateSequences_internal( cur->offset < dictLimit ? dictEnd : iend; BYTE const* const lowMatchPtr = cur->offset < dictLimit ? dictStart : lowPrefixPtr; - - curForwardMatchLength = ZSTD_count_2segments( - ip, pMatch, iend, - matchEnd, lowPrefixPtr); + curForwardMatchLength = + ZSTD_count_2segments(split, pMatch, iend, matchEnd, lowPrefixPtr); if (curForwardMatchLength < minMatchLength) { continue; } - curBackwardMatchLength = - ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch, - lowMatchPtr); - curTotalMatchLength = curForwardMatchLength + - curBackwardMatchLength; + curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch_2segments( + split, anchor, pMatch, lowMatchPtr, dictStart, dictEnd); } else { /* !extDict */ BYTE const* const pMatch = base + cur->offset; - curForwardMatchLength = ZSTD_count(ip, pMatch, iend); + curForwardMatchLength = ZSTD_count(split, pMatch, iend); if (curForwardMatchLength < minMatchLength) { continue; } curBackwardMatchLength = - ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch, - lowPrefixPtr); - curTotalMatchLength = curForwardMatchLength + - curBackwardMatchLength; + ZSTD_ldm_countBackwardsMatch(split, anchor, pMatch, lowPrefixPtr); } + curTotalMatchLength = curForwardMatchLength + curBackwardMatchLength; if (curTotalMatchLength > bestMatchLength) { bestMatchLength = curTotalMatchLength; @@ -362,57 +448,54 @@ static size_t ZSTD_ldm_generateSequences_internal( bestEntry = cur; } } - } - - /* No match found -- continue searching */ - if (bestEntry == NULL) { - ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, - hBits, current, - *params); - ip++; - continue; - } - /* Match found */ - mLength = forwardMatchLength + backwardMatchLength; - ip -= backwardMatchLength; + /* No match found -- insert an entry into the hash table + * and process the next candidate match */ + if (bestEntry == NULL) { + ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params); + continue; + } - { - /* Store the sequence: - * ip = current - backwardMatchLength - * The match is at (bestEntry->offset - backwardMatchLength) - */ - U32 const matchIndex = bestEntry->offset; - U32 const offset = current - matchIndex; - rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size; - - /* Out of sequence storage */ - if (rawSeqStore->size == rawSeqStore->capacity) - return ERROR(dstSize_tooSmall); - seq->litLength = (U32)(ip - anchor); - seq->matchLength = (U32)mLength; - seq->offset = offset; - rawSeqStore->size++; - } + /* Match found */ + offset = (U32)(split - base) - bestEntry->offset; + mLength = forwardMatchLength + backwardMatchLength; + { + rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size; + + /* Out of sequence storage */ + if (rawSeqStore->size == rawSeqStore->capacity) + return ERROR(dstSize_tooSmall); + seq->litLength = (U32)(split - backwardMatchLength - anchor); + seq->matchLength = (U32)mLength; + seq->offset = offset; + rawSeqStore->size++; + } - /* Insert the current entry into the hash table */ - ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits, - (U32)(lastHashed - base), - *params); + /* Insert the current entry into the hash table --- it must be + * done after the previous block to avoid clobbering bestEntry */ + ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params); - assert(ip + backwardMatchLength == lastHashed); + anchor = split + forwardMatchLength; - /* Fill the hash table from lastHashed+1 to ip+mLength*/ - /* Heuristic: don't need to fill the entire table at end of block */ - if (ip + mLength <= ilimit) { - rollingHash = ZSTD_ldm_fillLdmHashTable( - ldmState, rollingHash, lastHashed, - ip + mLength, base, hBits, *params); - lastHashed = ip + mLength - 1; + /* If we find a match that ends after the data that we've hashed + * then we have a repeating, overlapping, pattern. E.g. all zeros. + * If one repetition of the pattern matches our `stopMask` then all + * repetitions will. We don't need to insert them all into out table, + * only the first one. So skip over overlapping matches. + * This is a major speed boost (20x) for compressing a single byte + * repeated, when that byte ends up in the table. + */ + if (anchor > ip + hashed) { + ZSTD_ldm_gear_reset(&hashState, anchor - minMatchLength, minMatchLength); + /* Continue the outer loop at anchor (ip + hashed == anchor). */ + ip = anchor - hashed; + break; + } } - ip += mLength; - anchor = ip; + + ip += hashed; } + return iend - anchor; } @@ -461,7 +544,7 @@ size_t ZSTD_ldm_generateSequences( assert(chunkStart < iend); /* 1. Perform overflow correction if necessary. */ - if (ZSTD_window_needOverflowCorrection(ldmState->window, chunkEnd)) { + if (ZSTD_window_needOverflowCorrection(ldmState->window, 0, maxDist, ldmState->loadedDictEnd, chunkStart, chunkEnd)) { U32 const ldmHSize = 1U << params->hashLog; U32 const correction = ZSTD_window_correctOverflow( &ldmState->window, /* cycleLog */ 0, maxDist, chunkStart); @@ -475,7 +558,7 @@ size_t ZSTD_ldm_generateSequences( * the window through early invalidation. * TODO: * Test the chunk size. * * Try invalidation after the sequence generation and test the - * the offset against maxDist directly. + * offset against maxDist directly. * * NOTE: Because of dictionaries + sequence splitting we MUST make sure * that any offset used is valid at the END of the sequence, since it may @@ -505,7 +588,9 @@ size_t ZSTD_ldm_generateSequences( return 0; } -void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch) { +void +ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch) +{ while (srcSize > 0 && rawSeqStore->pos < rawSeqStore->size) { rawSeq* seq = rawSeqStore->seq + rawSeqStore->pos; if (srcSize <= seq->litLength) { @@ -564,14 +649,32 @@ static rawSeq maybeSplitSequence(rawSeqStore_t* rawSeqStore, return sequence; } +void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes) { + U32 currPos = (U32)(rawSeqStore->posInSequence + nbBytes); + while (currPos && rawSeqStore->pos < rawSeqStore->size) { + rawSeq currSeq = rawSeqStore->seq[rawSeqStore->pos]; + if (currPos >= currSeq.litLength + currSeq.matchLength) { + currPos -= currSeq.litLength + currSeq.matchLength; + rawSeqStore->pos++; + } else { + rawSeqStore->posInSequence = currPos; + break; + } + } + if (currPos == 0 || rawSeqStore->pos == rawSeqStore->size) { + rawSeqStore->posInSequence = 0; + } +} + size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + ZSTD_paramSwitch_e useRowMatchFinder, void const* src, size_t srcSize) { const ZSTD_compressionParameters* const cParams = &ms->cParams; unsigned const minMatch = cParams->minMatch; ZSTD_blockCompressor const blockCompressor = - ZSTD_selectBlockCompressor(cParams->strategy, ZSTD_matchState_dictMode(ms)); + ZSTD_selectBlockCompressor(cParams->strategy, useRowMatchFinder, ZSTD_matchState_dictMode(ms)); /* Input bounds */ BYTE const* const istart = (BYTE const*)src; BYTE const* const iend = istart + srcSize; @@ -579,14 +682,22 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, BYTE const* ip = istart; DEBUGLOG(5, "ZSTD_ldm_blockCompress: srcSize=%zu", srcSize); + /* If using opt parser, use LDMs only as candidates rather than always accepting them */ + if (cParams->strategy >= ZSTD_btopt) { + size_t lastLLSize; + ms->ldmSeqStore = rawSeqStore; + lastLLSize = blockCompressor(ms, seqStore, rep, src, srcSize); + ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore, srcSize); + return lastLLSize; + } + assert(rawSeqStore->pos <= rawSeqStore->size); assert(rawSeqStore->size <= rawSeqStore->capacity); - /* Loop through each sequence and apply the block compressor to the lits */ + /* Loop through each sequence and apply the block compressor to the literals */ while (rawSeqStore->pos < rawSeqStore->size && ip < iend) { /* maybeSplitSequence updates rawSeqStore->pos */ rawSeq const sequence = maybeSplitSequence(rawSeqStore, (U32)(iend - ip), minMatch); - int i; /* End signal */ if (sequence.offset == 0) break; @@ -599,6 +710,7 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, /* Run the block compressor */ DEBUGLOG(5, "pos %u : calling block compressor on segment of size %u", (unsigned)(ip-istart), sequence.litLength); { + int i; size_t const newLitLength = blockCompressor(ms, seqStore, rep, ip, sequence.litLength); ip += sequence.litLength; @@ -608,8 +720,8 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, rep[0] = sequence.offset; /* Store the sequence */ ZSTD_storeSeq(seqStore, newLitLength, ip - newLitLength, iend, - sequence.offset + ZSTD_REP_MOVE, - sequence.matchLength - MINMATCH); + OFFSET_TO_OFFBASE(sequence.offset), + sequence.matchLength); ip += sequence.matchLength; } } @@ -620,4 +732,4 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, return blockCompressor(ms, seqStore, rep, ip, iend - ip); } -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/compress/zstd_opt.cpp b/src/duckdb/third_party/zstd/compress/zstd_opt.cpp index 09e9bff21..12cf55793 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_opt.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_opt.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -12,44 +12,54 @@ #include "zstd/compress/hist.h" #include "zstd/compress/zstd_opt.h" +namespace duckdb_zstd { + +#if !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR) #define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats */ -#define ZSTD_FREQ_DIV 4 /* log factor when using previous stats to init next stats */ #define ZSTD_MAX_PRICE (1<<30) -#define ZSTD_PREDEF_THRESHOLD 1024 /* if srcSize < ZSTD_PREDEF_THRESHOLD, symbols' cost is assumed static, directly determined by pre-defined distributions */ +#define ZSTD_PREDEF_THRESHOLD 8 /* if srcSize < ZSTD_PREDEF_THRESHOLD, symbols' cost is assumed static, directly determined by pre-defined distributions */ /*-************************************* * Price functions for optimal parser ***************************************/ -#if 0 /* approximation at bit level */ +#if 0 /* approximation at bit level (for tests) */ # define BITCOST_ACCURACY 0 # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) -# define WEIGHT(stat) ((void)opt, ZSTD_bitWeight(stat)) -#elif 0 /* fractional bit accuracy */ +# define WEIGHT(stat, opt) ((void)(opt), ZSTD_bitWeight(stat)) +#elif 0 /* fractional bit accuracy (for tests) */ # define BITCOST_ACCURACY 8 # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) -# define WEIGHT(stat,opt) ((void)opt, ZSTD_fracWeight(stat)) +# define WEIGHT(stat,opt) ((void)(opt), ZSTD_fracWeight(stat)) #else /* opt==approx, ultra==accurate */ # define BITCOST_ACCURACY 8 # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) -# define WEIGHT(stat,opt) (opt ? ZSTD_fracWeight(stat) : ZSTD_bitWeight(stat)) +# define WEIGHT(stat,opt) ((opt) ? ZSTD_fracWeight(stat) : ZSTD_bitWeight(stat)) #endif -namespace duckdb_zstd { - +/* ZSTD_bitWeight() : + * provide estimated "cost" of a stat in full bits only */ MEM_STATIC U32 ZSTD_bitWeight(U32 stat) { return (ZSTD_highbit32(stat+1) * BITCOST_MULTIPLIER); } +/* ZSTD_fracWeight() : + * provide fractional-bit "cost" of a stat, + * using linear interpolation approximation */ MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat) { U32 const stat = rawStat + 1; U32 const hb = ZSTD_highbit32(stat); U32 const BWeight = hb * BITCOST_MULTIPLIER; + /* Fweight was meant for "Fractional weight" + * but it's effectively a value between 1 and 2 + * using fixed point arithmetic */ U32 const FWeight = (stat << BITCOST_ACCURACY) >> hb; U32 const weight = BWeight + FWeight; assert(hb + BITCOST_ACCURACY < 31); @@ -60,7 +70,7 @@ MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat) /* debugging function, * @return price in bytes as fractional value * for debug messages only */ -MEM_STATIC double ZSTD_fCost(U32 price) +MEM_STATIC double ZSTD_fCost(int price) { return (double)price / (BITCOST_MULTIPLIER*8); } @@ -68,7 +78,7 @@ MEM_STATIC double ZSTD_fCost(U32 price) static int ZSTD_compressedLiterals(optState_t const* const optPtr) { - return optPtr->literalCompressionMode != ZSTD_lcm_uncompressed; + return optPtr->literalCompressionMode != ZSTD_ps_disable; } static void ZSTD_setBasePrices(optState_t* optPtr, int optLevel) @@ -81,25 +91,52 @@ static void ZSTD_setBasePrices(optState_t* optPtr, int optLevel) } -/* ZSTD_downscaleStat() : - * reduce all elements in table by a factor 2^(ZSTD_FREQ_DIV+malus) - * return the resulting sum of elements */ -static U32 ZSTD_downscaleStat(unsigned* table, U32 lastEltIndex, int malus) +static U32 sum_u32(const unsigned table[], size_t nbElts) +{ + size_t n; + U32 total = 0; + for (n=0; n 0 && ZSTD_FREQ_DIV+malus < 31); + DEBUGLOG(5, "ZSTD_downscaleStats (nbElts=%u, shift=%u)", + (unsigned)lastEltIndex+1, (unsigned)shift ); + assert(shift < 30); for (s=0; s> (ZSTD_FREQ_DIV+malus)); - sum += table[s]; + unsigned const base = base1 ? 1 : (table[s]>0); + unsigned const newStat = base + (table[s] >> shift); + sum += newStat; + table[s] = newStat; } return sum; } +/* ZSTD_scaleStats() : + * reduce all elt frequencies in table if sum too large + * return the resulting sum of elements */ +static U32 ZSTD_scaleStats(unsigned* table, U32 lastEltIndex, U32 logTarget) +{ + U32 const prevsum = sum_u32(table, lastEltIndex+1); + U32 const factor = prevsum >> logTarget; + DEBUGLOG(5, "ZSTD_scaleStats (nbElts=%u, target=%u)", (unsigned)lastEltIndex+1, (unsigned)logTarget); + assert(logTarget < 30); + if (factor <= 1) return prevsum; + return ZSTD_downscaleStats(table, lastEltIndex, ZSTD_highbit32(factor), base_1guaranteed); +} + /* ZSTD_rescaleFreqs() : * if first block (detected by optPtr->litLengthSum == 0) : init statistics * take hints from dictionary if there is one - * or init from zero, using src for literals stats, or flat 1 for match symbols + * and init from zero if there is none, + * using src for literals stats, and baseline stats for sequence symbols * otherwise downscale existing stats, to be used as seed for next block. */ static void @@ -111,24 +148,28 @@ ZSTD_rescaleFreqs(optState_t* const optPtr, DEBUGLOG(5, "ZSTD_rescaleFreqs (srcSize=%u)", (unsigned)srcSize); optPtr->priceType = zop_dynamic; - if (optPtr->litLengthSum == 0) { /* first block : init */ - if (srcSize <= ZSTD_PREDEF_THRESHOLD) { /* heuristic */ - DEBUGLOG(5, "(srcSize <= ZSTD_PREDEF_THRESHOLD) => zop_predef"); + if (optPtr->litLengthSum == 0) { /* no literals stats collected -> first block assumed -> init */ + + /* heuristic: use pre-defined stats for too small inputs */ + if (srcSize <= ZSTD_PREDEF_THRESHOLD) { + DEBUGLOG(5, "srcSize <= %i : use predefined stats", ZSTD_PREDEF_THRESHOLD); optPtr->priceType = zop_predef; } assert(optPtr->symbolCosts != NULL); if (optPtr->symbolCosts->huf.repeatMode == HUF_repeat_valid) { - /* huffman table presumed generated by dictionary */ + + /* huffman stats covering the full value set : table presumed generated by dictionary */ optPtr->priceType = zop_dynamic; if (compressedLiterals) { + /* generate literals statistics from huffman table */ unsigned lit; assert(optPtr->litFreq != NULL); optPtr->litSum = 0; for (lit=0; lit<=MaxLit; lit++) { U32 const scaleLog = 11; /* scale to 2K */ - U32 const bitCost = HUF_getNbBits(optPtr->symbolCosts->huf.CTable, lit); + U32 const bitCost = HUF_getNbBitsFromCTable(optPtr->symbolCosts->huf.CTable, lit); assert(bitCost <= scaleLog); optPtr->litFreq[lit] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/; optPtr->litSum += optPtr->litFreq[lit]; @@ -170,20 +211,26 @@ ZSTD_rescaleFreqs(optState_t* const optPtr, optPtr->offCodeSum += optPtr->offCodeFreq[of]; } } - } else { /* not a dictionary */ + } else { /* first block, no dictionary */ assert(optPtr->litFreq != NULL); if (compressedLiterals) { + /* base initial cost of literals on direct frequency within src */ unsigned lit = MaxLit; HIST_count_simple(optPtr->litFreq, &lit, src, srcSize); /* use raw first block to init statistics */ - optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1); + optPtr->litSum = ZSTD_downscaleStats(optPtr->litFreq, MaxLit, 8, base_0possible); } - { unsigned ll; - for (ll=0; ll<=MaxLL; ll++) - optPtr->litLengthFreq[ll] = 1; + { unsigned const baseLLfreqs[MaxLL+1] = { + 4, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1 + }; + ZSTD_memcpy(optPtr->litLengthFreq, baseLLfreqs, sizeof(baseLLfreqs)); + optPtr->litLengthSum = sum_u32(baseLLfreqs, MaxLL+1); } - optPtr->litLengthSum = MaxLL+1; { unsigned ml; for (ml=0; ml<=MaxML; ml++) @@ -191,21 +238,25 @@ ZSTD_rescaleFreqs(optState_t* const optPtr, } optPtr->matchLengthSum = MaxML+1; - { unsigned of; - for (of=0; of<=MaxOff; of++) - optPtr->offCodeFreq[of] = 1; + { unsigned const baseOFCfreqs[MaxOff+1] = { + 6, 2, 1, 1, 2, 3, 4, 4, + 4, 3, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1 + }; + ZSTD_memcpy(optPtr->offCodeFreq, baseOFCfreqs, sizeof(baseOFCfreqs)); + optPtr->offCodeSum = sum_u32(baseOFCfreqs, MaxOff+1); } - optPtr->offCodeSum = MaxOff+1; } - } else { /* new block : re-use previous statistics, scaled down */ + } else { /* new block : scale down accumulated statistics */ if (compressedLiterals) - optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1); - optPtr->litLengthSum = ZSTD_downscaleStat(optPtr->litLengthFreq, MaxLL, 0); - optPtr->matchLengthSum = ZSTD_downscaleStat(optPtr->matchLengthFreq, MaxML, 0); - optPtr->offCodeSum = ZSTD_downscaleStat(optPtr->offCodeFreq, MaxOff, 0); + optPtr->litSum = ZSTD_scaleStats(optPtr->litFreq, MaxLit, 12); + optPtr->litLengthSum = ZSTD_scaleStats(optPtr->litLengthFreq, MaxLL, 11); + optPtr->matchLengthSum = ZSTD_scaleStats(optPtr->matchLengthFreq, MaxML, 11); + optPtr->offCodeSum = ZSTD_scaleStats(optPtr->offCodeFreq, MaxOff, 11); } ZSTD_setBasePrices(optPtr, optLevel); @@ -218,6 +269,7 @@ static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength, const optState_t* const optPtr, int optLevel) { + DEBUGLOG(8, "ZSTD_rawLiteralsCost (%u literals)", litLength); if (litLength == 0) return 0; if (!ZSTD_compressedLiterals(optPtr)) @@ -227,11 +279,14 @@ static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength, return (litLength*6) * BITCOST_MULTIPLIER; /* 6 bit per literal - no statistic used */ /* dynamic statistics */ - { U32 price = litLength * optPtr->litSumBasePrice; + { U32 price = optPtr->litSumBasePrice * litLength; + U32 const litPriceMax = optPtr->litSumBasePrice - BITCOST_MULTIPLIER; U32 u; + assert(optPtr->litSumBasePrice >= BITCOST_MULTIPLIER); for (u=0; u < litLength; u++) { - assert(WEIGHT(optPtr->litFreq[literals[u]], optLevel) <= optPtr->litSumBasePrice); /* literal cost should never be negative */ - price -= WEIGHT(optPtr->litFreq[literals[u]], optLevel); + U32 litPrice = WEIGHT(optPtr->litFreq[literals[u]], optLevel); + if (UNLIKELY(litPrice > litPriceMax)) litPrice = litPriceMax; + price -= litPrice; } return price; } @@ -241,33 +296,46 @@ static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength, * cost of literalLength symbol */ static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr, int optLevel) { - if (optPtr->priceType == zop_predef) return WEIGHT(litLength, optLevel); + assert(litLength <= ZSTD_BLOCKSIZE_MAX); + if (optPtr->priceType == zop_predef) + return WEIGHT(litLength, optLevel); + + /* ZSTD_LLcode() can't compute litLength price for sizes >= ZSTD_BLOCKSIZE_MAX + * because it isn't representable in the zstd format. + * So instead just pretend it would cost 1 bit more than ZSTD_BLOCKSIZE_MAX - 1. + * In such a case, the block would be all literals. + */ + if (litLength == ZSTD_BLOCKSIZE_MAX) + return BITCOST_MULTIPLIER + ZSTD_litLengthPrice(ZSTD_BLOCKSIZE_MAX - 1, optPtr, optLevel); /* dynamic statistics */ { U32 const llCode = ZSTD_LLcode(litLength); - return (ZSTDInternalConstants::LL_bits[llCode] * BITCOST_MULTIPLIER) + return (LL_bits[llCode] * BITCOST_MULTIPLIER) + optPtr->litLengthSumBasePrice - WEIGHT(optPtr->litLengthFreq[llCode], optLevel); } } /* ZSTD_getMatchPrice() : - * Provides the cost of the match part (offset + matchLength) of a sequence + * Provides the cost of the match part (offset + matchLength) of a sequence. * Must be combined with ZSTD_fullLiteralsCost() to get the full cost of a sequence. - * optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) */ + * @offBase : sumtype, representing an offset or a repcode, and using numeric representation of ZSTD_storeSeq() + * @optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) + */ FORCE_INLINE_TEMPLATE U32 -ZSTD_getMatchPrice(U32 const offset, +ZSTD_getMatchPrice(U32 const offBase, U32 const matchLength, const optState_t* const optPtr, int const optLevel) { U32 price; - U32 const offCode = ZSTD_highbit32(offset+1); + U32 const offCode = ZSTD_highbit32(offBase); U32 const mlBase = matchLength - MINMATCH; assert(matchLength >= MINMATCH); - if (optPtr->priceType == zop_predef) /* fixed scheme, do not use statistics */ - return WEIGHT(mlBase, optLevel) + ((16 + offCode) * BITCOST_MULTIPLIER); + if (optPtr->priceType == zop_predef) /* fixed scheme, does not use statistics */ + return WEIGHT(mlBase, optLevel) + + ((16 + offCode) * BITCOST_MULTIPLIER); /* emulated offset cost */ /* dynamic statistics */ price = (offCode * BITCOST_MULTIPLIER) + (optPtr->offCodeSumBasePrice - WEIGHT(optPtr->offCodeFreq[offCode], optLevel)); @@ -276,7 +344,7 @@ ZSTD_getMatchPrice(U32 const offset, /* match Length */ { U32 const mlCode = ZSTD_MLcode(mlBase); - price += (ZSTDInternalConstants::ML_bits[mlCode] * BITCOST_MULTIPLIER) + (optPtr->matchLengthSumBasePrice - WEIGHT(optPtr->matchLengthFreq[mlCode], optLevel)); + price += (ML_bits[mlCode] * BITCOST_MULTIPLIER) + (optPtr->matchLengthSumBasePrice - WEIGHT(optPtr->matchLengthFreq[mlCode], optLevel)); } price += BITCOST_MULTIPLIER / 5; /* heuristic : make matches a bit more costly to favor less sequences -> faster decompression speed */ @@ -286,10 +354,10 @@ ZSTD_getMatchPrice(U32 const offset, } /* ZSTD_updateStats() : - * assumption : literals + litLengtn <= iend */ + * assumption : literals + litLength <= iend */ static void ZSTD_updateStats(optState_t* const optPtr, U32 litLength, const BYTE* literals, - U32 offsetCode, U32 matchLength) + U32 offBase, U32 matchLength) { /* literals */ if (ZSTD_compressedLiterals(optPtr)) { @@ -305,8 +373,8 @@ static void ZSTD_updateStats(optState_t* const optPtr, optPtr->litLengthSum++; } - /* match offset code (0-2=>repCode; 3+=>offset+2) */ - { U32 const offCode = ZSTD_highbit32(offsetCode+1); + /* offset code : follows storeSeq() numeric representation */ + { U32 const offCode = ZSTD_highbit32(offBase); assert(offCode <= MaxOff); optPtr->offCodeFreq[offCode]++; optPtr->offCodeSum++; @@ -340,9 +408,11 @@ MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length) /* Update hashTable3 up to ip (excluded) Assumption : always within prefix (i.e. not within extDict) */ -static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms, - U32* nextToUpdate3, - const BYTE* const ip) +static +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +U32 ZSTD_insertAndFindFirstIndexHash3 (const ZSTD_matchState_t* ms, + U32* nextToUpdate3, + const BYTE* const ip) { U32* const hashTable3 = ms->hashTable3; U32 const hashLog3 = ms->hashLog3; @@ -366,11 +436,15 @@ static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms, * Binary Tree search ***************************************/ /** ZSTD_insertBt1() : add one or multiple positions to tree. - * ip : assumed <= iend-8 . + * @param ip assumed <= iend-8 . + * @param target The target of ZSTD_updateTree_internal() - we are filling to this position * @return : nb of positions added */ -static U32 ZSTD_insertBt1( - ZSTD_matchState_t* ms, +static +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +U32 ZSTD_insertBt1( + const ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iend, + U32 const target, U32 const mls, const int extDict) { const ZSTD_compressionParameters* const cParams = &ms->cParams; @@ -388,32 +462,36 @@ static U32 ZSTD_insertBt1( const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* match; - const U32 current = (U32)(ip-base); - const U32 btLow = btMask >= current ? 0 : current - btMask; - U32* smallerPtr = bt + 2*(current&btMask); + const U32 curr = (U32)(ip-base); + const U32 btLow = btMask >= curr ? 0 : curr - btMask; + U32* smallerPtr = bt + 2*(curr&btMask); U32* largerPtr = smallerPtr + 1; U32 dummy32; /* to be nullified at the end */ - U32 const windowLow = ms->window.lowLimit; - U32 matchEndIdx = current+8+1; + /* windowLow is based on target because + * we only need positions that will be in the window at the end of the tree update. + */ + U32 const windowLow = ZSTD_getLowestMatchIndex(ms, target, cParams->windowLog); + U32 matchEndIdx = curr+8+1; size_t bestLength = 8; U32 nbCompares = 1U << cParams->searchLog; #ifdef ZSTD_C_PREDICT - U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0); - U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1); + U32 predictedSmall = *(bt + 2*((curr-1)&btMask) + 0); + U32 predictedLarge = *(bt + 2*((curr-1)&btMask) + 1); predictedSmall += (predictedSmall>0); predictedLarge += (predictedLarge>0); #endif /* ZSTD_C_PREDICT */ - DEBUGLOG(8, "ZSTD_insertBt1 (%u)", current); + DEBUGLOG(8, "ZSTD_insertBt1 (%u)", curr); + assert(curr <= target); assert(ip <= iend-8); /* required for h calculation */ - hashTable[h] = current; /* Update Hash Table */ + hashTable[h] = curr; /* Update Hash Table */ assert(windowLow > 0); - while (nbCompares-- && (matchIndex >= windowLow)) { + for (; nbCompares && (matchIndex >= windowLow); --nbCompares) { U32* const nextPtr = bt + 2*(matchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ - assert(matchIndex < current); + assert(matchIndex < curr); #ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */ const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */ @@ -476,12 +554,13 @@ static U32 ZSTD_insertBt1( *smallerPtr = *largerPtr = 0; { U32 positions = 0; if (bestLength > 384) positions = MIN(192, (U32)(bestLength - 384)); /* speed optimization */ - assert(matchEndIdx > current + 8); - return MAX(positions, matchEndIdx - (current + 8)); + assert(matchEndIdx > curr + 8); + return MAX(positions, matchEndIdx - (curr + 8)); } } FORCE_INLINE_TEMPLATE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR void ZSTD_updateTree_internal( ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iend, @@ -490,11 +569,11 @@ void ZSTD_updateTree_internal( const BYTE* const base = ms->window.base; U32 const target = (U32)(ip - base); U32 idx = ms->nextToUpdate; - DEBUGLOG(6, "ZSTD_updateTree_internal, from %u to %u (dictMode:%u)", + DEBUGLOG(7, "ZSTD_updateTree_internal, from %u to %u (dictMode:%u)", idx, target, dictMode); while(idx < target) { - U32 const forward = ZSTD_insertBt1(ms, base+idx, iend, mls, dictMode == ZSTD_extDict); + U32 const forward = ZSTD_insertBt1(ms, base+idx, iend, target, mls, dictMode == ZSTD_extDict); assert(idx < (U32)(idx + forward)); idx += forward; } @@ -508,20 +587,23 @@ void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend) { } FORCE_INLINE_TEMPLATE -U32 ZSTD_insertBtAndGetAllMatches ( - ZSTD_match_t* matches, /* store result (found matches) in this table (presumed large enough) */ - ZSTD_matchState_t* ms, - U32* nextToUpdate3, - const BYTE* const ip, const BYTE* const iLimit, const ZSTD_dictMode_e dictMode, - const U32 rep[ZSTD_REP_NUM], - U32 const ll0, /* tells if associated literal length is 0 or not. This value must be 0 or 1 */ - const U32 lengthToBeat, - U32 const mls /* template */) +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +U32 +ZSTD_insertBtAndGetAllMatches ( + ZSTD_match_t* matches, /* store result (found matches) in this table (presumed large enough) */ + ZSTD_matchState_t* ms, + U32* nextToUpdate3, + const BYTE* const ip, const BYTE* const iLimit, + const ZSTD_dictMode_e dictMode, + const U32 rep[ZSTD_REP_NUM], + const U32 ll0, /* tells if associated literal length is 0 or not. This value must be 0 or 1 */ + const U32 lengthToBeat, + const U32 mls /* template */) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1); const BYTE* const base = ms->window.base; - U32 const current = (U32)(ip-base); + U32 const curr = (U32)(ip-base); U32 const hashLog = cParams->hashLog; U32 const minMatch = (mls==3) ? 3 : 4; U32* const hashTable = ms->hashTable; @@ -535,12 +617,12 @@ U32 ZSTD_insertBtAndGetAllMatches ( U32 const dictLimit = ms->window.dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; - U32 const btLow = (btMask >= current) ? 0 : current - btMask; - U32 const windowLow = ZSTD_getLowestMatchIndex(ms, current, cParams->windowLog); + U32 const btLow = (btMask >= curr) ? 0 : curr - btMask; + U32 const windowLow = ZSTD_getLowestMatchIndex(ms, curr, cParams->windowLog); U32 const matchLow = windowLow ? windowLow : 1; - U32* smallerPtr = bt + 2*(current&btMask); - U32* largerPtr = bt + 2*(current&btMask) + 1; - U32 matchEndIdx = current+8+1; /* farthest referenced position of any match => detects repetitive patterns */ + U32* smallerPtr = bt + 2*(curr&btMask); + U32* largerPtr = bt + 2*(curr&btMask) + 1; + U32 matchEndIdx = curr+8+1; /* farthest referenced position of any match => detects repetitive patterns */ U32 dummy32; /* to be nullified at the end */ U32 mnum = 0; U32 nbCompares = 1U << cParams->searchLog; @@ -559,7 +641,7 @@ U32 ZSTD_insertBtAndGetAllMatches ( U32 const dmsBtLow = dictMode == ZSTD_dictMatchState && dmsBtMask < dmsHighLimit - dmsLowLimit ? dmsHighLimit - dmsBtMask : dmsLowLimit; size_t bestLength = lengthToBeat-1; - DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", current); + DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", curr); /* check repCode */ assert(ll0 <= 1); /* necessarily 1 or 0 */ @@ -567,29 +649,29 @@ U32 ZSTD_insertBtAndGetAllMatches ( U32 repCode; for (repCode = ll0; repCode < lastR; repCode++) { U32 const repOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; - U32 const repIndex = current - repOffset; + U32 const repIndex = curr - repOffset; U32 repLen = 0; - assert(current >= dictLimit); - if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < current-dictLimit) { /* equivalent to `current > repIndex >= dictLimit` */ + assert(curr >= dictLimit); + if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < curr-dictLimit) { /* equivalent to `curr > repIndex >= dictLimit` */ /* We must validate the repcode offset because when we're using a dictionary the * valid offset range shrinks when the dictionary goes out of bounds. */ if ((repIndex >= windowLow) & (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch))) { repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch; } - } else { /* repIndex < dictLimit || repIndex >= current */ + } else { /* repIndex < dictLimit || repIndex >= curr */ const BYTE* const repMatch = dictMode == ZSTD_dictMatchState ? dmsBase + repIndex - dmsIndexDelta : dictBase + repIndex; - assert(current >= windowLow); + assert(curr >= windowLow); if ( dictMode == ZSTD_extDict - && ( ((repOffset-1) /*intentional overflow*/ < current - windowLow) /* equivalent to `current > repIndex >= windowLow` */ + && ( ((repOffset-1) /*intentional overflow*/ < curr - windowLow) /* equivalent to `curr > repIndex >= windowLow` */ & (((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */) && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) { repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dictEnd, prefixStart) + minMatch; } if (dictMode == ZSTD_dictMatchState - && ( ((repOffset-1) /*intentional overflow*/ < current - (dmsLowLimit + dmsIndexDelta)) /* equivalent to `current > repIndex >= dmsLowLimit` */ + && ( ((repOffset-1) /*intentional overflow*/ < curr - (dmsLowLimit + dmsIndexDelta)) /* equivalent to `curr > repIndex >= dmsLowLimit` */ & ((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */ && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) { repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dmsEnd, prefixStart) + minMatch; @@ -599,7 +681,7 @@ U32 ZSTD_insertBtAndGetAllMatches ( DEBUGLOG(8, "found repCode %u (ll0:%u, offset:%u) of length %u", repCode, ll0, repOffset, repLen); bestLength = repLen; - matches[mnum].off = repCode - ll0; + matches[mnum].off = REPCODE_TO_OFFBASE(repCode - ll0 + 1); /* expect value between 1 and 3 */ matches[mnum].len = (U32)repLen; mnum++; if ( (repLen > sufficient_len) @@ -611,7 +693,7 @@ U32 ZSTD_insertBtAndGetAllMatches ( if ((mls == 3) /*static*/ && (bestLength < mls)) { U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, nextToUpdate3, ip); if ((matchIndex3 >= matchLow) - & (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) { + & (curr - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) { size_t mlen; if ((dictMode == ZSTD_noDict) /*static*/ || (dictMode == ZSTD_dictMatchState) /*static*/ || (matchIndex3 >= dictLimit)) { const BYTE* const match = base + matchIndex3; @@ -626,26 +708,26 @@ U32 ZSTD_insertBtAndGetAllMatches ( DEBUGLOG(8, "found small match with hlog3, of length %u", (U32)mlen); bestLength = mlen; - assert(current > matchIndex3); + assert(curr > matchIndex3); assert(mnum==0); /* no prior solution */ - matches[0].off = (current - matchIndex3) + ZSTD_REP_MOVE; + matches[0].off = OFFSET_TO_OFFBASE(curr - matchIndex3); matches[0].len = (U32)mlen; mnum = 1; if ( (mlen > sufficient_len) | (ip+mlen == iLimit) ) { /* best possible length */ - ms->nextToUpdate = current+1; /* skip insertion */ + ms->nextToUpdate = curr+1; /* skip insertion */ return 1; } } } /* no dictMatchState lookup: dicts don't have a populated HC3 table */ - } + } /* if (mls == 3) */ - hashTable[h] = current; /* Update Hash Table */ + hashTable[h] = curr; /* Update Hash Table */ - while (nbCompares-- && (matchIndex >= matchLow)) { + for (; nbCompares && (matchIndex >= matchLow); --nbCompares) { U32* const nextPtr = bt + 2*(matchIndex & btMask); const BYTE* match; size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ - assert(current > matchIndex); + assert(curr > matchIndex); if ((dictMode == ZSTD_noDict) || (dictMode == ZSTD_dictMatchState) || (matchIndex+matchLength >= dictLimit)) { assert(matchIndex+matchLength >= dictLimit); /* ensure the condition is correct when !extDict */ @@ -661,21 +743,20 @@ U32 ZSTD_insertBtAndGetAllMatches ( } if (matchLength > bestLength) { - DEBUGLOG(8, "found match of length %u at distance %u (offCode=%u)", - (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE); + DEBUGLOG(8, "found match of length %u at distance %u (offBase=%u)", + (U32)matchLength, curr - matchIndex, OFFSET_TO_OFFBASE(curr - matchIndex)); assert(matchEndIdx > matchIndex); if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; bestLength = matchLength; - matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE; + matches[mnum].off = OFFSET_TO_OFFBASE(curr - matchIndex); matches[mnum].len = (U32)matchLength; mnum++; if ( (matchLength > ZSTD_OPT_NUM) | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) { if (dictMode == ZSTD_dictMatchState) nbCompares = 0; /* break should also skip searching dms */ break; /* drop, to preserve bt consistency (miss a little bit of compression) */ - } - } + } } if (match[matchLength] < ip[matchLength]) { /* match smaller than current */ @@ -694,12 +775,13 @@ U32 ZSTD_insertBtAndGetAllMatches ( *smallerPtr = *largerPtr = 0; + assert(nbCompares <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */ if (dictMode == ZSTD_dictMatchState && nbCompares) { size_t const dmsH = ZSTD_hashPtr(ip, dmsHashLog, mls); U32 dictMatchIndex = dms->hashTable[dmsH]; const U32* const dmsBt = dms->chainTable; commonLengthSmaller = commonLengthLarger = 0; - while (nbCompares-- && (dictMatchIndex > dmsLowLimit)) { + for (; nbCompares && (dictMatchIndex > dmsLowLimit); --nbCompares) { const U32* const nextPtr = dmsBt + 2*(dictMatchIndex & dmsBtMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ const BYTE* match = dmsBase + dictMatchIndex; @@ -709,19 +791,18 @@ U32 ZSTD_insertBtAndGetAllMatches ( if (matchLength > bestLength) { matchIndex = dictMatchIndex + dmsIndexDelta; - DEBUGLOG(8, "found dms match of length %u at distance %u (offCode=%u)", - (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE); + DEBUGLOG(8, "found dms match of length %u at distance %u (offBase=%u)", + (U32)matchLength, curr - matchIndex, OFFSET_TO_OFFBASE(curr - matchIndex)); if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; bestLength = matchLength; - matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE; + matches[mnum].off = OFFSET_TO_OFFBASE(curr - matchIndex); matches[mnum].len = (U32)matchLength; mnum++; if ( (matchLength > ZSTD_OPT_NUM) | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) { break; /* drop, to guarantee consistency (miss a little bit of compression) */ - } - } + } } if (dictMatchIndex <= dmsBtLow) { break; } /* beyond tree size, stop the search */ if (match[matchLength] < ip[matchLength]) { @@ -731,52 +812,244 @@ U32 ZSTD_insertBtAndGetAllMatches ( /* match is larger than current */ commonLengthLarger = matchLength; dictMatchIndex = nextPtr[0]; - } - } - } + } } } /* if (dictMode == ZSTD_dictMatchState) */ - assert(matchEndIdx > current+8); + assert(matchEndIdx > curr+8); ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */ return mnum; } +typedef U32 (*ZSTD_getAllMatchesFn)( + ZSTD_match_t*, + ZSTD_matchState_t*, + U32*, + const BYTE*, + const BYTE*, + const U32 rep[ZSTD_REP_NUM], + U32 const ll0, + U32 const lengthToBeat); -FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches ( - ZSTD_match_t* matches, /* store result (match found, increasing size) in this table */ - ZSTD_matchState_t* ms, - U32* nextToUpdate3, - const BYTE* ip, const BYTE* const iHighLimit, const ZSTD_dictMode_e dictMode, - const U32 rep[ZSTD_REP_NUM], - U32 const ll0, - U32 const lengthToBeat) +FORCE_INLINE_TEMPLATE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +U32 ZSTD_btGetAllMatches_internal( + ZSTD_match_t* matches, + ZSTD_matchState_t* ms, + U32* nextToUpdate3, + const BYTE* ip, + const BYTE* const iHighLimit, + const U32 rep[ZSTD_REP_NUM], + U32 const ll0, + U32 const lengthToBeat, + const ZSTD_dictMode_e dictMode, + const U32 mls) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; - U32 const matchLengthSearch = cParams->minMatch; - DEBUGLOG(8, "ZSTD_BtGetAllMatches"); - if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */ - ZSTD_updateTree_internal(ms, ip, iHighLimit, matchLengthSearch, dictMode); - switch(matchLengthSearch) - { - case 3 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 3); - default : - case 4 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 4); - case 5 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 5); - case 7 : - case 6 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 6); + assert(BOUNDED(3, ms->cParams.minMatch, 6) == mls); + DEBUGLOG(8, "ZSTD_BtGetAllMatches(dictMode=%d, mls=%u)", (int)dictMode, mls); + if (ip < ms->window.base + ms->nextToUpdate) + return 0; /* skipped area */ + ZSTD_updateTree_internal(ms, ip, iHighLimit, mls, dictMode); + return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, mls); +} + +#define ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, mls) ZSTD_btGetAllMatches_##dictMode##_##mls + +#define GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, mls) \ + static U32 ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, mls)( \ + ZSTD_match_t* matches, \ + ZSTD_matchState_t* ms, \ + U32* nextToUpdate3, \ + const BYTE* ip, \ + const BYTE* const iHighLimit, \ + const U32 rep[ZSTD_REP_NUM], \ + U32 const ll0, \ + U32 const lengthToBeat) \ + { \ + return ZSTD_btGetAllMatches_internal( \ + matches, ms, nextToUpdate3, ip, iHighLimit, \ + rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \ + } + +#define GEN_ZSTD_BT_GET_ALL_MATCHES(dictMode) \ + GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 3) \ + GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 4) \ + GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 5) \ + GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 6) + +GEN_ZSTD_BT_GET_ALL_MATCHES(noDict) +GEN_ZSTD_BT_GET_ALL_MATCHES(extDict) +GEN_ZSTD_BT_GET_ALL_MATCHES(dictMatchState) + +#define ZSTD_BT_GET_ALL_MATCHES_ARRAY(dictMode) \ + { \ + ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 3), \ + ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 4), \ + ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 5), \ + ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 6) \ + } + +static ZSTD_getAllMatchesFn +ZSTD_selectBtGetAllMatches(ZSTD_matchState_t const* ms, ZSTD_dictMode_e const dictMode) +{ + ZSTD_getAllMatchesFn const getAllMatchesFns[3][4] = { + ZSTD_BT_GET_ALL_MATCHES_ARRAY(noDict), + ZSTD_BT_GET_ALL_MATCHES_ARRAY(extDict), + ZSTD_BT_GET_ALL_MATCHES_ARRAY(dictMatchState) + }; + U32 const mls = BOUNDED(3, ms->cParams.minMatch, 6); + assert((U32)dictMode < 3); + assert(mls - 3 < 4); + return getAllMatchesFns[(int)dictMode][mls - 3]; +} + +/************************* +* LDM helper functions * +*************************/ + +/* Struct containing info needed to make decision about ldm inclusion */ +typedef struct { + rawSeqStore_t seqStore; /* External match candidates store for this block */ + U32 startPosInBlock; /* Start position of the current match candidate */ + U32 endPosInBlock; /* End position of the current match candidate */ + U32 offset; /* Offset of the match candidate */ +} ZSTD_optLdm_t; + +/* ZSTD_optLdm_skipRawSeqStoreBytes(): + * Moves forward in @rawSeqStore by @nbBytes, + * which will update the fields 'pos' and 'posInSequence'. + */ +static void ZSTD_optLdm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes) +{ + U32 currPos = (U32)(rawSeqStore->posInSequence + nbBytes); + while (currPos && rawSeqStore->pos < rawSeqStore->size) { + rawSeq currSeq = rawSeqStore->seq[rawSeqStore->pos]; + if (currPos >= currSeq.litLength + currSeq.matchLength) { + currPos -= currSeq.litLength + currSeq.matchLength; + rawSeqStore->pos++; + } else { + rawSeqStore->posInSequence = currPos; + break; + } + } + if (currPos == 0 || rawSeqStore->pos == rawSeqStore->size) { + rawSeqStore->posInSequence = 0; } } +/* ZSTD_opt_getNextMatchAndUpdateSeqStore(): + * Calculates the beginning and end of the next match in the current block. + * Updates 'pos' and 'posInSequence' of the ldmSeqStore. + */ +static void +ZSTD_opt_getNextMatchAndUpdateSeqStore(ZSTD_optLdm_t* optLdm, U32 currPosInBlock, + U32 blockBytesRemaining) +{ + rawSeq currSeq; + U32 currBlockEndPos; + U32 literalsBytesRemaining; + U32 matchBytesRemaining; + + /* Setting match end position to MAX to ensure we never use an LDM during this block */ + if (optLdm->seqStore.size == 0 || optLdm->seqStore.pos >= optLdm->seqStore.size) { + optLdm->startPosInBlock = UINT_MAX; + optLdm->endPosInBlock = UINT_MAX; + return; + } + /* Calculate appropriate bytes left in matchLength and litLength + * after adjusting based on ldmSeqStore->posInSequence */ + currSeq = optLdm->seqStore.seq[optLdm->seqStore.pos]; + assert(optLdm->seqStore.posInSequence <= currSeq.litLength + currSeq.matchLength); + currBlockEndPos = currPosInBlock + blockBytesRemaining; + literalsBytesRemaining = (optLdm->seqStore.posInSequence < currSeq.litLength) ? + currSeq.litLength - (U32)optLdm->seqStore.posInSequence : + 0; + matchBytesRemaining = (literalsBytesRemaining == 0) ? + currSeq.matchLength - ((U32)optLdm->seqStore.posInSequence - currSeq.litLength) : + currSeq.matchLength; + + /* If there are more literal bytes than bytes remaining in block, no ldm is possible */ + if (literalsBytesRemaining >= blockBytesRemaining) { + optLdm->startPosInBlock = UINT_MAX; + optLdm->endPosInBlock = UINT_MAX; + ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, blockBytesRemaining); + return; + } -/*-******************************* -* Optimal parser -*********************************/ + /* Matches may be < MINMATCH by this process. In that case, we will reject them + when we are deciding whether or not to add the ldm */ + optLdm->startPosInBlock = currPosInBlock + literalsBytesRemaining; + optLdm->endPosInBlock = optLdm->startPosInBlock + matchBytesRemaining; + optLdm->offset = currSeq.offset; + + if (optLdm->endPosInBlock > currBlockEndPos) { + /* Match ends after the block ends, we can't use the whole match */ + optLdm->endPosInBlock = currBlockEndPos; + ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, currBlockEndPos - currPosInBlock); + } else { + /* Consume nb of bytes equal to size of sequence left */ + ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, literalsBytesRemaining + matchBytesRemaining); + } +} + +/* ZSTD_optLdm_maybeAddMatch(): + * Adds a match if it's long enough, + * based on it's 'matchStartPosInBlock' and 'matchEndPosInBlock', + * into 'matches'. Maintains the correct ordering of 'matches'. + */ +static void ZSTD_optLdm_maybeAddMatch(ZSTD_match_t* matches, U32* nbMatches, + const ZSTD_optLdm_t* optLdm, U32 currPosInBlock) +{ + U32 const posDiff = currPosInBlock - optLdm->startPosInBlock; + /* Note: ZSTD_match_t actually contains offBase and matchLength (before subtracting MINMATCH) */ + U32 const candidateMatchLength = optLdm->endPosInBlock - optLdm->startPosInBlock - posDiff; + + /* Ensure that current block position is not outside of the match */ + if (currPosInBlock < optLdm->startPosInBlock + || currPosInBlock >= optLdm->endPosInBlock + || candidateMatchLength < MINMATCH) { + return; + } + if (*nbMatches == 0 || ((candidateMatchLength > matches[*nbMatches-1].len) && *nbMatches < ZSTD_OPT_NUM)) { + U32 const candidateOffBase = OFFSET_TO_OFFBASE(optLdm->offset); + DEBUGLOG(6, "ZSTD_optLdm_maybeAddMatch(): Adding ldm candidate match (offBase: %u matchLength %u) at block position=%u", + candidateOffBase, candidateMatchLength, currPosInBlock); + matches[*nbMatches].len = candidateMatchLength; + matches[*nbMatches].off = candidateOffBase; + (*nbMatches)++; + } +} -static U32 ZSTD_totalLen(ZSTD_optimal_t sol) +/* ZSTD_optLdm_processMatchCandidate(): + * Wrapper function to update ldm seq store and call ldm functions as necessary. + */ +static void +ZSTD_optLdm_processMatchCandidate(ZSTD_optLdm_t* optLdm, + ZSTD_match_t* matches, U32* nbMatches, + U32 currPosInBlock, U32 remainingBytes) { - return sol.litlen + sol.mlen; + if (optLdm->seqStore.size == 0 || optLdm->seqStore.pos >= optLdm->seqStore.size) { + return; + } + + if (currPosInBlock >= optLdm->endPosInBlock) { + if (currPosInBlock > optLdm->endPosInBlock) { + /* The position at which ZSTD_optLdm_processMatchCandidate() is called is not necessarily + * at the end of a match from the ldm seq store, and will often be some bytes + * over beyond matchEndPosInBlock. As such, we need to correct for these "overshoots" + */ + U32 const posOvershoot = currPosInBlock - optLdm->endPosInBlock; + ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, posOvershoot); + } + ZSTD_opt_getNextMatchAndUpdateSeqStore(optLdm, currPosInBlock, remainingBytes); + } + ZSTD_optLdm_maybeAddMatch(matches, nbMatches, optLdm, currPosInBlock); } + +/*-******************************* +* Optimal parser +*********************************/ + #if 0 /* debug */ static void @@ -794,7 +1067,13 @@ listStats(const U32* table, int lastEltID) #endif -FORCE_INLINE_TEMPLATE size_t +#define LIT_PRICE(_p) (int)ZSTD_rawLiteralsCost(_p, 1, optStatePtr, optLevel) +#define LL_PRICE(_l) (int)ZSTD_litLengthPrice(_l, optStatePtr, optLevel) +#define LL_INCPRICE(_l) (LL_PRICE(_l) - LL_PRICE(_l-1)) + +FORCE_INLINE_TEMPLATE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +size_t ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -812,13 +1091,22 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, const BYTE* const prefixStart = base + ms->window.dictLimit; const ZSTD_compressionParameters* const cParams = &ms->cParams; + ZSTD_getAllMatchesFn getAllMatches = ZSTD_selectBtGetAllMatches(ms, dictMode); + U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1); U32 const minMatch = (cParams->minMatch == 3) ? 3 : 4; U32 nextToUpdate3 = ms->nextToUpdate; ZSTD_optimal_t* const opt = optStatePtr->priceTable; ZSTD_match_t* const matches = optStatePtr->matchTable; - ZSTD_optimal_t lastSequence; + ZSTD_optimal_t lastStretch; + ZSTD_optLdm_t optLdm; + + ZSTD_memset(&lastStretch, 0, sizeof(ZSTD_optimal_t)); + + optLdm.seqStore = ms->ldmSeqStore ? *ms->ldmSeqStore : kNullRawSeqStore; + optLdm.endPosInBlock = optLdm.startPosInBlock = optLdm.offset = 0; + ZSTD_opt_getNextMatchAndUpdateSeqStore(&optLdm, (U32)(ip-istart), (U32)(iend-ip)); /* init */ DEBUGLOG(5, "ZSTD_compressBlock_opt_generic: current=%u, prefix=%u, nextToUpdate=%u", @@ -834,102 +1122,141 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, /* find first match */ { U32 const litlen = (U32)(ip - anchor); U32 const ll0 = !litlen; - U32 const nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, ip, iend, dictMode, rep, ll0, minMatch); - if (!nbMatches) { ip++; continue; } + U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, ip, iend, rep, ll0, minMatch); + ZSTD_optLdm_processMatchCandidate(&optLdm, matches, &nbMatches, + (U32)(ip-istart), (U32)(iend-ip)); + if (!nbMatches) { + DEBUGLOG(8, "no match found at cPos %u", (unsigned)(ip-istart)); + ip++; + continue; + } + + /* Match found: let's store this solution, and eventually find more candidates. + * During this forward pass, @opt is used to store stretches, + * defined as "a match followed by N literals". + * Note how this is different from a Sequence, which is "N literals followed by a match". + * Storing stretches allows us to store different match predecessors + * for each literal position part of a literals run. */ /* initialize opt[0] */ - { U32 i ; for (i=0; i immediate encoding */ { U32 const maxML = matches[nbMatches-1].len; - U32 const maxOffset = matches[nbMatches-1].off; - DEBUGLOG(6, "found %u matches of maxLength=%u and maxOffCode=%u at cPos=%u => start new series", - nbMatches, maxML, maxOffset, (U32)(ip-prefixStart)); + U32 const maxOffBase = matches[nbMatches-1].off; + DEBUGLOG(6, "found %u matches of maxLength=%u and maxOffBase=%u at cPos=%u => start new series", + nbMatches, maxML, maxOffBase, (U32)(ip-prefixStart)); if (maxML > sufficient_len) { - lastSequence.litlen = litlen; - lastSequence.mlen = maxML; - lastSequence.off = maxOffset; - DEBUGLOG(6, "large match (%u>%u), immediate encoding", + lastStretch.litlen = 0; + lastStretch.mlen = maxML; + lastStretch.off = maxOffBase; + DEBUGLOG(6, "large match (%u>%u) => immediate encoding", maxML, sufficient_len); cur = 0; - last_pos = ZSTD_totalLen(lastSequence); + last_pos = maxML; goto _shortestPath; } } /* set prices for first matches starting position == 0 */ - { U32 const literalsPrice = opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel); - U32 pos; + assert(opt[0].price >= 0); + { U32 pos; U32 matchNb; for (pos = 1; pos < minMatch; pos++) { - opt[pos].price = ZSTD_MAX_PRICE; /* mlen, litlen and price will be fixed during forward scanning */ + opt[pos].price = ZSTD_MAX_PRICE; + opt[pos].mlen = 0; + opt[pos].litlen = litlen + pos; } for (matchNb = 0; matchNb < nbMatches; matchNb++) { - U32 const offset = matches[matchNb].off; + U32 const offBase = matches[matchNb].off; U32 const end = matches[matchNb].len; for ( ; pos <= end ; pos++ ) { - U32 const matchPrice = ZSTD_getMatchPrice(offset, pos, optStatePtr, optLevel); - U32 const sequencePrice = literalsPrice + matchPrice; + int const matchPrice = (int)ZSTD_getMatchPrice(offBase, pos, optStatePtr, optLevel); + int const sequencePrice = opt[0].price + matchPrice; DEBUGLOG(7, "rPos:%u => set initial price : %.2f", pos, ZSTD_fCost(sequencePrice)); opt[pos].mlen = pos; - opt[pos].off = offset; - opt[pos].litlen = litlen; - opt[pos].price = sequencePrice; - } } + opt[pos].off = offBase; + opt[pos].litlen = 0; /* end of match */ + opt[pos].price = sequencePrice + LL_PRICE(0); + } + } last_pos = pos-1; + opt[pos].price = ZSTD_MAX_PRICE; } } /* check further positions */ for (cur = 1; cur <= last_pos; cur++) { const BYTE* const inr = ip + cur; - assert(cur < ZSTD_OPT_NUM); - DEBUGLOG(7, "cPos:%zi==rPos:%u", inr-istart, cur) + assert(cur <= ZSTD_OPT_NUM); + DEBUGLOG(7, "cPos:%zi==rPos:%u", inr-istart, cur); /* Fix current position with one literal if cheaper */ - { U32 const litlen = (opt[cur-1].mlen == 0) ? opt[cur-1].litlen + 1 : 1; + { U32 const litlen = opt[cur-1].litlen + 1; int const price = opt[cur-1].price - + ZSTD_rawLiteralsCost(ip+cur-1, 1, optStatePtr, optLevel) - + ZSTD_litLengthPrice(litlen, optStatePtr, optLevel) - - ZSTD_litLengthPrice(litlen-1, optStatePtr, optLevel); + + LIT_PRICE(ip+cur-1) + + LL_INCPRICE(litlen); assert(price < 1000000000); /* overflow check */ if (price <= opt[cur].price) { + ZSTD_optimal_t const prevMatch = opt[cur]; DEBUGLOG(7, "cPos:%zi==rPos:%u : better price (%.2f<=%.2f) using literal (ll==%u) (hist:%u,%u,%u)", inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), litlen, opt[cur-1].rep[0], opt[cur-1].rep[1], opt[cur-1].rep[2]); - opt[cur].mlen = 0; - opt[cur].off = 0; + opt[cur] = opt[cur-1]; opt[cur].litlen = litlen; opt[cur].price = price; + if ( (optLevel >= 1) /* additional check only for higher modes */ + && (prevMatch.litlen == 0) /* replace a match */ + && (LL_INCPRICE(1) < 0) /* ll1 is cheaper than ll0 */ + && LIKELY(ip + cur < iend) + ) { + /* check next position, in case it would be cheaper */ + int with1literal = prevMatch.price + LIT_PRICE(ip+cur) + LL_INCPRICE(1); + int withMoreLiterals = price + LIT_PRICE(ip+cur) + LL_INCPRICE(litlen+1); + DEBUGLOG(7, "then at next rPos %u : match+1lit %.2f vs %ulits %.2f", + cur+1, ZSTD_fCost(with1literal), litlen+1, ZSTD_fCost(withMoreLiterals)); + if ( (with1literal < withMoreLiterals) + && (with1literal < opt[cur+1].price) ) { + /* update offset history - before it disappears */ + U32 const prev = cur - prevMatch.mlen; + repcodes_t const newReps = ZSTD_newRep(opt[prev].rep, prevMatch.off, opt[prev].litlen==0); + assert(cur >= prevMatch.mlen); + DEBUGLOG(7, "==> match+1lit is cheaper (%.2f < %.2f) (hist:%u,%u,%u) !", + ZSTD_fCost(with1literal), ZSTD_fCost(withMoreLiterals), + newReps.rep[0], newReps.rep[1], newReps.rep[2] ); + opt[cur+1] = prevMatch; /* mlen & offbase */ + ZSTD_memcpy(opt[cur+1].rep, &newReps, sizeof(repcodes_t)); + opt[cur+1].litlen = 1; + opt[cur+1].price = with1literal; + if (last_pos < cur+1) last_pos = cur+1; + } + } } else { - DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f) (hist:%u,%u,%u)", - inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), - opt[cur].rep[0], opt[cur].rep[1], opt[cur].rep[2]); + DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f)", + inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price)); } } - /* Set the repcodes of the current position. We must do it here - * because we rely on the repcodes of the 2nd to last sequence being - * correct to set the next chunks repcodes during the backward - * traversal. + /* Offset history is not updated during match comparison. + * Do it here, now that the match is selected and confirmed. */ ZSTD_STATIC_ASSERT(sizeof(opt[cur].rep) == sizeof(repcodes_t)); assert(cur >= opt[cur].mlen); - if (opt[cur].mlen != 0) { + if (opt[cur].litlen == 0) { + /* just finished a match => alter offset history */ U32 const prev = cur - opt[cur].mlen; - repcodes_t newReps = ZSTD_updateRep(opt[prev].rep, opt[cur].off, opt[cur].litlen==0); - memcpy(opt[cur].rep, &newReps, sizeof(repcodes_t)); - } else { - memcpy(opt[cur].rep, opt[cur - 1].rep, sizeof(repcodes_t)); + repcodes_t const newReps = ZSTD_newRep(opt[prev].rep, opt[cur].off, opt[prev].litlen==0); + ZSTD_memcpy(opt[cur].rep, &newReps, sizeof(repcodes_t)); } /* last match must start at a minimum distance of 8 from oend */ @@ -939,33 +1266,36 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, if ( (optLevel==0) /*static_test*/ && (opt[cur+1].price <= opt[cur].price + (BITCOST_MULTIPLIER/2)) ) { - DEBUGLOG(7, "move to next rPos:%u : price is <=", cur+1); + DEBUGLOG(7, "skip current position : next rPos(%u) price is cheaper", cur+1); continue; /* skip unpromising positions; about ~+6% speed, -0.01 ratio */ } - { U32 const ll0 = (opt[cur].mlen != 0); - U32 const litlen = (opt[cur].mlen == 0) ? opt[cur].litlen : 0; - U32 const previousPrice = opt[cur].price; - U32 const basePrice = previousPrice + ZSTD_litLengthPrice(0, optStatePtr, optLevel); - U32 const nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, inr, iend, dictMode, opt[cur].rep, ll0, minMatch); + assert(opt[cur].price >= 0); + { U32 const ll0 = (opt[cur].litlen == 0); + int const previousPrice = opt[cur].price; + int const basePrice = previousPrice + LL_PRICE(0); + U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, inr, iend, opt[cur].rep, ll0, minMatch); U32 matchNb; + + ZSTD_optLdm_processMatchCandidate(&optLdm, matches, &nbMatches, + (U32)(inr-istart), (U32)(iend-inr)); + if (!nbMatches) { DEBUGLOG(7, "rPos:%u : no match found", cur); continue; } - { U32 const maxML = matches[nbMatches-1].len; - DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of maxLength=%u", - inr-istart, cur, nbMatches, maxML); - - if ( (maxML > sufficient_len) - || (cur + maxML >= ZSTD_OPT_NUM) ) { - lastSequence.mlen = maxML; - lastSequence.off = matches[nbMatches-1].off; - lastSequence.litlen = litlen; - cur -= (opt[cur].mlen==0) ? opt[cur].litlen : 0; /* last sequence is actually only literals, fix cur to last match - note : may underflow, in which case, it's first sequence, and it's okay */ - last_pos = cur + ZSTD_totalLen(lastSequence); - if (cur > ZSTD_OPT_NUM) cur = 0; /* underflow => first match */ + { U32 const longestML = matches[nbMatches-1].len; + DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of longest ML=%u", + inr-istart, cur, nbMatches, longestML); + + if ( (longestML > sufficient_len) + || (cur + longestML >= ZSTD_OPT_NUM) + || (ip + cur + longestML >= iend) ) { + lastStretch.mlen = longestML; + lastStretch.off = matches[nbMatches-1].off; + lastStretch.litlen = 0; + last_pos = cur + longestML; goto _shortestPath; } } @@ -976,20 +1306,25 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, U32 const startML = (matchNb>0) ? matches[matchNb-1].len+1 : minMatch; U32 mlen; - DEBUGLOG(7, "testing match %u => offCode=%4u, mlen=%2u, llen=%2u", - matchNb, matches[matchNb].off, lastML, litlen); + DEBUGLOG(7, "testing match %u => offBase=%4u, mlen=%2u, llen=%2u", + matchNb, matches[matchNb].off, lastML, opt[cur].litlen); for (mlen = lastML; mlen >= startML; mlen--) { /* scan downward */ U32 const pos = cur + mlen; - int const price = basePrice + ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel); + int const price = basePrice + (int)ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel); if ((pos > last_pos) || (price < opt[pos].price)) { DEBUGLOG(7, "rPos:%u (ml=%2u) => new better price (%.2f<%.2f)", pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price)); - while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } /* fill empty positions */ + while (last_pos < pos) { + /* fill empty positions, for future comparisons */ + last_pos++; + opt[last_pos].price = ZSTD_MAX_PRICE; + opt[last_pos].litlen = !0; /* just needs to be != 0, to mean "not an end of match" */ + } opt[pos].mlen = mlen; opt[pos].off = offset; - opt[pos].litlen = litlen; + opt[pos].litlen = 0; opt[pos].price = price; } else { DEBUGLOG(7, "rPos:%u (ml=%2u) => new price is worse (%.2f>=%.2f)", @@ -997,52 +1332,86 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, if (optLevel==0) break; /* early update abort; gets ~+10% speed for about -0.01 ratio loss */ } } } } + opt[last_pos+1].price = ZSTD_MAX_PRICE; } /* for (cur = 1; cur <= last_pos; cur++) */ - lastSequence = opt[last_pos]; - cur = last_pos > ZSTD_totalLen(lastSequence) ? last_pos - ZSTD_totalLen(lastSequence) : 0; /* single sequence, and it starts before `ip` */ - assert(cur < ZSTD_OPT_NUM); /* control overflow*/ + lastStretch = opt[last_pos]; + assert(cur >= lastStretch.mlen); + cur = last_pos - lastStretch.mlen; _shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */ assert(opt[0].mlen == 0); + assert(last_pos >= lastStretch.mlen); + assert(cur == last_pos - lastStretch.mlen); - /* Set the next chunk's repcodes based on the repcodes of the beginning - * of the last match, and the last sequence. This avoids us having to - * update them while traversing the sequences. - */ - if (lastSequence.mlen != 0) { - repcodes_t reps = ZSTD_updateRep(opt[cur].rep, lastSequence.off, lastSequence.litlen==0); - memcpy(rep, &reps, sizeof(reps)); + if (lastStretch.mlen==0) { + /* no solution : all matches have been converted into literals */ + assert(lastStretch.litlen == (ip - anchor) + last_pos); + ip += last_pos; + continue; + } + assert(lastStretch.off > 0); + + /* Update offset history */ + if (lastStretch.litlen == 0) { + /* finishing on a match : update offset history */ + repcodes_t const reps = ZSTD_newRep(opt[cur].rep, lastStretch.off, opt[cur].litlen==0); + ZSTD_memcpy(rep, &reps, sizeof(repcodes_t)); } else { - memcpy(rep, opt[cur].rep, sizeof(repcodes_t)); + ZSTD_memcpy(rep, lastStretch.rep, sizeof(repcodes_t)); + assert(cur >= lastStretch.litlen); + cur -= lastStretch.litlen; } - { U32 const storeEnd = cur + 1; + /* Let's write the shortest path solution. + * It is stored in @opt in reverse order, + * starting from @storeEnd (==cur+2), + * effectively partially @opt overwriting. + * Content is changed too: + * - So far, @opt stored stretches, aka a match followed by literals + * - Now, it will store sequences, aka literals followed by a match + */ + { U32 const storeEnd = cur + 2; U32 storeStart = storeEnd; - U32 seqPos = cur; + U32 stretchPos = cur; DEBUGLOG(6, "start reverse traversal (last_pos:%u, cur:%u)", last_pos, cur); (void)last_pos; - assert(storeEnd < ZSTD_OPT_NUM); - DEBUGLOG(6, "last sequence copied into pos=%u (llen=%u,mlen=%u,ofc=%u)", - storeEnd, lastSequence.litlen, lastSequence.mlen, lastSequence.off); - opt[storeEnd] = lastSequence; - while (seqPos > 0) { - U32 const backDist = ZSTD_totalLen(opt[seqPos]); + assert(storeEnd < ZSTD_OPT_SIZE); + DEBUGLOG(6, "last stretch copied into pos=%u (llen=%u,mlen=%u,ofc=%u)", + storeEnd, lastStretch.litlen, lastStretch.mlen, lastStretch.off); + if (lastStretch.litlen > 0) { + /* last "sequence" is unfinished: just a bunch of literals */ + opt[storeEnd].litlen = lastStretch.litlen; + opt[storeEnd].mlen = 0; + storeStart = storeEnd-1; + opt[storeStart] = lastStretch; + } { + opt[storeEnd] = lastStretch; /* note: litlen will be fixed */ + storeStart = storeEnd; + } + while (1) { + ZSTD_optimal_t nextStretch = opt[stretchPos]; + opt[storeStart].litlen = nextStretch.litlen; + DEBUGLOG(6, "selected sequence (llen=%u,mlen=%u,ofc=%u)", + opt[storeStart].litlen, opt[storeStart].mlen, opt[storeStart].off); + if (nextStretch.mlen == 0) { + /* reaching beginning of segment */ + break; + } storeStart--; - DEBUGLOG(6, "sequence from rPos=%u copied into pos=%u (llen=%u,mlen=%u,ofc=%u)", - seqPos, storeStart, opt[seqPos].litlen, opt[seqPos].mlen, opt[seqPos].off); - opt[storeStart] = opt[seqPos]; - seqPos = (seqPos > backDist) ? seqPos - backDist : 0; + opt[storeStart] = nextStretch; /* note: litlen will be fixed */ + assert(nextStretch.litlen + nextStretch.mlen <= stretchPos); + stretchPos -= nextStretch.litlen + nextStretch.mlen; } /* save sequences */ - DEBUGLOG(6, "sending selected sequences into seqStore") + DEBUGLOG(6, "sending selected sequences into seqStore"); { U32 storePos; for (storePos=storeStart; storePos <= storeEnd; storePos++) { U32 const llen = opt[storePos].litlen; U32 const mlen = opt[storePos].mlen; - U32 const offCode = opt[storePos].off; + U32 const offBase = opt[storePos].off; U32 const advance = llen + mlen; DEBUGLOG(6, "considering seq starting at %zi, llen=%u, mlen=%u", anchor - istart, (unsigned)llen, (unsigned)mlen); @@ -1054,11 +1423,14 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, } assert(anchor + llen <= iend); - ZSTD_updateStats(optStatePtr, llen, anchor, offCode, mlen); - ZSTD_storeSeq(seqStore, llen, anchor, iend, offCode, mlen-MINMATCH); + ZSTD_updateStats(optStatePtr, llen, anchor, offBase, mlen); + ZSTD_storeSeq(seqStore, llen, anchor, iend, offBase, mlen); anchor += advance; ip = anchor; } } + DEBUGLOG(7, "new offset history : %u, %u, %u", rep[0], rep[1], rep[2]); + + /* update all costs */ ZSTD_setBasePrices(optStatePtr, optLevel); } } /* while (ip < ilimit) */ @@ -1066,53 +1438,54 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, /* Return the last literals size */ return (size_t)(iend - anchor); } +#endif /* build exclusions */ + +#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR +static size_t ZSTD_compressBlock_opt0( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + const void* src, size_t srcSize, const ZSTD_dictMode_e dictMode) +{ + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /* optLevel */, dictMode); +} +#endif +#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR +static size_t ZSTD_compressBlock_opt2( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + const void* src, size_t srcSize, const ZSTD_dictMode_e dictMode) +{ + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /* optLevel */, dictMode); +} +#endif +#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR size_t ZSTD_compressBlock_btopt( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_compressBlock_btopt"); - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_noDict); + return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_noDict); } +#endif -/* used in 2-pass strategy */ -static U32 ZSTD_upscaleStat(unsigned* table, U32 lastEltIndex, int bonus) -{ - U32 s, sum=0; - assert(ZSTD_FREQ_DIV+bonus >= 0); - for (s=0; slitSum = ZSTD_upscaleStat(optPtr->litFreq, MaxLit, 0); - optPtr->litLengthSum = ZSTD_upscaleStat(optPtr->litLengthFreq, MaxLL, 0); - optPtr->matchLengthSum = ZSTD_upscaleStat(optPtr->matchLengthFreq, MaxML, 0); - optPtr->offCodeSum = ZSTD_upscaleStat(optPtr->offCodeFreq, MaxOff, 0); -} +#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR /* ZSTD_initStats_ultra(): * make a first compression pass, just to seed stats with more accurate starting values. * only works on first block, with no dictionary and no ldm. - * this function cannot error, hence its contract must be respected. + * this function cannot error out, its narrow contract must be respected. */ -static void -ZSTD_initStats_ultra(ZSTD_matchState_t* ms, - seqStore_t* seqStore, - U32 rep[ZSTD_REP_NUM], - const void* src, size_t srcSize) +static +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +void ZSTD_initStats_ultra(ZSTD_matchState_t* ms, + seqStore_t* seqStore, + U32 rep[ZSTD_REP_NUM], + const void* src, size_t srcSize) { U32 tmpRep[ZSTD_REP_NUM]; /* updated rep codes will sink here */ - memcpy(tmpRep, rep, sizeof(tmpRep)); + ZSTD_memcpy(tmpRep, rep, sizeof(tmpRep)); DEBUGLOG(4, "ZSTD_initStats_ultra (srcSize=%zu)", srcSize); assert(ms->opt.litLengthSum == 0); /* first block */ @@ -1120,17 +1493,15 @@ ZSTD_initStats_ultra(ZSTD_matchState_t* ms, assert(ms->window.dictLimit == ms->window.lowLimit); /* no dictionary */ assert(ms->window.dictLimit - ms->nextToUpdate <= 1); /* no prefix (note: intentional overflow, defined as 2-complement) */ - ZSTD_compressBlock_opt_generic(ms, seqStore, tmpRep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); /* generate stats into ms->opt*/ + ZSTD_compressBlock_opt2(ms, seqStore, tmpRep, src, srcSize, ZSTD_noDict); /* generate stats into ms->opt*/ - /* invalidate first scan from history */ + /* invalidate first scan from history, only keep entropy stats */ ZSTD_resetSeqStore(seqStore); ms->window.base -= srcSize; ms->window.dictLimit += (U32)srcSize; ms->window.lowLimit = ms->window.dictLimit; ms->nextToUpdate = ms->window.dictLimit; - /* re-inforce weight of collected statistics */ - ZSTD_upscaleStats(&ms->opt); } size_t ZSTD_compressBlock_btultra( @@ -1138,20 +1509,20 @@ size_t ZSTD_compressBlock_btultra( const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_compressBlock_btultra (srcSize=%zu)", srcSize); - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); + return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_noDict); } size_t ZSTD_compressBlock_btultra2( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - U32 const current = (U32)((const BYTE*)src - ms->window.base); + U32 const curr = (U32)((const BYTE*)src - ms->window.base); DEBUGLOG(5, "ZSTD_compressBlock_btultra2 (srcSize=%zu)", srcSize); - /* 2-pass strategy: + /* 2-passes strategy: * this strategy makes a first pass over first block to collect statistics - * and seed next round's statistics with it. - * After 1st pass, function forgets everything, and starts a new block. + * in order to seed next round's statistics with it. + * After 1st pass, function forgets history, and starts a new block. * Consequently, this can only work if no data has been previously loaded in tables, * aka, no dictionary, no prefix, no ldm preprocessing. * The compression ratio gain is generally small (~0.5% on first block), @@ -1160,45 +1531,50 @@ size_t ZSTD_compressBlock_btultra2( if ( (ms->opt.litLengthSum==0) /* first block */ && (seqStore->sequences == seqStore->sequencesStart) /* no ldm */ && (ms->window.dictLimit == ms->window.lowLimit) /* no dictionary */ - && (current == ms->window.dictLimit) /* start of frame, nothing already loaded nor skipped */ - && (srcSize > ZSTD_PREDEF_THRESHOLD) + && (curr == ms->window.dictLimit) /* start of frame, nothing already loaded nor skipped */ + && (srcSize > ZSTD_PREDEF_THRESHOLD) /* input large enough to not employ default stats */ ) { ZSTD_initStats_ultra(ms, seqStore, rep, src, srcSize); } - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); + return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_noDict); } +#endif +#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR size_t ZSTD_compressBlock_btopt_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_dictMatchState); + return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_dictMatchState); } -size_t ZSTD_compressBlock_btultra_dictMatchState( +size_t ZSTD_compressBlock_btopt_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_dictMatchState); + return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_extDict); } +#endif -size_t ZSTD_compressBlock_btopt_extDict( +#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR +size_t ZSTD_compressBlock_btultra_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_extDict); + return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_dictMatchState); } size_t ZSTD_compressBlock_btultra_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_extDict); + return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_extDict); } +#endif /* note : no btultra2 variant for extDict nor dictMatchState, * because btultra2 is not meant to work with dictionaries * and is only specific for the first block (no prefix) */ -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/compress/zstdmt_compress.cpp b/src/duckdb/third_party/zstd/compress/zstdmt_compress.cpp new file mode 100644 index 000000000..f0522c8ff --- /dev/null +++ b/src/duckdb/third_party/zstd/compress/zstdmt_compress.cpp @@ -0,0 +1,1885 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +/* ====== Compiler specifics ====== */ +#if defined(_MSC_VER) +# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ +#endif + + +/* ====== Dependencies ====== */ +#include "zstd/common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */ +#include "zstd/common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset, INT_MAX, UINT_MAX */ +#include "zstd/common/mem.h" /* MEM_STATIC */ +#include "zstd/common/pool.h" /* threadpool */ +#include "zstd/common/threading.h" /* mutex */ +#include "zstd/compress/zstd_compress_internal.h" /* MIN, ERROR, ZSTD_*, ZSTD_highbit32 */ +#include "zstd/compress/zstd_ldm.h" +#include "zstd/compress/zstdmt_compress.h" + +/* Guards code to support resizing the SeqPool. + * We will want to resize the SeqPool to save memory in the future. + * Until then, comment the code out since it is unused. + */ +#define ZSTD_RESIZE_SEQPOOL 0 + +/* ====== Debug ====== */ +#if defined(DEBUGLEVEL) && (DEBUGLEVEL>=2) \ + && !defined(_MSC_VER) \ + && !defined(__MINGW32__) + +# include +# include +# include + +# define DEBUG_PRINTHEX(l,p,n) \ + do { \ + unsigned debug_u; \ + for (debug_u=0; debug_u<(n); debug_u++) \ + RAWLOG(l, "%02X ", ((const unsigned char*)(p))[debug_u]); \ + RAWLOG(l, " \n"); \ + } while (0) + +static unsigned long long GetCurrentClockTimeMicroseconds(void) +{ + static clock_t _ticksPerSecond = 0; + if (_ticksPerSecond <= 0) _ticksPerSecond = sysconf(_SC_CLK_TCK); + + { struct tms junk; clock_t newTicks = (clock_t) times(&junk); + return ((((unsigned long long)newTicks)*(1000000))/_ticksPerSecond); +} } + +#define MUTEX_WAIT_TIME_DLEVEL 6 +#define ZSTD_PTHREAD_MUTEX_LOCK(mutex) \ + do { \ + if (DEBUGLEVEL >= MUTEX_WAIT_TIME_DLEVEL) { \ + unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \ + ZSTD_pthread_mutex_lock(mutex); \ + { unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \ + unsigned long long const elapsedTime = (afterTime-beforeTime); \ + if (elapsedTime > 1000) { \ + /* or whatever threshold you like; I'm using 1 millisecond here */ \ + DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, \ + "Thread took %llu microseconds to acquire mutex %s \n", \ + elapsedTime, #mutex); \ + } } \ + } else { \ + ZSTD_pthread_mutex_lock(mutex); \ + } \ + } while (0) + +#else + +# define ZSTD_PTHREAD_MUTEX_LOCK(m) ZSTD_pthread_mutex_lock(m) +# define DEBUG_PRINTHEX(l,p,n) do { } while (0) + +#endif + +namespace duckdb_zstd { + +/* ===== Buffer Pool ===== */ +/* a single Buffer Pool can be invoked from multiple threads in parallel */ + +typedef struct buffer_s { + void* start; + size_t capacity; +} buffer_t; + +static const buffer_t g_nullBuffer = { NULL, 0 }; + +typedef struct ZSTDMT_bufferPool_s { + ZSTD_pthread_mutex_t poolMutex; + size_t bufferSize; + unsigned totalBuffers; + unsigned nbBuffers; + ZSTD_customMem cMem; + buffer_t* buffers; +} ZSTDMT_bufferPool; + +static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool) +{ + DEBUGLOG(3, "ZSTDMT_freeBufferPool (address:%08X)", (U32)(size_t)bufPool); + if (!bufPool) return; /* compatibility with free on NULL */ + if (bufPool->buffers) { + unsigned u; + for (u=0; utotalBuffers; u++) { + DEBUGLOG(4, "free buffer %2u (address:%08X)", u, (U32)(size_t)bufPool->buffers[u].start); + ZSTD_customFree(bufPool->buffers[u].start, bufPool->cMem); + } + ZSTD_customFree(bufPool->buffers, bufPool->cMem); + } + ZSTD_pthread_mutex_destroy(&bufPool->poolMutex); + ZSTD_customFree(bufPool, bufPool->cMem); +} + +static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned maxNbBuffers, ZSTD_customMem cMem) +{ + ZSTDMT_bufferPool* const bufPool = + (ZSTDMT_bufferPool*)ZSTD_customCalloc(sizeof(ZSTDMT_bufferPool), cMem); + if (bufPool==NULL) return NULL; + if (ZSTD_pthread_mutex_init(&bufPool->poolMutex, NULL)) { + ZSTD_customFree(bufPool, cMem); + return NULL; + } + bufPool->buffers = (buffer_t*)ZSTD_customCalloc(maxNbBuffers * sizeof(buffer_t), cMem); + if (bufPool->buffers==NULL) { + ZSTDMT_freeBufferPool(bufPool); + return NULL; + } + bufPool->bufferSize = 64 KB; + bufPool->totalBuffers = maxNbBuffers; + bufPool->nbBuffers = 0; + bufPool->cMem = cMem; + return bufPool; +} + +/* only works at initialization, not during compression */ +static size_t ZSTDMT_sizeof_bufferPool(ZSTDMT_bufferPool* bufPool) +{ + size_t const poolSize = sizeof(*bufPool); + size_t const arraySize = bufPool->totalBuffers * sizeof(buffer_t); + unsigned u; + size_t totalBufferSize = 0; + ZSTD_pthread_mutex_lock(&bufPool->poolMutex); + for (u=0; utotalBuffers; u++) + totalBufferSize += bufPool->buffers[u].capacity; + ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); + + return poolSize + arraySize + totalBufferSize; +} + +/* ZSTDMT_setBufferSize() : + * all future buffers provided by this buffer pool will have _at least_ this size + * note : it's better for all buffers to have same size, + * as they become freely interchangeable, reducing malloc/free usages and memory fragmentation */ +static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* const bufPool, size_t const bSize) +{ + ZSTD_pthread_mutex_lock(&bufPool->poolMutex); + DEBUGLOG(4, "ZSTDMT_setBufferSize: bSize = %u", (U32)bSize); + bufPool->bufferSize = bSize; + ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); +} + + +static ZSTDMT_bufferPool* ZSTDMT_expandBufferPool(ZSTDMT_bufferPool* srcBufPool, unsigned maxNbBuffers) +{ + if (srcBufPool==NULL) return NULL; + if (srcBufPool->totalBuffers >= maxNbBuffers) /* good enough */ + return srcBufPool; + /* need a larger buffer pool */ + { ZSTD_customMem const cMem = srcBufPool->cMem; + size_t const bSize = srcBufPool->bufferSize; /* forward parameters */ + ZSTDMT_bufferPool* newBufPool; + ZSTDMT_freeBufferPool(srcBufPool); + newBufPool = ZSTDMT_createBufferPool(maxNbBuffers, cMem); + if (newBufPool==NULL) return newBufPool; + ZSTDMT_setBufferSize(newBufPool, bSize); + return newBufPool; + } +} + +/** ZSTDMT_getBuffer() : + * assumption : bufPool must be valid + * @return : a buffer, with start pointer and size + * note: allocation may fail, in this case, start==NULL and size==0 */ +static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool) +{ + size_t const bSize = bufPool->bufferSize; + DEBUGLOG(5, "ZSTDMT_getBuffer: bSize = %u", (U32)bufPool->bufferSize); + ZSTD_pthread_mutex_lock(&bufPool->poolMutex); + if (bufPool->nbBuffers) { /* try to use an existing buffer */ + buffer_t const buf = bufPool->buffers[--(bufPool->nbBuffers)]; + size_t const availBufferSize = buf.capacity; + bufPool->buffers[bufPool->nbBuffers] = g_nullBuffer; + if ((availBufferSize >= bSize) & ((availBufferSize>>3) <= bSize)) { + /* large enough, but not too much */ + DEBUGLOG(5, "ZSTDMT_getBuffer: provide buffer %u of size %u", + bufPool->nbBuffers, (U32)buf.capacity); + ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); + return buf; + } + /* size conditions not respected : scratch this buffer, create new one */ + DEBUGLOG(5, "ZSTDMT_getBuffer: existing buffer does not meet size conditions => freeing"); + ZSTD_customFree(buf.start, bufPool->cMem); + } + ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); + /* create new buffer */ + DEBUGLOG(5, "ZSTDMT_getBuffer: create a new buffer"); + { buffer_t buffer; + void* const start = ZSTD_customMalloc(bSize, bufPool->cMem); + buffer.start = start; /* note : start can be NULL if malloc fails ! */ + buffer.capacity = (start==NULL) ? 0 : bSize; + if (start==NULL) { + DEBUGLOG(5, "ZSTDMT_getBuffer: buffer allocation failure !!"); + } else { + DEBUGLOG(5, "ZSTDMT_getBuffer: created buffer of size %u", (U32)bSize); + } + return buffer; + } +} + +#if ZSTD_RESIZE_SEQPOOL +/** ZSTDMT_resizeBuffer() : + * assumption : bufPool must be valid + * @return : a buffer that is at least the buffer pool buffer size. + * If a reallocation happens, the data in the input buffer is copied. + */ +static buffer_t ZSTDMT_resizeBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buffer) +{ + size_t const bSize = bufPool->bufferSize; + if (buffer.capacity < bSize) { + void* const start = ZSTD_customMalloc(bSize, bufPool->cMem); + buffer_t newBuffer; + newBuffer.start = start; + newBuffer.capacity = start == NULL ? 0 : bSize; + if (start != NULL) { + assert(newBuffer.capacity >= buffer.capacity); + ZSTD_memcpy(newBuffer.start, buffer.start, buffer.capacity); + DEBUGLOG(5, "ZSTDMT_resizeBuffer: created buffer of size %u", (U32)bSize); + return newBuffer; + } + DEBUGLOG(5, "ZSTDMT_resizeBuffer: buffer allocation failure !!"); + } + return buffer; +} +#endif + +/* store buffer for later re-use, up to pool capacity */ +static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf) +{ + DEBUGLOG(5, "ZSTDMT_releaseBuffer"); + if (buf.start == NULL) return; /* compatible with release on NULL */ + ZSTD_pthread_mutex_lock(&bufPool->poolMutex); + if (bufPool->nbBuffers < bufPool->totalBuffers) { + bufPool->buffers[bufPool->nbBuffers++] = buf; /* stored for later use */ + DEBUGLOG(5, "ZSTDMT_releaseBuffer: stored buffer of size %u in slot %u", + (U32)buf.capacity, (U32)(bufPool->nbBuffers-1)); + ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); + return; + } + ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); + /* Reached bufferPool capacity (note: should not happen) */ + DEBUGLOG(5, "ZSTDMT_releaseBuffer: pool capacity reached => freeing "); + ZSTD_customFree(buf.start, bufPool->cMem); +} + +/* We need 2 output buffers per worker since each dstBuff must be flushed after it is released. + * The 3 additional buffers are as follows: + * 1 buffer for input loading + * 1 buffer for "next input" when submitting current one + * 1 buffer stuck in queue */ +#define BUF_POOL_MAX_NB_BUFFERS(nbWorkers) (2*(nbWorkers) + 3) + +/* After a worker releases its rawSeqStore, it is immediately ready for reuse. + * So we only need one seq buffer per worker. */ +#define SEQ_POOL_MAX_NB_BUFFERS(nbWorkers) (nbWorkers) + +/* ===== Seq Pool Wrapper ====== */ + +typedef ZSTDMT_bufferPool ZSTDMT_seqPool; + +static size_t ZSTDMT_sizeof_seqPool(ZSTDMT_seqPool* seqPool) +{ + return ZSTDMT_sizeof_bufferPool(seqPool); +} + +static rawSeqStore_t bufferToSeq(buffer_t buffer) +{ + rawSeqStore_t seq = kNullRawSeqStore; + seq.seq = (rawSeq*)buffer.start; + seq.capacity = buffer.capacity / sizeof(rawSeq); + return seq; +} + +static buffer_t seqToBuffer(rawSeqStore_t seq) +{ + buffer_t buffer; + buffer.start = seq.seq; + buffer.capacity = seq.capacity * sizeof(rawSeq); + return buffer; +} + +static rawSeqStore_t ZSTDMT_getSeq(ZSTDMT_seqPool* seqPool) +{ + if (seqPool->bufferSize == 0) { + return kNullRawSeqStore; + } + return bufferToSeq(ZSTDMT_getBuffer(seqPool)); +} + +#if ZSTD_RESIZE_SEQPOOL +static rawSeqStore_t ZSTDMT_resizeSeq(ZSTDMT_seqPool* seqPool, rawSeqStore_t seq) +{ + return bufferToSeq(ZSTDMT_resizeBuffer(seqPool, seqToBuffer(seq))); +} +#endif + +static void ZSTDMT_releaseSeq(ZSTDMT_seqPool* seqPool, rawSeqStore_t seq) +{ + ZSTDMT_releaseBuffer(seqPool, seqToBuffer(seq)); +} + +static void ZSTDMT_setNbSeq(ZSTDMT_seqPool* const seqPool, size_t const nbSeq) +{ + ZSTDMT_setBufferSize(seqPool, nbSeq * sizeof(rawSeq)); +} + +static ZSTDMT_seqPool* ZSTDMT_createSeqPool(unsigned nbWorkers, ZSTD_customMem cMem) +{ + ZSTDMT_seqPool* const seqPool = ZSTDMT_createBufferPool(SEQ_POOL_MAX_NB_BUFFERS(nbWorkers), cMem); + if (seqPool == NULL) return NULL; + ZSTDMT_setNbSeq(seqPool, 0); + return seqPool; +} + +static void ZSTDMT_freeSeqPool(ZSTDMT_seqPool* seqPool) +{ + ZSTDMT_freeBufferPool(seqPool); +} + +static ZSTDMT_seqPool* ZSTDMT_expandSeqPool(ZSTDMT_seqPool* pool, U32 nbWorkers) +{ + return ZSTDMT_expandBufferPool(pool, SEQ_POOL_MAX_NB_BUFFERS(nbWorkers)); +} + + +/* ===== CCtx Pool ===== */ +/* a single CCtx Pool can be invoked from multiple threads in parallel */ + +typedef struct { + ZSTD_pthread_mutex_t poolMutex; + int totalCCtx; + int availCCtx; + ZSTD_customMem cMem; + ZSTD_CCtx** cctxs; +} ZSTDMT_CCtxPool; + +/* note : all CCtx borrowed from the pool must be reverted back to the pool _before_ freeing the pool */ +static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool) +{ + if (!pool) return; + ZSTD_pthread_mutex_destroy(&pool->poolMutex); + if (pool->cctxs) { + int cid; + for (cid=0; cidtotalCCtx; cid++) + ZSTD_freeCCtx(pool->cctxs[cid]); /* free compatible with NULL */ + ZSTD_customFree(pool->cctxs, pool->cMem); + } + ZSTD_customFree(pool, pool->cMem); +} + +/* ZSTDMT_createCCtxPool() : + * implies nbWorkers >= 1 , checked by caller ZSTDMT_createCCtx() */ +static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(int nbWorkers, + ZSTD_customMem cMem) +{ + ZSTDMT_CCtxPool* const cctxPool = + (ZSTDMT_CCtxPool*) ZSTD_customCalloc(sizeof(ZSTDMT_CCtxPool), cMem); + assert(nbWorkers > 0); + if (!cctxPool) return NULL; + if (ZSTD_pthread_mutex_init(&cctxPool->poolMutex, NULL)) { + ZSTD_customFree(cctxPool, cMem); + return NULL; + } + cctxPool->totalCCtx = nbWorkers; + cctxPool->cctxs = (ZSTD_CCtx**)ZSTD_customCalloc(nbWorkers * sizeof(ZSTD_CCtx*), cMem); + if (!cctxPool->cctxs) { + ZSTDMT_freeCCtxPool(cctxPool); + return NULL; + } + cctxPool->cMem = cMem; + cctxPool->cctxs[0] = ZSTD_createCCtx_advanced(cMem); + if (!cctxPool->cctxs[0]) { ZSTDMT_freeCCtxPool(cctxPool); return NULL; } + cctxPool->availCCtx = 1; /* at least one cctx for single-thread mode */ + DEBUGLOG(3, "cctxPool created, with %u workers", nbWorkers); + return cctxPool; +} + +static ZSTDMT_CCtxPool* ZSTDMT_expandCCtxPool(ZSTDMT_CCtxPool* srcPool, + int nbWorkers) +{ + if (srcPool==NULL) return NULL; + if (nbWorkers <= srcPool->totalCCtx) return srcPool; /* good enough */ + /* need a larger cctx pool */ + { ZSTD_customMem const cMem = srcPool->cMem; + ZSTDMT_freeCCtxPool(srcPool); + return ZSTDMT_createCCtxPool(nbWorkers, cMem); + } +} + +/* only works during initialization phase, not during compression */ +static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool) +{ + ZSTD_pthread_mutex_lock(&cctxPool->poolMutex); + { unsigned const nbWorkers = cctxPool->totalCCtx; + size_t const poolSize = sizeof(*cctxPool); + size_t const arraySize = cctxPool->totalCCtx * sizeof(ZSTD_CCtx*); + size_t totalCCtxSize = 0; + unsigned u; + for (u=0; ucctxs[u]); + } + ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex); + assert(nbWorkers > 0); + return poolSize + arraySize + totalCCtxSize; + } +} + +static ZSTD_CCtx* ZSTDMT_getCCtx(ZSTDMT_CCtxPool* cctxPool) +{ + DEBUGLOG(5, "ZSTDMT_getCCtx"); + ZSTD_pthread_mutex_lock(&cctxPool->poolMutex); + if (cctxPool->availCCtx) { + cctxPool->availCCtx--; + { ZSTD_CCtx* const cctx = cctxPool->cctxs[cctxPool->availCCtx]; + ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex); + return cctx; + } } + ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex); + DEBUGLOG(5, "create one more CCtx"); + return ZSTD_createCCtx_advanced(cctxPool->cMem); /* note : can be NULL, when creation fails ! */ +} + +static void ZSTDMT_releaseCCtx(ZSTDMT_CCtxPool* pool, ZSTD_CCtx* cctx) +{ + if (cctx==NULL) return; /* compatibility with release on NULL */ + ZSTD_pthread_mutex_lock(&pool->poolMutex); + if (pool->availCCtx < pool->totalCCtx) + pool->cctxs[pool->availCCtx++] = cctx; + else { + /* pool overflow : should not happen, since totalCCtx==nbWorkers */ + DEBUGLOG(4, "CCtx pool overflow : free cctx"); + ZSTD_freeCCtx(cctx); + } + ZSTD_pthread_mutex_unlock(&pool->poolMutex); +} + +/* ==== Serial State ==== */ + +typedef struct { + void const* start; + size_t size; +} range_t; + +typedef struct { + /* All variables in the struct are protected by mutex. */ + ZSTD_pthread_mutex_t mutex; + ZSTD_pthread_cond_t cond; + ZSTD_CCtx_params params; + ldmState_t ldmState; + XXH64_state_t xxhState; + unsigned nextJobID; + /* Protects ldmWindow. + * Must be acquired after the main mutex when acquiring both. + */ + ZSTD_pthread_mutex_t ldmWindowMutex; + ZSTD_pthread_cond_t ldmWindowCond; /* Signaled when ldmWindow is updated */ + ZSTD_window_t ldmWindow; /* A thread-safe copy of ldmState.window */ +} serialState_t; + +static int +ZSTDMT_serialState_reset(serialState_t* serialState, + ZSTDMT_seqPool* seqPool, + ZSTD_CCtx_params params, + size_t jobSize, + const void* dict, size_t const dictSize, + ZSTD_dictContentType_e dictContentType) +{ + /* Adjust parameters */ + if (params.ldmParams.enableLdm == ZSTD_ps_enable) { + DEBUGLOG(4, "LDM window size = %u KB", (1U << params.cParams.windowLog) >> 10); + ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams); + assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); + assert(params.ldmParams.hashRateLog < 32); + } else { + ZSTD_memset(¶ms.ldmParams, 0, sizeof(params.ldmParams)); + } + serialState->nextJobID = 0; + if (params.fParams.checksumFlag) + XXH64_reset(&serialState->xxhState, 0); + if (params.ldmParams.enableLdm == ZSTD_ps_enable) { + ZSTD_customMem cMem = params.customMem; + unsigned const hashLog = params.ldmParams.hashLog; + size_t const hashSize = ((size_t)1 << hashLog) * sizeof(ldmEntry_t); + unsigned const bucketLog = + params.ldmParams.hashLog - params.ldmParams.bucketSizeLog; + unsigned const prevBucketLog = + serialState->params.ldmParams.hashLog - + serialState->params.ldmParams.bucketSizeLog; + size_t const numBuckets = (size_t)1 << bucketLog; + /* Size the seq pool tables */ + ZSTDMT_setNbSeq(seqPool, ZSTD_ldm_getMaxNbSeq(params.ldmParams, jobSize)); + /* Reset the window */ + ZSTD_window_init(&serialState->ldmState.window); + /* Resize tables and output space if necessary. */ + if (serialState->ldmState.hashTable == NULL || serialState->params.ldmParams.hashLog < hashLog) { + ZSTD_customFree(serialState->ldmState.hashTable, cMem); + serialState->ldmState.hashTable = (ldmEntry_t*)ZSTD_customMalloc(hashSize, cMem); + } + if (serialState->ldmState.bucketOffsets == NULL || prevBucketLog < bucketLog) { + ZSTD_customFree(serialState->ldmState.bucketOffsets, cMem); + serialState->ldmState.bucketOffsets = (BYTE*)ZSTD_customMalloc(numBuckets, cMem); + } + if (!serialState->ldmState.hashTable || !serialState->ldmState.bucketOffsets) + return 1; + /* Zero the tables */ + ZSTD_memset(serialState->ldmState.hashTable, 0, hashSize); + ZSTD_memset(serialState->ldmState.bucketOffsets, 0, numBuckets); + + /* Update window state and fill hash table with dict */ + serialState->ldmState.loadedDictEnd = 0; + if (dictSize > 0) { + if (dictContentType == ZSTD_dct_rawContent) { + BYTE const* const dictEnd = (const BYTE*)dict + dictSize; + ZSTD_window_update(&serialState->ldmState.window, dict, dictSize, /* forceNonContiguous */ 0); + ZSTD_ldm_fillHashTable(&serialState->ldmState, (const BYTE*)dict, dictEnd, ¶ms.ldmParams); + serialState->ldmState.loadedDictEnd = params.forceWindow ? 0 : (U32)(dictEnd - serialState->ldmState.window.base); + } else { + /* don't even load anything */ + } + } + + /* Initialize serialState's copy of ldmWindow. */ + serialState->ldmWindow = serialState->ldmState.window; + } + + serialState->params = params; + serialState->params.jobSize = (U32)jobSize; + return 0; +} + +static int ZSTDMT_serialState_init(serialState_t* serialState) +{ + int initError = 0; + ZSTD_memset(serialState, 0, sizeof(*serialState)); + initError |= ZSTD_pthread_mutex_init(&serialState->mutex, NULL); + initError |= ZSTD_pthread_cond_init(&serialState->cond, NULL); + initError |= ZSTD_pthread_mutex_init(&serialState->ldmWindowMutex, NULL); + initError |= ZSTD_pthread_cond_init(&serialState->ldmWindowCond, NULL); + return initError; +} + +static void ZSTDMT_serialState_free(serialState_t* serialState) +{ + ZSTD_customMem cMem = serialState->params.customMem; + ZSTD_pthread_mutex_destroy(&serialState->mutex); + ZSTD_pthread_cond_destroy(&serialState->cond); + ZSTD_pthread_mutex_destroy(&serialState->ldmWindowMutex); + ZSTD_pthread_cond_destroy(&serialState->ldmWindowCond); + ZSTD_customFree(serialState->ldmState.hashTable, cMem); + ZSTD_customFree(serialState->ldmState.bucketOffsets, cMem); +} + +static void ZSTDMT_serialState_update(serialState_t* serialState, + ZSTD_CCtx* jobCCtx, rawSeqStore_t seqStore, + range_t src, unsigned jobID) +{ + /* Wait for our turn */ + ZSTD_PTHREAD_MUTEX_LOCK(&serialState->mutex); + while (serialState->nextJobID < jobID) { + DEBUGLOG(5, "wait for serialState->cond"); + ZSTD_pthread_cond_wait(&serialState->cond, &serialState->mutex); + } + /* A future job may error and skip our job */ + if (serialState->nextJobID == jobID) { + /* It is now our turn, do any processing necessary */ + if (serialState->params.ldmParams.enableLdm == ZSTD_ps_enable) { + size_t error; + assert(seqStore.seq != NULL && seqStore.pos == 0 && + seqStore.size == 0 && seqStore.capacity > 0); + assert(src.size <= serialState->params.jobSize); + ZSTD_window_update(&serialState->ldmState.window, src.start, src.size, /* forceNonContiguous */ 0); + error = ZSTD_ldm_generateSequences( + &serialState->ldmState, &seqStore, + &serialState->params.ldmParams, src.start, src.size); + /* We provide a large enough buffer to never fail. */ + assert(!ZSTD_isError(error)); (void)error; + /* Update ldmWindow to match the ldmState.window and signal the main + * thread if it is waiting for a buffer. + */ + ZSTD_PTHREAD_MUTEX_LOCK(&serialState->ldmWindowMutex); + serialState->ldmWindow = serialState->ldmState.window; + ZSTD_pthread_cond_signal(&serialState->ldmWindowCond); + ZSTD_pthread_mutex_unlock(&serialState->ldmWindowMutex); + } + if (serialState->params.fParams.checksumFlag && src.size > 0) + XXH64_update(&serialState->xxhState, src.start, src.size); + } + /* Now it is the next jobs turn */ + serialState->nextJobID++; + ZSTD_pthread_cond_broadcast(&serialState->cond); + ZSTD_pthread_mutex_unlock(&serialState->mutex); + + if (seqStore.size > 0) { + ZSTD_referenceExternalSequences(jobCCtx, seqStore.seq, seqStore.size); + assert(serialState->params.ldmParams.enableLdm == ZSTD_ps_enable); + } +} + +static void ZSTDMT_serialState_ensureFinished(serialState_t* serialState, + unsigned jobID, size_t cSize) +{ + ZSTD_PTHREAD_MUTEX_LOCK(&serialState->mutex); + if (serialState->nextJobID <= jobID) { + assert(ZSTD_isError(cSize)); (void)cSize; + DEBUGLOG(5, "Skipping past job %u because of error", jobID); + serialState->nextJobID = jobID + 1; + ZSTD_pthread_cond_broadcast(&serialState->cond); + + ZSTD_PTHREAD_MUTEX_LOCK(&serialState->ldmWindowMutex); + ZSTD_window_clear(&serialState->ldmWindow); + ZSTD_pthread_cond_signal(&serialState->ldmWindowCond); + ZSTD_pthread_mutex_unlock(&serialState->ldmWindowMutex); + } + ZSTD_pthread_mutex_unlock(&serialState->mutex); + +} + + +/* ------------------------------------------ */ +/* ===== Worker thread ===== */ +/* ------------------------------------------ */ + +static const range_t kNullRange = { NULL, 0 }; + +typedef struct { + size_t consumed; /* SHARED - set0 by mtctx, then modified by worker AND read by mtctx */ + size_t cSize; /* SHARED - set0 by mtctx, then modified by worker AND read by mtctx, then set0 by mtctx */ + ZSTD_pthread_mutex_t job_mutex; /* Thread-safe - used by mtctx and worker */ + ZSTD_pthread_cond_t job_cond; /* Thread-safe - used by mtctx and worker */ + ZSTDMT_CCtxPool* cctxPool; /* Thread-safe - used by mtctx and (all) workers */ + ZSTDMT_bufferPool* bufPool; /* Thread-safe - used by mtctx and (all) workers */ + ZSTDMT_seqPool* seqPool; /* Thread-safe - used by mtctx and (all) workers */ + serialState_t* serial; /* Thread-safe - used by mtctx and (all) workers */ + buffer_t dstBuff; /* set by worker (or mtctx), then read by worker & mtctx, then modified by mtctx => no barrier */ + range_t prefix; /* set by mtctx, then read by worker & mtctx => no barrier */ + range_t src; /* set by mtctx, then read by worker & mtctx => no barrier */ + unsigned jobID; /* set by mtctx, then read by worker => no barrier */ + unsigned firstJob; /* set by mtctx, then read by worker => no barrier */ + unsigned lastJob; /* set by mtctx, then read by worker => no barrier */ + ZSTD_CCtx_params params; /* set by mtctx, then read by worker => no barrier */ + const ZSTD_CDict* cdict; /* set by mtctx, then read by worker => no barrier */ + unsigned long long fullFrameSize; /* set by mtctx, then read by worker => no barrier */ + size_t dstFlushed; /* used only by mtctx */ + unsigned frameChecksumNeeded; /* used only by mtctx */ +} ZSTDMT_jobDescription; + +#define JOB_ERROR(e) \ + do { \ + ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex); \ + job->cSize = e; \ + ZSTD_pthread_mutex_unlock(&job->job_mutex); \ + goto _endJob; \ + } while (0) + +/* ZSTDMT_compressionJob() is a POOL_function type */ +static void ZSTDMT_compressionJob(void* jobDescription) +{ + ZSTDMT_jobDescription* const job = (ZSTDMT_jobDescription*)jobDescription; + ZSTD_CCtx_params jobParams = job->params; /* do not modify job->params ! copy it, modify the copy */ + ZSTD_CCtx* const cctx = ZSTDMT_getCCtx(job->cctxPool); + rawSeqStore_t rawSeqStore = ZSTDMT_getSeq(job->seqPool); + buffer_t dstBuff = job->dstBuff; + size_t lastCBlockSize = 0; + + /* resources */ + if (cctx==NULL) JOB_ERROR(ERROR(memory_allocation)); + if (dstBuff.start == NULL) { /* streaming job : doesn't provide a dstBuffer */ + dstBuff = ZSTDMT_getBuffer(job->bufPool); + if (dstBuff.start==NULL) JOB_ERROR(ERROR(memory_allocation)); + job->dstBuff = dstBuff; /* this value can be read in ZSTDMT_flush, when it copies the whole job */ + } + if (jobParams.ldmParams.enableLdm == ZSTD_ps_enable && rawSeqStore.seq == NULL) + JOB_ERROR(ERROR(memory_allocation)); + + /* Don't compute the checksum for chunks, since we compute it externally, + * but write it in the header. + */ + if (job->jobID != 0) jobParams.fParams.checksumFlag = 0; + /* Don't run LDM for the chunks, since we handle it externally */ + jobParams.ldmParams.enableLdm = ZSTD_ps_disable; + /* Correct nbWorkers to 0. */ + jobParams.nbWorkers = 0; + + + /* init */ + if (job->cdict) { + size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, job->cdict, &jobParams, job->fullFrameSize); + assert(job->firstJob); /* only allowed for first job */ + if (ZSTD_isError(initError)) JOB_ERROR(initError); + } else { /* srcStart points at reloaded section */ + U64 const pledgedSrcSize = job->firstJob ? job->fullFrameSize : job->src.size; + { size_t const forceWindowError = ZSTD_CCtxParams_setParameter(&jobParams, ZSTD_c_forceMaxWindow, !job->firstJob); + if (ZSTD_isError(forceWindowError)) JOB_ERROR(forceWindowError); + } + if (!job->firstJob) { + size_t const err = ZSTD_CCtxParams_setParameter(&jobParams, ZSTD_c_deterministicRefPrefix, 0); + if (ZSTD_isError(err)) JOB_ERROR(err); + } + { size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, + job->prefix.start, job->prefix.size, ZSTD_dct_rawContent, /* load dictionary in "content-only" mode (no header analysis) */ + ZSTD_dtlm_fast, + NULL, /*cdict*/ + &jobParams, pledgedSrcSize); + if (ZSTD_isError(initError)) JOB_ERROR(initError); + } } + + /* Perform serial step as early as possible, but after CCtx initialization */ + ZSTDMT_serialState_update(job->serial, cctx, rawSeqStore, job->src, job->jobID); + + if (!job->firstJob) { /* flush and overwrite frame header when it's not first job */ + size_t const hSize = ZSTD_compressContinue_public(cctx, dstBuff.start, dstBuff.capacity, job->src.start, 0); + if (ZSTD_isError(hSize)) JOB_ERROR(hSize); + DEBUGLOG(5, "ZSTDMT_compressionJob: flush and overwrite %u bytes of frame header (not first job)", (U32)hSize); + ZSTD_invalidateRepCodes(cctx); + } + + /* compress */ + { size_t const chunkSize = 4*ZSTD_BLOCKSIZE_MAX; + int const nbChunks = (int)((job->src.size + (chunkSize-1)) / chunkSize); + const BYTE* ip = (const BYTE*) job->src.start; + BYTE* const ostart = (BYTE*)dstBuff.start; + BYTE* op = ostart; + BYTE* oend = op + dstBuff.capacity; + int chunkNb; + if (sizeof(size_t) > sizeof(int)) assert(job->src.size < ((size_t)INT_MAX) * chunkSize); /* check overflow */ + DEBUGLOG(5, "ZSTDMT_compressionJob: compress %u bytes in %i blocks", (U32)job->src.size, nbChunks); + assert(job->cSize == 0); + for (chunkNb = 1; chunkNb < nbChunks; chunkNb++) { + size_t const cSize = ZSTD_compressContinue_public(cctx, op, oend-op, ip, chunkSize); + if (ZSTD_isError(cSize)) JOB_ERROR(cSize); + ip += chunkSize; + op += cSize; assert(op < oend); + /* stats */ + ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex); + job->cSize += cSize; + job->consumed = chunkSize * chunkNb; + DEBUGLOG(5, "ZSTDMT_compressionJob: compress new block : cSize==%u bytes (total: %u)", + (U32)cSize, (U32)job->cSize); + ZSTD_pthread_cond_signal(&job->job_cond); /* warns some more data is ready to be flushed */ + ZSTD_pthread_mutex_unlock(&job->job_mutex); + } + /* last block */ + assert(chunkSize > 0); + assert((chunkSize & (chunkSize - 1)) == 0); /* chunkSize must be power of 2 for mask==(chunkSize-1) to work */ + if ((nbChunks > 0) | job->lastJob /*must output a "last block" flag*/ ) { + size_t const lastBlockSize1 = job->src.size & (chunkSize-1); + size_t const lastBlockSize = ((lastBlockSize1==0) & (job->src.size>=chunkSize)) ? chunkSize : lastBlockSize1; + size_t const cSize = (job->lastJob) ? + ZSTD_compressEnd_public(cctx, op, oend-op, ip, lastBlockSize) : + ZSTD_compressContinue_public(cctx, op, oend-op, ip, lastBlockSize); + if (ZSTD_isError(cSize)) JOB_ERROR(cSize); + lastCBlockSize = cSize; + } } + if (!job->firstJob) { + /* Double check that we don't have an ext-dict, because then our + * repcode invalidation doesn't work. + */ + assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window)); + } + ZSTD_CCtx_trace(cctx, 0); + +_endJob: + ZSTDMT_serialState_ensureFinished(job->serial, job->jobID, job->cSize); + if (job->prefix.size > 0) + DEBUGLOG(5, "Finished with prefix: %zx", (size_t)job->prefix.start); + DEBUGLOG(5, "Finished with source: %zx", (size_t)job->src.start); + /* release resources */ + ZSTDMT_releaseSeq(job->seqPool, rawSeqStore); + ZSTDMT_releaseCCtx(job->cctxPool, cctx); + /* report */ + ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex); + if (ZSTD_isError(job->cSize)) assert(lastCBlockSize == 0); + job->cSize += lastCBlockSize; + job->consumed = job->src.size; /* when job->consumed == job->src.size , compression job is presumed completed */ + ZSTD_pthread_cond_signal(&job->job_cond); + ZSTD_pthread_mutex_unlock(&job->job_mutex); +} + + +/* ------------------------------------------ */ +/* ===== Multi-threaded compression ===== */ +/* ------------------------------------------ */ + +typedef struct { + range_t prefix; /* read-only non-owned prefix buffer */ + buffer_t buffer; + size_t filled; +} inBuff_t; + +typedef struct { + BYTE* buffer; /* The round input buffer. All jobs get references + * to pieces of the buffer. ZSTDMT_tryGetInputRange() + * handles handing out job input buffers, and makes + * sure it doesn't overlap with any pieces still in use. + */ + size_t capacity; /* The capacity of buffer. */ + size_t pos; /* The position of the current inBuff in the round + * buffer. Updated past the end if the inBuff once + * the inBuff is sent to the worker thread. + * pos <= capacity. + */ +} roundBuff_t; + +static const roundBuff_t kNullRoundBuff = {NULL, 0, 0}; + +#define RSYNC_LENGTH 32 +/* Don't create chunks smaller than the zstd block size. + * This stops us from regressing compression ratio too much, + * and ensures our output fits in ZSTD_compressBound(). + * + * If this is shrunk < ZSTD_BLOCKSIZELOG_MIN then + * ZSTD_COMPRESSBOUND() will need to be updated. + */ +#define RSYNC_MIN_BLOCK_LOG ZSTD_BLOCKSIZELOG_MAX +#define RSYNC_MIN_BLOCK_SIZE (1< one job is already prepared, but pool has shortage of workers. Don't create a new job. */ + inBuff_t inBuff; + roundBuff_t roundBuff; + serialState_t serial; + rsyncState_t rsync; + unsigned jobIDMask; + unsigned doneJobID; + unsigned nextJobID; + unsigned frameEnded; + unsigned allJobsCompleted; + unsigned long long frameContentSize; + unsigned long long consumed; + unsigned long long produced; + ZSTD_customMem cMem; + ZSTD_CDict* cdictLocal; + const ZSTD_CDict* cdict; + unsigned providedFactory: 1; +}; + +static void ZSTDMT_freeJobsTable(ZSTDMT_jobDescription* jobTable, U32 nbJobs, ZSTD_customMem cMem) +{ + U32 jobNb; + if (jobTable == NULL) return; + for (jobNb=0; jobNb mtctx->jobIDMask+1) { /* need more job capacity */ + ZSTDMT_freeJobsTable(mtctx->jobs, mtctx->jobIDMask+1, mtctx->cMem); + mtctx->jobIDMask = 0; + mtctx->jobs = ZSTDMT_createJobsTable(&nbJobs, mtctx->cMem); + if (mtctx->jobs==NULL) return ERROR(memory_allocation); + assert((nbJobs != 0) && ((nbJobs & (nbJobs - 1)) == 0)); /* ensure nbJobs is a power of 2 */ + mtctx->jobIDMask = nbJobs - 1; + } + return 0; +} + + +/* ZSTDMT_CCtxParam_setNbWorkers(): + * Internal use only */ +static size_t ZSTDMT_CCtxParam_setNbWorkers(ZSTD_CCtx_params* params, unsigned nbWorkers) +{ + return ZSTD_CCtxParams_setParameter(params, ZSTD_c_nbWorkers, (int)nbWorkers); +} + +MEM_STATIC ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced_internal(unsigned nbWorkers, ZSTD_customMem cMem, ZSTD_threadPool* pool) +{ + ZSTDMT_CCtx* mtctx; + U32 nbJobs = nbWorkers + 2; + int initError; + DEBUGLOG(3, "ZSTDMT_createCCtx_advanced (nbWorkers = %u)", nbWorkers); + + if (nbWorkers < 1) return NULL; + nbWorkers = MIN(nbWorkers , ZSTDMT_NBWORKERS_MAX); + if ((cMem.customAlloc!=NULL) ^ (cMem.customFree!=NULL)) + /* invalid custom allocator */ + return NULL; + + mtctx = (ZSTDMT_CCtx*) ZSTD_customCalloc(sizeof(ZSTDMT_CCtx), cMem); + if (!mtctx) return NULL; + ZSTDMT_CCtxParam_setNbWorkers(&mtctx->params, nbWorkers); + mtctx->cMem = cMem; + mtctx->allJobsCompleted = 1; + if (pool != NULL) { + mtctx->factory = pool; + mtctx->providedFactory = 1; + } + else { + mtctx->factory = POOL_create_advanced(nbWorkers, 0, cMem); + mtctx->providedFactory = 0; + } + mtctx->jobs = ZSTDMT_createJobsTable(&nbJobs, cMem); + assert(nbJobs > 0); assert((nbJobs & (nbJobs - 1)) == 0); /* ensure nbJobs is a power of 2 */ + mtctx->jobIDMask = nbJobs - 1; + mtctx->bufPool = ZSTDMT_createBufferPool(BUF_POOL_MAX_NB_BUFFERS(nbWorkers), cMem); + mtctx->cctxPool = ZSTDMT_createCCtxPool(nbWorkers, cMem); + mtctx->seqPool = ZSTDMT_createSeqPool(nbWorkers, cMem); + initError = ZSTDMT_serialState_init(&mtctx->serial); + mtctx->roundBuff = kNullRoundBuff; + if (!mtctx->factory | !mtctx->jobs | !mtctx->bufPool | !mtctx->cctxPool | !mtctx->seqPool | initError) { + ZSTDMT_freeCCtx(mtctx); + return NULL; + } + DEBUGLOG(3, "mt_cctx created, for %u threads", nbWorkers); + return mtctx; +} + +ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, ZSTD_customMem cMem, ZSTD_threadPool* pool) +{ +#ifdef ZSTD_MULTITHREAD + return ZSTDMT_createCCtx_advanced_internal(nbWorkers, cMem, pool); +#else + (void)nbWorkers; + (void)cMem; + (void)pool; + return NULL; +#endif +} + + +/* ZSTDMT_releaseAllJobResources() : + * note : ensure all workers are killed first ! */ +static void ZSTDMT_releaseAllJobResources(ZSTDMT_CCtx* mtctx) +{ + unsigned jobID; + DEBUGLOG(3, "ZSTDMT_releaseAllJobResources"); + for (jobID=0; jobID <= mtctx->jobIDMask; jobID++) { + /* Copy the mutex/cond out */ + ZSTD_pthread_mutex_t const mutex = mtctx->jobs[jobID].job_mutex; + ZSTD_pthread_cond_t const cond = mtctx->jobs[jobID].job_cond; + + DEBUGLOG(4, "job%02u: release dst address %08X", jobID, (U32)(size_t)mtctx->jobs[jobID].dstBuff.start); + ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff); + + /* Clear the job description, but keep the mutex/cond */ + ZSTD_memset(&mtctx->jobs[jobID], 0, sizeof(mtctx->jobs[jobID])); + mtctx->jobs[jobID].job_mutex = mutex; + mtctx->jobs[jobID].job_cond = cond; + } + mtctx->inBuff.buffer = g_nullBuffer; + mtctx->inBuff.filled = 0; + mtctx->allJobsCompleted = 1; +} + +static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* mtctx) +{ + DEBUGLOG(4, "ZSTDMT_waitForAllJobsCompleted"); + while (mtctx->doneJobID < mtctx->nextJobID) { + unsigned const jobID = mtctx->doneJobID & mtctx->jobIDMask; + ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[jobID].job_mutex); + while (mtctx->jobs[jobID].consumed < mtctx->jobs[jobID].src.size) { + DEBUGLOG(4, "waiting for jobCompleted signal from job %u", mtctx->doneJobID); /* we want to block when waiting for data to flush */ + ZSTD_pthread_cond_wait(&mtctx->jobs[jobID].job_cond, &mtctx->jobs[jobID].job_mutex); + } + ZSTD_pthread_mutex_unlock(&mtctx->jobs[jobID].job_mutex); + mtctx->doneJobID++; + } +} + +size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx) +{ + if (mtctx==NULL) return 0; /* compatible with free on NULL */ + if (!mtctx->providedFactory) + POOL_free(mtctx->factory); /* stop and free worker threads */ + ZSTDMT_releaseAllJobResources(mtctx); /* release job resources into pools first */ + ZSTDMT_freeJobsTable(mtctx->jobs, mtctx->jobIDMask+1, mtctx->cMem); + ZSTDMT_freeBufferPool(mtctx->bufPool); + ZSTDMT_freeCCtxPool(mtctx->cctxPool); + ZSTDMT_freeSeqPool(mtctx->seqPool); + ZSTDMT_serialState_free(&mtctx->serial); + ZSTD_freeCDict(mtctx->cdictLocal); + if (mtctx->roundBuff.buffer) + ZSTD_customFree(mtctx->roundBuff.buffer, mtctx->cMem); + ZSTD_customFree(mtctx, mtctx->cMem); + return 0; +} + +size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx) +{ + if (mtctx == NULL) return 0; /* supports sizeof NULL */ + return sizeof(*mtctx) + + POOL_sizeof(mtctx->factory) + + ZSTDMT_sizeof_bufferPool(mtctx->bufPool) + + (mtctx->jobIDMask+1) * sizeof(ZSTDMT_jobDescription) + + ZSTDMT_sizeof_CCtxPool(mtctx->cctxPool) + + ZSTDMT_sizeof_seqPool(mtctx->seqPool) + + ZSTD_sizeof_CDict(mtctx->cdictLocal) + + mtctx->roundBuff.capacity; +} + + +/* ZSTDMT_resize() : + * @return : error code if fails, 0 on success */ +static size_t ZSTDMT_resize(ZSTDMT_CCtx* mtctx, unsigned nbWorkers) +{ + if (POOL_resize(mtctx->factory, nbWorkers)) return ERROR(memory_allocation); + FORWARD_IF_ERROR( ZSTDMT_expandJobsTable(mtctx, nbWorkers) , ""); + mtctx->bufPool = ZSTDMT_expandBufferPool(mtctx->bufPool, BUF_POOL_MAX_NB_BUFFERS(nbWorkers)); + if (mtctx->bufPool == NULL) return ERROR(memory_allocation); + mtctx->cctxPool = ZSTDMT_expandCCtxPool(mtctx->cctxPool, nbWorkers); + if (mtctx->cctxPool == NULL) return ERROR(memory_allocation); + mtctx->seqPool = ZSTDMT_expandSeqPool(mtctx->seqPool, nbWorkers); + if (mtctx->seqPool == NULL) return ERROR(memory_allocation); + ZSTDMT_CCtxParam_setNbWorkers(&mtctx->params, nbWorkers); + return 0; +} + + +/*! ZSTDMT_updateCParams_whileCompressing() : + * Updates a selected set of compression parameters, remaining compatible with currently active frame. + * New parameters will be applied to next compression job. */ +void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_params* cctxParams) +{ + U32 const saved_wlog = mtctx->params.cParams.windowLog; /* Do not modify windowLog while compressing */ + int const compressionLevel = cctxParams->compressionLevel; + DEBUGLOG(5, "ZSTDMT_updateCParams_whileCompressing (level:%i)", + compressionLevel); + mtctx->params.compressionLevel = compressionLevel; + { ZSTD_compressionParameters cParams = ZSTD_getCParamsFromCCtxParams(cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); + cParams.windowLog = saved_wlog; + mtctx->params.cParams = cParams; + } +} + +/* ZSTDMT_getFrameProgression(): + * tells how much data has been consumed (input) and produced (output) for current frame. + * able to count progression inside worker threads. + * Note : mutex will be acquired during statistics collection inside workers. */ +ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx) +{ + ZSTD_frameProgression fps; + DEBUGLOG(5, "ZSTDMT_getFrameProgression"); + fps.ingested = mtctx->consumed + mtctx->inBuff.filled; + fps.consumed = mtctx->consumed; + fps.produced = fps.flushed = mtctx->produced; + fps.currentJobID = mtctx->nextJobID; + fps.nbActiveWorkers = 0; + { unsigned jobNb; + unsigned lastJobNb = mtctx->nextJobID + mtctx->jobReady; assert(mtctx->jobReady <= 1); + DEBUGLOG(6, "ZSTDMT_getFrameProgression: jobs: from %u to <%u (jobReady:%u)", + mtctx->doneJobID, lastJobNb, mtctx->jobReady); + for (jobNb = mtctx->doneJobID ; jobNb < lastJobNb ; jobNb++) { + unsigned const wJobID = jobNb & mtctx->jobIDMask; + ZSTDMT_jobDescription* jobPtr = &mtctx->jobs[wJobID]; + ZSTD_pthread_mutex_lock(&jobPtr->job_mutex); + { size_t const cResult = jobPtr->cSize; + size_t const produced = ZSTD_isError(cResult) ? 0 : cResult; + size_t const flushed = ZSTD_isError(cResult) ? 0 : jobPtr->dstFlushed; + assert(flushed <= produced); + fps.ingested += jobPtr->src.size; + fps.consumed += jobPtr->consumed; + fps.produced += produced; + fps.flushed += flushed; + fps.nbActiveWorkers += (jobPtr->consumed < jobPtr->src.size); + } + ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex); + } + } + return fps; +} + + +size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx) +{ + size_t toFlush; + unsigned const jobID = mtctx->doneJobID; + assert(jobID <= mtctx->nextJobID); + if (jobID == mtctx->nextJobID) return 0; /* no active job => nothing to flush */ + + /* look into oldest non-fully-flushed job */ + { unsigned const wJobID = jobID & mtctx->jobIDMask; + ZSTDMT_jobDescription* const jobPtr = &mtctx->jobs[wJobID]; + ZSTD_pthread_mutex_lock(&jobPtr->job_mutex); + { size_t const cResult = jobPtr->cSize; + size_t const produced = ZSTD_isError(cResult) ? 0 : cResult; + size_t const flushed = ZSTD_isError(cResult) ? 0 : jobPtr->dstFlushed; + assert(flushed <= produced); + assert(jobPtr->consumed <= jobPtr->src.size); + toFlush = produced - flushed; + /* if toFlush==0, nothing is available to flush. + * However, jobID is expected to still be active: + * if jobID was already completed and fully flushed, + * ZSTDMT_flushProduced() should have already moved onto next job. + * Therefore, some input has not yet been consumed. */ + if (toFlush==0) { + assert(jobPtr->consumed < jobPtr->src.size); + } + } + ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex); + } + + return toFlush; +} + + +/* ------------------------------------------ */ +/* ===== Multi-threaded compression ===== */ +/* ------------------------------------------ */ + +static unsigned ZSTDMT_computeTargetJobLog(const ZSTD_CCtx_params* params) +{ + unsigned jobLog; + if (params->ldmParams.enableLdm == ZSTD_ps_enable) { + /* In Long Range Mode, the windowLog is typically oversized. + * In which case, it's preferable to determine the jobSize + * based on cycleLog instead. */ + jobLog = MAX(21, ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy) + 3); + } else { + jobLog = MAX(20, params->cParams.windowLog + 2); + } + return MIN(jobLog, (unsigned)ZSTDMT_JOBLOG_MAX); +} + +static int ZSTDMT_overlapLog_default(ZSTD_strategy strat) +{ + switch(strat) + { + case ZSTD_btultra2: + return 9; + case ZSTD_btultra: + case ZSTD_btopt: + return 8; + case ZSTD_btlazy2: + case ZSTD_lazy2: + return 7; + case ZSTD_lazy: + case ZSTD_greedy: + case ZSTD_dfast: + case ZSTD_fast: + default:; + } + return 6; +} + +static int ZSTDMT_overlapLog(int ovlog, ZSTD_strategy strat) +{ + assert(0 <= ovlog && ovlog <= 9); + if (ovlog == 0) return ZSTDMT_overlapLog_default(strat); + return ovlog; +} + +static size_t ZSTDMT_computeOverlapSize(const ZSTD_CCtx_params* params) +{ + int const overlapRLog = 9 - ZSTDMT_overlapLog(params->overlapLog, params->cParams.strategy); + int ovLog = (overlapRLog >= 8) ? 0 : (params->cParams.windowLog - overlapRLog); + assert(0 <= overlapRLog && overlapRLog <= 8); + if (params->ldmParams.enableLdm == ZSTD_ps_enable) { + /* In Long Range Mode, the windowLog is typically oversized. + * In which case, it's preferable to determine the jobSize + * based on chainLog instead. + * Then, ovLog becomes a fraction of the jobSize, rather than windowSize */ + ovLog = MIN(params->cParams.windowLog, ZSTDMT_computeTargetJobLog(params) - 2) + - overlapRLog; + } + assert(0 <= ovLog && ovLog <= ZSTD_WINDOWLOG_MAX); + DEBUGLOG(4, "overlapLog : %i", params->overlapLog); + DEBUGLOG(4, "overlap size : %i", 1 << ovLog); + return (ovLog==0) ? 0 : (size_t)1 << ovLog; +} + +/* ====================================== */ +/* ======= Streaming API ======= */ +/* ====================================== */ + +size_t ZSTDMT_initCStream_internal( + ZSTDMT_CCtx* mtctx, + const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, + const ZSTD_CDict* cdict, ZSTD_CCtx_params params, + unsigned long long pledgedSrcSize) +{ + DEBUGLOG(4, "ZSTDMT_initCStream_internal (pledgedSrcSize=%u, nbWorkers=%u, cctxPool=%u)", + (U32)pledgedSrcSize, params.nbWorkers, mtctx->cctxPool->totalCCtx); + + /* params supposed partially fully validated at this point */ + assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); + assert(!((dict) && (cdict))); /* either dict or cdict, not both */ + + /* init */ + if (params.nbWorkers != mtctx->params.nbWorkers) + FORWARD_IF_ERROR( ZSTDMT_resize(mtctx, params.nbWorkers) , ""); + + if (params.jobSize != 0 && params.jobSize < ZSTDMT_JOBSIZE_MIN) params.jobSize = ZSTDMT_JOBSIZE_MIN; + if (params.jobSize > (size_t)ZSTDMT_JOBSIZE_MAX) params.jobSize = (size_t)ZSTDMT_JOBSIZE_MAX; + + DEBUGLOG(4, "ZSTDMT_initCStream_internal: %u workers", params.nbWorkers); + + if (mtctx->allJobsCompleted == 0) { /* previous compression not correctly finished */ + ZSTDMT_waitForAllJobsCompleted(mtctx); + ZSTDMT_releaseAllJobResources(mtctx); + mtctx->allJobsCompleted = 1; + } + + mtctx->params = params; + mtctx->frameContentSize = pledgedSrcSize; + if (dict) { + ZSTD_freeCDict(mtctx->cdictLocal); + mtctx->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, + ZSTD_dlm_byCopy, dictContentType, /* note : a loadPrefix becomes an internal CDict */ + params.cParams, mtctx->cMem); + mtctx->cdict = mtctx->cdictLocal; + if (mtctx->cdictLocal == NULL) return ERROR(memory_allocation); + } else { + ZSTD_freeCDict(mtctx->cdictLocal); + mtctx->cdictLocal = NULL; + mtctx->cdict = cdict; + } + + mtctx->targetPrefixSize = ZSTDMT_computeOverlapSize(¶ms); + DEBUGLOG(4, "overlapLog=%i => %u KB", params.overlapLog, (U32)(mtctx->targetPrefixSize>>10)); + mtctx->targetSectionSize = params.jobSize; + if (mtctx->targetSectionSize == 0) { + mtctx->targetSectionSize = 1ULL << ZSTDMT_computeTargetJobLog(¶ms); + } + assert(mtctx->targetSectionSize <= (size_t)ZSTDMT_JOBSIZE_MAX); + + if (params.rsyncable) { + /* Aim for the targetsectionSize as the average job size. */ + U32 const jobSizeKB = (U32)(mtctx->targetSectionSize >> 10); + U32 const rsyncBits = (assert(jobSizeKB >= 1), ZSTD_highbit32(jobSizeKB) + 10); + /* We refuse to create jobs < RSYNC_MIN_BLOCK_SIZE bytes, so make sure our + * expected job size is at least 4x larger. */ + assert(rsyncBits >= RSYNC_MIN_BLOCK_LOG + 2); + DEBUGLOG(4, "rsyncLog = %u", rsyncBits); + mtctx->rsync.hash = 0; + mtctx->rsync.hitMask = (1ULL << rsyncBits) - 1; + mtctx->rsync.primePower = ZSTD_rollingHash_primePower(RSYNC_LENGTH); + } + if (mtctx->targetSectionSize < mtctx->targetPrefixSize) mtctx->targetSectionSize = mtctx->targetPrefixSize; /* job size must be >= overlap size */ + DEBUGLOG(4, "Job Size : %u KB (note : set to %u)", (U32)(mtctx->targetSectionSize>>10), (U32)params.jobSize); + DEBUGLOG(4, "inBuff Size : %u KB", (U32)(mtctx->targetSectionSize>>10)); + ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(mtctx->targetSectionSize)); + { + /* If ldm is enabled we need windowSize space. */ + size_t const windowSize = mtctx->params.ldmParams.enableLdm == ZSTD_ps_enable ? (1U << mtctx->params.cParams.windowLog) : 0; + /* Two buffers of slack, plus extra space for the overlap + * This is the minimum slack that LDM works with. One extra because + * flush might waste up to targetSectionSize-1 bytes. Another extra + * for the overlap (if > 0), then one to fill which doesn't overlap + * with the LDM window. + */ + size_t const nbSlackBuffers = 2 + (mtctx->targetPrefixSize > 0); + size_t const slackSize = mtctx->targetSectionSize * nbSlackBuffers; + /* Compute the total size, and always have enough slack */ + size_t const nbWorkers = MAX(mtctx->params.nbWorkers, 1); + size_t const sectionsSize = mtctx->targetSectionSize * nbWorkers; + size_t const capacity = MAX(windowSize, sectionsSize) + slackSize; + if (mtctx->roundBuff.capacity < capacity) { + if (mtctx->roundBuff.buffer) + ZSTD_customFree(mtctx->roundBuff.buffer, mtctx->cMem); + mtctx->roundBuff.buffer = (BYTE*)ZSTD_customMalloc(capacity, mtctx->cMem); + if (mtctx->roundBuff.buffer == NULL) { + mtctx->roundBuff.capacity = 0; + return ERROR(memory_allocation); + } + mtctx->roundBuff.capacity = capacity; + } + } + DEBUGLOG(4, "roundBuff capacity : %u KB", (U32)(mtctx->roundBuff.capacity>>10)); + mtctx->roundBuff.pos = 0; + mtctx->inBuff.buffer = g_nullBuffer; + mtctx->inBuff.filled = 0; + mtctx->inBuff.prefix = kNullRange; + mtctx->doneJobID = 0; + mtctx->nextJobID = 0; + mtctx->frameEnded = 0; + mtctx->allJobsCompleted = 0; + mtctx->consumed = 0; + mtctx->produced = 0; + if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params, mtctx->targetSectionSize, + dict, dictSize, dictContentType)) + return ERROR(memory_allocation); + return 0; +} + + +/* ZSTDMT_writeLastEmptyBlock() + * Write a single empty block with an end-of-frame to finish a frame. + * Job must be created from streaming variant. + * This function is always successful if expected conditions are fulfilled. + */ +static void ZSTDMT_writeLastEmptyBlock(ZSTDMT_jobDescription* job) +{ + assert(job->lastJob == 1); + assert(job->src.size == 0); /* last job is empty -> will be simplified into a last empty block */ + assert(job->firstJob == 0); /* cannot be first job, as it also needs to create frame header */ + assert(job->dstBuff.start == NULL); /* invoked from streaming variant only (otherwise, dstBuff might be user's output) */ + job->dstBuff = ZSTDMT_getBuffer(job->bufPool); + if (job->dstBuff.start == NULL) { + job->cSize = ERROR(memory_allocation); + return; + } + assert(job->dstBuff.capacity >= ZSTD_blockHeaderSize); /* no buffer should ever be that small */ + job->src = kNullRange; + job->cSize = ZSTD_writeLastEmptyBlock(job->dstBuff.start, job->dstBuff.capacity); + assert(!ZSTD_isError(job->cSize)); + assert(job->consumed == 0); +} + +static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* mtctx, size_t srcSize, ZSTD_EndDirective endOp) +{ + unsigned const jobID = mtctx->nextJobID & mtctx->jobIDMask; + int const endFrame = (endOp == ZSTD_e_end); + + if (mtctx->nextJobID > mtctx->doneJobID + mtctx->jobIDMask) { + DEBUGLOG(5, "ZSTDMT_createCompressionJob: will not create new job : table is full"); + assert((mtctx->nextJobID & mtctx->jobIDMask) == (mtctx->doneJobID & mtctx->jobIDMask)); + return 0; + } + + if (!mtctx->jobReady) { + BYTE const* src = (BYTE const*)mtctx->inBuff.buffer.start; + DEBUGLOG(5, "ZSTDMT_createCompressionJob: preparing job %u to compress %u bytes with %u preload ", + mtctx->nextJobID, (U32)srcSize, (U32)mtctx->inBuff.prefix.size); + mtctx->jobs[jobID].src.start = src; + mtctx->jobs[jobID].src.size = srcSize; + assert(mtctx->inBuff.filled >= srcSize); + mtctx->jobs[jobID].prefix = mtctx->inBuff.prefix; + mtctx->jobs[jobID].consumed = 0; + mtctx->jobs[jobID].cSize = 0; + mtctx->jobs[jobID].params = mtctx->params; + mtctx->jobs[jobID].cdict = mtctx->nextJobID==0 ? mtctx->cdict : NULL; + mtctx->jobs[jobID].fullFrameSize = mtctx->frameContentSize; + mtctx->jobs[jobID].dstBuff = g_nullBuffer; + mtctx->jobs[jobID].cctxPool = mtctx->cctxPool; + mtctx->jobs[jobID].bufPool = mtctx->bufPool; + mtctx->jobs[jobID].seqPool = mtctx->seqPool; + mtctx->jobs[jobID].serial = &mtctx->serial; + mtctx->jobs[jobID].jobID = mtctx->nextJobID; + mtctx->jobs[jobID].firstJob = (mtctx->nextJobID==0); + mtctx->jobs[jobID].lastJob = endFrame; + mtctx->jobs[jobID].frameChecksumNeeded = mtctx->params.fParams.checksumFlag && endFrame && (mtctx->nextJobID>0); + mtctx->jobs[jobID].dstFlushed = 0; + + /* Update the round buffer pos and clear the input buffer to be reset */ + mtctx->roundBuff.pos += srcSize; + mtctx->inBuff.buffer = g_nullBuffer; + mtctx->inBuff.filled = 0; + /* Set the prefix */ + if (!endFrame) { + size_t const newPrefixSize = MIN(srcSize, mtctx->targetPrefixSize); + mtctx->inBuff.prefix.start = src + srcSize - newPrefixSize; + mtctx->inBuff.prefix.size = newPrefixSize; + } else { /* endFrame==1 => no need for another input buffer */ + mtctx->inBuff.prefix = kNullRange; + mtctx->frameEnded = endFrame; + if (mtctx->nextJobID == 0) { + /* single job exception : checksum is already calculated directly within worker thread */ + mtctx->params.fParams.checksumFlag = 0; + } } + + if ( (srcSize == 0) + && (mtctx->nextJobID>0)/*single job must also write frame header*/ ) { + DEBUGLOG(5, "ZSTDMT_createCompressionJob: creating a last empty block to end frame"); + assert(endOp == ZSTD_e_end); /* only possible case : need to end the frame with an empty last block */ + ZSTDMT_writeLastEmptyBlock(mtctx->jobs + jobID); + mtctx->nextJobID++; + return 0; + } + } + + DEBUGLOG(5, "ZSTDMT_createCompressionJob: posting job %u : %u bytes (end:%u, jobNb == %u (mod:%u))", + mtctx->nextJobID, + (U32)mtctx->jobs[jobID].src.size, + mtctx->jobs[jobID].lastJob, + mtctx->nextJobID, + jobID); + if (POOL_tryAdd(mtctx->factory, ZSTDMT_compressionJob, &mtctx->jobs[jobID])) { + mtctx->nextJobID++; + mtctx->jobReady = 0; + } else { + DEBUGLOG(5, "ZSTDMT_createCompressionJob: no worker available for job %u", mtctx->nextJobID); + mtctx->jobReady = 1; + } + return 0; +} + + +/*! ZSTDMT_flushProduced() : + * flush whatever data has been produced but not yet flushed in current job. + * move to next job if current one is fully flushed. + * `output` : `pos` will be updated with amount of data flushed . + * `blockToFlush` : if >0, the function will block and wait if there is no data available to flush . + * @return : amount of data remaining within internal buffer, 0 if no more, 1 if unknown but > 0, or an error code */ +static size_t ZSTDMT_flushProduced(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, unsigned blockToFlush, ZSTD_EndDirective end) +{ + unsigned const wJobID = mtctx->doneJobID & mtctx->jobIDMask; + DEBUGLOG(5, "ZSTDMT_flushProduced (blocking:%u , job %u <= %u)", + blockToFlush, mtctx->doneJobID, mtctx->nextJobID); + assert(output->size >= output->pos); + + ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[wJobID].job_mutex); + if ( blockToFlush + && (mtctx->doneJobID < mtctx->nextJobID) ) { + assert(mtctx->jobs[wJobID].dstFlushed <= mtctx->jobs[wJobID].cSize); + while (mtctx->jobs[wJobID].dstFlushed == mtctx->jobs[wJobID].cSize) { /* nothing to flush */ + if (mtctx->jobs[wJobID].consumed == mtctx->jobs[wJobID].src.size) { + DEBUGLOG(5, "job %u is completely consumed (%u == %u) => don't wait for cond, there will be none", + mtctx->doneJobID, (U32)mtctx->jobs[wJobID].consumed, (U32)mtctx->jobs[wJobID].src.size); + break; + } + DEBUGLOG(5, "waiting for something to flush from job %u (currently flushed: %u bytes)", + mtctx->doneJobID, (U32)mtctx->jobs[wJobID].dstFlushed); + ZSTD_pthread_cond_wait(&mtctx->jobs[wJobID].job_cond, &mtctx->jobs[wJobID].job_mutex); /* block when nothing to flush but some to come */ + } } + + /* try to flush something */ + { size_t cSize = mtctx->jobs[wJobID].cSize; /* shared */ + size_t const srcConsumed = mtctx->jobs[wJobID].consumed; /* shared */ + size_t const srcSize = mtctx->jobs[wJobID].src.size; /* read-only, could be done after mutex lock, but no-declaration-after-statement */ + ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex); + if (ZSTD_isError(cSize)) { + DEBUGLOG(5, "ZSTDMT_flushProduced: job %u : compression error detected : %s", + mtctx->doneJobID, ZSTD_getErrorName(cSize)); + ZSTDMT_waitForAllJobsCompleted(mtctx); + ZSTDMT_releaseAllJobResources(mtctx); + return cSize; + } + /* add frame checksum if necessary (can only happen once) */ + assert(srcConsumed <= srcSize); + if ( (srcConsumed == srcSize) /* job completed -> worker no longer active */ + && mtctx->jobs[wJobID].frameChecksumNeeded ) { + U32 const checksum = (U32)XXH64_digest(&mtctx->serial.xxhState); + DEBUGLOG(4, "ZSTDMT_flushProduced: writing checksum : %08X \n", checksum); + MEM_writeLE32((char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].cSize, checksum); + cSize += 4; + mtctx->jobs[wJobID].cSize += 4; /* can write this shared value, as worker is no longer active */ + mtctx->jobs[wJobID].frameChecksumNeeded = 0; + } + + if (cSize > 0) { /* compression is ongoing or completed */ + size_t const toFlush = MIN(cSize - mtctx->jobs[wJobID].dstFlushed, output->size - output->pos); + DEBUGLOG(5, "ZSTDMT_flushProduced: Flushing %u bytes from job %u (completion:%u/%u, generated:%u)", + (U32)toFlush, mtctx->doneJobID, (U32)srcConsumed, (U32)srcSize, (U32)cSize); + assert(mtctx->doneJobID < mtctx->nextJobID); + assert(cSize >= mtctx->jobs[wJobID].dstFlushed); + assert(mtctx->jobs[wJobID].dstBuff.start != NULL); + if (toFlush > 0) { + ZSTD_memcpy((char*)output->dst + output->pos, + (const char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].dstFlushed, + toFlush); + } + output->pos += toFlush; + mtctx->jobs[wJobID].dstFlushed += toFlush; /* can write : this value is only used by mtctx */ + + if ( (srcConsumed == srcSize) /* job is completed */ + && (mtctx->jobs[wJobID].dstFlushed == cSize) ) { /* output buffer fully flushed => free this job position */ + DEBUGLOG(5, "Job %u completed (%u bytes), moving to next one", + mtctx->doneJobID, (U32)mtctx->jobs[wJobID].dstFlushed); + ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[wJobID].dstBuff); + DEBUGLOG(5, "dstBuffer released"); + mtctx->jobs[wJobID].dstBuff = g_nullBuffer; + mtctx->jobs[wJobID].cSize = 0; /* ensure this job slot is considered "not started" in future check */ + mtctx->consumed += srcSize; + mtctx->produced += cSize; + mtctx->doneJobID++; + } } + + /* return value : how many bytes left in buffer ; fake it to 1 when unknown but >0 */ + if (cSize > mtctx->jobs[wJobID].dstFlushed) return (cSize - mtctx->jobs[wJobID].dstFlushed); + if (srcSize > srcConsumed) return 1; /* current job not completely compressed */ + } + if (mtctx->doneJobID < mtctx->nextJobID) return 1; /* some more jobs ongoing */ + if (mtctx->jobReady) return 1; /* one job is ready to push, just not yet in the list */ + if (mtctx->inBuff.filled > 0) return 1; /* input is not empty, and still needs to be converted into a job */ + mtctx->allJobsCompleted = mtctx->frameEnded; /* all jobs are entirely flushed => if this one is last one, frame is completed */ + if (end == ZSTD_e_end) return !mtctx->frameEnded; /* for ZSTD_e_end, question becomes : is frame completed ? instead of : are internal buffers fully flushed ? */ + return 0; /* internal buffers fully flushed */ +} + +/** + * Returns the range of data used by the earliest job that is not yet complete. + * If the data of the first job is broken up into two segments, we cover both + * sections. + */ +static range_t ZSTDMT_getInputDataInUse(ZSTDMT_CCtx* mtctx) +{ + unsigned const firstJobID = mtctx->doneJobID; + unsigned const lastJobID = mtctx->nextJobID; + unsigned jobID; + + for (jobID = firstJobID; jobID < lastJobID; ++jobID) { + unsigned const wJobID = jobID & mtctx->jobIDMask; + size_t consumed; + + ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[wJobID].job_mutex); + consumed = mtctx->jobs[wJobID].consumed; + ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex); + + if (consumed < mtctx->jobs[wJobID].src.size) { + range_t range = mtctx->jobs[wJobID].prefix; + if (range.size == 0) { + /* Empty prefix */ + range = mtctx->jobs[wJobID].src; + } + /* Job source in multiple segments not supported yet */ + assert(range.start <= mtctx->jobs[wJobID].src.start); + return range; + } + } + return kNullRange; +} + +/** + * Returns non-zero iff buffer and range overlap. + */ +static int ZSTDMT_isOverlapped(buffer_t buffer, range_t range) +{ + BYTE const* const bufferStart = (BYTE const*)buffer.start; + BYTE const* const rangeStart = (BYTE const*)range.start; + + if (rangeStart == NULL || bufferStart == NULL) + return 0; + + { + BYTE const* const bufferEnd = bufferStart + buffer.capacity; + BYTE const* const rangeEnd = rangeStart + range.size; + + /* Empty ranges cannot overlap */ + if (bufferStart == bufferEnd || rangeStart == rangeEnd) + return 0; + + return bufferStart < rangeEnd && rangeStart < bufferEnd; + } +} + +static int ZSTDMT_doesOverlapWindow(buffer_t buffer, ZSTD_window_t window) +{ + range_t extDict; + range_t prefix; + + DEBUGLOG(5, "ZSTDMT_doesOverlapWindow"); + extDict.start = window.dictBase + window.lowLimit; + extDict.size = window.dictLimit - window.lowLimit; + + prefix.start = window.base + window.dictLimit; + prefix.size = window.nextSrc - (window.base + window.dictLimit); + DEBUGLOG(5, "extDict [0x%zx, 0x%zx)", + (size_t)extDict.start, + (size_t)extDict.start + extDict.size); + DEBUGLOG(5, "prefix [0x%zx, 0x%zx)", + (size_t)prefix.start, + (size_t)prefix.start + prefix.size); + + return ZSTDMT_isOverlapped(buffer, extDict) + || ZSTDMT_isOverlapped(buffer, prefix); +} + +static void ZSTDMT_waitForLdmComplete(ZSTDMT_CCtx* mtctx, buffer_t buffer) +{ + if (mtctx->params.ldmParams.enableLdm == ZSTD_ps_enable) { + ZSTD_pthread_mutex_t* mutex = &mtctx->serial.ldmWindowMutex; + DEBUGLOG(5, "ZSTDMT_waitForLdmComplete"); + DEBUGLOG(5, "source [0x%zx, 0x%zx)", + (size_t)buffer.start, + (size_t)buffer.start + buffer.capacity); + ZSTD_PTHREAD_MUTEX_LOCK(mutex); + while (ZSTDMT_doesOverlapWindow(buffer, mtctx->serial.ldmWindow)) { + DEBUGLOG(5, "Waiting for LDM to finish..."); + ZSTD_pthread_cond_wait(&mtctx->serial.ldmWindowCond, mutex); + } + DEBUGLOG(6, "Done waiting for LDM to finish"); + ZSTD_pthread_mutex_unlock(mutex); + } +} + +/** + * Attempts to set the inBuff to the next section to fill. + * If any part of the new section is still in use we give up. + * Returns non-zero if the buffer is filled. + */ +static int ZSTDMT_tryGetInputRange(ZSTDMT_CCtx* mtctx) +{ + range_t const inUse = ZSTDMT_getInputDataInUse(mtctx); + size_t const spaceLeft = mtctx->roundBuff.capacity - mtctx->roundBuff.pos; + size_t const target = mtctx->targetSectionSize; + buffer_t buffer; + + DEBUGLOG(5, "ZSTDMT_tryGetInputRange"); + assert(mtctx->inBuff.buffer.start == NULL); + assert(mtctx->roundBuff.capacity >= target); + + if (spaceLeft < target) { + /* ZSTD_invalidateRepCodes() doesn't work for extDict variants. + * Simply copy the prefix to the beginning in that case. + */ + BYTE* const start = (BYTE*)mtctx->roundBuff.buffer; + size_t const prefixSize = mtctx->inBuff.prefix.size; + + buffer.start = start; + buffer.capacity = prefixSize; + if (ZSTDMT_isOverlapped(buffer, inUse)) { + DEBUGLOG(5, "Waiting for buffer..."); + return 0; + } + ZSTDMT_waitForLdmComplete(mtctx, buffer); + ZSTD_memmove(start, mtctx->inBuff.prefix.start, prefixSize); + mtctx->inBuff.prefix.start = start; + mtctx->roundBuff.pos = prefixSize; + } + buffer.start = mtctx->roundBuff.buffer + mtctx->roundBuff.pos; + buffer.capacity = target; + + if (ZSTDMT_isOverlapped(buffer, inUse)) { + DEBUGLOG(5, "Waiting for buffer..."); + return 0; + } + assert(!ZSTDMT_isOverlapped(buffer, mtctx->inBuff.prefix)); + + ZSTDMT_waitForLdmComplete(mtctx, buffer); + + DEBUGLOG(5, "Using prefix range [%zx, %zx)", + (size_t)mtctx->inBuff.prefix.start, + (size_t)mtctx->inBuff.prefix.start + mtctx->inBuff.prefix.size); + DEBUGLOG(5, "Using source range [%zx, %zx)", + (size_t)buffer.start, + (size_t)buffer.start + buffer.capacity); + + + mtctx->inBuff.buffer = buffer; + mtctx->inBuff.filled = 0; + assert(mtctx->roundBuff.pos + buffer.capacity <= mtctx->roundBuff.capacity); + return 1; +} + +typedef struct { + size_t toLoad; /* The number of bytes to load from the input. */ + int flush; /* Boolean declaring if we must flush because we found a synchronization point. */ +} syncPoint_t; + +/** + * Searches through the input for a synchronization point. If one is found, we + * will instruct the caller to flush, and return the number of bytes to load. + * Otherwise, we will load as many bytes as possible and instruct the caller + * to continue as normal. + */ +static syncPoint_t +findSynchronizationPoint(ZSTDMT_CCtx const* mtctx, ZSTD_inBuffer const input) +{ + BYTE const* const istart = (BYTE const*)input.src + input.pos; + U64 const primePower = mtctx->rsync.primePower; + U64 const hitMask = mtctx->rsync.hitMask; + + syncPoint_t syncPoint; + U64 hash; + BYTE const* prev; + size_t pos; + + syncPoint.toLoad = MIN(input.size - input.pos, mtctx->targetSectionSize - mtctx->inBuff.filled); + syncPoint.flush = 0; + if (!mtctx->params.rsyncable) + /* Rsync is disabled. */ + return syncPoint; + if (mtctx->inBuff.filled + input.size - input.pos < RSYNC_MIN_BLOCK_SIZE) + /* We don't emit synchronization points if it would produce too small blocks. + * We don't have enough input to find a synchronization point, so don't look. + */ + return syncPoint; + if (mtctx->inBuff.filled + syncPoint.toLoad < RSYNC_LENGTH) + /* Not enough to compute the hash. + * We will miss any synchronization points in this RSYNC_LENGTH byte + * window. However, since it depends only in the internal buffers, if the + * state is already synchronized, we will remain synchronized. + * Additionally, the probability that we miss a synchronization point is + * low: RSYNC_LENGTH / targetSectionSize. + */ + return syncPoint; + /* Initialize the loop variables. */ + if (mtctx->inBuff.filled < RSYNC_MIN_BLOCK_SIZE) { + /* We don't need to scan the first RSYNC_MIN_BLOCK_SIZE positions + * because they can't possibly be a sync point. So we can start + * part way through the input buffer. + */ + pos = RSYNC_MIN_BLOCK_SIZE - mtctx->inBuff.filled; + if (pos >= RSYNC_LENGTH) { + prev = istart + pos - RSYNC_LENGTH; + hash = ZSTD_rollingHash_compute(prev, RSYNC_LENGTH); + } else { + assert(mtctx->inBuff.filled >= RSYNC_LENGTH); + prev = (BYTE const*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled - RSYNC_LENGTH; + hash = ZSTD_rollingHash_compute(prev + pos, (RSYNC_LENGTH - pos)); + hash = ZSTD_rollingHash_append(hash, istart, pos); + } + } else { + /* We have enough bytes buffered to initialize the hash, + * and have processed enough bytes to find a sync point. + * Start scanning at the beginning of the input. + */ + assert(mtctx->inBuff.filled >= RSYNC_MIN_BLOCK_SIZE); + assert(RSYNC_MIN_BLOCK_SIZE >= RSYNC_LENGTH); + pos = 0; + prev = (BYTE const*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled - RSYNC_LENGTH; + hash = ZSTD_rollingHash_compute(prev, RSYNC_LENGTH); + if ((hash & hitMask) == hitMask) { + /* We're already at a sync point so don't load any more until + * we're able to flush this sync point. + * This likely happened because the job table was full so we + * couldn't add our job. + */ + syncPoint.toLoad = 0; + syncPoint.flush = 1; + return syncPoint; + } + } + /* Starting with the hash of the previous RSYNC_LENGTH bytes, roll + * through the input. If we hit a synchronization point, then cut the + * job off, and tell the compressor to flush the job. Otherwise, load + * all the bytes and continue as normal. + * If we go too long without a synchronization point (targetSectionSize) + * then a block will be emitted anyways, but this is okay, since if we + * are already synchronized we will remain synchronized. + */ + assert(pos < RSYNC_LENGTH || ZSTD_rollingHash_compute(istart + pos - RSYNC_LENGTH, RSYNC_LENGTH) == hash); + for (; pos < syncPoint.toLoad; ++pos) { + BYTE const toRemove = pos < RSYNC_LENGTH ? prev[pos] : istart[pos - RSYNC_LENGTH]; + /* This assert is very expensive, and Debian compiles with asserts enabled. + * So disable it for now. We can get similar coverage by checking it at the + * beginning & end of the loop. + * assert(pos < RSYNC_LENGTH || ZSTD_rollingHash_compute(istart + pos - RSYNC_LENGTH, RSYNC_LENGTH) == hash); + */ + hash = ZSTD_rollingHash_rotate(hash, toRemove, istart[pos], primePower); + assert(mtctx->inBuff.filled + pos >= RSYNC_MIN_BLOCK_SIZE); + if ((hash & hitMask) == hitMask) { + syncPoint.toLoad = pos + 1; + syncPoint.flush = 1; + ++pos; /* for assert */ + break; + } + } + assert(pos < RSYNC_LENGTH || ZSTD_rollingHash_compute(istart + pos - RSYNC_LENGTH, RSYNC_LENGTH) == hash); + return syncPoint; +} + +size_t ZSTDMT_nextInputSizeHint(const ZSTDMT_CCtx* mtctx) +{ + size_t hintInSize = mtctx->targetSectionSize - mtctx->inBuff.filled; + if (hintInSize==0) hintInSize = mtctx->targetSectionSize; + return hintInSize; +} + +/** ZSTDMT_compressStream_generic() : + * internal use only - exposed to be invoked from zstd_compress.c + * assumption : output and input are valid (pos <= size) + * @return : minimum amount of data remaining to flush, 0 if none */ +size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, + ZSTD_outBuffer* output, + ZSTD_inBuffer* input, + ZSTD_EndDirective endOp) +{ + unsigned forwardInputProgress = 0; + DEBUGLOG(5, "ZSTDMT_compressStream_generic (endOp=%u, srcSize=%u)", + (U32)endOp, (U32)(input->size - input->pos)); + assert(output->pos <= output->size); + assert(input->pos <= input->size); + + if ((mtctx->frameEnded) && (endOp==ZSTD_e_continue)) { + /* current frame being ended. Only flush/end are allowed */ + return ERROR(stage_wrong); + } + + /* fill input buffer */ + if ( (!mtctx->jobReady) + && (input->size > input->pos) ) { /* support NULL input */ + if (mtctx->inBuff.buffer.start == NULL) { + assert(mtctx->inBuff.filled == 0); /* Can't fill an empty buffer */ + if (!ZSTDMT_tryGetInputRange(mtctx)) { + /* It is only possible for this operation to fail if there are + * still compression jobs ongoing. + */ + DEBUGLOG(5, "ZSTDMT_tryGetInputRange failed"); + assert(mtctx->doneJobID != mtctx->nextJobID); + } else + DEBUGLOG(5, "ZSTDMT_tryGetInputRange completed successfully : mtctx->inBuff.buffer.start = %p", mtctx->inBuff.buffer.start); + } + if (mtctx->inBuff.buffer.start != NULL) { + syncPoint_t const syncPoint = findSynchronizationPoint(mtctx, *input); + if (syncPoint.flush && endOp == ZSTD_e_continue) { + endOp = ZSTD_e_flush; + } + assert(mtctx->inBuff.buffer.capacity >= mtctx->targetSectionSize); + DEBUGLOG(5, "ZSTDMT_compressStream_generic: adding %u bytes on top of %u to buffer of size %u", + (U32)syncPoint.toLoad, (U32)mtctx->inBuff.filled, (U32)mtctx->targetSectionSize); + ZSTD_memcpy((char*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled, (const char*)input->src + input->pos, syncPoint.toLoad); + input->pos += syncPoint.toLoad; + mtctx->inBuff.filled += syncPoint.toLoad; + forwardInputProgress = syncPoint.toLoad>0; + } + } + if ((input->pos < input->size) && (endOp == ZSTD_e_end)) { + /* Can't end yet because the input is not fully consumed. + * We are in one of these cases: + * - mtctx->inBuff is NULL & empty: we couldn't get an input buffer so don't create a new job. + * - We filled the input buffer: flush this job but don't end the frame. + * - We hit a synchronization point: flush this job but don't end the frame. + */ + assert(mtctx->inBuff.filled == 0 || mtctx->inBuff.filled == mtctx->targetSectionSize || mtctx->params.rsyncable); + endOp = ZSTD_e_flush; + } + + if ( (mtctx->jobReady) + || (mtctx->inBuff.filled >= mtctx->targetSectionSize) /* filled enough : let's compress */ + || ((endOp != ZSTD_e_continue) && (mtctx->inBuff.filled > 0)) /* something to flush : let's go */ + || ((endOp == ZSTD_e_end) && (!mtctx->frameEnded)) ) { /* must finish the frame with a zero-size block */ + size_t const jobSize = mtctx->inBuff.filled; + assert(mtctx->inBuff.filled <= mtctx->targetSectionSize); + FORWARD_IF_ERROR( ZSTDMT_createCompressionJob(mtctx, jobSize, endOp) , ""); + } + + /* check for potential compressed data ready to be flushed */ + { size_t const remainingToFlush = ZSTDMT_flushProduced(mtctx, output, !forwardInputProgress, endOp); /* block if there was no forward input progress */ + if (input->pos < input->size) return MAX(remainingToFlush, 1); /* input not consumed : do not end flush yet */ + DEBUGLOG(5, "end of ZSTDMT_compressStream_generic: remainingToFlush = %u", (U32)remainingToFlush); + return remainingToFlush; + } +} + +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/decompress/huf_decompress.cpp b/src/duckdb/third_party/zstd/decompress/huf_decompress.cpp index 3c9a8cdff..736e2f06d 100644 --- a/src/duckdb/third_party/zstd/decompress/huf_decompress.cpp +++ b/src/duckdb/third_party/zstd/decompress/huf_decompress.cpp @@ -1,7 +1,7 @@ /* ****************************************************************** * huff0 huffman decoder, * part of Finite State Entropy library - * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * You can contact the author at : * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -15,19 +15,31 @@ /* ************************************************************** * Dependencies ****************************************************************/ -#include /* memcpy, memset */ +#include "zstd/common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset */ #include "zstd/common/compiler.h" #include "zstd/common/bitstream.h" /* BIT_* */ #include "zstd/common/fse.h" /* to compress headers */ #include "zstd/common/huf.h" -#include "zstd/common/huf_static.h" #include "zstd/common/error_private.h" +#include "zstd/common/zstd_internal.h" +#include "zstd/common/bits.h" /* ZSTD_highbit32, ZSTD_countTrailingZeros64 */ + +/* ************************************************************** +* Constants +****************************************************************/ + +#define HUF_DECODER_FAST_TABLELOG 11 -namespace duckdb_zstd { /* ************************************************************** * Macros ****************************************************************/ +#ifdef HUF_DISABLE_FAST_DECODE +# define HUF_ENABLE_FAST_DECODE 0 +#else +# define HUF_ENABLE_FAST_DECODE 1 +#endif + /* These two optional macros force the use one way or another of the two * Huffman decompression implementations. You can't force in both directions * at the same time. @@ -37,11 +49,33 @@ namespace duckdb_zstd { #error "Cannot force the use of the X1 and X2 decoders at the same time!" #endif +/* When DYNAMIC_BMI2 is enabled, fast decoders are only called when bmi2 is + * supported at runtime, so we can add the BMI2 target attribute. + * When it is disabled, we will still get BMI2 if it is enabled statically. + */ +#if DYNAMIC_BMI2 +# define HUF_FAST_BMI2_ATTRS BMI2_TARGET_ATTRIBUTE +#else +# define HUF_FAST_BMI2_ATTRS +#endif + +#ifdef __cplusplus +# define HUF_EXTERN_C extern "C" +#else +# define HUF_EXTERN_C +#endif +#define HUF_ASM_DECL HUF_EXTERN_C + +#if DYNAMIC_BMI2 +# define HUF_NEED_BMI2_FUNCTION 1 +#else +# define HUF_NEED_BMI2_FUNCTION 0 +#endif /* ************************************************************** * Error Management ****************************************************************/ -// #define HUF_isError ERR_isError +#define HUF_isError ERR_isError /* ************************************************************** @@ -50,10 +84,16 @@ namespace duckdb_zstd { #define HUF_ALIGN(x, a) HUF_ALIGN_MASK((x), (a) - 1) #define HUF_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) +namespace duckdb_zstd { /* ************************************************************** * BMI2 Variant Wrappers ****************************************************************/ +typedef size_t (*HUF_DecompressUsingDTableFn)(void *dst, size_t dstSize, + const void *cSrc, + size_t cSrcSize, + const HUF_DTable *DTable); + #if DYNAMIC_BMI2 #define HUF_DGEN(fn) \ @@ -66,7 +106,7 @@ namespace duckdb_zstd { return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \ } \ \ - static TARGET_ATTRIBUTE("bmi2") size_t fn##_bmi2( \ + static BMI2_TARGET_ATTRIBUTE size_t fn##_bmi2( \ void* dst, size_t dstSize, \ const void* cSrc, size_t cSrcSize, \ const HUF_DTable* DTable) \ @@ -75,9 +115,9 @@ namespace duckdb_zstd { } \ \ static size_t fn(void* dst, size_t dstSize, void const* cSrc, \ - size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \ + size_t cSrcSize, HUF_DTable const* DTable, int flags) \ { \ - if (bmi2) { \ + if (flags & HUF_flags_bmi2) { \ return fn##_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); \ } \ return fn##_default(dst, dstSize, cSrc, cSrcSize, DTable); \ @@ -87,9 +127,9 @@ namespace duckdb_zstd { #define HUF_DGEN(fn) \ static size_t fn(void* dst, size_t dstSize, void const* cSrc, \ - size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \ + size_t cSrcSize, HUF_DTable const* DTable, int flags) \ { \ - (void)bmi2; \ + (void)flags; \ return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \ } @@ -104,92 +144,379 @@ typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; static DTableDesc HUF_getDTableDesc(const HUF_DTable* table) { DTableDesc dtd; - memcpy(&dtd, table, sizeof(dtd)); + ZSTD_memcpy(&dtd, table, sizeof(dtd)); return dtd; } +static size_t HUF_initFastDStream(BYTE const* ip) { + BYTE const lastByte = ip[7]; + size_t const bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; + size_t const value = MEM_readLEST(ip) | 1; + assert(bitsConsumed <= 8); + assert(sizeof(size_t) == 8); + return value << bitsConsumed; +} + + +/** + * The input/output arguments to the Huffman fast decoding loop: + * + * ip [in/out] - The input pointers, must be updated to reflect what is consumed. + * op [in/out] - The output pointers, must be updated to reflect what is written. + * bits [in/out] - The bitstream containers, must be updated to reflect the current state. + * dt [in] - The decoding table. + * ilowest [in] - The beginning of the valid range of the input. Decoders may read + * down to this pointer. It may be below iend[0]. + * oend [in] - The end of the output stream. op[3] must not cross oend. + * iend [in] - The end of each input stream. ip[i] may cross iend[i], + * as long as it is above ilowest, but that indicates corruption. + */ +typedef struct { + BYTE const* ip[4]; + BYTE* op[4]; + U64 bits[4]; + void const* dt; + BYTE const* ilowest; + BYTE* oend; + BYTE const* iend[4]; +} HUF_DecompressFastArgs; + +typedef void (*HUF_DecompressFastLoopFn)(HUF_DecompressFastArgs*); + +/** + * Initializes args for the fast decoding loop. + * @returns 1 on success + * 0 if the fallback implementation should be used. + * Or an error code on failure. + */ +static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* dst, size_t dstSize, void const* src, size_t srcSize, const HUF_DTable* DTable) +{ + void const* dt = DTable + 1; + U32 const dtLog = HUF_getDTableDesc(DTable).tableLog; + + const BYTE* const istart = (const BYTE*)src; + + BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize); + + /* The fast decoding loop assumes 64-bit little-endian. + * This condition is false on x32. + */ + if (!MEM_isLittleEndian() || MEM_32bits()) + return 0; + + /* Avoid nullptr addition */ + if (dstSize == 0) + return 0; + assert(dst != NULL); + + /* strict minimum : jump table + 1 byte per stream */ + if (srcSize < 10) + return ERROR(corruption_detected); + + /* Must have at least 8 bytes per stream because we don't handle initializing smaller bit containers. + * If table log is not correct at this point, fallback to the old decoder. + * On small inputs we don't have enough data to trigger the fast loop, so use the old decoder. + */ + if (dtLog != HUF_DECODER_FAST_TABLELOG) + return 0; + + /* Read the jump table. */ + { + size_t const length1 = MEM_readLE16(istart); + size_t const length2 = MEM_readLE16(istart+2); + size_t const length3 = MEM_readLE16(istart+4); + size_t const length4 = srcSize - (length1 + length2 + length3 + 6); + args->iend[0] = istart + 6; /* jumpTable */ + args->iend[1] = args->iend[0] + length1; + args->iend[2] = args->iend[1] + length2; + args->iend[3] = args->iend[2] + length3; + + /* HUF_initFastDStream() requires this, and this small of an input + * won't benefit from the ASM loop anyways. + */ + if (length1 < 8 || length2 < 8 || length3 < 8 || length4 < 8) + return 0; + if (length4 > srcSize) return ERROR(corruption_detected); /* overflow */ + } + /* ip[] contains the position that is currently loaded into bits[]. */ + args->ip[0] = args->iend[1] - sizeof(U64); + args->ip[1] = args->iend[2] - sizeof(U64); + args->ip[2] = args->iend[3] - sizeof(U64); + args->ip[3] = (BYTE const*)src + srcSize - sizeof(U64); + + /* op[] contains the output pointers. */ + args->op[0] = (BYTE*)dst; + args->op[1] = args->op[0] + (dstSize+3)/4; + args->op[2] = args->op[1] + (dstSize+3)/4; + args->op[3] = args->op[2] + (dstSize+3)/4; + + /* No point to call the ASM loop for tiny outputs. */ + if (args->op[3] >= oend) + return 0; + + /* bits[] is the bit container. + * It is read from the MSB down to the LSB. + * It is shifted left as it is read, and zeros are + * shifted in. After the lowest valid bit a 1 is + * set, so that CountTrailingZeros(bits[]) can be used + * to count how many bits we've consumed. + */ + args->bits[0] = HUF_initFastDStream(args->ip[0]); + args->bits[1] = HUF_initFastDStream(args->ip[1]); + args->bits[2] = HUF_initFastDStream(args->ip[2]); + args->bits[3] = HUF_initFastDStream(args->ip[3]); + + /* The decoders must be sure to never read beyond ilowest. + * This is lower than iend[0], but allowing decoders to read + * down to ilowest can allow an extra iteration or two in the + * fast loop. + */ + args->ilowest = istart; + + args->oend = oend; + args->dt = dt; + + return 1; +} + +static size_t HUF_initRemainingDStream(BIT_DStream_t* bit, HUF_DecompressFastArgs const* args, int stream, BYTE* segmentEnd) +{ + /* Validate that we haven't overwritten. */ + if (args->op[stream] > segmentEnd) + return ERROR(corruption_detected); + /* Validate that we haven't read beyond iend[]. + * Note that ip[] may be < iend[] because the MSB is + * the next bit to read, and we may have consumed 100% + * of the stream, so down to iend[i] - 8 is valid. + */ + if (args->ip[stream] < args->iend[stream] - 8) + return ERROR(corruption_detected); + + /* Construct the BIT_DStream_t. */ + assert(sizeof(size_t) == 8); + bit->bitContainer = MEM_readLEST(args->ip[stream]); + bit->bitsConsumed = ZSTD_countTrailingZeros64(args->bits[stream]); + bit->start = (const char*)args->ilowest; + bit->limitPtr = bit->start + sizeof(size_t); + bit->ptr = (const char*)args->ip[stream]; + + return 0; +} + +/* Calls X(N) for each stream 0, 1, 2, 3. */ +#define HUF_4X_FOR_EACH_STREAM(X) \ + do { \ + X(0); \ + X(1); \ + X(2); \ + X(3); \ + } while (0) + +/* Calls X(N, var) for each stream 0, 1, 2, 3. */ +#define HUF_4X_FOR_EACH_STREAM_WITH_VAR(X, var) \ + do { \ + X(0, (var)); \ + X(1, (var)); \ + X(2, (var)); \ + X(3, (var)); \ + } while (0) + #ifndef HUF_FORCE_DECOMPRESS_X2 /*-***************************/ /* single-symbol decoding */ /*-***************************/ -typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX1; /* single-symbol decoding */ +typedef struct { BYTE nbBits; BYTE byte; } HUF_DEltX1; /* single-symbol decoding */ + +/** + * Packs 4 HUF_DEltX1 structs into a U64. This is used to lay down 4 entries at + * a time. + */ +static U64 HUF_DEltX1_set4(BYTE symbol, BYTE nbBits) { + U64 D4; + if (MEM_isLittleEndian()) { + D4 = (U64)((symbol << 8) + nbBits); + } else { + D4 = (U64)(symbol + (nbBits << 8)); + } + assert(D4 < (1U << 16)); + D4 *= 0x0001000100010001ULL; + return D4; +} -size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize) +/** + * Increase the tableLog to targetTableLog and rescales the stats. + * If tableLog > targetTableLog this is a no-op. + * @returns New tableLog + */ +static U32 HUF_rescaleStats(BYTE* huffWeight, U32* rankVal, U32 nbSymbols, U32 tableLog, U32 targetTableLog) +{ + if (tableLog > targetTableLog) + return tableLog; + if (tableLog < targetTableLog) { + U32 const scale = targetTableLog - tableLog; + U32 s; + /* Increase the weight for all non-zero probability symbols by scale. */ + for (s = 0; s < nbSymbols; ++s) { + huffWeight[s] += (BYTE)((huffWeight[s] == 0) ? 0 : scale); + } + /* Update rankVal to reflect the new weights. + * All weights except 0 get moved to weight + scale. + * Weights [1, scale] are empty. + */ + for (s = targetTableLog; s > scale; --s) { + rankVal[s] = rankVal[s - scale]; + } + for (s = scale; s > 0; --s) { + rankVal[s] = 0; + } + } + return targetTableLog; +} + +typedef struct { + U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; + U32 rankStart[HUF_TABLELOG_ABSOLUTEMAX + 1]; + U32 statsWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; + BYTE symbols[HUF_SYMBOLVALUE_MAX + 1]; + BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; +} HUF_ReadDTableX1_Workspace; + +size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int flags) { U32 tableLog = 0; U32 nbSymbols = 0; size_t iSize; void* const dtPtr = DTable + 1; HUF_DEltX1* const dt = (HUF_DEltX1*)dtPtr; + HUF_ReadDTableX1_Workspace* wksp = (HUF_ReadDTableX1_Workspace*)workSpace; - U32* rankVal; - BYTE* huffWeight; - size_t spaceUsed32 = 0; - - rankVal = (U32 *)workSpace + spaceUsed32; - spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1; - huffWeight = (BYTE *)((U32 *)workSpace + spaceUsed32); - spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2; - - if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge); + DEBUG_STATIC_ASSERT(HUF_DECOMPRESS_WORKSPACE_SIZE >= sizeof(*wksp)); + if (sizeof(*wksp) > wkspSize) return ERROR(tableLog_tooLarge); DEBUG_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable)); - /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ + /* ZSTD_memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ - iSize = HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize); + iSize = HUF_readStats_wksp(wksp->huffWeight, HUF_SYMBOLVALUE_MAX + 1, wksp->rankVal, &nbSymbols, &tableLog, src, srcSize, wksp->statsWksp, sizeof(wksp->statsWksp), flags); if (HUF_isError(iSize)) return iSize; + /* Table header */ { DTableDesc dtd = HUF_getDTableDesc(DTable); + U32 const maxTableLog = dtd.maxTableLog + 1; + U32 const targetTableLog = MIN(maxTableLog, HUF_DECODER_FAST_TABLELOG); + tableLog = HUF_rescaleStats(wksp->huffWeight, wksp->rankVal, nbSymbols, tableLog, targetTableLog); if (tableLog > (U32)(dtd.maxTableLog+1)) return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */ dtd.tableType = 0; dtd.tableLog = (BYTE)tableLog; - memcpy(DTable, &dtd, sizeof(dtd)); + ZSTD_memcpy(DTable, &dtd, sizeof(dtd)); } - /* Calculate starting value for each rank */ - { U32 n, nextRankStart = 0; - for (n=1; n> 1; - size_t const uStart = rankVal[w]; - size_t const uEnd = uStart + length; - size_t u; - HUF_DEltX1 D; - D.byte = (BYTE)n; - D.nbBits = (BYTE)(tableLog + 1 - w); - rankVal[w] = (U32)uEnd; - if (length < 4) { - /* Use length in the loop bound so the compiler knows it is short. */ - for (u = 0; u < length; ++u) - dt[uStart + u] = D; - } else { - /* Unroll the loop 4 times, we know it is a power of 2. */ - for (u = uStart; u < uEnd; u += 4) { - dt[u + 0] = D; - dt[u + 1] = D; - dt[u + 2] = D; - dt[u + 3] = D; - } } } } - return iSize; -} + /* Compute symbols and rankStart given rankVal: + * + * rankVal already contains the number of values of each weight. + * + * symbols contains the symbols ordered by weight. First are the rankVal[0] + * weight 0 symbols, followed by the rankVal[1] weight 1 symbols, and so on. + * symbols[0] is filled (but unused) to avoid a branch. + * + * rankStart contains the offset where each rank belongs in the DTable. + * rankStart[0] is not filled because there are no entries in the table for + * weight 0. + */ + { int n; + U32 nextRankStart = 0; + int const unroll = 4; + int const nLimit = (int)nbSymbols - unroll + 1; + for (n=0; n<(int)tableLog+1; n++) { + U32 const curr = nextRankStart; + nextRankStart += wksp->rankVal[n]; + wksp->rankStart[n] = curr; + } + for (n=0; n < nLimit; n += unroll) { + int u; + for (u=0; u < unroll; ++u) { + size_t const w = wksp->huffWeight[n+u]; + wksp->symbols[wksp->rankStart[w]++] = (BYTE)(n+u); + } + } + for (; n < (int)nbSymbols; ++n) { + size_t const w = wksp->huffWeight[n]; + wksp->symbols[wksp->rankStart[w]++] = (BYTE)n; + } + } -size_t HUF_readDTableX1(HUF_DTable* DTable, const void* src, size_t srcSize) -{ - U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; - return HUF_readDTableX1_wksp(DTable, src, srcSize, - workSpace, sizeof(workSpace)); + /* fill DTable + * We fill all entries of each weight in order. + * That way length is a constant for each iteration of the outer loop. + * We can switch based on the length to a different inner loop which is + * optimized for that particular case. + */ + { U32 w; + int symbol = wksp->rankVal[0]; + int rankStart = 0; + for (w=1; wrankVal[w]; + int const length = (1 << w) >> 1; + int uStart = rankStart; + BYTE const nbBits = (BYTE)(tableLog + 1 - w); + int s; + int u; + switch (length) { + case 1: + for (s=0; ssymbols[symbol + s]; + D.nbBits = nbBits; + dt[uStart] = D; + uStart += 1; + } + break; + case 2: + for (s=0; ssymbols[symbol + s]; + D.nbBits = nbBits; + dt[uStart+0] = D; + dt[uStart+1] = D; + uStart += 2; + } + break; + case 4: + for (s=0; ssymbols[symbol + s], nbBits); + MEM_write64(dt + uStart, D4); + uStart += 4; + } + break; + case 8: + for (s=0; ssymbols[symbol + s], nbBits); + MEM_write64(dt + uStart, D4); + MEM_write64(dt + uStart + 4, D4); + uStart += 8; + } + break; + default: + for (s=0; ssymbols[symbol + s], nbBits); + for (u=0; u < length; u += 16) { + MEM_write64(dt + uStart + u + 0, D4); + MEM_write64(dt + uStart + u + 4, D4); + MEM_write64(dt + uStart + u + 8, D4); + MEM_write64(dt + uStart + u + 12, D4); + } + assert(u == length); + uStart += length; + } + break; + } + symbol += symbolCount; + rankStart += symbolCount * length; + } + } + return iSize; } FORCE_INLINE_TEMPLATE BYTE @@ -202,15 +529,19 @@ HUF_decodeSymbolX1(BIT_DStream_t* Dstream, const HUF_DEltX1* dt, const U32 dtLog } #define HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) \ - *ptr++ = HUF_decodeSymbolX1(DStreamPtr, dt, dtLog) + do { *ptr++ = HUF_decodeSymbolX1(DStreamPtr, dt, dtLog); } while (0) -#define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr) \ - if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \ - HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) +#define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr) \ + do { \ + if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \ + HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr); \ + } while (0) -#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \ - if (MEM_64bits()) \ - HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) +#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \ + do { \ + if (MEM_64bits()) \ + HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr); \ + } while (0) HINT_INLINE size_t HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX1* const dt, const U32 dtLog) @@ -218,11 +549,15 @@ HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, cons BYTE* const pStart = p; /* up to 4 symbols at a time */ - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) { - HUF_DECODE_SYMBOLX1_2(p, bitDPtr); - HUF_DECODE_SYMBOLX1_1(p, bitDPtr); - HUF_DECODE_SYMBOLX1_2(p, bitDPtr); - HUF_DECODE_SYMBOLX1_0(p, bitDPtr); + if ((pEnd - p) > 3) { + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) { + HUF_DECODE_SYMBOLX1_2(p, bitDPtr); + HUF_DECODE_SYMBOLX1_1(p, bitDPtr); + HUF_DECODE_SYMBOLX1_2(p, bitDPtr); + HUF_DECODE_SYMBOLX1_0(p, bitDPtr); + } + } else { + BIT_reloadDStream(bitDPtr); } /* [0-3] symbols remaining */ @@ -234,7 +569,7 @@ HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, cons while (p < pEnd) HUF_DECODE_SYMBOLX1_0(p, bitDPtr); - return pEnd-pStart; + return (size_t)(pEnd-pStart); } FORCE_INLINE_TEMPLATE size_t @@ -244,7 +579,7 @@ HUF_decompress1X1_usingDTable_internal_body( const HUF_DTable* DTable) { BYTE* op = (BYTE*)dst; - BYTE* const oend = op + dstSize; + BYTE* const oend = ZSTD_maybeNullPtrAdd(op, dstSize); const void* dtPtr = DTable + 1; const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr; BIT_DStream_t bitD; @@ -260,6 +595,10 @@ HUF_decompress1X1_usingDTable_internal_body( return dstSize; } +/* HUF_decompress4X1_usingDTable_internal_body(): + * Conditions : + * @dstSize >= 6 + */ FORCE_INLINE_TEMPLATE size_t HUF_decompress4X1_usingDTable_internal_body( void* dst, size_t dstSize, @@ -268,6 +607,7 @@ HUF_decompress4X1_usingDTable_internal_body( { /* Check */ if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ + if (dstSize < 6) return ERROR(corruption_detected); /* stream 4-split doesn't work */ { const BYTE* const istart = (const BYTE*) cSrc; BYTE* const ostart = (BYTE*) dst; @@ -302,33 +642,37 @@ HUF_decompress4X1_usingDTable_internal_body( U32 endSignal = 1; if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ + if (opStart4 > oend) return ERROR(corruption_detected); /* overflow */ + assert(dstSize >= 6); /* validated above */ CHECK_F( BIT_initDStream(&bitD1, istart1, length1) ); CHECK_F( BIT_initDStream(&bitD2, istart2, length2) ); CHECK_F( BIT_initDStream(&bitD3, istart3, length3) ); CHECK_F( BIT_initDStream(&bitD4, istart4, length4) ); /* up to 16 symbols per loop (4 symbols per stream) in 64-bit mode */ - for ( ; (endSignal) & (op4 < olimit) ; ) { - HUF_DECODE_SYMBOLX1_2(op1, &bitD1); - HUF_DECODE_SYMBOLX1_2(op2, &bitD2); - HUF_DECODE_SYMBOLX1_2(op3, &bitD3); - HUF_DECODE_SYMBOLX1_2(op4, &bitD4); - HUF_DECODE_SYMBOLX1_1(op1, &bitD1); - HUF_DECODE_SYMBOLX1_1(op2, &bitD2); - HUF_DECODE_SYMBOLX1_1(op3, &bitD3); - HUF_DECODE_SYMBOLX1_1(op4, &bitD4); - HUF_DECODE_SYMBOLX1_2(op1, &bitD1); - HUF_DECODE_SYMBOLX1_2(op2, &bitD2); - HUF_DECODE_SYMBOLX1_2(op3, &bitD3); - HUF_DECODE_SYMBOLX1_2(op4, &bitD4); - HUF_DECODE_SYMBOLX1_0(op1, &bitD1); - HUF_DECODE_SYMBOLX1_0(op2, &bitD2); - HUF_DECODE_SYMBOLX1_0(op3, &bitD3); - HUF_DECODE_SYMBOLX1_0(op4, &bitD4); - endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; - endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; - endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; - endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; + if ((size_t)(oend - op4) >= sizeof(size_t)) { + for ( ; (endSignal) & (op4 < olimit) ; ) { + HUF_DECODE_SYMBOLX1_2(op1, &bitD1); + HUF_DECODE_SYMBOLX1_2(op2, &bitD2); + HUF_DECODE_SYMBOLX1_2(op3, &bitD3); + HUF_DECODE_SYMBOLX1_2(op4, &bitD4); + HUF_DECODE_SYMBOLX1_1(op1, &bitD1); + HUF_DECODE_SYMBOLX1_1(op2, &bitD2); + HUF_DECODE_SYMBOLX1_1(op3, &bitD3); + HUF_DECODE_SYMBOLX1_1(op4, &bitD4); + HUF_DECODE_SYMBOLX1_2(op1, &bitD1); + HUF_DECODE_SYMBOLX1_2(op2, &bitD2); + HUF_DECODE_SYMBOLX1_2(op3, &bitD3); + HUF_DECODE_SYMBOLX1_2(op4, &bitD4); + HUF_DECODE_SYMBOLX1_0(op1, &bitD1); + HUF_DECODE_SYMBOLX1_0(op2, &bitD2); + HUF_DECODE_SYMBOLX1_0(op3, &bitD3); + HUF_DECODE_SYMBOLX1_0(op4, &bitD4); + endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; + } } /* check corruption */ @@ -354,99 +698,230 @@ HUF_decompress4X1_usingDTable_internal_body( } } +#if HUF_NEED_BMI2_FUNCTION +static BMI2_TARGET_ATTRIBUTE +size_t HUF_decompress4X1_usingDTable_internal_bmi2(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} +#endif -typedef size_t (*HUF_decompress_usingDTable_t)(void *dst, size_t dstSize, - const void *cSrc, - size_t cSrcSize, - const HUF_DTable *DTable); +static +size_t HUF_decompress4X1_usingDTable_internal_default(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} -HUF_DGEN(HUF_decompress1X1_usingDTable_internal) -HUF_DGEN(HUF_decompress4X1_usingDTable_internal) +static HUF_FAST_BMI2_ATTRS +void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs* args) +{ + U64 bits[4]; + BYTE const* ip[4]; + BYTE* op[4]; + U16 const* const dtable = (U16 const*)args->dt; + BYTE* const oend = args->oend; + BYTE const* const ilowest = args->ilowest; + + /* Copy the arguments to local variables */ + ZSTD_memcpy(&bits, &args->bits, sizeof(bits)); + ZSTD_memcpy((void*)(&ip), &args->ip, sizeof(ip)); + ZSTD_memcpy(&op, &args->op, sizeof(op)); + + assert(MEM_isLittleEndian()); + assert(!MEM_32bits()); + + for (;;) { + BYTE* olimit; + int stream; + + /* Assert loop preconditions */ +#ifndef NDEBUG + for (stream = 0; stream < 4; ++stream) { + assert(op[stream] <= (stream == 3 ? oend : op[stream + 1])); + assert(ip[stream] >= ilowest); + } +#endif + /* Compute olimit */ + { + /* Each iteration produces 5 output symbols per stream */ + size_t const oiters = (size_t)(oend - op[3]) / 5; + /* Each iteration consumes up to 11 bits * 5 = 55 bits < 7 bytes + * per stream. + */ + size_t const iiters = (size_t)(ip[0] - ilowest) / 7; + /* We can safely run iters iterations before running bounds checks */ + size_t const iters = MIN(oiters, iiters); + size_t const symbols = iters * 5; + + /* We can simply check that op[3] < olimit, instead of checking all + * of our bounds, since we can't hit the other bounds until we've run + * iters iterations, which only happens when op[3] == olimit. + */ + olimit = op[3] + symbols; + + /* Exit fast decoding loop once we reach the end. */ + if (op[3] == olimit) + break; + + /* Exit the decoding loop if any input pointer has crossed the + * previous one. This indicates corruption, and a precondition + * to our loop is that ip[i] >= ip[0]. + */ + for (stream = 1; stream < 4; ++stream) { + if (ip[stream] < ip[stream - 1]) + goto _out; + } + } +#ifndef NDEBUG + for (stream = 1; stream < 4; ++stream) { + assert(ip[stream] >= ip[stream - 1]); + } +#endif +#define HUF_4X1_DECODE_SYMBOL(_stream, _symbol) \ + do { \ + int const index = (int)(bits[(_stream)] >> 53); \ + int const entry = (int)dtable[index]; \ + bits[(_stream)] <<= (entry & 0x3F); \ + op[(_stream)][(_symbol)] = (BYTE)((entry >> 8) & 0xFF); \ + } while (0) + +#define HUF_4X1_RELOAD_STREAM(_stream) \ + do { \ + int const ctz = ZSTD_countTrailingZeros64(bits[(_stream)]); \ + int const nbBits = ctz & 7; \ + int const nbBytes = ctz >> 3; \ + op[(_stream)] += 5; \ + ip[(_stream)] -= nbBytes; \ + bits[(_stream)] = MEM_read64(ip[(_stream)]) | 1; \ + bits[(_stream)] <<= nbBits; \ + } while (0) + + /* Manually unroll the loop because compilers don't consistently + * unroll the inner loops, which destroys performance. + */ + do { + /* Decode 5 symbols in each of the 4 streams */ + HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 0); + HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 1); + HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 2); + HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 3); + HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 4); + + /* Reload each of the 4 the bitstreams */ + HUF_4X_FOR_EACH_STREAM(HUF_4X1_RELOAD_STREAM); + } while (op[3] < olimit); + +#undef HUF_4X1_DECODE_SYMBOL +#undef HUF_4X1_RELOAD_STREAM + } -size_t HUF_decompress1X1_usingDTable( - void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize, - const HUF_DTable* DTable) -{ - DTableDesc dtd = HUF_getDTableDesc(DTable); - if (dtd.tableType != 0) return ERROR(GENERIC); - return HUF_decompress1X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +_out: + + /* Save the final values of each of the state variables back to args. */ + ZSTD_memcpy(&args->bits, &bits, sizeof(bits)); + ZSTD_memcpy((void*)(&args->ip), &ip, sizeof(ip)); + ZSTD_memcpy(&args->op, &op, sizeof(op)); } -size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize, - void* workSpace, size_t wkspSize) +/** + * @returns @p dstSize on success (>= 6) + * 0 if the fallback implementation should be used + * An error if an error occurred + */ +static HUF_FAST_BMI2_ATTRS +size_t +HUF_decompress4X1_usingDTable_internal_fast( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable, + HUF_DecompressFastLoopFn loopFn) { - const BYTE* ip = (const BYTE*) cSrc; + void const* dt = DTable + 1; + BYTE const* const ilowest = (BYTE const*)cSrc; + BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize); + HUF_DecompressFastArgs args; + { size_t const ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); + FORWARD_IF_ERROR(ret, "Failed to init fast loop args"); + if (ret == 0) + return 0; + } - size_t const hSize = HUF_readDTableX1_wksp(DCtx, cSrc, cSrcSize, workSpace, wkspSize); - if (HUF_isError(hSize)) return hSize; - if (hSize >= cSrcSize) return ERROR(srcSize_wrong); - ip += hSize; cSrcSize -= hSize; + assert(args.ip[0] >= args.ilowest); + loopFn(&args); + + /* Our loop guarantees that ip[] >= ilowest and that we haven't + * overwritten any op[]. + */ + assert(args.ip[0] >= ilowest); + assert(args.ip[0] >= ilowest); + assert(args.ip[1] >= ilowest); + assert(args.ip[2] >= ilowest); + assert(args.ip[3] >= ilowest); + assert(args.op[3] <= oend); + + assert(ilowest == args.ilowest); + assert(ilowest + 6 == args.iend[0]); + (void)ilowest; + + /* finish bit streams one by one. */ + { size_t const segmentSize = (dstSize+3) / 4; + BYTE* segmentEnd = (BYTE*)dst; + int i; + for (i = 0; i < 4; ++i) { + BIT_DStream_t bit; + if (segmentSize <= (size_t)(oend - segmentEnd)) + segmentEnd += segmentSize; + else + segmentEnd = oend; + FORWARD_IF_ERROR(HUF_initRemainingDStream(&bit, &args, i, segmentEnd), "corruption"); + /* Decompress and validate that we've produced exactly the expected length. */ + args.op[i] += HUF_decodeStreamX1(args.op[i], &bit, segmentEnd, (HUF_DEltX1 const*)dt, HUF_DECODER_FAST_TABLELOG); + if (args.op[i] != segmentEnd) return ERROR(corruption_detected); + } + } - return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0); + /* decoded size */ + assert(dstSize != 0); + return dstSize; } +HUF_DGEN(HUF_decompress1X1_usingDTable_internal) -size_t HUF_decompress1X1_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize) -{ - U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; - return HUF_decompress1X1_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize, - workSpace, sizeof(workSpace)); -} - -size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +static size_t HUF_decompress4X1_usingDTable_internal(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable, int flags) { - HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX); - return HUF_decompress1X1_DCtx (DTable, dst, dstSize, cSrc, cSrcSize); -} + HUF_DecompressUsingDTableFn fallbackFn = HUF_decompress4X1_usingDTable_internal_default; + HUF_DecompressFastLoopFn loopFn = HUF_decompress4X1_usingDTable_internal_fast_c_loop; -size_t HUF_decompress4X1_usingDTable( - void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize, - const HUF_DTable* DTable) -{ - DTableDesc dtd = HUF_getDTableDesc(DTable); - if (dtd.tableType != 0) return ERROR(GENERIC); - return HUF_decompress4X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#if DYNAMIC_BMI2 + if (flags & HUF_flags_bmi2) { + fallbackFn = HUF_decompress4X1_usingDTable_internal_bmi2; + } else { + return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); + } +#endif + if (HUF_ENABLE_FAST_DECODE && !(flags & HUF_flags_disableFast)) { + size_t const ret = HUF_decompress4X1_usingDTable_internal_fast(dst, dstSize, cSrc, cSrcSize, DTable, loopFn); + if (ret != 0) + return ret; + } + return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); } -static size_t HUF_decompress4X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, +static size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, - void* workSpace, size_t wkspSize, int bmi2) + void* workSpace, size_t wkspSize, int flags) { const BYTE* ip = (const BYTE*) cSrc; - size_t const hSize = HUF_readDTableX1_wksp (dctx, cSrc, cSrcSize, - workSpace, wkspSize); + size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize, flags); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; - return HUF_decompress4X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2); -} - -size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize, - void* workSpace, size_t wkspSize) -{ - return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, 0); -} - - -size_t HUF_decompress4X1_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; - return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, - workSpace, sizeof(workSpace)); -} -size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX); - return HUF_decompress4X1_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); + return HUF_decompress4X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, flags); } #endif /* HUF_FORCE_DECOMPRESS_X2 */ @@ -459,209 +934,322 @@ size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cS /* *************************/ typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX2; /* double-symbols decoding */ -typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t; +typedef struct { BYTE symbol; } sortedSymbol_t; typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1]; typedef rankValCol_t rankVal_t[HUF_TABLELOG_MAX]; +/** + * Constructs a HUF_DEltX2 in a U32. + */ +static U32 HUF_buildDEltX2U32(U32 symbol, U32 nbBits, U32 baseSeq, int level) +{ + U32 seq; + DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, sequence) == 0); + DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, nbBits) == 2); + DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, length) == 3); + DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(U32)); + if (MEM_isLittleEndian()) { + seq = level == 1 ? symbol : (baseSeq + (symbol << 8)); + return seq + (nbBits << 16) + ((U32)level << 24); + } else { + seq = level == 1 ? (symbol << 8) : ((baseSeq << 8) + symbol); + return (seq << 16) + (nbBits << 8) + (U32)level; + } +} -/* HUF_fillDTableX2Level2() : - * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */ -static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 sizeLog, const U32 consumed, - const U32* rankValOrigin, const int minWeight, - const sortedSymbol_t* sortedSymbols, const U32 sortedListSize, - U32 nbBitsBaseline, U16 baseSeq) +/** + * Constructs a HUF_DEltX2. + */ +static HUF_DEltX2 HUF_buildDEltX2(U32 symbol, U32 nbBits, U32 baseSeq, int level) { HUF_DEltX2 DElt; - U32 rankVal[HUF_TABLELOG_MAX + 1]; + U32 const val = HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level); + DEBUG_STATIC_ASSERT(sizeof(DElt) == sizeof(val)); + ZSTD_memcpy(&DElt, &val, sizeof(val)); + return DElt; +} - /* get pre-calculated rankVal */ - memcpy(rankVal, rankValOrigin, sizeof(rankVal)); +/** + * Constructs 2 HUF_DEltX2s and packs them into a U64. + */ +static U64 HUF_buildDEltX2U64(U32 symbol, U32 nbBits, U16 baseSeq, int level) +{ + U32 DElt = HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level); + return (U64)DElt + ((U64)DElt << 32); +} - /* fill skipped values */ +/** + * Fills the DTable rank with all the symbols from [begin, end) that are each + * nbBits long. + * + * @param DTableRank The start of the rank in the DTable. + * @param begin The first symbol to fill (inclusive). + * @param end The last symbol to fill (exclusive). + * @param nbBits Each symbol is nbBits long. + * @param tableLog The table log. + * @param baseSeq If level == 1 { 0 } else { the first level symbol } + * @param level The level in the table. Must be 1 or 2. + */ +static void HUF_fillDTableX2ForWeight( + HUF_DEltX2* DTableRank, + sortedSymbol_t const* begin, sortedSymbol_t const* end, + U32 nbBits, U32 tableLog, + U16 baseSeq, int const level) +{ + U32 const length = 1U << ((tableLog - nbBits) & 0x1F /* quiet static-analyzer */); + const sortedSymbol_t* ptr; + assert(level >= 1 && level <= 2); + switch (length) { + case 1: + for (ptr = begin; ptr != end; ++ptr) { + HUF_DEltX2 const DElt = HUF_buildDEltX2(ptr->symbol, nbBits, baseSeq, level); + *DTableRank++ = DElt; + } + break; + case 2: + for (ptr = begin; ptr != end; ++ptr) { + HUF_DEltX2 const DElt = HUF_buildDEltX2(ptr->symbol, nbBits, baseSeq, level); + DTableRank[0] = DElt; + DTableRank[1] = DElt; + DTableRank += 2; + } + break; + case 4: + for (ptr = begin; ptr != end; ++ptr) { + U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); + ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); + DTableRank += 4; + } + break; + case 8: + for (ptr = begin; ptr != end; ++ptr) { + U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); + ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 4, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 6, &DEltX2, sizeof(DEltX2)); + DTableRank += 8; + } + break; + default: + for (ptr = begin; ptr != end; ++ptr) { + U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); + HUF_DEltX2* const DTableRankEnd = DTableRank + length; + for (; DTableRank != DTableRankEnd; DTableRank += 8) { + ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 4, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 6, &DEltX2, sizeof(DEltX2)); + } + } + break; + } +} + +/* HUF_fillDTableX2Level2() : + * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */ +static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 targetLog, const U32 consumedBits, + const U32* rankVal, const int minWeight, const int maxWeight1, + const sortedSymbol_t* sortedSymbols, U32 const* rankStart, + U32 nbBitsBaseline, U16 baseSeq) +{ + /* Fill skipped values (all positions up to rankVal[minWeight]). + * These are positions only get a single symbol because the combined weight + * is too large. + */ if (minWeight>1) { - U32 i, skipSize = rankVal[minWeight]; - MEM_writeLE16(&(DElt.sequence), baseSeq); - DElt.nbBits = (BYTE)(consumed); - DElt.length = 1; - for (i = 0; i < skipSize; i++) - DTable[i] = DElt; + U32 const length = 1U << ((targetLog - consumedBits) & 0x1F /* quiet static-analyzer */); + U64 const DEltX2 = HUF_buildDEltX2U64(baseSeq, consumedBits, /* baseSeq */ 0, /* level */ 1); + int const skipSize = rankVal[minWeight]; + assert(length > 1); + assert((U32)skipSize < length); + switch (length) { + case 2: + assert(skipSize == 1); + ZSTD_memcpy(DTable, &DEltX2, sizeof(DEltX2)); + break; + case 4: + assert(skipSize <= 4); + ZSTD_memcpy(DTable + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + 2, &DEltX2, sizeof(DEltX2)); + break; + default: + { + int i; + for (i = 0; i < skipSize; i += 8) { + ZSTD_memcpy(DTable + i + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + i + 2, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + i + 4, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + i + 6, &DEltX2, sizeof(DEltX2)); + } + } + } } - /* fill DTable */ - { U32 s; for (s=0; s= 1 */ - - rankVal[weight] += length; - } } + /* Fill each of the second level symbols by weight. */ + { + int w; + for (w = minWeight; w < maxWeight1; ++w) { + int const begin = rankStart[w]; + int const end = rankStart[w+1]; + U32 const nbBits = nbBitsBaseline - w; + U32 const totalBits = nbBits + consumedBits; + HUF_fillDTableX2ForWeight( + DTable + rankVal[w], + sortedSymbols + begin, sortedSymbols + end, + totalBits, targetLog, + baseSeq, /* level */ 2); + } + } } - static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog, - const sortedSymbol_t* sortedList, const U32 sortedListSize, - const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight, + const sortedSymbol_t* sortedList, + const U32* rankStart, rankValCol_t* rankValOrigin, const U32 maxWeight, const U32 nbBitsBaseline) { - U32 rankVal[HUF_TABLELOG_MAX + 1]; + U32* const rankVal = rankValOrigin[0]; const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */ const U32 minBits = nbBitsBaseline - maxWeight; - U32 s; - - memcpy(rankVal, rankValOrigin, sizeof(rankVal)); - - /* fill DTable */ - for (s=0; s= minBits) { /* enough room for a second symbol */ - U32 sortedRank; + int w; + int const wEnd = (int)maxWeight + 1; + + /* Fill DTable in order of weight. */ + for (w = 1; w < wEnd; ++w) { + int const begin = (int)rankStart[w]; + int const end = (int)rankStart[w+1]; + U32 const nbBits = nbBitsBaseline - w; + + if (targetLog-nbBits >= minBits) { + /* Enough room for a second symbol. */ + int start = rankVal[w]; + U32 const length = 1U << ((targetLog - nbBits) & 0x1F /* quiet static-analyzer */); int minWeight = nbBits + scaleLog; + int s; if (minWeight < 1) minWeight = 1; - sortedRank = rankStart[minWeight]; - HUF_fillDTableX2Level2(DTable+start, targetLog-nbBits, nbBits, - rankValOrigin[nbBits], minWeight, - sortedList+sortedRank, sortedListSize-sortedRank, - nbBitsBaseline, symbol); + /* Fill the DTable for every symbol of weight w. + * These symbols get at least 1 second symbol. + */ + for (s = begin; s != end; ++s) { + HUF_fillDTableX2Level2( + DTable + start, targetLog, nbBits, + rankValOrigin[nbBits], minWeight, wEnd, + sortedList, rankStart, + nbBitsBaseline, sortedList[s].symbol); + start += length; + } } else { - HUF_DEltX2 DElt; - MEM_writeLE16(&(DElt.sequence), symbol); - DElt.nbBits = (BYTE)(nbBits); - DElt.length = 1; - { U32 const end = start + length; - U32 u; - for (u = start; u < end; u++) DTable[u] = DElt; - } } - rankVal[weight] += length; + /* Only a single symbol. */ + HUF_fillDTableX2ForWeight( + DTable + rankVal[w], + sortedList + begin, sortedList + end, + nbBits, targetLog, + /* baseSeq */ 0, /* level */ 1); + } } } +typedef struct { + rankValCol_t rankVal[HUF_TABLELOG_MAX]; + U32 rankStats[HUF_TABLELOG_MAX + 1]; + U32 rankStart0[HUF_TABLELOG_MAX + 3]; + sortedSymbol_t sortedSymbol[HUF_SYMBOLVALUE_MAX + 1]; + BYTE weightList[HUF_SYMBOLVALUE_MAX + 1]; + U32 calleeWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; +} HUF_ReadDTableX2_Workspace; + size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, - void* workSpace, size_t wkspSize) + void* workSpace, size_t wkspSize, int flags) { - U32 tableLog, maxW, sizeOfSort, nbSymbols; + U32 tableLog, maxW, nbSymbols; DTableDesc dtd = HUF_getDTableDesc(DTable); - U32 const maxTableLog = dtd.maxTableLog; + U32 maxTableLog = dtd.maxTableLog; size_t iSize; void* dtPtr = DTable+1; /* force compiler to avoid strict-aliasing */ HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr; U32 *rankStart; - rankValCol_t* rankVal; - U32* rankStats; - U32* rankStart0; - sortedSymbol_t* sortedSymbol; - BYTE* weightList; - size_t spaceUsed32 = 0; - - rankVal = (rankValCol_t *)((U32 *)workSpace + spaceUsed32); - spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2; - rankStats = (U32 *)workSpace + spaceUsed32; - spaceUsed32 += HUF_TABLELOG_MAX + 1; - rankStart0 = (U32 *)workSpace + spaceUsed32; - spaceUsed32 += HUF_TABLELOG_MAX + 2; - sortedSymbol = (sortedSymbol_t *)workSpace + (spaceUsed32 * sizeof(U32)) / sizeof(sortedSymbol_t); - spaceUsed32 += HUF_ALIGN(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 1), sizeof(U32)) >> 2; - weightList = (BYTE *)((U32 *)workSpace + spaceUsed32); - spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2; - - if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge); - - rankStart = rankStart0 + 1; - memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1)); + HUF_ReadDTableX2_Workspace* const wksp = (HUF_ReadDTableX2_Workspace*)workSpace; + + if (sizeof(*wksp) > wkspSize) return ERROR(GENERIC); + + rankStart = wksp->rankStart0 + 1; + ZSTD_memset(wksp->rankStats, 0, sizeof(wksp->rankStats)); + ZSTD_memset(wksp->rankStart0, 0, sizeof(wksp->rankStart0)); DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */ if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge); - /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ + /* ZSTD_memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ - iSize = HUF_readStats(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize); + iSize = HUF_readStats_wksp(wksp->weightList, HUF_SYMBOLVALUE_MAX + 1, wksp->rankStats, &nbSymbols, &tableLog, src, srcSize, wksp->calleeWksp, sizeof(wksp->calleeWksp), flags); if (HUF_isError(iSize)) return iSize; /* check result */ if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */ + if (tableLog <= HUF_DECODER_FAST_TABLELOG && maxTableLog > HUF_DECODER_FAST_TABLELOG) maxTableLog = HUF_DECODER_FAST_TABLELOG; /* find maxWeight */ - for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ + for (maxW = tableLog; wksp->rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ /* Get start index of each weight */ { U32 w, nextRankStart = 0; for (w=1; wrankStats[w]; + rankStart[w] = curr; } rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/ - sizeOfSort = nextRankStart; + rankStart[maxW+1] = nextRankStart; } /* sort symbols by weight */ { U32 s; for (s=0; sweightList[s]; U32 const r = rankStart[w]++; - sortedSymbol[r].symbol = (BYTE)s; - sortedSymbol[r].weight = (BYTE)w; + wksp->sortedSymbol[r].symbol = (BYTE)s; } rankStart[0] = 0; /* forget 0w symbols; this is beginning of weight(1) */ } /* Build rankVal */ - { U32* const rankVal0 = rankVal[0]; + { U32* const rankVal0 = wksp->rankVal[0]; { int const rescale = (maxTableLog-tableLog) - 1; /* tableLog <= maxTableLog */ U32 nextRankVal = 0; U32 w; for (w=1; wrankStats[w] << (w+rescale); + rankVal0[w] = curr; } } { U32 const minBits = tableLog+1 - maxW; U32 consumed; for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) { - U32* const rankValPtr = rankVal[consumed]; + U32* const rankValPtr = wksp->rankVal[consumed]; U32 w; for (w = 1; w < maxW+1; w++) { rankValPtr[w] = rankVal0[w] >> consumed; } } } } HUF_fillDTableX2(dt, maxTableLog, - sortedSymbol, sizeOfSort, - rankStart0, rankVal, maxW, + wksp->sortedSymbol, + wksp->rankStart0, wksp->rankVal, maxW, tableLog+1); dtd.tableLog = (BYTE)maxTableLog; dtd.tableType = 1; - memcpy(DTable, &dtd, sizeof(dtd)); + ZSTD_memcpy(DTable, &dtd, sizeof(dtd)); return iSize; } -size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize) -{ - U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; - return HUF_readDTableX2_wksp(DTable, src, srcSize, - workSpace, sizeof(workSpace)); -} - FORCE_INLINE_TEMPLATE U32 HUF_decodeSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog) { size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ - memcpy(op, dt+val, 2); + ZSTD_memcpy(op, &dt[val].sequence, 2); BIT_skipBits(DStream, dt[val].nbBits); return dt[val].length; } @@ -670,28 +1258,34 @@ FORCE_INLINE_TEMPLATE U32 HUF_decodeLastSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog) { size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ - memcpy(op, dt+val, 1); - if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits); - else { + ZSTD_memcpy(op, &dt[val].sequence, 1); + if (dt[val].length==1) { + BIT_skipBits(DStream, dt[val].nbBits); + } else { if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) { BIT_skipBits(DStream, dt[val].nbBits); if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8)) /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */ DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8); - } } + } + } return 1; } #define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \ - ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) + do { ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog); } while (0) -#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \ - if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \ - ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) +#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \ + do { \ + if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \ + ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog); \ + } while (0) -#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \ - if (MEM_64bits()) \ - ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) +#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \ + do { \ + if (MEM_64bits()) \ + ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog); \ + } while (0) HINT_INLINE size_t HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd, @@ -700,19 +1294,37 @@ HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd, BYTE* const pStart = p; /* up to 8 symbols at a time */ - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) { - HUF_DECODE_SYMBOLX2_2(p, bitDPtr); - HUF_DECODE_SYMBOLX2_1(p, bitDPtr); - HUF_DECODE_SYMBOLX2_2(p, bitDPtr); - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + if ((size_t)(pEnd - p) >= sizeof(bitDPtr->bitContainer)) { + if (dtLog <= 11 && MEM_64bits()) { + /* up to 10 symbols at a time */ + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-9)) { + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + } + } else { + /* up to 8 symbols at a time */ + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) { + HUF_DECODE_SYMBOLX2_2(p, bitDPtr); + HUF_DECODE_SYMBOLX2_1(p, bitDPtr); + HUF_DECODE_SYMBOLX2_2(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + } + } + } else { + BIT_reloadDStream(bitDPtr); } /* closer to end : up to 2 symbols at a time */ - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2)) - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + if ((size_t)(pEnd - p) >= 2) { + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2)) + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); - while (p <= pEnd-2) - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); /* no need to reload : reached the end of DStream */ + while (p <= pEnd-2) + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); /* no need to reload : reached the end of DStream */ + } if (p < pEnd) p += HUF_decodeLastSymbolX2(p, bitDPtr, dt, dtLog); @@ -733,7 +1345,7 @@ HUF_decompress1X2_usingDTable_internal_body( /* decode */ { BYTE* const ostart = (BYTE*) dst; - BYTE* const oend = ostart + dstSize; + BYTE* const oend = ZSTD_maybeNullPtrAdd(ostart, dstSize); const void* const dtPtr = DTable+1; /* force compiler to not use strict-aliasing */ const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr; DTableDesc const dtd = HUF_getDTableDesc(DTable); @@ -747,6 +1359,10 @@ HUF_decompress1X2_usingDTable_internal_body( return dstSize; } +/* HUF_decompress4X2_usingDTable_internal_body(): + * Conditions: + * @dstSize >= 6 + */ FORCE_INLINE_TEMPLATE size_t HUF_decompress4X2_usingDTable_internal_body( void* dst, size_t dstSize, @@ -754,6 +1370,7 @@ HUF_decompress4X2_usingDTable_internal_body( const HUF_DTable* DTable) { if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ + if (dstSize < 6) return ERROR(corruption_detected); /* stream 4-split doesn't work */ { const BYTE* const istart = (const BYTE*) cSrc; BYTE* const ostart = (BYTE*) dst; @@ -787,58 +1404,62 @@ HUF_decompress4X2_usingDTable_internal_body( DTableDesc const dtd = HUF_getDTableDesc(DTable); U32 const dtLog = dtd.tableLog; - if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ + if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ + if (opStart4 > oend) return ERROR(corruption_detected); /* overflow */ + assert(dstSize >= 6 /* validated above */); CHECK_F( BIT_initDStream(&bitD1, istart1, length1) ); CHECK_F( BIT_initDStream(&bitD2, istart2, length2) ); CHECK_F( BIT_initDStream(&bitD3, istart3, length3) ); CHECK_F( BIT_initDStream(&bitD4, istart4, length4) ); /* 16-32 symbols per loop (4-8 symbols per stream) */ - for ( ; (endSignal) & (op4 < olimit); ) { + if ((size_t)(oend - op4) >= sizeof(size_t)) { + for ( ; (endSignal) & (op4 < olimit); ) { #if defined(__clang__) && (defined(__x86_64__) || defined(__i386__)) - HUF_DECODE_SYMBOLX2_2(op1, &bitD1); - HUF_DECODE_SYMBOLX2_1(op1, &bitD1); - HUF_DECODE_SYMBOLX2_2(op1, &bitD1); - HUF_DECODE_SYMBOLX2_0(op1, &bitD1); - HUF_DECODE_SYMBOLX2_2(op2, &bitD2); - HUF_DECODE_SYMBOLX2_1(op2, &bitD2); - HUF_DECODE_SYMBOLX2_2(op2, &bitD2); - HUF_DECODE_SYMBOLX2_0(op2, &bitD2); - endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; - endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; - HUF_DECODE_SYMBOLX2_2(op3, &bitD3); - HUF_DECODE_SYMBOLX2_1(op3, &bitD3); - HUF_DECODE_SYMBOLX2_2(op3, &bitD3); - HUF_DECODE_SYMBOLX2_0(op3, &bitD3); - HUF_DECODE_SYMBOLX2_2(op4, &bitD4); - HUF_DECODE_SYMBOLX2_1(op4, &bitD4); - HUF_DECODE_SYMBOLX2_2(op4, &bitD4); - HUF_DECODE_SYMBOLX2_0(op4, &bitD4); - endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; - endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_1(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_0(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_1(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_0(op2, &bitD2); + endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_1(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_0(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_1(op4, &bitD4); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_0(op4, &bitD4); + endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; #else - HUF_DECODE_SYMBOLX2_2(op1, &bitD1); - HUF_DECODE_SYMBOLX2_2(op2, &bitD2); - HUF_DECODE_SYMBOLX2_2(op3, &bitD3); - HUF_DECODE_SYMBOLX2_2(op4, &bitD4); - HUF_DECODE_SYMBOLX2_1(op1, &bitD1); - HUF_DECODE_SYMBOLX2_1(op2, &bitD2); - HUF_DECODE_SYMBOLX2_1(op3, &bitD3); - HUF_DECODE_SYMBOLX2_1(op4, &bitD4); - HUF_DECODE_SYMBOLX2_2(op1, &bitD1); - HUF_DECODE_SYMBOLX2_2(op2, &bitD2); - HUF_DECODE_SYMBOLX2_2(op3, &bitD3); - HUF_DECODE_SYMBOLX2_2(op4, &bitD4); - HUF_DECODE_SYMBOLX2_0(op1, &bitD1); - HUF_DECODE_SYMBOLX2_0(op2, &bitD2); - HUF_DECODE_SYMBOLX2_0(op3, &bitD3); - HUF_DECODE_SYMBOLX2_0(op4, &bitD4); - endSignal = (U32)LIKELY( - (U32)(BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished) - & (U32)(BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished) - & (U32)(BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished) - & (U32)(BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished)); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_1(op1, &bitD1); + HUF_DECODE_SYMBOLX2_1(op2, &bitD2); + HUF_DECODE_SYMBOLX2_1(op3, &bitD3); + HUF_DECODE_SYMBOLX2_1(op4, &bitD4); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_0(op1, &bitD1); + HUF_DECODE_SYMBOLX2_0(op2, &bitD2); + HUF_DECODE_SYMBOLX2_0(op3, &bitD3); + HUF_DECODE_SYMBOLX2_0(op4, &bitD4); + endSignal = (U32)LIKELY((U32) + (BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished) + & (BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished) + & (BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished) + & (BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished)); #endif + } } /* check corruption */ @@ -862,94 +1483,268 @@ HUF_decompress4X2_usingDTable_internal_body( } } -HUF_DGEN(HUF_decompress1X2_usingDTable_internal) -HUF_DGEN(HUF_decompress4X2_usingDTable_internal) +#if HUF_NEED_BMI2_FUNCTION +static BMI2_TARGET_ATTRIBUTE +size_t HUF_decompress4X2_usingDTable_internal_bmi2(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} +#endif -size_t HUF_decompress1X2_usingDTable( - void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize, - const HUF_DTable* DTable) -{ - DTableDesc dtd = HUF_getDTableDesc(DTable); - if (dtd.tableType != 1) return ERROR(GENERIC); - return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +static +size_t HUF_decompress4X2_usingDTable_internal_default(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); } -size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize, - void* workSpace, size_t wkspSize) +static HUF_FAST_BMI2_ATTRS +void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs* args) { - const BYTE* ip = (const BYTE*) cSrc; + U64 bits[4]; + BYTE const* ip[4]; + BYTE* op[4]; + BYTE* oend[4]; + HUF_DEltX2 const* const dtable = (HUF_DEltX2 const*)args->dt; + BYTE const* const ilowest = args->ilowest; + + /* Copy the arguments to local registers. */ + ZSTD_memcpy(&bits, &args->bits, sizeof(bits)); + ZSTD_memcpy((void*)(&ip), &args->ip, sizeof(ip)); + ZSTD_memcpy(&op, &args->op, sizeof(op)); + + oend[0] = op[1]; + oend[1] = op[2]; + oend[2] = op[3]; + oend[3] = args->oend; + + assert(MEM_isLittleEndian()); + assert(!MEM_32bits()); + + for (;;) { + BYTE* olimit; + int stream; + + /* Assert loop preconditions */ +#ifndef NDEBUG + for (stream = 0; stream < 4; ++stream) { + assert(op[stream] <= oend[stream]); + assert(ip[stream] >= ilowest); + } +#endif + /* Compute olimit */ + { + /* Each loop does 5 table lookups for each of the 4 streams. + * Each table lookup consumes up to 11 bits of input, and produces + * up to 2 bytes of output. + */ + /* We can consume up to 7 bytes of input per iteration per stream. + * We also know that each input pointer is >= ip[0]. So we can run + * iters loops before running out of input. + */ + size_t iters = (size_t)(ip[0] - ilowest) / 7; + /* Each iteration can produce up to 10 bytes of output per stream. + * Each output stream my advance at different rates. So take the + * minimum number of safe iterations among all the output streams. + */ + for (stream = 0; stream < 4; ++stream) { + size_t const oiters = (size_t)(oend[stream] - op[stream]) / 10; + iters = MIN(iters, oiters); + } + + /* Each iteration produces at least 5 output symbols. So until + * op[3] crosses olimit, we know we haven't executed iters + * iterations yet. This saves us maintaining an iters counter, + * at the expense of computing the remaining # of iterations + * more frequently. + */ + olimit = op[3] + (iters * 5); + + /* Exit the fast decoding loop once we reach the end. */ + if (op[3] == olimit) + break; + + /* Exit the decoding loop if any input pointer has crossed the + * previous one. This indicates corruption, and a precondition + * to our loop is that ip[i] >= ip[0]. + */ + for (stream = 1; stream < 4; ++stream) { + if (ip[stream] < ip[stream - 1]) + goto _out; + } + } - size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, - workSpace, wkspSize); - if (HUF_isError(hSize)) return hSize; - if (hSize >= cSrcSize) return ERROR(srcSize_wrong); - ip += hSize; cSrcSize -= hSize; +#ifndef NDEBUG + for (stream = 1; stream < 4; ++stream) { + assert(ip[stream] >= ip[stream - 1]); + } +#endif - return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0); -} +#define HUF_4X2_DECODE_SYMBOL(_stream, _decode3) \ + do { \ + if ((_decode3) || (_stream) != 3) { \ + int const index = (int)(bits[(_stream)] >> 53); \ + HUF_DEltX2 const entry = dtable[index]; \ + MEM_write16(op[(_stream)], entry.sequence); \ + bits[(_stream)] <<= (entry.nbBits) & 0x3F; \ + op[(_stream)] += (entry.length); \ + } \ + } while (0) + +#define HUF_4X2_RELOAD_STREAM(_stream) \ + do { \ + HUF_4X2_DECODE_SYMBOL(3, 1); \ + { \ + int const ctz = ZSTD_countTrailingZeros64(bits[(_stream)]); \ + int const nbBits = ctz & 7; \ + int const nbBytes = ctz >> 3; \ + ip[(_stream)] -= nbBytes; \ + bits[(_stream)] = MEM_read64(ip[(_stream)]) | 1; \ + bits[(_stream)] <<= nbBits; \ + } \ + } while (0) + + /* Manually unroll the loop because compilers don't consistently + * unroll the inner loops, which destroys performance. + */ + do { + /* Decode 5 symbols from each of the first 3 streams. + * The final stream will be decoded during the reload phase + * to reduce register pressure. + */ + HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0); + HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0); + HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0); + HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0); + HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0); + + /* Decode one symbol from the final stream */ + HUF_4X2_DECODE_SYMBOL(3, 1); + + /* Decode 4 symbols from the final stream & reload bitstreams. + * The final stream is reloaded last, meaning that all 5 symbols + * are decoded from the final stream before it is reloaded. + */ + HUF_4X_FOR_EACH_STREAM(HUF_4X2_RELOAD_STREAM); + } while (op[3] < olimit); + } +#undef HUF_4X2_DECODE_SYMBOL +#undef HUF_4X2_RELOAD_STREAM -size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize) -{ - U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; - return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize, - workSpace, sizeof(workSpace)); -} +_out: -size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX); - return HUF_decompress1X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); + /* Save the final values of each of the state variables back to args. */ + ZSTD_memcpy(&args->bits, &bits, sizeof(bits)); + ZSTD_memcpy((void*)(&args->ip), &ip, sizeof(ip)); + ZSTD_memcpy(&args->op, &op, sizeof(op)); } -size_t HUF_decompress4X2_usingDTable( + +static HUF_FAST_BMI2_ATTRS size_t +HUF_decompress4X2_usingDTable_internal_fast( void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, - const HUF_DTable* DTable) + const HUF_DTable* DTable, + HUF_DecompressFastLoopFn loopFn) { + void const* dt = DTable + 1; + const BYTE* const ilowest = (const BYTE*)cSrc; + BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize); + HUF_DecompressFastArgs args; + { + size_t const ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); + FORWARD_IF_ERROR(ret, "Failed to init asm args"); + if (ret == 0) + return 0; + } + + assert(args.ip[0] >= args.ilowest); + loopFn(&args); + + /* note : op4 already verified within main loop */ + assert(args.ip[0] >= ilowest); + assert(args.ip[1] >= ilowest); + assert(args.ip[2] >= ilowest); + assert(args.ip[3] >= ilowest); + assert(args.op[3] <= oend); + + assert(ilowest == args.ilowest); + assert(ilowest + 6 == args.iend[0]); + (void)ilowest; + + /* finish bitStreams one by one */ + { + size_t const segmentSize = (dstSize+3) / 4; + BYTE* segmentEnd = (BYTE*)dst; + int i; + for (i = 0; i < 4; ++i) { + BIT_DStream_t bit; + if (segmentSize <= (size_t)(oend - segmentEnd)) + segmentEnd += segmentSize; + else + segmentEnd = oend; + FORWARD_IF_ERROR(HUF_initRemainingDStream(&bit, &args, i, segmentEnd), "corruption"); + args.op[i] += HUF_decodeStreamX2(args.op[i], &bit, segmentEnd, (HUF_DEltX2 const*)dt, HUF_DECODER_FAST_TABLELOG); + if (args.op[i] != segmentEnd) + return ERROR(corruption_detected); + } + } + + /* decoded size */ + return dstSize; +} + +static size_t HUF_decompress4X2_usingDTable_internal(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable, int flags) { - DTableDesc dtd = HUF_getDTableDesc(DTable); - if (dtd.tableType != 1) return ERROR(GENERIC); - return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); + HUF_DecompressUsingDTableFn fallbackFn = HUF_decompress4X2_usingDTable_internal_default; + HUF_DecompressFastLoopFn loopFn = HUF_decompress4X2_usingDTable_internal_fast_c_loop; + +#if DYNAMIC_BMI2 + if (flags & HUF_flags_bmi2) { + fallbackFn = HUF_decompress4X2_usingDTable_internal_bmi2; + } else { + return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); + } +#endif + + if (HUF_ENABLE_FAST_DECODE && !(flags & HUF_flags_disableFast)) { + size_t const ret = HUF_decompress4X2_usingDTable_internal_fast(dst, dstSize, cSrc, cSrcSize, DTable, loopFn); + if (ret != 0) + return ret; + } + return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); } -static size_t HUF_decompress4X2_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, +HUF_DGEN(HUF_decompress1X2_usingDTable_internal) + +size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, - void* workSpace, size_t wkspSize, int bmi2) + void* workSpace, size_t wkspSize, int flags) { const BYTE* ip = (const BYTE*) cSrc; - size_t hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, - workSpace, wkspSize); + size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, + workSpace, wkspSize, flags); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; - return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2); + return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, flags); } -size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, +static size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, - void* workSpace, size_t wkspSize) + void* workSpace, size_t wkspSize, int flags) { - return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, /* bmi2 */ 0); -} - + const BYTE* ip = (const BYTE*) cSrc; -size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize) -{ - U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; - return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, - workSpace, sizeof(workSpace)); -} + size_t hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, + workSpace, wkspSize, flags); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; -size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX); - return HUF_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); + return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, flags); } #endif /* HUF_FORCE_DECOMPRESS_X1 */ @@ -959,66 +1754,28 @@ size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cS /* Universal decompression selectors */ /* ***********************************/ -size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, - const void* cSrc, size_t cSrcSize, - const HUF_DTable* DTable) -{ - DTableDesc const dtd = HUF_getDTableDesc(DTable); -#if defined(HUF_FORCE_DECOMPRESS_X1) - (void)dtd; - assert(dtd.tableType == 0); - return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); -#elif defined(HUF_FORCE_DECOMPRESS_X2) - (void)dtd; - assert(dtd.tableType == 1); - return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); -#else - return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) : - HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); -#endif -} - -size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, - const void* cSrc, size_t cSrcSize, - const HUF_DTable* DTable) -{ - DTableDesc const dtd = HUF_getDTableDesc(DTable); -#if defined(HUF_FORCE_DECOMPRESS_X1) - (void)dtd; - assert(dtd.tableType == 0); - return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); -#elif defined(HUF_FORCE_DECOMPRESS_X2) - (void)dtd; - assert(dtd.tableType == 1); - return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); -#else - return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) : - HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); -#endif -} - #if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2) typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t; -static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] = +static const algo_time_t algoTime[16 /* Quantization */][2 /* single, double */] = { /* single, double, quad */ - {{0,0}, {1,1}, {2,2}}, /* Q==0 : impossible */ - {{0,0}, {1,1}, {2,2}}, /* Q==1 : impossible */ - {{ 38,130}, {1313, 74}, {2151, 38}}, /* Q == 2 : 12-18% */ - {{ 448,128}, {1353, 74}, {2238, 41}}, /* Q == 3 : 18-25% */ - {{ 556,128}, {1353, 74}, {2238, 47}}, /* Q == 4 : 25-32% */ - {{ 714,128}, {1418, 74}, {2436, 53}}, /* Q == 5 : 32-38% */ - {{ 883,128}, {1437, 74}, {2464, 61}}, /* Q == 6 : 38-44% */ - {{ 897,128}, {1515, 75}, {2622, 68}}, /* Q == 7 : 44-50% */ - {{ 926,128}, {1613, 75}, {2730, 75}}, /* Q == 8 : 50-56% */ - {{ 947,128}, {1729, 77}, {3359, 77}}, /* Q == 9 : 56-62% */ - {{1107,128}, {2083, 81}, {4006, 84}}, /* Q ==10 : 62-69% */ - {{1177,128}, {2379, 87}, {4785, 88}}, /* Q ==11 : 69-75% */ - {{1242,128}, {2415, 93}, {5155, 84}}, /* Q ==12 : 75-81% */ - {{1349,128}, {2644,106}, {5260,106}}, /* Q ==13 : 81-87% */ - {{1455,128}, {2422,124}, {4174,124}}, /* Q ==14 : 87-93% */ - {{ 722,128}, {1891,145}, {1936,146}}, /* Q ==15 : 93-99% */ + {{0,0}, {1,1}}, /* Q==0 : impossible */ + {{0,0}, {1,1}}, /* Q==1 : impossible */ + {{ 150,216}, { 381,119}}, /* Q == 2 : 12-18% */ + {{ 170,205}, { 514,112}}, /* Q == 3 : 18-25% */ + {{ 177,199}, { 539,110}}, /* Q == 4 : 25-32% */ + {{ 197,194}, { 644,107}}, /* Q == 5 : 32-38% */ + {{ 221,192}, { 735,107}}, /* Q == 6 : 38-44% */ + {{ 256,189}, { 881,106}}, /* Q == 7 : 44-50% */ + {{ 359,188}, {1167,109}}, /* Q == 8 : 50-56% */ + {{ 582,187}, {1570,114}}, /* Q == 9 : 56-62% */ + {{ 688,187}, {1712,122}}, /* Q ==10 : 62-69% */ + {{ 825,186}, {1965,136}}, /* Q ==11 : 69-75% */ + {{ 976,185}, {2131,150}}, /* Q ==12 : 75-81% */ + {{1180,186}, {2070,175}}, /* Q ==13 : 81-87% */ + {{1377,185}, {1731,202}}, /* Q ==14 : 87-93% */ + {{1412,185}, {1695,202}}, /* Q ==15 : 93-99% */ }; #endif @@ -1045,188 +1802,92 @@ U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize) U32 const D256 = (U32)(dstSize >> 8); U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256); U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256); - DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, to reduce cache eviction */ + DTime1 += DTime1 >> 5; /* small advantage to algorithm using less memory, to reduce cache eviction */ return DTime1 < DTime0; } #endif } - -typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); - -size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ -#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2) - static const decompressionAlgo decompress[2] = { HUF_decompress4X1, HUF_decompress4X2 }; -#endif - - /* validation checks */ - if (dstSize == 0) return ERROR(dstSize_tooSmall); - if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ - if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ - if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ - - { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); -#if defined(HUF_FORCE_DECOMPRESS_X1) - (void)algoNb; - assert(algoNb == 0); - return HUF_decompress4X1(dst, dstSize, cSrc, cSrcSize); -#elif defined(HUF_FORCE_DECOMPRESS_X2) - (void)algoNb; - assert(algoNb == 1); - return HUF_decompress4X2(dst, dstSize, cSrc, cSrcSize); -#else - return decompress[algoNb](dst, dstSize, cSrc, cSrcSize); -#endif - } -} - -size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - /* validation checks */ - if (dstSize == 0) return ERROR(dstSize_tooSmall); - if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ - if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ - if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ - - { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); -#if defined(HUF_FORCE_DECOMPRESS_X1) - (void)algoNb; - assert(algoNb == 0); - return HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize); -#elif defined(HUF_FORCE_DECOMPRESS_X2) - (void)algoNb; - assert(algoNb == 1); - return HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize); -#else - return algoNb ? HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) : - HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ; -#endif - } -} - -size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) -{ - U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; - return HUF_decompress4X_hufOnly_wksp(dctx, dst, dstSize, cSrc, cSrcSize, - workSpace, sizeof(workSpace)); -} - - -size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, - size_t dstSize, const void* cSrc, - size_t cSrcSize, void* workSpace, - size_t wkspSize) -{ - /* validation checks */ - if (dstSize == 0) return ERROR(dstSize_tooSmall); - if (cSrcSize == 0) return ERROR(corruption_detected); - - { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); -#if defined(HUF_FORCE_DECOMPRESS_X1) - (void)algoNb; - assert(algoNb == 0); - return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize); -#elif defined(HUF_FORCE_DECOMPRESS_X2) - (void)algoNb; - assert(algoNb == 1); - return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize); -#else - return algoNb ? HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, - cSrcSize, workSpace, wkspSize): - HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize); -#endif - } -} - size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, - void* workSpace, size_t wkspSize) + void* workSpace, size_t wkspSize, int flags) { /* validation checks */ if (dstSize == 0) return ERROR(dstSize_tooSmall); if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ - if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ - if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + if (cSrcSize == dstSize) { ZSTD_memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { ZSTD_memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); #if defined(HUF_FORCE_DECOMPRESS_X1) (void)algoNb; assert(algoNb == 0); return HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc, - cSrcSize, workSpace, wkspSize); + cSrcSize, workSpace, wkspSize, flags); #elif defined(HUF_FORCE_DECOMPRESS_X2) (void)algoNb; assert(algoNb == 1); return HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, - cSrcSize, workSpace, wkspSize); + cSrcSize, workSpace, wkspSize, flags); #else return algoNb ? HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, - cSrcSize, workSpace, wkspSize): + cSrcSize, workSpace, wkspSize, flags): HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc, - cSrcSize, workSpace, wkspSize); + cSrcSize, workSpace, wkspSize, flags); #endif } } -size_t HUF_decompress1X_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, - const void* cSrc, size_t cSrcSize) -{ - U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; - return HUF_decompress1X_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, - workSpace, sizeof(workSpace)); -} - -size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2) +size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags) { DTableDesc const dtd = HUF_getDTableDesc(DTable); #if defined(HUF_FORCE_DECOMPRESS_X1) (void)dtd; assert(dtd.tableType == 0); - return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); + return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); #elif defined(HUF_FORCE_DECOMPRESS_X2) (void)dtd; assert(dtd.tableType == 1); - return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); + return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); #else - return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) : - HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); + return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags) : + HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); #endif } #ifndef HUF_FORCE_DECOMPRESS_X2 -size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2) +size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags) { const BYTE* ip = (const BYTE*) cSrc; - size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize); + size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize, flags); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; - return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2); + return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, flags); } #endif -size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2) +size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags) { DTableDesc const dtd = HUF_getDTableDesc(DTable); #if defined(HUF_FORCE_DECOMPRESS_X1) (void)dtd; assert(dtd.tableType == 0); - return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); + return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); #elif defined(HUF_FORCE_DECOMPRESS_X2) (void)dtd; assert(dtd.tableType == 1); - return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); + return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); #else - return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) : - HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); + return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags) : + HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); #endif } -size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2) +size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags) { /* validation checks */ if (dstSize == 0) return ERROR(dstSize_tooSmall); @@ -1236,16 +1897,16 @@ size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t ds #if defined(HUF_FORCE_DECOMPRESS_X1) (void)algoNb; assert(algoNb == 0); - return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2); + return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags); #elif defined(HUF_FORCE_DECOMPRESS_X2) (void)algoNb; assert(algoNb == 1); - return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2); + return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags); #else - return algoNb ? HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2) : - HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2); + return algoNb ? HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags) : + HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags); #endif } } -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/decompress/zstd_ddict.cpp b/src/duckdb/third_party/zstd/decompress/zstd_ddict.cpp index ecb71145f..2c6c0ded6 100644 --- a/src/duckdb/third_party/zstd/decompress/zstd_ddict.cpp +++ b/src/duckdb/third_party/zstd/decompress/zstd_ddict.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,18 +14,19 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include /* memcpy, memmove, memset */ +#include "zstd/common/allocations.h" /* ZSTD_customMalloc, ZSTD_customFree */ +#include "zstd/common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include "zstd/common/cpu.h" /* bmi2 */ #include "zstd/common/mem.h" /* low level memory routines */ +#define FSE_STATIC_LINKING_ONLY #include "zstd/common/fse.h" -#include "zstd/common/fse_static.h" #include "zstd/common/huf.h" -#include "zstd/common/huf_static.h" #include "zstd/decompress/zstd_decompress_internal.h" #include "zstd/decompress/zstd_ddict.h" -// #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) -// # include "../legacy/zstd_legacy.h" -// #endif +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) +// # include "zstd/legacy/zstd_legacy.h" // DuckDB: comment out otherwise amalgamation won't be happy +#endif namespace duckdb_zstd { @@ -126,14 +127,14 @@ static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, ddict->dictContent = dict; if (!dict) dictSize = 0; } else { - void* const internalBuffer = ZSTD_malloc(dictSize, ddict->cMem); + void* const internalBuffer = ZSTD_customMalloc(dictSize, ddict->cMem); ddict->dictBuffer = internalBuffer; ddict->dictContent = internalBuffer; if (!internalBuffer) return ERROR(memory_allocation); - memcpy(internalBuffer, dict, dictSize); + ZSTD_memcpy(internalBuffer, dict, dictSize); } ddict->dictSize = dictSize; - ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ + ddict->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */ /* parse dictionary content */ FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) , ""); @@ -146,9 +147,9 @@ ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, ZSTD_customMem customMem) { - if (!customMem.customAlloc ^ !customMem.customFree) return NULL; + if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; - { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_malloc(sizeof(ZSTD_DDict), customMem); + { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_customMalloc(sizeof(ZSTD_DDict), customMem); if (ddict == NULL) return NULL; ddict->cMem = customMem; { size_t const initResult = ZSTD_initDDict_internal(ddict, @@ -197,7 +198,7 @@ const ZSTD_DDict* ZSTD_initStaticDDict( if ((size_t)sBuffer & 7) return NULL; /* 8-aligned */ if (sBufferSize < neededSpace) return NULL; if (dictLoadMethod == ZSTD_dlm_byCopy) { - memcpy(ddict+1, dict, dictSize); /* local copy */ + ZSTD_memcpy(ddict+1, dict, dictSize); /* local copy */ dict = ddict+1; } if (ZSTD_isError( ZSTD_initDDict_internal(ddict, @@ -212,8 +213,8 @@ size_t ZSTD_freeDDict(ZSTD_DDict* ddict) { if (ddict==NULL) return 0; /* support free on NULL */ { ZSTD_customMem const cMem = ddict->cMem; - ZSTD_free(ddict->dictBuffer, cMem); - ZSTD_free(ddict, cMem); + ZSTD_customFree(ddict->dictBuffer, cMem); + ZSTD_customFree(ddict, cMem); return 0; } } @@ -239,7 +240,7 @@ size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict) unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict) { if (ddict==NULL) return 0; - return ZSTD_getDictID_fromDict(ddict->dictContent, ddict->dictSize); + return ddict->dictID; } -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/decompress/zstd_decompress.cpp b/src/duckdb/third_party/zstd/decompress/zstd_decompress.cpp index 19ebd9078..1a10de56d 100644 --- a/src/duckdb/third_party/zstd/decompress/zstd_decompress.cpp +++ b/src/duckdb/third_party/zstd/decompress/zstd_decompress.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -55,88 +55,167 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include /* memcpy, memmove, memset */ +#include "zstd/common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include "zstd/common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */ +#include "zstd/common/error_private.h" +#include "zstd/common/zstd_internal.h" /* blockProperties_t */ #include "zstd/common/mem.h" /* low level memory routines */ +#include "zstd/common/bits.h" /* ZSTD_highbit32 */ +#define FSE_STATIC_LINKING_ONLY #include "zstd/common/fse.h" -#include "zstd/common/fse_static.h" #include "zstd/common/huf.h" -#include "zstd/common/huf_static.h" -#include "zstd/common/zstd_internal.h" /* blockProperties_t */ +#include "zstd/common/xxhash.hpp" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */ +#include "zstd/common/xxhash_static.hpp" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */ #include "zstd/decompress/zstd_decompress_internal.h" /* ZSTD_DCtx */ #include "zstd/decompress/zstd_ddict.h" /* ZSTD_DDictDictContent */ #include "zstd/decompress/zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */ -// #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) -// # include "../legacy/zstd_legacy.h" -// #endif +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) +// # include "zstd/legacy/zstd_legacy.h" // DuckDB: comment out otherwise amalgamation won't be happy +#endif + + + +/************************************* + * Multiple DDicts Hashset internals * + *************************************/ + +#define DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT 4 +#define DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT 3 /* These two constants represent SIZE_MULT/COUNT_MULT load factor without using a float. */ + /* Currently, that means a 0.75 load factor. */ + /* So, if count * COUNT_MULT / size * SIZE_MULT != 0, then we've exceeded */ + /* the load factor of the ddict hash set. */ + +#define DDICT_HASHSET_TABLE_BASE_SIZE 64 +#define DDICT_HASHSET_RESIZE_FACTOR 2 + namespace duckdb_zstd { -const U32 ZSTDConstants::LL_base[MaxLL+1] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 18, 20, 22, 24, 28, 32, 40, - 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, - 0x2000, 0x4000, 0x8000, 0x10000 }; - -const U32 ZSTDConstants::OF_base[MaxOff+1] = { - 0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, - 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD, - 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, - 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD }; - -const U32 ZSTDConstants::OF_bits[MaxOff+1] = { - 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 }; - -const U32 ZSTDConstants::ML_base[MaxML+1] = { - 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, 37, 39, 41, 43, 47, 51, 59, - 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803, - 0x1003, 0x2003, 0x4003, 0x8003, 0x10003 }; - -const size_t ZSTDInternalConstants::ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; -const U32 ZSTDInternalConstants::LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 2, 2, 3, 3, - 4, 6, 7, 8, 9,10,11,12, - 13,14,15,16 }; -const S16 ZSTDInternalConstants::LL_defaultNorm[MaxLL+1] = { 4, 3, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 3, 2, 1, 1, 1, 1, 1, - -1,-1,-1,-1 }; -#define LL_DEFAULTNORMLOG 6 /* for static allocation */ -const U32 ZSTDInternalConstants::LL_defaultNormLog = LL_DEFAULTNORMLOG; -const U32 ZSTDInternalConstants::ML_bits[MaxML+1] = { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 2, 2, 3, 3, - 4, 4, 5, 7, 8, 9,10,11, - 12,13,14,15,16 }; -const S16 ZSTDInternalConstants::ML_defaultNorm[MaxML+1] = { 1, 4, 3, 2, 2, 2, 2, 2, - 2, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1,-1,-1, - -1,-1,-1,-1,-1 }; -#define ML_DEFAULTNORMLOG 6 /* for static allocation */ -const U32 ZSTDInternalConstants::ML_defaultNormLog = ML_DEFAULTNORMLOG; - -const S16 ZSTDInternalConstants::OF_defaultNorm[DefaultMaxOff+1] = { 1, 1, 1, 1, 1, 1, 2, 2, - 2, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - -1,-1,-1,-1,-1 }; -#define OF_DEFAULTNORMLOG 5 /* for static allocation */ -const U32 ZSTDInternalConstants::OF_defaultNormLog = OF_DEFAULTNORMLOG; -const U32 ZSTDInternalConstants::repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; - -const ZSTD_customMem ZSTDInternalConstants::ZSTD_defaultCMem = { NULL, NULL, NULL }; /**< this constant defers to stdlib's functions */ + +/* Hash function to determine starting position of dict insertion within the table + * Returns an index between [0, hashSet->ddictPtrTableSize] + */ +static size_t ZSTD_DDictHashSet_getIndex(const ZSTD_DDictHashSet* hashSet, U32 dictID) { + const U64 hash = XXH64(&dictID, sizeof(U32), 0); + /* DDict ptr table size is a multiple of 2, use size - 1 as mask to get index within [0, hashSet->ddictPtrTableSize) */ + return hash & (hashSet->ddictPtrTableSize - 1); +} + +/* Adds DDict to a hashset without resizing it. + * If inserting a DDict with a dictID that already exists in the set, replaces the one in the set. + * Returns 0 if successful, or a zstd error code if something went wrong. + */ +static size_t ZSTD_DDictHashSet_emplaceDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict) { + const U32 dictID = ZSTD_getDictID_fromDDict(ddict); + size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID); + const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1; + RETURN_ERROR_IF(hashSet->ddictPtrCount == hashSet->ddictPtrTableSize, GENERIC, "Hash set is full!"); + DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx); + while (hashSet->ddictPtrTable[idx] != NULL) { + /* Replace existing ddict if inserting ddict with same dictID */ + if (ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]) == dictID) { + DEBUGLOG(4, "DictID already exists, replacing rather than adding"); + hashSet->ddictPtrTable[idx] = ddict; + return 0; + } + idx &= idxRangeMask; + idx++; + } + DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx); + hashSet->ddictPtrTable[idx] = ddict; + hashSet->ddictPtrCount++; + return 0; +} + +/* Expands hash table by factor of DDICT_HASHSET_RESIZE_FACTOR and + * rehashes all values, allocates new table, frees old table. + * Returns 0 on success, otherwise a zstd error code. + */ +static size_t ZSTD_DDictHashSet_expand(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) { + size_t newTableSize = hashSet->ddictPtrTableSize * DDICT_HASHSET_RESIZE_FACTOR; + const ZSTD_DDict** newTable = (const ZSTD_DDict**)ZSTD_customCalloc(sizeof(ZSTD_DDict*) * newTableSize, customMem); + const ZSTD_DDict** oldTable = hashSet->ddictPtrTable; + size_t oldTableSize = hashSet->ddictPtrTableSize; + size_t i; + + DEBUGLOG(4, "Expanding DDict hash table! Old size: %zu new size: %zu", oldTableSize, newTableSize); + RETURN_ERROR_IF(!newTable, memory_allocation, "Expanded hashset allocation failed!"); + hashSet->ddictPtrTable = newTable; + hashSet->ddictPtrTableSize = newTableSize; + hashSet->ddictPtrCount = 0; + for (i = 0; i < oldTableSize; ++i) { + if (oldTable[i] != NULL) { + FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, oldTable[i]), ""); + } + } + ZSTD_customFree((void*)oldTable, customMem); + DEBUGLOG(4, "Finished re-hash"); + return 0; +} + +/* Fetches a DDict with the given dictID + * Returns the ZSTD_DDict* with the requested dictID. If it doesn't exist, then returns NULL. + */ +static const ZSTD_DDict* ZSTD_DDictHashSet_getDDict(ZSTD_DDictHashSet* hashSet, U32 dictID) { + size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID); + const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1; + DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx); + for (;;) { + size_t currDictID = ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]); + if (currDictID == dictID || currDictID == 0) { + /* currDictID == 0 implies a NULL ddict entry */ + break; + } else { + idx &= idxRangeMask; /* Goes to start of table when we reach the end */ + idx++; + } + } + DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx); + return hashSet->ddictPtrTable[idx]; +} + +/* Allocates space for and returns a ddict hash set + * The hash set's ZSTD_DDict* table has all values automatically set to NULL to begin with. + * Returns NULL if allocation failed. + */ +static ZSTD_DDictHashSet* ZSTD_createDDictHashSet(ZSTD_customMem customMem) { + ZSTD_DDictHashSet* ret = (ZSTD_DDictHashSet*)ZSTD_customMalloc(sizeof(ZSTD_DDictHashSet), customMem); + DEBUGLOG(4, "Allocating new hash set"); + if (!ret) + return NULL; + ret->ddictPtrTable = (const ZSTD_DDict**)ZSTD_customCalloc(DDICT_HASHSET_TABLE_BASE_SIZE * sizeof(ZSTD_DDict*), customMem); + if (!ret->ddictPtrTable) { + ZSTD_customFree(ret, customMem); + return NULL; + } + ret->ddictPtrTableSize = DDICT_HASHSET_TABLE_BASE_SIZE; + ret->ddictPtrCount = 0; + return ret; +} + +/* Frees the table of ZSTD_DDict* within a hashset, then frees the hashset itself. + * Note: The ZSTD_DDict* within the table are NOT freed. + */ +static void ZSTD_freeDDictHashSet(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) { + DEBUGLOG(4, "Freeing ddict hash set"); + if (hashSet && hashSet->ddictPtrTable) { + ZSTD_customFree((void*)hashSet->ddictPtrTable, customMem); + } + if (hashSet) { + ZSTD_customFree(hashSet, customMem); + } +} + +/* Public function: Adds a DDict into the ZSTD_DDictHashSet, possibly triggering a resize of the hash set. + * Returns 0 on success, or a ZSTD error. + */ +static size_t ZSTD_DDictHashSet_addDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict, ZSTD_customMem customMem) { + DEBUGLOG(4, "Adding dict ID: %u to hashset with - Count: %zu Tablesize: %zu", ZSTD_getDictID_fromDDict(ddict), hashSet->ddictPtrCount, hashSet->ddictPtrTableSize); + if (hashSet->ddictPtrCount * DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT / hashSet->ddictPtrTableSize * DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT != 0) { + FORWARD_IF_ERROR(ZSTD_DDictHashSet_expand(hashSet, customMem), ""); + } + FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict), ""); + return 0; +} /*-************************************************************* * Context management @@ -160,11 +239,21 @@ static size_t ZSTD_startingInputLength(ZSTD_format_e format) return startingInputLength; } +static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx) +{ + assert(dctx->streamStage == zdss_init); + dctx->format = ZSTD_f_zstd1; + dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; + dctx->outBufferMode = ZSTD_bm_buffered; + dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum; + dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict; + dctx->disableHufAsm = 0; + dctx->maxBlockSizeParam = 0; +} + static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) { - dctx->format = ZSTD_f_zstd1; /* ZSTD_decompressBegin() invokes ZSTD_startingInputLength() with argument dctx->format */ dctx->staticSize = 0; - dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; dctx->ddict = NULL; dctx->ddictLocal = NULL; dctx->dictEnd = NULL; @@ -174,12 +263,18 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) dctx->inBuffSize = 0; dctx->outBuffSize = 0; dctx->streamStage = zdss_init; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) dctx->legacyContext = NULL; dctx->previousLegacyVersion = 0; +#endif dctx->noForwardProgress = 0; dctx->oversizedDuration = 0; - dctx->bmi2 = 0; - dctx->outBufferMode = ZSTD_obm_buffered; + dctx->isFrameDecompression = 1; +#if DYNAMIC_BMI2 + dctx->bmi2 = ZSTD_cpuSupportsBmi2(); +#endif + dctx->ddictSet = NULL; + ZSTD_DCtx_resetParameters(dctx); #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION dctx->dictContentEndForFuzzing = NULL; #endif @@ -198,11 +293,10 @@ ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize) return dctx; } -ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) -{ - if (!customMem.customAlloc ^ !customMem.customFree) return NULL; +static ZSTD_DCtx* ZSTD_createDCtx_internal(ZSTD_customMem customMem) { + if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; - { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_malloc(sizeof(*dctx), customMem); + { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_customMalloc(sizeof(*dctx), customMem); if (!dctx) return NULL; dctx->customMem = customMem; ZSTD_initDCtx_internal(dctx); @@ -210,10 +304,15 @@ ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) } } +ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) +{ + return ZSTD_createDCtx_internal(customMem); +} + ZSTD_DCtx* ZSTD_createDCtx(void) { DEBUGLOG(3, "ZSTD_createDCtx"); - return ZSTD_createDCtx_advanced(ZSTDInternalConstants::ZSTD_defaultCMem); + return ZSTD_createDCtx_internal(ZSTD_defaultCMem); } static void ZSTD_clearDict(ZSTD_DCtx* dctx) @@ -230,13 +329,17 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx) RETURN_ERROR_IF(dctx->staticSize, memory_allocation, "not compatible with static DCtx"); { ZSTD_customMem const cMem = dctx->customMem; ZSTD_clearDict(dctx); - ZSTD_free(dctx->inBuff, cMem); + ZSTD_customFree(dctx->inBuff, cMem); dctx->inBuff = NULL; #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) if (dctx->legacyContext) ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion); #endif - ZSTD_free(dctx, cMem); + if (dctx->ddictSet) { + ZSTD_freeDDictHashSet(dctx->ddictSet, cMem); + dctx->ddictSet = NULL; + } + ZSTD_customFree(dctx, cMem); return 0; } } @@ -245,7 +348,30 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx) void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) { size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx); - memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */ + ZSTD_memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */ +} + +/* Given a dctx with a digested frame params, re-selects the correct ZSTD_DDict based on + * the requested dict ID from the frame. If there exists a reference to the correct ZSTD_DDict, then + * accordingly sets the ddict to be used to decompress the frame. + * + * If no DDict is found, then no action is taken, and the ZSTD_DCtx::ddict remains as-is. + * + * ZSTD_d_refMultipleDDicts must be enabled for this function to be called. + */ +static void ZSTD_DCtx_selectFrameDDict(ZSTD_DCtx* dctx) { + assert(dctx->refMultipleDDicts && dctx->ddictSet); + DEBUGLOG(4, "Adjusting DDict based on requested dict ID from frame"); + if (dctx->ddict) { + const ZSTD_DDict* frameDDict = ZSTD_DDictHashSet_getDDict(dctx->ddictSet, dctx->fParams.dictID); + if (frameDDict) { + DEBUGLOG(4, "DDict found!"); + ZSTD_clearDict(dctx); + dctx->dictID = dctx->fParams.dictID; + dctx->ddict = frameDDict; + dctx->dictUses = ZSTD_use_indefinitely; + } + } } @@ -271,8 +397,19 @@ unsigned ZSTD_isFrame(const void* buffer, size_t size) return 0; } -static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 }; -static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 }; +/*! ZSTD_isSkippableFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame. + * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. + */ +unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size) +{ + if (size < ZSTD_FRAMEIDSIZE) return 0; + { U32 const magic = MEM_readLE32(buffer); + if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1; + } + return 0; +} + /** ZSTD_frameHeaderSize_internal() : * srcSize must be large enough to reach header size fields. * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless. @@ -308,23 +445,47 @@ size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize) * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless * @return : 0, `zfhPtr` is correctly filled, * >0, `srcSize` is too small, value is wanted `srcSize` amount, - * or an error code, which can be tested using ZSTD_isError() */ +** or an error code, which can be tested using ZSTD_isError() */ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format) { const BYTE* ip = (const BYTE*)src; size_t const minInputSize = ZSTD_startingInputLength(format); - memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */ - if (srcSize < minInputSize) return minInputSize; - RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter"); + DEBUGLOG(5, "ZSTD_getFrameHeader_advanced: minInputSize = %zu, srcSize = %zu", minInputSize, srcSize); + + if (srcSize > 0) { + /* note : technically could be considered an assert(), since it's an invalid entry */ + RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter : src==NULL, but srcSize>0"); + } + if (srcSize < minInputSize) { + if (srcSize > 0 && format != ZSTD_f_zstd1_magicless) { + /* when receiving less than @minInputSize bytes, + * control these bytes at least correspond to a supported magic number + * in order to error out early if they don't. + **/ + size_t const toCopy = MIN(4, srcSize); + unsigned char hbuf[4]; MEM_writeLE32(hbuf, ZSTD_MAGICNUMBER); + assert(src != NULL); + ZSTD_memcpy(hbuf, src, toCopy); + if ( MEM_readLE32(hbuf) != ZSTD_MAGICNUMBER ) { + /* not a zstd frame : let's check if it's a skippable frame */ + MEM_writeLE32(hbuf, ZSTD_MAGIC_SKIPPABLE_START); + ZSTD_memcpy(hbuf, src, toCopy); + if ((MEM_readLE32(hbuf) & ZSTD_MAGIC_SKIPPABLE_MASK) != ZSTD_MAGIC_SKIPPABLE_START) { + RETURN_ERROR(prefix_unknown, + "first bytes don't correspond to any supported magic number"); + } } } + return minInputSize; + } + ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzers may not understand that zfhPtr will be read only if return value is zero, since they are 2 different signals */ if ( (format != ZSTD_f_zstd1_magicless) && (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) { if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ if (srcSize < ZSTD_SKIPPABLEHEADERSIZE) return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */ - memset(zfhPtr, 0, sizeof(*zfhPtr)); + ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE); zfhPtr->frameType = ZSTD_skippableFrame; return 0; @@ -359,7 +520,9 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s } switch(dictIDSizeCode) { - default: assert(0); /* impossible */ + default: + assert(0); /* impossible */ + ZSTD_FALLTHROUGH; case 0 : break; case 1 : dictID = ip[pos]; pos++; break; case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break; @@ -367,7 +530,9 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s } switch(fcsID) { - default: assert(0); /* impossible */ + default: + assert(0); /* impossible */ + ZSTD_FALLTHROUGH; case 0 : if (singleSegment) frameContentSize = ip[pos]; break; case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break; case 2 : frameContentSize = MEM_readLE32(ip+pos); break; @@ -396,7 +561,6 @@ size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t src return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1); } - /** ZSTD_getFrameContentSize() : * compatible with legacy mode * @return : decompressed size of the single frame pointed to be `src` if known, otherwise @@ -430,18 +594,52 @@ static size_t readSkippableFrameSize(void const* src, size_t srcSize) sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE); RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32, frameParameter_unsupported, ""); - { - size_t const skippableSize = skippableHeaderSize + sizeU32; + { size_t const skippableSize = skippableHeaderSize + sizeU32; RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, ""); return skippableSize; } } +/*! ZSTD_readSkippableFrame() : + * Retrieves content of a skippable frame, and writes it to dst buffer. + * + * The parameter magicVariant will receive the magicVariant that was supplied when the frame was written, + * i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested + * in the magicVariant. + * + * Returns an error if destination buffer is not large enough, or if this is not a valid skippable frame. + * + * @return : number of bytes written or a ZSTD error. + */ +size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, + unsigned* magicVariant, /* optional, can be NULL */ + const void* src, size_t srcSize) +{ + RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, ""); + + { U32 const magicNumber = MEM_readLE32(src); + size_t skippableFrameSize = readSkippableFrameSize(src, srcSize); + size_t skippableContentSize = skippableFrameSize - ZSTD_SKIPPABLEHEADERSIZE; + + /* check input validity */ + RETURN_ERROR_IF(!ZSTD_isSkippableFrame(src, srcSize), frameParameter_unsupported, ""); + RETURN_ERROR_IF(skippableFrameSize < ZSTD_SKIPPABLEHEADERSIZE || skippableFrameSize > srcSize, srcSize_wrong, ""); + RETURN_ERROR_IF(skippableContentSize > dstCapacity, dstSize_tooSmall, ""); + + /* deliver payload */ + if (skippableContentSize > 0 && dst != NULL) + ZSTD_memcpy(dst, (const BYTE *)src + ZSTD_SKIPPABLEHEADERSIZE, skippableContentSize); + if (magicVariant != NULL) + *magicVariant = magicNumber - ZSTD_MAGIC_SKIPPABLE_START; + return skippableContentSize; + } +} + /** ZSTD_findDecompressedSize() : - * compatible with legacy mode * `srcSize` must be the exact length of some number of ZSTD compressed and/or * skippable frames - * @return : decompressed size of the frames contained */ + * note: compatible with legacy mode + * @return : decompressed size of the frames contained */ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize) { unsigned long long totalDstSize = 0; @@ -451,9 +649,7 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize) if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { size_t const skippableSize = readSkippableFrameSize(src, srcSize); - if (ZSTD_isError(skippableSize)) { - return ZSTD_CONTENTSIZE_ERROR; - } + if (ZSTD_isError(skippableSize)) return ZSTD_CONTENTSIZE_ERROR; assert(skippableSize <= srcSize); src = (const BYTE *)src + skippableSize; @@ -461,17 +657,17 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize) continue; } - { unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize); - if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret; + { unsigned long long const fcs = ZSTD_getFrameContentSize(src, srcSize); + if (fcs >= ZSTD_CONTENTSIZE_ERROR) return fcs; - /* check for overflow */ - if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR; - totalDstSize += ret; + if (totalDstSize + fcs < totalDstSize) + return ZSTD_CONTENTSIZE_ERROR; /* check for overflow */ + totalDstSize += fcs; } + /* skip to next frame */ { size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize); - if (ZSTD_isError(frameSrcSize)) { - return ZSTD_CONTENTSIZE_ERROR; - } + if (ZSTD_isError(frameSrcSize)) return ZSTD_CONTENTSIZE_ERROR; + assert(frameSrcSize <= srcSize); src = (const BYTE *)src + frameSrcSize; srcSize -= frameSrcSize; @@ -501,12 +697,19 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize) /** ZSTD_decodeFrameHeader() : * `headerSize` must be the size provided by ZSTD_frameHeaderSize(). + * If multiple DDict references are enabled, also will choose the correct DDict to use. * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize) { size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format); if (ZSTD_isError(result)) return result; /* invalid header */ RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small"); + + /* Reference DDict requested by frame if dctx references multiple ddicts */ + if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts && dctx->ddictSet) { + ZSTD_DCtx_selectFrameDDict(dctx); + } + #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* Skip the dictID check in fuzzing mode, because it makes the search * harder. @@ -514,7 +717,9 @@ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t he RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID), dictionary_wrong, ""); #endif - if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0); + dctx->validateChecksum = (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) ? 1 : 0; + if (dctx->validateChecksum) XXH64_reset(&dctx->xxhState, 0); + dctx->processedCSize += headerSize; return 0; } @@ -526,17 +731,17 @@ static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret) return frameSizeInfo; } -static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize) +static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize, ZSTD_format_e format) { ZSTD_frameSizeInfo frameSizeInfo; - memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo)); + ZSTD_memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo)); #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) - if (ZSTD_isLegacy(src, srcSize)) + if (format == ZSTD_f_zstd1 && ZSTD_isLegacy(src, srcSize)) return ZSTD_findFrameSizeInfoLegacy(src, srcSize); #endif - if ((srcSize >= ZSTD_SKIPPABLEHEADERSIZE) + if (format == ZSTD_f_zstd1 && (srcSize >= ZSTD_SKIPPABLEHEADERSIZE) && (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize); assert(ZSTD_isError(frameSizeInfo.compressedSize) || @@ -550,7 +755,7 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize ZSTD_frameHeader zfh; /* Extract Frame Header */ - { size_t const ret = ZSTD_getFrameHeader(&zfh, src, srcSize); + { size_t const ret = ZSTD_getFrameHeader_advanced(&zfh, src, srcSize, format); if (ZSTD_isError(ret)) return ZSTD_errorFrameSizeInfo(ret); if (ret > 0) @@ -567,11 +772,11 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize if (ZSTD_isError(cBlockSize)) return ZSTD_errorFrameSizeInfo(cBlockSize); - if (ZSTDInternalConstants::ZSTD_blockHeaderSize + cBlockSize > remainingSize) + if (ZSTD_blockHeaderSize + cBlockSize > remainingSize) return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong)); - ip += ZSTDInternalConstants::ZSTD_blockHeaderSize + cBlockSize; - remainingSize -= ZSTDInternalConstants::ZSTD_blockHeaderSize + cBlockSize; + ip += ZSTD_blockHeaderSize + cBlockSize; + remainingSize -= ZSTD_blockHeaderSize + cBlockSize; nbBlocks++; if (blockProperties.lastBlock) break; @@ -584,23 +789,26 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize ip += 4; } - frameSizeInfo.compressedSize = ip - ipstart; + frameSizeInfo.nbBlocks = nbBlocks; + frameSizeInfo.compressedSize = (size_t)(ip - ipstart); frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) ? zfh.frameContentSize - : nbBlocks * zfh.blockSizeMax; + : (unsigned long long)nbBlocks * zfh.blockSizeMax; return frameSizeInfo; } } +static size_t ZSTD_findFrameCompressedSize_advanced(const void *src, size_t srcSize, ZSTD_format_e format) { + ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize, format); + return frameSizeInfo.compressedSize; +} + /** ZSTD_findFrameCompressedSize() : - * compatible with legacy mode - * `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame - * `srcSize` must be at least as large as the frame contained - * @return : the compressed size of the frame starting at `src` */ + * See docs in zstd.h + * Note: compatible with legacy mode */ size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize) { - ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize); - return frameSizeInfo.compressedSize; + return ZSTD_findFrameCompressedSize_advanced(src, srcSize, ZSTD_f_zstd1); } /** ZSTD_decompressBound() : @@ -614,7 +822,7 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize) unsigned long long bound = 0; /* Iterate over each frame */ while (srcSize > 0) { - ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize); + ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize, ZSTD_f_zstd1); size_t const compressedSize = frameSizeInfo.compressedSize; unsigned long long const decompressedBound = frameSizeInfo.decompressedBound; if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR) @@ -627,6 +835,48 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize) return bound; } +size_t ZSTD_decompressionMargin(void const* src, size_t srcSize) +{ + size_t margin = 0; + unsigned maxBlockSize = 0; + + /* Iterate over each frame */ + while (srcSize > 0) { + ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize, ZSTD_f_zstd1); + size_t const compressedSize = frameSizeInfo.compressedSize; + unsigned long long const decompressedBound = frameSizeInfo.decompressedBound; + ZSTD_frameHeader zfh; + + FORWARD_IF_ERROR(ZSTD_getFrameHeader(&zfh, src, srcSize), ""); + if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR) + return ERROR(corruption_detected); + + if (zfh.frameType == ZSTD_frame) { + /* Add the frame header to our margin */ + margin += zfh.headerSize; + /* Add the checksum to our margin */ + margin += zfh.checksumFlag ? 4 : 0; + /* Add 3 bytes per block */ + margin += 3 * frameSizeInfo.nbBlocks; + + /* Compute the max block size */ + maxBlockSize = MAX(maxBlockSize, zfh.blockSizeMax); + } else { + assert(zfh.frameType == ZSTD_skippableFrame); + /* Add the entire skippable frame size to our margin. */ + margin += compressedSize; + } + + assert(srcSize >= compressedSize); + src = (const BYTE*)src + compressedSize; + srcSize -= compressedSize; + } + + /* Add the max block size back to the margin. */ + margin += maxBlockSize; + + return margin; +} /*-************************************************************* * Frame decoding @@ -637,7 +887,7 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize) size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize) { DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize); - ZSTD_checkContinuity(dctx, blockStart); + ZSTD_checkContinuity(dctx, blockStart, blockSize); dctx->previousDstEnd = (const char*)blockStart + blockSize; return blockSize; } @@ -647,12 +897,12 @@ static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_copyRawBlock"); + RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, ""); if (dst == NULL) { if (srcSize == 0) return 0; RETURN_ERROR(dstBuffer_null, ""); } - RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, ""); - memcpy(dst, src, srcSize); + ZSTD_memmove(dst, src, srcSize); return srcSize; } @@ -660,15 +910,41 @@ static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity, BYTE b, size_t regenSize) { + RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, ""); if (dst == NULL) { if (regenSize == 0) return 0; RETURN_ERROR(dstBuffer_null, ""); } - RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, ""); - memset(dst, b, regenSize); + ZSTD_memset(dst, b, regenSize); return regenSize; } +static void ZSTD_DCtx_trace_end(ZSTD_DCtx const* dctx, U64 uncompressedSize, U64 compressedSize, unsigned streaming) +{ +#if ZSTD_TRACE + if (dctx->traceCtx && ZSTD_trace_decompress_end != NULL) { + ZSTD_Trace trace; + ZSTD_memset(&trace, 0, sizeof(trace)); + trace.version = ZSTD_VERSION_NUMBER; + trace.streaming = streaming; + if (dctx->ddict) { + trace.dictionaryID = ZSTD_getDictID_fromDDict(dctx->ddict); + trace.dictionarySize = ZSTD_DDict_dictSize(dctx->ddict); + trace.dictionaryIsCold = dctx->ddictIsCold; + } + trace.uncompressedSize = (size_t)uncompressedSize; + trace.compressedSize = (size_t)compressedSize; + trace.dctx = dctx; + ZSTD_trace_decompress_end(dctx->traceCtx, &trace); + } +#else + (void)dctx; + (void)uncompressedSize; + (void)compressedSize; + (void)streaming; +#endif +} + /*! ZSTD_decompressFrame() : * @dctx must be properly initialized @@ -678,8 +954,9 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void** srcPtr, size_t *srcSizePtr) { - const BYTE* ip = (const BYTE*)(*srcPtr); - BYTE* const ostart = (BYTE* const)dst; + const BYTE* const istart = (const BYTE*)(*srcPtr); + const BYTE* ip = istart; + BYTE* const ostart = (BYTE*)dst; BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart; BYTE* op = ostart; size_t remainingSrcSize = *srcSizePtr; @@ -688,51 +965,77 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, /* check */ RETURN_ERROR_IF( - remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN(dctx->format)+ZSTDInternalConstants::ZSTD_blockHeaderSize, + remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN(dctx->format)+ZSTD_blockHeaderSize, srcSize_wrong, ""); /* Frame Header */ { size_t const frameHeaderSize = ZSTD_frameHeaderSize_internal( ip, ZSTD_FRAMEHEADERSIZE_PREFIX(dctx->format), dctx->format); if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; - RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTDInternalConstants::ZSTD_blockHeaderSize, + RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize, srcSize_wrong, ""); FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) , ""); ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize; } + /* Shrink the blockSizeMax if enabled */ + if (dctx->maxBlockSizeParam != 0) + dctx->fParams.blockSizeMax = MIN(dctx->fParams.blockSizeMax, (unsigned)dctx->maxBlockSizeParam); + /* Loop on each block */ while (1) { + BYTE* oBlockEnd = oend; size_t decodedSize; blockProperties_t blockProperties; size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSrcSize, &blockProperties); if (ZSTD_isError(cBlockSize)) return cBlockSize; - ip += ZSTDInternalConstants::ZSTD_blockHeaderSize; - remainingSrcSize -= ZSTDInternalConstants::ZSTD_blockHeaderSize; + ip += ZSTD_blockHeaderSize; + remainingSrcSize -= ZSTD_blockHeaderSize; RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong, ""); + if (ip >= op && ip < oBlockEnd) { + /* We are decompressing in-place. Limit the output pointer so that we + * don't overwrite the block that we are currently reading. This will + * fail decompression if the input & output pointers aren't spaced + * far enough apart. + * + * This is important to set, even when the pointers are far enough + * apart, because ZSTD_decompressBlock_internal() can decide to store + * literals in the output buffer, after the block it is decompressing. + * Since we don't want anything to overwrite our input, we have to tell + * ZSTD_decompressBlock_internal to never write past ip. + * + * See ZSTD_allocateLiteralsBuffer() for reference. + */ + oBlockEnd = op + (ip - op); + } + switch(blockProperties.blockType) { case bt_compressed: - decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize, /* frame */ 1); + assert(dctx->isFrameDecompression == 1); + decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oBlockEnd-op), ip, cBlockSize, not_streaming); break; case bt_raw : - decodedSize = ZSTD_copyRawBlock(op, oend-op, ip, cBlockSize); + /* Use oend instead of oBlockEnd because this function is safe to overlap. It uses memmove. */ + decodedSize = ZSTD_copyRawBlock(op, (size_t)(oend-op), ip, cBlockSize); break; case bt_rle : - decodedSize = ZSTD_setRleBlock(op, oend-op, *ip, blockProperties.origSize); + decodedSize = ZSTD_setRleBlock(op, (size_t)(oBlockEnd-op), *ip, blockProperties.origSize); break; case bt_reserved : default: RETURN_ERROR(corruption_detected, "invalid block type"); } - - if (ZSTD_isError(decodedSize)) return decodedSize; - if (dctx->fParams.checksumFlag) + FORWARD_IF_ERROR(decodedSize, "Block decompression failure"); + DEBUGLOG(5, "Decompressed block of dSize = %u", (unsigned)decodedSize); + if (dctx->validateChecksum) { XXH64_update(&dctx->xxhState, op, decodedSize); - if (decodedSize != 0) + } + if (decodedSize) /* support dst = NULL,0 */ { op += decodedSize; + } assert(ip != NULL); ip += cBlockSize; remainingSrcSize -= cBlockSize; @@ -744,22 +1047,27 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, corruption_detected, ""); } if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */ - U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState); - U32 checkRead; RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, ""); - checkRead = MEM_readLE32(ip); - RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, ""); + if (!dctx->forceIgnoreChecksum) { + U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState); + U32 checkRead; + checkRead = MEM_readLE32(ip); + RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, ""); + } ip += 4; remainingSrcSize -= 4; } - + ZSTD_DCtx_trace_end(dctx, (U64)(op-ostart), (U64)(ip-istart), /* streaming */ 0); /* Allow caller to get size read */ + DEBUGLOG(4, "ZSTD_decompressFrame: decompressed frame of size %zi, consuming %zi bytes of input", op-ostart, ip - (const BYTE*)*srcPtr); *srcPtr = ip; *srcSizePtr = remainingSrcSize; - return op-ostart; + return (size_t)(op-ostart); } -static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, +static +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict, size_t dictSize, @@ -779,7 +1087,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, while (srcSize >= ZSTD_startingInputLength(dctx->format)) { #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) - if (ZSTD_isLegacy(src, srcSize)) { + if (dctx->format == ZSTD_f_zstd1 && ZSTD_isLegacy(src, srcSize)) { size_t decodedSize; size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize); if (ZSTD_isError(frameSize)) return frameSize; @@ -789,7 +1097,16 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize); if (ZSTD_isError(decodedSize)) return decodedSize; - assert(decodedSize <=- dstCapacity); + { + unsigned long long const expectedSize = ZSTD_getFrameContentSize(src, srcSize); + RETURN_ERROR_IF(expectedSize == ZSTD_CONTENTSIZE_ERROR, corruption_detected, "Corrupted frame header!"); + if (expectedSize != ZSTD_CONTENTSIZE_UNKNOWN) { + RETURN_ERROR_IF(expectedSize != decodedSize, corruption_detected, + "Frame header size does not match decoded size!"); + } + } + + assert(decodedSize <= dstCapacity); dst = (BYTE*)dst + decodedSize; dstCapacity -= decodedSize; @@ -800,17 +1117,18 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, } #endif - { U32 const magicNumber = MEM_readLE32(src); - DEBUGLOG(4, "reading magic number %08X (expecting %08X)", - (unsigned)magicNumber, ZSTD_MAGICNUMBER); + if (dctx->format == ZSTD_f_zstd1 && srcSize >= 4) { + U32 const magicNumber = MEM_readLE32(src); + DEBUGLOG(5, "reading magic number %08X", (unsigned)magicNumber); if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { + /* skippable frame detected : skip it */ size_t const skippableSize = readSkippableFrameSize(src, srcSize); - FORWARD_IF_ERROR(skippableSize, "readSkippableFrameSize failed"); + FORWARD_IF_ERROR(skippableSize, "invalid skippable frame"); assert(skippableSize <= srcSize); src = (const BYTE *)src + skippableSize; srcSize -= skippableSize; - continue; + continue; /* check next frame */ } } if (ddict) { @@ -821,7 +1139,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, * use this in all cases but ddict */ FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), ""); } - ZSTD_checkContinuity(dctx, dst); + ZSTD_checkContinuity(dctx, dst, dstCapacity); { const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity, &src, &srcSize); @@ -829,15 +1147,13 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, (ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown) && (moreThan1Frame==1), srcSize_wrong, - "at least one frame successfully completed, but following " - "bytes are garbage: it's more likely to be a srcSize error, " - "specifying more bytes than compressed size of frame(s). This " - "error message replaces ERROR(prefix_unknown), which would be " - "confusing, as the first header is actually correct. Note that " - "one could be unlucky, it might be a corruption error instead, " - "happening right at the place where we expect zstd magic " - "bytes. But this is _much_ less likely than a srcSize field " - "error."); + "At least one frame successfully completed, " + "but following bytes are garbage: " + "it's more likely to be a srcSize error, " + "specifying more input bytes than size of frame(s). " + "Note: one could be unlucky, it might be a corruption error instead, " + "happening right at the place where we expect zstd magic bytes. " + "But this is _much_ less likely than a srcSize field error."); if (ZSTD_isError(res)) return res; assert(res <= dstCapacity); if (res != 0) @@ -849,7 +1165,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, RETURN_ERROR_IF(srcSize, srcSize_wrong, "input not entirely consumed"); - return (BYTE*)dst - (BYTE*)dststart; + return (size_t)((BYTE*)dst - (BYTE*)dststart); } size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, @@ -866,7 +1182,7 @@ static ZSTD_DDict const* ZSTD_getDDict(ZSTD_DCtx* dctx) switch (dctx->dictUses) { default: assert(0 /* Impossible */); - /* fall-through */ + ZSTD_FALLTHROUGH; case ZSTD_dont_use: ZSTD_clearDict(dctx); return NULL; @@ -888,7 +1204,7 @@ size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t sr { #if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1) size_t regenSize; - ZSTD_DCtx* const dctx = ZSTD_createDCtx(); + ZSTD_DCtx* const dctx = ZSTD_createDCtx_internal(ZSTD_defaultCMem); RETURN_ERROR_IF(dctx==NULL, memory_allocation, "NULL pointer!"); regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize); ZSTD_freeDCtx(dctx); @@ -908,8 +1224,8 @@ size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t sr size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; } /** - * Similar to ZSTD_nextSrcSizeToDecompress(), but when when a block input can be streamed, - * we allow taking a partial block as the input. Currently only raw uncompressed blocks can + * Similar to ZSTD_nextSrcSizeToDecompress(), but when a block input can be streamed, we + * allow taking a partial block as the input. Currently only raw uncompressed blocks can * be streamed. * * For blocks that can be streamed, this allows us to reduce the latency until we produce @@ -922,7 +1238,7 @@ static size_t ZSTD_nextSrcSizeToDecompressWithInputSize(ZSTD_DCtx* dctx, size_t return dctx->expected; if (dctx->bType != bt_raw) return dctx->expected; - return MIN(MAX(inputSize, 1), dctx->expected); + return BOUNDED(1, inputSize, dctx->expected); } ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) { @@ -930,7 +1246,9 @@ ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) { { default: /* should not happen */ assert(0); + ZSTD_FALLTHROUGH; case ZSTDds_getFrameHeaderSize: + ZSTD_FALLTHROUGH; case ZSTDds_decodeFrameHeader: return ZSTDnit_frameHeader; case ZSTDds_decodeBlockHeader: @@ -942,6 +1260,7 @@ ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) { case ZSTDds_checkChecksum: return ZSTDnit_checksum; case ZSTDds_decodeSkippableHeader: + ZSTD_FALLTHROUGH; case ZSTDds_skipFrame: return ZSTDnit_skippableFrame; } @@ -958,7 +1277,9 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize); /* Sanity check */ RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed"); - if (dstCapacity) ZSTD_checkContinuity(dctx, dst); + ZSTD_checkContinuity(dctx, dst, dstCapacity); + + dctx->processedCSize += srcSize; switch (dctx->stage) { @@ -967,29 +1288,29 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c if (dctx->format == ZSTD_f_zstd1) { /* allows header */ assert(srcSize >= ZSTD_FRAMEIDSIZE); /* to read skippable magic number */ if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ - memcpy(dctx->headerBuffer, src, srcSize); + ZSTD_memcpy(dctx->headerBuffer, src, srcSize); dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize; /* remaining to load to get full skippable frame header */ dctx->stage = ZSTDds_decodeSkippableHeader; return 0; } } dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format); if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize; - memcpy(dctx->headerBuffer, src, srcSize); + ZSTD_memcpy(dctx->headerBuffer, src, srcSize); dctx->expected = dctx->headerSize - srcSize; dctx->stage = ZSTDds_decodeFrameHeader; return 0; case ZSTDds_decodeFrameHeader: assert(src != NULL); - memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize); + ZSTD_memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize); FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize), ""); - dctx->expected = ZSTDInternalConstants::ZSTD_blockHeaderSize; + dctx->expected = ZSTD_blockHeaderSize; dctx->stage = ZSTDds_decodeBlockHeader; return 0; case ZSTDds_decodeBlockHeader: { blockProperties_t bp; - size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTDInternalConstants::ZSTD_blockHeaderSize, &bp); + size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp); if (ZSTD_isError(cBlockSize)) return cBlockSize; RETURN_ERROR_IF(cBlockSize > dctx->fParams.blockSizeMax, corruption_detected, "Block Size Exceeds Maximum"); dctx->expected = cBlockSize; @@ -1009,7 +1330,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c dctx->stage = ZSTDds_getFrameHeaderSize; } } else { - dctx->expected = ZSTDInternalConstants::ZSTD_blockHeaderSize; /* jump to next header */ + dctx->expected = ZSTD_blockHeaderSize; /* jump to next header */ dctx->stage = ZSTDds_decodeBlockHeader; } return 0; @@ -1023,7 +1344,8 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c { case bt_compressed: DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed"); - rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1); + assert(dctx->isFrameDecompression == 1); + rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, is_streaming); dctx->expected = 0; /* Streaming not supported */ break; case bt_raw : @@ -1045,7 +1367,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum"); DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize); dctx->decodedSize += rSize; - if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize); + if (dctx->validateChecksum) XXH64_update(&dctx->xxhState, dst, rSize); dctx->previousDstEnd = (char*)dst + rSize; /* Stay on the same stage until we are finished streaming the block. */ @@ -1063,22 +1385,27 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c dctx->expected = 4; dctx->stage = ZSTDds_checkChecksum; } else { + ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1); dctx->expected = 0; /* ends here */ dctx->stage = ZSTDds_getFrameHeaderSize; } } else { dctx->stage = ZSTDds_decodeBlockHeader; - dctx->expected = ZSTDInternalConstants::ZSTD_blockHeaderSize; + dctx->expected = ZSTD_blockHeaderSize; } return rSize; } case ZSTDds_checkChecksum: assert(srcSize == 4); /* guaranteed by dctx->expected */ - { U32 const h32 = (U32)XXH64_digest(&dctx->xxhState); - U32 const check32 = MEM_readLE32(src); - DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32); - RETURN_ERROR_IF(check32 != h32, checksum_wrong, ""); + { + if (dctx->validateChecksum) { + U32 const h32 = (U32)XXH64_digest(&dctx->xxhState); + U32 const check32 = MEM_readLE32(src); + DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32); + RETURN_ERROR_IF(check32 != h32, checksum_wrong, ""); + } + ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1); dctx->expected = 0; dctx->stage = ZSTDds_getFrameHeaderSize; return 0; @@ -1087,7 +1414,8 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c case ZSTDds_decodeSkippableHeader: assert(src != NULL); assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE); - memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */ + assert(dctx->format != ZSTD_f_zstd1_magicless); + ZSTD_memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */ dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */ dctx->stage = ZSTDds_skipFrame; return 0; @@ -1099,7 +1427,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c default: assert(0); /* impossible */ - RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */ + RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */ } } @@ -1140,11 +1468,11 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, /* in minimal huffman, we always use X1 variants */ size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable, dictPtr, dictEnd - dictPtr, - workspace, workspaceSize); + workspace, workspaceSize, /* flags */ 0); #else size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable, - dictPtr, dictEnd - dictPtr, - workspace, workspaceSize); + dictPtr, (size_t)(dictEnd - dictPtr), + workspace, workspaceSize, /* flags */ 0); #endif RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, ""); dictPtr += hSize; @@ -1152,40 +1480,46 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, { short offcodeNCount[MaxOff+1]; unsigned offcodeMaxValue = MaxOff, offcodeLog; - size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); + size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, (size_t)(dictEnd-dictPtr)); RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, ""); RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted, ""); RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, ""); ZSTD_buildFSETable( entropy->OFTable, offcodeNCount, offcodeMaxValue, - ZSTDConstants::OF_base, ZSTDConstants::OF_bits, - offcodeLog); + OF_base, OF_bits, + offcodeLog, + entropy->workspace, sizeof(entropy->workspace), + /* bmi2 */0); dictPtr += offcodeHeaderSize; } { short matchlengthNCount[MaxML+1]; unsigned matchlengthMaxValue = MaxML, matchlengthLog; - size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); + size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, (size_t)(dictEnd-dictPtr)); RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, ""); RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted, ""); RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, ""); ZSTD_buildFSETable( entropy->MLTable, matchlengthNCount, matchlengthMaxValue, - ZSTDConstants::ML_base, ZSTDInternalConstants::ML_bits, - matchlengthLog); + ML_base, ML_bits, + matchlengthLog, + entropy->workspace, sizeof(entropy->workspace), + /* bmi2 */ 0); dictPtr += matchlengthHeaderSize; } { short litlengthNCount[MaxLL+1]; unsigned litlengthMaxValue = MaxLL, litlengthLog; - size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); + size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, (size_t)(dictEnd-dictPtr)); RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, ""); RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted, ""); RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, ""); ZSTD_buildFSETable( entropy->LLTable, litlengthNCount, litlengthMaxValue, - ZSTDConstants::LL_base, ZSTDInternalConstants::LL_bits, - litlengthLog); + LL_base, LL_bits, + litlengthLog, + entropy->workspace, sizeof(entropy->workspace), + /* bmi2 */ 0); dictPtr += litlengthHeaderSize; } @@ -1199,7 +1533,7 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, entropy->rep[i] = rep; } } - return dictPtr - (const BYTE*)dict; + return (size_t)(dictPtr - (const BYTE*)dict); } static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) @@ -1223,24 +1557,27 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict return ZSTD_refDictContent(dctx, dict, dictSize); } -static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; - size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) { assert(dctx != NULL); +#if ZSTD_TRACE + dctx->traceCtx = (ZSTD_trace_decompress_begin != NULL) ? ZSTD_trace_decompress_begin(dctx) : 0; +#endif dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */ dctx->stage = ZSTDds_getFrameHeaderSize; + dctx->processedCSize = 0; dctx->decodedSize = 0; dctx->previousDstEnd = NULL; dctx->prefixStart = NULL; dctx->virtualStart = NULL; dctx->dictEnd = NULL; - dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ + dctx->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */ dctx->litEntropy = dctx->fseEntropy = 0; dctx->dictID = 0; dctx->bType = bt_reserved; + dctx->isFrameDecompression = 1; ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue)); - memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */ + ZSTD_memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */ dctx->LLTptr = dctx->entropy.LLTable; dctx->MLTptr = dctx->entropy.MLTable; dctx->OFTptr = dctx->entropy.OFTable; @@ -1297,7 +1634,7 @@ unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize) * This could for one of the following reasons : * - The frame does not require a dictionary (most common case). * - The frame was built with dictID intentionally removed. - * Needed dictionary is a hidden information. + * Needed dictionary is a hidden piece of information. * Note : this use case also happens when using a non-conformant dictionary. * - `srcSize` is too small, and as a result, frame header could not be decoded. * Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`. @@ -1306,7 +1643,7 @@ unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize) * ZSTD_getFrameHeader(), which will provide a more precise error code. */ unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize) { - ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0 }; + ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0, 0, 0 }; size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize); if (ZSTD_isError(hError)) return 0; return zfp.dictID; @@ -1335,7 +1672,7 @@ size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, ZSTD_DStream* ZSTD_createDStream(void) { DEBUGLOG(3, "ZSTD_createDStream"); - return ZSTD_createDStream_advanced(ZSTDInternalConstants::ZSTD_defaultCMem); + return ZSTD_createDCtx_internal(ZSTD_defaultCMem); } ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize) @@ -1345,7 +1682,7 @@ ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize) ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem) { - return ZSTD_createDCtx_advanced(customMem); + return ZSTD_createDCtx_internal(customMem); } size_t ZSTD_freeDStream(ZSTD_DStream* zds) @@ -1356,7 +1693,7 @@ size_t ZSTD_freeDStream(ZSTD_DStream* zds) /* *** Initialization *** */ -size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTDInternalConstants::ZSTD_blockHeaderSize; } +size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; } size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; } size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, @@ -1413,7 +1750,9 @@ size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t di size_t ZSTD_initDStream(ZSTD_DStream* zds) { DEBUGLOG(4, "ZSTD_initDStream"); - return ZSTD_initDStream_usingDDict(zds, NULL); + FORWARD_IF_ERROR(ZSTD_DCtx_reset(zds, ZSTD_reset_session_only), ""); + FORWARD_IF_ERROR(ZSTD_DCtx_refDDict(zds, NULL), ""); + return ZSTD_startingInputLength(zds->format); } /* ZSTD_initDStream_usingDDict() : @@ -1421,6 +1760,7 @@ size_t ZSTD_initDStream(ZSTD_DStream* zds) * this function cannot fail */ size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict) { + DEBUGLOG(4, "ZSTD_initDStream_usingDDict"); FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , ""); FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , ""); return ZSTD_startingInputLength(dctx->format); @@ -1431,6 +1771,7 @@ size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict) * this function cannot fail */ size_t ZSTD_resetDStream(ZSTD_DStream* dctx) { + DEBUGLOG(4, "ZSTD_resetDStream"); FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), ""); return ZSTD_startingInputLength(dctx->format); } @@ -1443,6 +1784,16 @@ size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) if (ddict) { dctx->ddict = ddict; dctx->dictUses = ZSTD_use_indefinitely; + if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts) { + if (dctx->ddictSet == NULL) { + dctx->ddictSet = ZSTD_createDDictHashSet(dctx->customMem); + if (!dctx->ddictSet) { + RETURN_ERROR(memory_allocation, "Failed to allocate memory for hash set!"); + } + } + assert(!dctx->staticSize); /* Impossible: ddictSet cannot have been allocated if static dctx */ + FORWARD_IF_ERROR(ZSTD_DDictHashSet_addDDict(dctx->ddictSet, ddict, dctx->customMem), ""); + } } return 0; } @@ -1464,7 +1815,7 @@ size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize) size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format) { - return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, format); + return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, (int)format); } ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) @@ -1481,9 +1832,26 @@ ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless); return bounds; case ZSTD_d_stableOutBuffer: - bounds.lowerBound = (int)ZSTD_obm_buffered; - bounds.upperBound = (int)ZSTD_obm_stable; + bounds.lowerBound = (int)ZSTD_bm_buffered; + bounds.upperBound = (int)ZSTD_bm_stable; + return bounds; + case ZSTD_d_forceIgnoreChecksum: + bounds.lowerBound = (int)ZSTD_d_validateChecksum; + bounds.upperBound = (int)ZSTD_d_ignoreChecksum; + return bounds; + case ZSTD_d_refMultipleDDicts: + bounds.lowerBound = (int)ZSTD_rmd_refSingleDDict; + bounds.upperBound = (int)ZSTD_rmd_refMultipleDDicts; + return bounds; + case ZSTD_d_disableHuffmanAssembly: + bounds.lowerBound = 0; + bounds.upperBound = 1; + return bounds; + case ZSTD_d_maxBlockSize: + bounds.lowerBound = ZSTD_BLOCKSIZE_MAX_MIN; + bounds.upperBound = ZSTD_BLOCKSIZE_MAX; return bounds; + default:; } bounds.error = ERROR(parameter_unsupported); @@ -1506,6 +1874,35 @@ static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value) RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound, ""); \ } +size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value) +{ + switch (param) { + case ZSTD_d_windowLogMax: + *value = (int)ZSTD_highbit32((U32)dctx->maxWindowSize); + return 0; + case ZSTD_d_format: + *value = (int)dctx->format; + return 0; + case ZSTD_d_stableOutBuffer: + *value = (int)dctx->outBufferMode; + return 0; + case ZSTD_d_forceIgnoreChecksum: + *value = (int)dctx->forceIgnoreChecksum; + return 0; + case ZSTD_d_refMultipleDDicts: + *value = (int)dctx->refMultipleDDicts; + return 0; + case ZSTD_d_disableHuffmanAssembly: + *value = (int)dctx->disableHufAsm; + return 0; + case ZSTD_d_maxBlockSize: + *value = dctx->maxBlockSizeParam; + return 0; + default:; + } + RETURN_ERROR(parameter_unsupported, ""); +} + size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value) { RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); @@ -1521,7 +1918,26 @@ size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value return 0; case ZSTD_d_stableOutBuffer: CHECK_DBOUNDS(ZSTD_d_stableOutBuffer, value); - dctx->outBufferMode = (ZSTD_outBufferMode_e)value; + dctx->outBufferMode = (ZSTD_bufferMode_e)value; + return 0; + case ZSTD_d_forceIgnoreChecksum: + CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value); + dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value; + return 0; + case ZSTD_d_refMultipleDDicts: + CHECK_DBOUNDS(ZSTD_d_refMultipleDDicts, value); + if (dctx->staticSize != 0) { + RETURN_ERROR(parameter_unsupported, "Static dctx does not support multiple DDicts!"); + } + dctx->refMultipleDDicts = (ZSTD_refMultipleDDicts_e)value; + return 0; + case ZSTD_d_disableHuffmanAssembly: + CHECK_DBOUNDS(ZSTD_d_disableHuffmanAssembly, value); + dctx->disableHufAsm = value != 0; + return 0; + case ZSTD_d_maxBlockSize: + if (value != 0) CHECK_DBOUNDS(ZSTD_d_maxBlockSize, value); + dctx->maxBlockSizeParam = value; return 0; default:; } @@ -1534,13 +1950,13 @@ size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset) || (reset == ZSTD_reset_session_and_parameters) ) { dctx->streamStage = zdss_init; dctx->noForwardProgress = 0; + dctx->isFrameDecompression = 1; } if ( (reset == ZSTD_reset_parameters) || (reset == ZSTD_reset_session_and_parameters) ) { RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); ZSTD_clearDict(dctx); - dctx->format = ZSTD_f_zstd1; - dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; + ZSTD_DCtx_resetParameters(dctx); } return 0; } @@ -1551,10 +1967,17 @@ size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx) return ZSTD_sizeof_DCtx(dctx); } -size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize) +static size_t ZSTD_decodingBufferSize_internal(unsigned long long windowSize, unsigned long long frameContentSize, size_t blockSizeMax) { - size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX); - unsigned long long const neededRBSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2); + size_t const blockSize = MIN((size_t)MIN(windowSize, ZSTD_BLOCKSIZE_MAX), blockSizeMax); + /* We need blockSize + WILDCOPY_OVERLENGTH worth of buffer so that if a block + * ends at windowSize + WILDCOPY_OVERLENGTH + 1 bytes, we can start writing + * the block at the beginning of the output buffer, and maintain a full window. + * + * We need another blockSize worth of buffer so that we can store split + * literals at the end of the block without overwriting the extDict window. + */ + unsigned long long const neededRBSize = windowSize + (blockSize * 2) + (WILDCOPY_OVERLENGTH * 2); unsigned long long const neededSize = MIN(frameContentSize, neededRBSize); size_t const minRBSize = (size_t) neededSize; RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize, @@ -1562,6 +1985,11 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long return minRBSize; } +size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize) +{ + return ZSTD_decodingBufferSize_internal(windowSize, frameContentSize, ZSTD_BLOCKSIZE_MAX); +} + size_t ZSTD_estimateDStreamSize(size_t windowSize) { size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX); @@ -1608,7 +2036,7 @@ static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const* { ZSTD_outBuffer const expect = zds->expectedOutBuffer; /* No requirement when ZSTD_obm_stable is not enabled. */ - if (zds->outBufferMode != ZSTD_obm_stable) + if (zds->outBufferMode != ZSTD_bm_stable) return 0; /* Any buffer is allowed in zdss_init, this must be the same for every other call until * the context is reset. @@ -1618,7 +2046,7 @@ static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const* /* The buffer must match our expectation exactly. */ if (expect.dst == output->dst && expect.pos == output->pos && expect.size == output->size) return 0; - RETURN_ERROR(dstBuffer_wrong, "ZSTD_obm_stable enabled but output differs!"); + RETURN_ERROR(dstBuffer_wrong, "ZSTD_d_stableOutBuffer enabled but output differs!"); } /* Calls ZSTD_decompressContinue() with the right parameters for ZSTD_decompressStream() @@ -1630,7 +2058,7 @@ static size_t ZSTD_decompressContinueStream( ZSTD_DStream* zds, char** op, char* oend, void const* src, size_t srcSize) { int const isSkipFrame = ZSTD_isSkipFrame(zds); - if (zds->outBufferMode == ZSTD_obm_buffered) { + if (zds->outBufferMode == ZSTD_bm_buffered) { size_t const dstSize = isSkipFrame ? 0 : zds->outBuffSize - zds->outStart; size_t const decodedSize = ZSTD_decompressContinue(zds, zds->outBuff + zds->outStart, dstSize, src, srcSize); @@ -1643,14 +2071,14 @@ static size_t ZSTD_decompressContinueStream( } } else { /* Write directly into the output buffer */ - size_t const dstSize = isSkipFrame ? 0 : oend - *op; + size_t const dstSize = isSkipFrame ? 0 : (size_t)(oend - *op); size_t const decodedSize = ZSTD_decompressContinue(zds, *op, dstSize, src, srcSize); FORWARD_IF_ERROR(decodedSize, ""); *op += decodedSize; /* Flushing is not needed. */ zds->streamStage = zdss_read; assert(*op <= oend); - assert(zds->outBufferMode == ZSTD_obm_stable); + assert(zds->outBufferMode == ZSTD_bm_stable); } return 0; } @@ -1688,10 +2116,12 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB DEBUGLOG(5, "stage zdss_init => transparent reset "); zds->streamStage = zdss_loadHeader; zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) zds->legacyVersion = 0; +#endif zds->hostageByte = 0; zds->expectedOutBuffer = *output; - /* fall-through */ + ZSTD_FALLTHROUGH; case zdss_loadHeader : DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip)); @@ -1705,7 +2135,9 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB } } #endif { size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format); - DEBUGLOG(5, "header size : %u", (U32)hSize); + if (zds->refMultipleDDicts && zds->ddictSet) { + ZSTD_DCtx_selectFrameDDict(zds); + } if (ZSTD_isError(hSize)) { #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart); @@ -1733,14 +2165,19 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB assert(iend >= ip); if (toLoad > remainingInput) { /* not enough input to load full header */ if (remainingInput > 0) { - memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput); + ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput); zds->lhSize += remainingInput; } input->pos = input->size; - return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTDInternalConstants::ZSTD_blockHeaderSize; /* remaining header bytes + next block header */ + /* check first few bytes */ + FORWARD_IF_ERROR( + ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format), + "First few bytes detected incorrect" ); + /* return hint input size */ + return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */ } assert(ip != NULL); - memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad; + ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad; break; } } @@ -1748,14 +2185,15 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN && zds->fParams.frameType != ZSTD_skippableFrame && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) { - size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend-istart); + size_t const cSize = ZSTD_findFrameCompressedSize_advanced(istart, (size_t)(iend-istart), zds->format); if (cSize <= (size_t)(iend-istart)) { /* shortcut : using single-pass mode */ - size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, oend-op, istart, cSize, ZSTD_getDDict(zds)); + size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds)); if (ZSTD_isError(decompressedSize)) return decompressedSize; - DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()") + DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()"); + assert(istart != NULL); ip = istart + cSize; - op += decompressedSize; + op = op ? op + decompressedSize : op; /* can occur if frameContentSize = 0 (empty frame) */ zds->expected = 0; zds->streamStage = zdss_init; someMoreWork = 0; @@ -1763,7 +2201,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB } } /* Check output buffer is large enough for ZSTD_odm_stable. */ - if (zds->outBufferMode == ZSTD_obm_stable + if (zds->outBufferMode == ZSTD_bm_stable && zds->fParams.frameType != ZSTD_skippableFrame && zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN && (U64)(size_t)(oend-op) < zds->fParams.frameContentSize) { @@ -1774,12 +2212,13 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB DEBUGLOG(4, "Consume header"); FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), ""); - if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ + if (zds->format == ZSTD_f_zstd1 + && (MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE); zds->stage = ZSTDds_skipFrame; } else { FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize), ""); - zds->expected = ZSTDInternalConstants::ZSTD_blockHeaderSize; + zds->expected = ZSTD_blockHeaderSize; zds->stage = ZSTDds_decodeBlockHeader; } @@ -1790,11 +2229,13 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN); RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize, frameParameter_windowTooLarge, ""); + if (zds->maxBlockSizeParam != 0) + zds->fParams.blockSizeMax = MIN(zds->fParams.blockSizeMax, (unsigned)zds->maxBlockSizeParam); /* Adapt buffer sizes to frame header instructions */ { size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */); - size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_obm_buffered - ? ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize) + size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_bm_buffered + ? ZSTD_decodingBufferSize_internal(zds->fParams.windowSize, zds->fParams.frameContentSize, zds->fParams.blockSizeMax) : 0; ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize); @@ -1815,10 +2256,10 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB bufferSize > zds->staticSize - sizeof(ZSTD_DCtx), memory_allocation, ""); } else { - ZSTD_free(zds->inBuff, zds->customMem); + ZSTD_customFree(zds->inBuff, zds->customMem); zds->inBuffSize = 0; zds->outBuffSize = 0; - zds->inBuff = (char*)ZSTD_malloc(bufferSize, zds->customMem); + zds->inBuff = (char*)ZSTD_customMalloc(bufferSize, zds->customMem); RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation, ""); } zds->inBuffSize = neededInBuffSize; @@ -1826,11 +2267,11 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB zds->outBuffSize = neededOutBuffSize; } } } zds->streamStage = zdss_read; - /* fall-through */ + ZSTD_FALLTHROUGH; case zdss_read: DEBUGLOG(5, "stage zdss_read"); - { size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip); + { size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip)); DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize); if (neededInSize==0) { /* end of frame */ zds->streamStage = zdss_init; @@ -1839,13 +2280,14 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB } if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */ FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), ""); + assert(ip != NULL); ip += neededInSize; /* Function modifies the stage so we must break */ break; } } if (ip==iend) { someMoreWork = 0; break; } /* no more input */ zds->streamStage = zdss_load; - /* fall-through */ + ZSTD_FALLTHROUGH; case zdss_load: { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds); @@ -1853,17 +2295,20 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB int const isSkipFrame = ZSTD_isSkipFrame(zds); size_t loadedSize; /* At this point we shouldn't be decompressing a block that we can stream. */ - assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip)); + assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip))); if (isSkipFrame) { loadedSize = MIN(toLoad, (size_t)(iend-ip)); } else { RETURN_ERROR_IF(toLoad > zds->inBuffSize - zds->inPos, corruption_detected, "should never happen"); - loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend-ip); + loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, (size_t)(iend-ip)); + } + if (loadedSize != 0) { + /* ip may be NULL */ + ip += loadedSize; + zds->inPos += loadedSize; } - ip += loadedSize; - zds->inPos += loadedSize; if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */ /* decode loaded input */ @@ -1873,14 +2318,17 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB break; } case zdss_flush: - { size_t const toFlushSize = zds->outEnd - zds->outStart; - size_t const flushedSize = ZSTD_limitCopy(op, oend-op, zds->outBuff + zds->outStart, toFlushSize); - op += flushedSize; + { + size_t const toFlushSize = zds->outEnd - zds->outStart; + size_t const flushedSize = ZSTD_limitCopy(op, (size_t)(oend-op), zds->outBuff + zds->outStart, toFlushSize); + + op = op ? op + flushedSize : op; + zds->outStart += flushedSize; if (flushedSize == toFlushSize) { /* flush completed */ zds->streamStage = zdss_read; if ( (zds->outBuffSize < zds->fParams.frameContentSize) - && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) { + && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) { DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)", (int)(zds->outBuffSize - zds->outStart), (U32)zds->fParams.blockSizeMax); @@ -1894,7 +2342,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB default: assert(0); /* impossible */ - RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */ + RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */ } } /* result */ @@ -1907,8 +2355,8 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB if ((ip==istart) && (op==ostart)) { /* no forward progress */ zds->noForwardProgress ++; if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) { - RETURN_ERROR_IF(op==oend, dstSize_tooSmall, ""); - RETURN_ERROR_IF(ip==iend, srcSize_wrong, ""); + RETURN_ERROR_IF(op==oend, noForwardProgress_destFull, ""); + RETURN_ERROR_IF(ip==iend, noForwardProgress_inputEmpty, ""); assert(0); } } else { @@ -1933,7 +2381,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB } return 1; } /* nextSrcSizeHint==0 */ - nextSrcSizeHint += ZSTDInternalConstants::ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */ + nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */ assert(zds->inPos <= nextSrcSizeHint); nextSrcSizeHint -= zds->inPos; /* part already loaded*/ return nextSrcSizeHint; @@ -1945,13 +2393,19 @@ size_t ZSTD_decompressStream_simpleArgs ( void* dst, size_t dstCapacity, size_t* dstPos, const void* src, size_t srcSize, size_t* srcPos) { - ZSTD_outBuffer output = { dst, dstCapacity, *dstPos }; - ZSTD_inBuffer input = { src, srcSize, *srcPos }; - /* ZSTD_compress_generic() will check validity of dstPos and srcPos */ - size_t const cErr = ZSTD_decompressStream(dctx, &output, &input); - *dstPos = output.pos; - *srcPos = input.pos; - return cErr; + ZSTD_outBuffer output; + ZSTD_inBuffer input; + output.dst = dst; + output.size = dstCapacity; + output.pos = *dstPos; + input.src = src; + input.size = srcSize; + input.pos = *srcPos; + { size_t const cErr = ZSTD_decompressStream(dctx, &output, &input); + *dstPos = output.pos; + *srcPos = input.pos; + return cErr; + } } -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/decompress/zstd_decompress_block.cpp b/src/duckdb/third_party/zstd/decompress/zstd_decompress_block.cpp index e86f19ce8..75955fdef 100644 --- a/src/duckdb/third_party/zstd/decompress/zstd_decompress_block.cpp +++ b/src/duckdb/third_party/zstd/decompress/zstd_decompress_block.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,18 +14,19 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include /* memcpy, memmove, memset */ +#include "zstd/common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ #include "zstd/common/compiler.h" /* prefetch */ +#include "zstd/common/cpu.h" /* bmi2 */ #include "zstd/common/mem.h" /* low level memory routines */ +#define FSE_STATIC_LINKING_ONLY #include "zstd/common/fse.h" -#include "zstd/common/fse_static.h" #include "zstd/common/huf.h" -#include "zstd/common/huf_static.h" #include "zstd/common/zstd_internal.h" #include "zstd/decompress/zstd_decompress_internal.h" /* ZSTD_DCtx */ #include "zstd/decompress/zstd_ddict.h" /* ZSTD_DDictDictContent */ #include "zstd/decompress/zstd_decompress_block.h" -namespace duckdb_zstd { +#include "zstd/common/bits.h" /* ZSTD_highbit32 */ + /*_******************************************************* * Macros **********************************************************/ @@ -39,23 +40,31 @@ namespace duckdb_zstd { #error "Cannot force the use of the short and the long ZSTD_decompressSequences variants!" #endif +namespace duckdb_zstd { /*_******************************************************* * Memory operations **********************************************************/ -static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); } +static void ZSTD_copy4(void* dst, const void* src) { ZSTD_memcpy(dst, src, 4); } /*-************************************************************* * Block decoding ***************************************************************/ +static size_t ZSTD_blockSizeMax(ZSTD_DCtx const* dctx) +{ + size_t const blockSizeMax = dctx->isFrameDecompression ? dctx->fParams.blockSizeMax : ZSTD_BLOCKSIZE_MAX; + assert(blockSizeMax <= ZSTD_BLOCKSIZE_MAX); + return blockSizeMax; +} + /*! ZSTD_getcBlockSize() : * Provides the size of compressed block from block header `src` */ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr) { - RETURN_ERROR_IF(srcSize < ZSTDInternalConstants::ZSTD_blockHeaderSize, srcSize_wrong, ""); + RETURN_ERROR_IF(srcSize < ZSTD_blockHeaderSize, srcSize_wrong, ""); { U32 const cBlockHeader = MEM_readLE24(src); U32 const cSize = cBlockHeader >> 3; @@ -68,36 +77,90 @@ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, } } +/* Allocate buffer for literals, either overlapping current dst, or split between dst and litExtraBuffer, or stored entirely within litExtraBuffer */ +static void ZSTD_allocateLiteralsBuffer(ZSTD_DCtx* dctx, void* const dst, const size_t dstCapacity, const size_t litSize, + const streaming_operation streaming, const size_t expectedWriteSize, const unsigned splitImmediately) +{ + size_t const blockSizeMax = ZSTD_blockSizeMax(dctx); + assert(litSize <= blockSizeMax); + assert(dctx->isFrameDecompression || streaming == not_streaming); + assert(expectedWriteSize <= blockSizeMax); + if (streaming == not_streaming && dstCapacity > blockSizeMax + WILDCOPY_OVERLENGTH + litSize + WILDCOPY_OVERLENGTH) { + /* If we aren't streaming, we can just put the literals after the output + * of the current block. We don't need to worry about overwriting the + * extDict of our window, because it doesn't exist. + * So if we have space after the end of the block, just put it there. + */ + dctx->litBuffer = (BYTE*)dst + blockSizeMax + WILDCOPY_OVERLENGTH; + dctx->litBufferEnd = dctx->litBuffer + litSize; + dctx->litBufferLocation = ZSTD_in_dst; + } else if (litSize <= ZSTD_LITBUFFEREXTRASIZE) { + /* Literals fit entirely within the extra buffer, put them there to avoid + * having to split the literals. + */ + dctx->litBuffer = dctx->litExtraBuffer; + dctx->litBufferEnd = dctx->litBuffer + litSize; + dctx->litBufferLocation = ZSTD_not_in_dst; + } else { + assert(blockSizeMax > ZSTD_LITBUFFEREXTRASIZE); + /* Literals must be split between the output block and the extra lit + * buffer. We fill the extra lit buffer with the tail of the literals, + * and put the rest of the literals at the end of the block, with + * WILDCOPY_OVERLENGTH of buffer room to allow for overreads. + * This MUST not write more than our maxBlockSize beyond dst, because in + * streaming mode, that could overwrite part of our extDict window. + */ + if (splitImmediately) { + /* won't fit in litExtraBuffer, so it will be split between end of dst and extra buffer */ + dctx->litBuffer = (BYTE*)dst + expectedWriteSize - litSize + ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH; + dctx->litBufferEnd = dctx->litBuffer + litSize - ZSTD_LITBUFFEREXTRASIZE; + } else { + /* initially this will be stored entirely in dst during huffman decoding, it will partially be shifted to litExtraBuffer after */ + dctx->litBuffer = (BYTE*)dst + expectedWriteSize - litSize; + dctx->litBufferEnd = (BYTE*)dst + expectedWriteSize; + } + dctx->litBufferLocation = ZSTD_split; + assert(dctx->litBufferEnd <= (BYTE*)dst + expectedWriteSize); + } +} -/* Hidden declaration for fullbench */ -size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, - const void* src, size_t srcSize); /*! ZSTD_decodeLiteralsBlock() : + * Where it is possible to do so without being stomped by the output during decompression, the literals block will be stored + * in the dstBuffer. If there is room to do so, it will be stored in full in the excess dst space after where the current + * block will be output. Otherwise it will be stored at the end of the current dst blockspace, with a small portion being + * stored in dctx->litExtraBuffer to help keep it "ahead" of the current output write. + * * @return : nb of bytes read from src (< srcSize ) * note : symbol not declared but exposed for fullbench */ -size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, - const void* src, size_t srcSize) /* note : srcSize < BLOCKSIZE */ +static size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, + const void* src, size_t srcSize, /* note : srcSize < BLOCKSIZE */ + void* dst, size_t dstCapacity, const streaming_operation streaming) { DEBUGLOG(5, "ZSTD_decodeLiteralsBlock"); RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected, ""); { const BYTE* const istart = (const BYTE*) src; symbolEncodingType_e const litEncType = (symbolEncodingType_e)(istart[0] & 3); + size_t const blockSizeMax = ZSTD_blockSizeMax(dctx); switch(litEncType) { case set_repeat: DEBUGLOG(5, "set_repeat flag : re-using stats from previous compressed literals block"); RETURN_ERROR_IF(dctx->litEntropy==0, dictionary_corrupted, ""); - /* fall-through */ + ZSTD_FALLTHROUGH; case set_compressed: - RETURN_ERROR_IF(srcSize < 5, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3"); + RETURN_ERROR_IF(srcSize < 5, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need up to 5 for case 3"); { size_t lhSize, litSize, litCSize; U32 singleStream=0; U32 const lhlCode = (istart[0] >> 2) & 3; U32 const lhc = MEM_readLE32(istart); size_t hufSuccess; + size_t expectedWriteSize = MIN(blockSizeMax, dstCapacity); + int const flags = 0 + | (ZSTD_DCtx_get_bmi2(dctx) ? HUF_flags_bmi2 : 0) + | (dctx->disableHufAsm ? HUF_flags_disableAsm : 0); switch(lhlCode) { case 0: case 1: default: /* note : default is impossible, since lhlCode into [0..3] */ @@ -120,8 +183,15 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, litCSize = (lhc >> 22) + ((size_t)istart[4] << 10); break; } - RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, ""); + RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(litSize > blockSizeMax, corruption_detected, ""); + if (!singleStream) + RETURN_ERROR_IF(litSize < MIN_LITERALS_FOR_4_STREAMS, literals_headerWrong, + "Not enough literals (%zu) for the 4-streams mode (min %u)", + litSize, MIN_LITERALS_FOR_4_STREAMS); RETURN_ERROR_IF(litCSize + lhSize > srcSize, corruption_detected, ""); + RETURN_ERROR_IF(expectedWriteSize < litSize , dstSize_tooSmall, ""); + ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 0); /* prefetch huffman table if cold */ if (dctx->ddictIsCold && (litSize > 768 /* heuristic */)) { @@ -130,13 +200,14 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, if (litEncType==set_repeat) { if (singleStream) { - hufSuccess = HUF_decompress1X_usingDTable_bmi2( + hufSuccess = HUF_decompress1X_usingDTable( dctx->litBuffer, litSize, istart+lhSize, litCSize, - dctx->HUFptr, dctx->bmi2); + dctx->HUFptr, flags); } else { - hufSuccess = HUF_decompress4X_usingDTable_bmi2( + assert(litSize >= MIN_LITERALS_FOR_4_STREAMS); + hufSuccess = HUF_decompress4X_usingDTable( dctx->litBuffer, litSize, istart+lhSize, litCSize, - dctx->HUFptr, dctx->bmi2); + dctx->HUFptr, flags); } } else { if (singleStream) { @@ -144,20 +215,29 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, hufSuccess = HUF_decompress1X_DCtx_wksp( dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->workspace, - sizeof(dctx->workspace)); + sizeof(dctx->workspace), flags); #else - hufSuccess = HUF_decompress1X1_DCtx_wksp_bmi2( + hufSuccess = HUF_decompress1X1_DCtx_wksp( dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->workspace, - sizeof(dctx->workspace), dctx->bmi2); + sizeof(dctx->workspace), flags); #endif } else { - hufSuccess = HUF_decompress4X_hufOnly_wksp_bmi2( + hufSuccess = HUF_decompress4X_hufOnly_wksp( dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->workspace, - sizeof(dctx->workspace), dctx->bmi2); + sizeof(dctx->workspace), flags); } } + if (dctx->litBufferLocation == ZSTD_split) + { + assert(litSize > ZSTD_LITBUFFEREXTRASIZE); + ZSTD_memcpy(dctx->litExtraBuffer, dctx->litBufferEnd - ZSTD_LITBUFFEREXTRASIZE, ZSTD_LITBUFFEREXTRASIZE); + ZSTD_memmove(dctx->litBuffer + ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH, dctx->litBuffer, litSize - ZSTD_LITBUFFEREXTRASIZE); + dctx->litBuffer += ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH; + dctx->litBufferEnd -= WILDCOPY_OVERLENGTH; + assert(dctx->litBufferEnd <= (BYTE*)dst + blockSizeMax); + } RETURN_ERROR_IF(HUF_isError(hufSuccess), corruption_detected, ""); @@ -165,13 +245,13 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, dctx->litSize = litSize; dctx->litEntropy = 1; if (litEncType==set_compressed) dctx->HUFptr = dctx->entropy.hufTable; - memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH); return litCSize + lhSize; } case set_basic: { size_t litSize, lhSize; U32 const lhlCode = ((istart[0]) >> 2) & 3; + size_t expectedWriteSize = MIN(blockSizeMax, dstCapacity); switch(lhlCode) { case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */ @@ -184,27 +264,42 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, break; case 3: lhSize = 3; + RETURN_ERROR_IF(srcSize<3, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need lhSize = 3"); litSize = MEM_readLE24(istart) >> 4; break; } + RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(litSize > blockSizeMax, corruption_detected, ""); + RETURN_ERROR_IF(expectedWriteSize < litSize, dstSize_tooSmall, ""); + ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 1); if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */ RETURN_ERROR_IF(litSize+lhSize > srcSize, corruption_detected, ""); - memcpy(dctx->litBuffer, istart+lhSize, litSize); + if (dctx->litBufferLocation == ZSTD_split) + { + ZSTD_memcpy(dctx->litBuffer, istart + lhSize, litSize - ZSTD_LITBUFFEREXTRASIZE); + ZSTD_memcpy(dctx->litExtraBuffer, istart + lhSize + litSize - ZSTD_LITBUFFEREXTRASIZE, ZSTD_LITBUFFEREXTRASIZE); + } + else + { + ZSTD_memcpy(dctx->litBuffer, istart + lhSize, litSize); + } dctx->litPtr = dctx->litBuffer; dctx->litSize = litSize; - memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH); return lhSize+litSize; } /* direct reference into compressed stream */ dctx->litPtr = istart+lhSize; dctx->litSize = litSize; + dctx->litBufferEnd = dctx->litPtr + litSize; + dctx->litBufferLocation = ZSTD_not_in_dst; return lhSize+litSize; } case set_rle: { U32 const lhlCode = ((istart[0]) >> 2) & 3; size_t litSize, lhSize; + size_t expectedWriteSize = MIN(blockSizeMax, dstCapacity); switch(lhlCode) { case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */ @@ -213,16 +308,28 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, break; case 1: lhSize = 2; + RETURN_ERROR_IF(srcSize<3, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need lhSize+1 = 3"); litSize = MEM_readLE16(istart) >> 4; break; case 3: lhSize = 3; + RETURN_ERROR_IF(srcSize<4, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need lhSize+1 = 4"); litSize = MEM_readLE24(istart) >> 4; - RETURN_ERROR_IF(srcSize<4, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4"); break; } - RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, ""); - memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH); + RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(litSize > blockSizeMax, corruption_detected, ""); + RETURN_ERROR_IF(expectedWriteSize < litSize, dstSize_tooSmall, ""); + ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 1); + if (dctx->litBufferLocation == ZSTD_split) + { + ZSTD_memset(dctx->litBuffer, istart[lhSize], litSize - ZSTD_LITBUFFEREXTRASIZE); + ZSTD_memset(dctx->litExtraBuffer, istart[lhSize], ZSTD_LITBUFFEREXTRASIZE); + } + else + { + ZSTD_memset(dctx->litBuffer, istart[lhSize], litSize); + } dctx->litPtr = dctx->litBuffer; dctx->litSize = litSize; return lhSize+1; @@ -233,9 +340,21 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, } } +/* Hidden declaration for fullbench */ +size_t ZSTD_decodeLiteralsBlock_wrapper(ZSTD_DCtx* dctx, + const void* src, size_t srcSize, + void* dst, size_t dstCapacity); +size_t ZSTD_decodeLiteralsBlock_wrapper(ZSTD_DCtx* dctx, + const void* src, size_t srcSize, + void* dst, size_t dstCapacity) +{ + dctx->isFrameDecompression = 0; + return ZSTD_decodeLiteralsBlock(dctx, src, srcSize, dst, dstCapacity, not_streaming); +} + /* Default FSE distribution tables. * These are pre-calculated FSE decoding tables using default distributions as defined in specification : - * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#default-distributions + * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#default-distributions * They were generated programmatically with following method : * - start from default distributions, present in /lib/common/zstd_internal.h * - generate tables normally, using ZSTD_buildFSETable() @@ -342,7 +461,7 @@ static const ZSTD_seqSymbol ML_defaultDTable[(1<nbBits = 0; cell->nextState = 0; assert(nbAddBits < 255); - cell->nbAdditionalBits = (BYTE)nbAddBits; + cell->nbAdditionalBits = nbAddBits; cell->baseValue = baseValue; } @@ -363,23 +482,26 @@ static void ZSTD_buildSeqTable_rle(ZSTD_seqSymbol* dt, U32 baseValue, U32 nbAddB * generate FSE decoding table for one symbol (ll, ml or off) * cannot fail if input is valid => * all inputs are presumed validated at this stage */ -void -ZSTD_buildFSETable(ZSTD_seqSymbol* dt, +FORCE_INLINE_TEMPLATE +void ZSTD_buildFSETable_body(ZSTD_seqSymbol* dt, const short* normalizedCounter, unsigned maxSymbolValue, - const U32* baseValue, const U32* nbAdditionalBits, - unsigned tableLog) + const U32* baseValue, const U8* nbAdditionalBits, + unsigned tableLog, void* wksp, size_t wkspSize) { ZSTD_seqSymbol* const tableDecode = dt+1; - U16 symbolNext[MaxSeq+1]; - U32 const maxSV1 = maxSymbolValue + 1; U32 const tableSize = 1 << tableLog; - U32 highThreshold = tableSize-1; + + U16* symbolNext = (U16*)wksp; + BYTE* spread = (BYTE*)(symbolNext + MaxSeq + 1); + U32 highThreshold = tableSize - 1; + /* Sanity Checks */ assert(maxSymbolValue <= MaxSeq); assert(tableLog <= MaxFSELog); - + assert(wkspSize >= ZSTD_BUILD_FSE_TABLE_WKSP_SIZE); + (void)wkspSize; /* Init, lay down lowprob symbols */ { ZSTD_seqSymbol_header DTableH; DTableH.tableLog = tableLog; @@ -395,34 +517,128 @@ ZSTD_buildFSETable(ZSTD_seqSymbol* dt, assert(normalizedCounter[s]>=0); symbolNext[s] = (U16)normalizedCounter[s]; } } } - memcpy(dt, &DTableH, sizeof(DTableH)); + ZSTD_memcpy(dt, &DTableH, sizeof(DTableH)); } /* Spread symbols */ - { U32 const tableMask = tableSize-1; + assert(tableSize <= 512); + /* Specialized symbol spreading for the case when there are + * no low probability (-1 count) symbols. When compressing + * small blocks we avoid low probability symbols to hit this + * case, since header decoding speed matters more. + */ + if (highThreshold == tableSize - 1) { + size_t const tableMask = tableSize-1; + size_t const step = FSE_TABLESTEP(tableSize); + /* First lay down the symbols in order. + * We use a uint64_t to lay down 8 bytes at a time. This reduces branch + * misses since small blocks generally have small table logs, so nearly + * all symbols have counts <= 8. We ensure we have 8 bytes at the end of + * our buffer to handle the over-write. + */ + { + U64 const add = 0x0101010101010101ull; + size_t pos = 0; + U64 sv = 0; + U32 s; + for (s=0; s=0); + pos += (size_t)n; + } + } + /* Now we spread those positions across the table. + * The benefit of doing it in two stages is that we avoid the + * variable size inner loop, which caused lots of branch misses. + * Now we can run through all the positions without any branch misses. + * We unroll the loop twice, since that is what empirically worked best. + */ + { + size_t position = 0; + size_t s; + size_t const unroll = 2; + assert(tableSize % unroll == 0); /* FSE_MIN_TABLELOG is 5 */ + for (s = 0; s < (size_t)tableSize; s += unroll) { + size_t u; + for (u = 0; u < unroll; ++u) { + size_t const uPosition = (position + (u * step)) & tableMask; + tableDecode[uPosition].baseValue = spread[s + u]; + } + position = (position + (unroll * step)) & tableMask; + } + assert(position == 0); + } + } else { + U32 const tableMask = tableSize-1; U32 const step = FSE_TABLESTEP(tableSize); U32 s, position = 0; for (s=0; s highThreshold) position = (position + step) & tableMask; /* lowprob area */ + while (UNLIKELY(position > highThreshold)) position = (position + step) & tableMask; /* lowprob area */ } } assert(position == 0); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ } /* Build Decoding table */ - { U32 u; + { + U32 u; for (u=0; u max, corruption_detected, ""); { U32 const symbol = *(const BYTE*)src; U32 const baseline = baseValue[symbol]; - U32 const nbBits = nbAdditionalBits[symbol]; + U8 const nbBits = nbAdditionalBits[symbol]; ZSTD_buildSeqTable_rle(DTableSpace, baseline, nbBits); } *DTablePtr = DTableSpace; @@ -466,7 +683,7 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize); RETURN_ERROR_IF(FSE_isError(headerSize), corruption_detected, ""); RETURN_ERROR_IF(tableLog > maxLog, corruption_detected, ""); - ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog); + ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog, wksp, wkspSize, bmi2); *DTablePtr = DTableSpace; return headerSize; } @@ -479,7 +696,7 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, const void* src, size_t srcSize) { - const BYTE* const istart = (const BYTE* const)src; + const BYTE* const istart = (const BYTE*)src; const BYTE* const iend = istart + srcSize; const BYTE* ip = istart; int nbSeq; @@ -490,15 +707,11 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, /* SeqHead */ nbSeq = *ip++; - if (!nbSeq) { - *nbSeqPtr=0; - RETURN_ERROR_IF(srcSize != 1, srcSize_wrong, ""); - return 1; - } if (nbSeq > 0x7F) { if (nbSeq == 0xFF) { RETURN_ERROR_IF(ip+2 > iend, srcSize_wrong, ""); - nbSeq = MEM_readLE16(ip) + LONGNBSEQ, ip+=2; + nbSeq = MEM_readLE16(ip) + LONGNBSEQ; + ip+=2; } else { RETURN_ERROR_IF(ip >= iend, srcSize_wrong, ""); nbSeq = ((nbSeq-0x80)<<8) + *ip++; @@ -506,8 +719,16 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, } *nbSeqPtr = nbSeq; + if (nbSeq == 0) { + /* No sequence : section ends immediately */ + RETURN_ERROR_IF(ip != iend, corruption_detected, + "extraneous data present in the Sequences section"); + return (size_t)(ip - istart); + } + /* FSE table descriptors */ RETURN_ERROR_IF(ip+1 > iend, srcSize_wrong, ""); /* minimum possible size: 1 byte for symbol encoding types */ + RETURN_ERROR_IF(*ip & 3, corruption_detected, ""); /* The last field, Reserved, must be all-zeroes. */ { symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6); symbolEncodingType_e const OFtype = (symbolEncodingType_e)((*ip >> 4) & 3); symbolEncodingType_e const MLtype = (symbolEncodingType_e)((*ip >> 2) & 3); @@ -517,9 +738,11 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, { size_t const llhSize = ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr, LLtype, MaxLL, LLFSELog, ip, iend-ip, - ZSTDConstants::LL_base, ZSTDInternalConstants::LL_bits, + LL_base, LL_bits, LL_defaultDTable, dctx->fseEntropy, - dctx->ddictIsCold, nbSeq); + dctx->ddictIsCold, nbSeq, + dctx->workspace, sizeof(dctx->workspace), + ZSTD_DCtx_get_bmi2(dctx)); RETURN_ERROR_IF(ZSTD_isError(llhSize), corruption_detected, "ZSTD_buildSeqTable failed"); ip += llhSize; } @@ -527,9 +750,11 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, { size_t const ofhSize = ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr, OFtype, MaxOff, OffFSELog, ip, iend-ip, - ZSTDConstants::OF_base, ZSTDConstants::OF_bits, + OF_base, OF_bits, OF_defaultDTable, dctx->fseEntropy, - dctx->ddictIsCold, nbSeq); + dctx->ddictIsCold, nbSeq, + dctx->workspace, sizeof(dctx->workspace), + ZSTD_DCtx_get_bmi2(dctx)); RETURN_ERROR_IF(ZSTD_isError(ofhSize), corruption_detected, "ZSTD_buildSeqTable failed"); ip += ofhSize; } @@ -537,9 +762,11 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, { size_t const mlhSize = ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr, MLtype, MaxML, MLFSELog, ip, iend-ip, - ZSTDConstants::ML_base, ZSTDInternalConstants::ML_bits, + ML_base, ML_bits, ML_defaultDTable, dctx->fseEntropy, - dctx->ddictIsCold, nbSeq); + dctx->ddictIsCold, nbSeq, + dctx->workspace, sizeof(dctx->workspace), + ZSTD_DCtx_get_bmi2(dctx)); RETURN_ERROR_IF(ZSTD_isError(mlhSize), corruption_detected, "ZSTD_buildSeqTable failed"); ip += mlhSize; } @@ -553,7 +780,6 @@ typedef struct { size_t litLength; size_t matchLength; size_t offset; - const BYTE* match; } seq_t; typedef struct { @@ -567,9 +793,6 @@ typedef struct { ZSTD_fseState stateOffb; ZSTD_fseState stateML; size_t prevOffset[ZSTD_REP_NUM]; - const BYTE* prefixStart; - const BYTE* dictEnd; - size_t pos; } seqState_t; /*! ZSTD_overlapCopy8() : @@ -612,7 +835,7 @@ HINT_INLINE void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) { * - ZSTD_overlap_src_before_dst: The src and dst may overlap and may be any distance apart. * The src buffer must be before the dst buffer. */ -static void ZSTD_safecopy(BYTE* op, BYTE* const oend_w, BYTE const* ip, ptrdiff_t length, ZSTD_overlap_e ovtype) { +static void ZSTD_safecopy(BYTE* op, const BYTE* const oend_w, BYTE const* ip, ptrdiff_t length, ZSTD_overlap_e ovtype) { ptrdiff_t const diff = op - ip; BYTE* const oend = op + length; @@ -628,6 +851,7 @@ static void ZSTD_safecopy(BYTE* op, BYTE* const oend_w, BYTE const* ip, ptrdiff_ /* Copy 8 bytes and ensure the offset >= 8 when there can be overlap. */ assert(length >= 8); ZSTD_overlapCopy8(&op, &ip, diff); + length -= 8; assert(op - ip >= 8); assert(op <= oend); } @@ -642,12 +866,35 @@ static void ZSTD_safecopy(BYTE* op, BYTE* const oend_w, BYTE const* ip, ptrdiff_ assert(oend > oend_w); ZSTD_wildcopy(op, ip, oend_w - op, ovtype); ip += oend_w - op; - op = oend_w; + op += oend_w - op; } /* Handle the leftovers. */ while (op < oend) *op++ = *ip++; } +/* ZSTD_safecopyDstBeforeSrc(): + * This version allows overlap with dst before src, or handles the non-overlap case with dst after src + * Kept separate from more common ZSTD_safecopy case to avoid performance impact to the safecopy common case */ +static void ZSTD_safecopyDstBeforeSrc(BYTE* op, const BYTE* ip, ptrdiff_t length) { + ptrdiff_t const diff = op - ip; + BYTE* const oend = op + length; + + if (length < 8 || diff > -8) { + /* Handle short lengths, close overlaps, and dst not before src. */ + while (op < oend) *op++ = *ip++; + return; + } + + if (op <= oend - WILDCOPY_OVERLENGTH && diff < -WILDCOPY_VECLEN) { + ZSTD_wildcopy(op, ip, oend - WILDCOPY_OVERLENGTH - op, ZSTD_no_overlap); + ip += oend - WILDCOPY_OVERLENGTH - op; + op += oend - WILDCOPY_OVERLENGTH - op; + } + + /* Handle the leftovers. */ + while (op < oend) *op++ = *ip++; +} + /* ZSTD_execSequenceEnd(): * This version handles cases that are near the end of the output buffer. It requires * more careful checks to make sure there is no overflow. By separating out these hard @@ -657,10 +904,11 @@ static void ZSTD_safecopy(BYTE* op, BYTE* const oend_w, BYTE const* ip, ptrdiff_ * to be optimized for many small sequences, since those fall into ZSTD_execSequence(). */ FORCE_NOINLINE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR size_t ZSTD_execSequenceEnd(BYTE* op, - BYTE* const oend, seq_t sequence, - const BYTE** litPtr, const BYTE* const litLimit, - const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) + BYTE* const oend, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) { BYTE* const oLitEnd = op + sequence.litLength; size_t const sequenceLength = sequence.litLength + sequence.matchLength; @@ -683,27 +931,78 @@ size_t ZSTD_execSequenceEnd(BYTE* op, if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { /* offset beyond prefix */ RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, ""); - match = dictEnd - (prefixStart-match); + match = dictEnd - (prefixStart - match); if (match + sequence.matchLength <= dictEnd) { - memmove(oLitEnd, match, sequence.matchLength); + ZSTD_memmove(oLitEnd, match, sequence.matchLength); return sequenceLength; } /* span extDict & currentPrefixSegment */ { size_t const length1 = dictEnd - match; - memmove(oLitEnd, match, length1); - op = oLitEnd + length1; - sequence.matchLength -= length1; - match = prefixStart; - } } + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } + } + ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst); + return sequenceLength; +} + +/* ZSTD_execSequenceEndSplitLitBuffer(): + * This version is intended to be used during instances where the litBuffer is still split. It is kept separate to avoid performance impact for the good case. + */ +FORCE_NOINLINE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +size_t ZSTD_execSequenceEndSplitLitBuffer(BYTE* op, + BYTE* const oend, const BYTE* const oend_w, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) +{ + BYTE* const oLitEnd = op + sequence.litLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; + const BYTE* const iLitEnd = *litPtr + sequence.litLength; + const BYTE* match = oLitEnd - sequence.offset; + + + /* bounds checks : careful of address space overflow in 32-bit mode */ + RETURN_ERROR_IF(sequenceLength > (size_t)(oend - op), dstSize_tooSmall, "last match must fit within dstBuffer"); + RETURN_ERROR_IF(sequence.litLength > (size_t)(litLimit - *litPtr), corruption_detected, "try to read beyond literal buffer"); + assert(op < op + sequenceLength); + assert(oLitEnd < op + sequenceLength); + + /* copy literals */ + RETURN_ERROR_IF(op > *litPtr && op < *litPtr + sequence.litLength, dstSize_tooSmall, "output should not catch up to and overwrite literal buffer"); + ZSTD_safecopyDstBeforeSrc(op, *litPtr, sequence.litLength); + op = oLitEnd; + *litPtr = iLitEnd; + + /* copy Match */ + if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { + /* offset beyond prefix */ + RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, ""); + match = dictEnd - (prefixStart - match); + if (match + sequence.matchLength <= dictEnd) { + ZSTD_memmove(oLitEnd, match, sequence.matchLength); + return sequenceLength; + } + /* span extDict & currentPrefixSegment */ + { size_t const length1 = dictEnd - match; + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } + } ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst); return sequenceLength; } HINT_INLINE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR size_t ZSTD_execSequence(BYTE* op, - BYTE* const oend, seq_t sequence, - const BYTE** litPtr, const BYTE* const litLimit, - const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) + BYTE* const oend, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) { BYTE* const oLitEnd = op + sequence.litLength; size_t const sequenceLength = sequence.litLength + sequence.matchLength; @@ -714,6 +1013,104 @@ size_t ZSTD_execSequence(BYTE* op, assert(op != NULL /* Precondition */); assert(oend_w < oend /* No underflow */); + +#if defined(__aarch64__) + /* prefetch sequence starting from match that will be used for copy later */ + PREFETCH_L1(match); +#endif + /* Handle edge cases in a slow path: + * - Read beyond end of literals + * - Match end is within WILDCOPY_OVERLIMIT of oend + * - 32-bit mode and the match length overflows + */ + if (UNLIKELY( + iLitEnd > litLimit || + oMatchEnd > oend_w || + (MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH))) + return ZSTD_execSequenceEnd(op, oend, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); + + /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */ + assert(op <= oLitEnd /* No overflow */); + assert(oLitEnd < oMatchEnd /* Non-zero match & no overflow */); + assert(oMatchEnd <= oend /* No underflow */); + assert(iLitEnd <= litLimit /* Literal length is in bounds */); + assert(oLitEnd <= oend_w /* Can wildcopy literals */); + assert(oMatchEnd <= oend_w /* Can wildcopy matches */); + + /* Copy Literals: + * Split out litLength <= 16 since it is nearly always true. +1.6% on gcc-9. + * We likely don't need the full 32-byte wildcopy. + */ + assert(WILDCOPY_OVERLENGTH >= 16); + ZSTD_copy16(op, (*litPtr)); + if (UNLIKELY(sequence.litLength > 16)) { + ZSTD_wildcopy(op + 16, (*litPtr) + 16, sequence.litLength - 16, ZSTD_no_overlap); + } + op = oLitEnd; + *litPtr = iLitEnd; /* update for next sequence */ + + /* Copy Match */ + if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { + /* offset beyond prefix -> go into extDict */ + RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, ""); + match = dictEnd + (match - prefixStart); + if (match + sequence.matchLength <= dictEnd) { + ZSTD_memmove(oLitEnd, match, sequence.matchLength); + return sequenceLength; + } + /* span extDict & currentPrefixSegment */ + { size_t const length1 = dictEnd - match; + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } + } + /* Match within prefix of 1 or more bytes */ + assert(op <= oMatchEnd); + assert(oMatchEnd <= oend_w); + assert(match >= prefixStart); + assert(sequence.matchLength >= 1); + + /* Nearly all offsets are >= WILDCOPY_VECLEN bytes, which means we can use wildcopy + * without overlap checking. + */ + if (LIKELY(sequence.offset >= WILDCOPY_VECLEN)) { + /* We bet on a full wildcopy for matches, since we expect matches to be + * longer than literals (in general). In silesia, ~10% of matches are longer + * than 16 bytes. + */ + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength, ZSTD_no_overlap); + return sequenceLength; + } + assert(sequence.offset < WILDCOPY_VECLEN); + + /* Copy 8 bytes and spread the offset to be >= 8. */ + ZSTD_overlapCopy8(&op, &match, sequence.offset); + + /* If the match length is > 8 bytes, then continue with the wildcopy. */ + if (sequence.matchLength > 8) { + assert(op < oMatchEnd); + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength - 8, ZSTD_overlap_src_before_dst); + } + return sequenceLength; +} + +HINT_INLINE +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, + BYTE* const oend, const BYTE* const oend_w, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) +{ + BYTE* const oLitEnd = op + sequence.litLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; + BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ + const BYTE* const iLitEnd = *litPtr + sequence.litLength; + const BYTE* match = oLitEnd - sequence.offset; + + assert(op != NULL /* Precondition */); + assert(oend_w < oend /* No underflow */); /* Handle edge cases in a slow path: * - Read beyond end of literals * - Match end is within WILDCOPY_OVERLIMIT of oend @@ -723,7 +1120,7 @@ size_t ZSTD_execSequence(BYTE* op, iLitEnd > litLimit || oMatchEnd > oend_w || (MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH))) - return ZSTD_execSequenceEnd(op, oend, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); + return ZSTD_execSequenceEndSplitLitBuffer(op, oend, oend_w, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */ assert(op <= oLitEnd /* No overflow */); @@ -751,12 +1148,12 @@ size_t ZSTD_execSequence(BYTE* op, RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, ""); match = dictEnd + (match - prefixStart); if (match + sequence.matchLength <= dictEnd) { - memmove(oLitEnd, match, sequence.matchLength); + ZSTD_memmove(oLitEnd, match, sequence.matchLength); return sequenceLength; } /* span extDict & currentPrefixSegment */ { size_t const length1 = dictEnd - match; - memmove(oLitEnd, match, length1); + ZSTD_memmove(oLitEnd, match, length1); op = oLitEnd + length1; sequence.matchLength -= length1; match = prefixStart; @@ -791,6 +1188,7 @@ size_t ZSTD_execSequence(BYTE* op, return sequenceLength; } + static void ZSTD_initFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, const ZSTD_seqSymbol* dt) { @@ -804,24 +1202,14 @@ ZSTD_initFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, const ZSTD_seqS } FORCE_INLINE_TEMPLATE void -ZSTD_updateFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD) +ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, U16 nextState, U32 nbBits) { - ZSTD_seqSymbol const DInfo = DStatePtr->table[DStatePtr->state]; - U32 const nbBits = DInfo.nbBits; size_t const lowBits = BIT_readBits(bitD, nbBits); - DStatePtr->state = DInfo.nextState + lowBits; -} - -FORCE_INLINE_TEMPLATE void -ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, ZSTD_seqSymbol const DInfo) -{ - U32 const nbBits = DInfo.nbBits; - size_t const lowBits = BIT_readBits(bitD, nbBits); - DStatePtr->state = DInfo.nextState + lowBits; + DStatePtr->state = nextState + lowBits; } /* We need to add at most (ZSTD_WINDOWLOG_MAX_32 - 1) bits to read the maximum - * offset bits. But we can only read at most (STREAM_ACCUMULATOR_MIN_32 - 1) + * offset bits. But we can only read at most STREAM_ACCUMULATOR_MIN_32 * bits before reloading. This value is the maximum number of bytes we read * after reloading when we are decoding long offsets. */ @@ -831,122 +1219,135 @@ ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, ZSTD : 0) typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e; -typedef enum { ZSTD_p_noPrefetch=0, ZSTD_p_prefetch=1 } ZSTD_prefetch_e; +/** + * ZSTD_decodeSequence(): + * @p longOffsets : tells the decoder to reload more bit while decoding large offsets + * only used in 32-bit mode + * @return : Sequence (litL + matchL + offset) + */ FORCE_INLINE_TEMPLATE seq_t -ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, const ZSTD_prefetch_e prefetch) +ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, const int isLastSeq) { seq_t seq; - ZSTD_seqSymbol const llDInfo = seqState->stateLL.table[seqState->stateLL.state]; - ZSTD_seqSymbol const mlDInfo = seqState->stateML.table[seqState->stateML.state]; - ZSTD_seqSymbol const ofDInfo = seqState->stateOffb.table[seqState->stateOffb.state]; - U32 const llBase = llDInfo.baseValue; - U32 const mlBase = mlDInfo.baseValue; - U32 const ofBase = ofDInfo.baseValue; - BYTE const llBits = llDInfo.nbAdditionalBits; - BYTE const mlBits = mlDInfo.nbAdditionalBits; - BYTE const ofBits = ofDInfo.nbAdditionalBits; - BYTE const totalBits = llBits+mlBits+ofBits; - - /* sequence */ - { size_t offset; - if (ofBits > 1) { - ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); - ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); - assert(ofBits <= MaxOff); - if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) { - U32 const extraBits = ofBits - MIN(ofBits, 32 - seqState->DStream.bitsConsumed); - offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); - BIT_reloadDStream(&seqState->DStream); - if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits); - assert(extraBits <= LONG_OFFSETS_MAX_EXTRA_BITS_32); /* to avoid another reload */ - } else { - offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ - if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); - } - seqState->prevOffset[2] = seqState->prevOffset[1]; - seqState->prevOffset[1] = seqState->prevOffset[0]; - seqState->prevOffset[0] = offset; - } else { - U32 const ll0 = (llBase == 0); - if (LIKELY((ofBits == 0))) { - if (LIKELY(!ll0)) - offset = seqState->prevOffset[0]; - else { - offset = seqState->prevOffset[1]; - seqState->prevOffset[1] = seqState->prevOffset[0]; - seqState->prevOffset[0] = offset; + /* + * ZSTD_seqSymbol is a 64 bits wide structure. + * It can be loaded in one operation + * and its fields extracted by simply shifting or bit-extracting on aarch64. + * GCC doesn't recognize this and generates more unnecessary ldr/ldrb/ldrh + * operations that cause performance drop. This can be avoided by using this + * ZSTD_memcpy hack. + */ +#if defined(__aarch64__) && (defined(__GNUC__) && !defined(__clang__)) + ZSTD_seqSymbol llDInfoS, mlDInfoS, ofDInfoS; + ZSTD_seqSymbol* const llDInfo = &llDInfoS; + ZSTD_seqSymbol* const mlDInfo = &mlDInfoS; + ZSTD_seqSymbol* const ofDInfo = &ofDInfoS; + ZSTD_memcpy(llDInfo, seqState->stateLL.table + seqState->stateLL.state, sizeof(ZSTD_seqSymbol)); + ZSTD_memcpy(mlDInfo, seqState->stateML.table + seqState->stateML.state, sizeof(ZSTD_seqSymbol)); + ZSTD_memcpy(ofDInfo, seqState->stateOffb.table + seqState->stateOffb.state, sizeof(ZSTD_seqSymbol)); +#else + const ZSTD_seqSymbol* const llDInfo = seqState->stateLL.table + seqState->stateLL.state; + const ZSTD_seqSymbol* const mlDInfo = seqState->stateML.table + seqState->stateML.state; + const ZSTD_seqSymbol* const ofDInfo = seqState->stateOffb.table + seqState->stateOffb.state; +#endif + seq.matchLength = mlDInfo->baseValue; + seq.litLength = llDInfo->baseValue; + { U32 const ofBase = ofDInfo->baseValue; + BYTE const llBits = llDInfo->nbAdditionalBits; + BYTE const mlBits = mlDInfo->nbAdditionalBits; + BYTE const ofBits = ofDInfo->nbAdditionalBits; + BYTE const totalBits = llBits+mlBits+ofBits; + + U16 const llNext = llDInfo->nextState; + U16 const mlNext = mlDInfo->nextState; + U16 const ofNext = ofDInfo->nextState; + U32 const llnbBits = llDInfo->nbBits; + U32 const mlnbBits = mlDInfo->nbBits; + U32 const ofnbBits = ofDInfo->nbBits; + + assert(llBits <= MaxLLBits); + assert(mlBits <= MaxMLBits); + assert(ofBits <= MaxOff); + /* + * As gcc has better branch and block analyzers, sometimes it is only + * valuable to mark likeliness for clang, it gives around 3-4% of + * performance. + */ + + /* sequence */ + { size_t offset; + if (ofBits > 1) { + ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); + ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); + ZSTD_STATIC_ASSERT(STREAM_ACCUMULATOR_MIN_32 > LONG_OFFSETS_MAX_EXTRA_BITS_32); + ZSTD_STATIC_ASSERT(STREAM_ACCUMULATOR_MIN_32 - LONG_OFFSETS_MAX_EXTRA_BITS_32 >= MaxMLBits); + if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) { + /* Always read extra bits, this keeps the logic simple, + * avoids branches, and avoids accidentally reading 0 bits. + */ + U32 const extraBits = LONG_OFFSETS_MAX_EXTRA_BITS_32; + offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); + BIT_reloadDStream(&seqState->DStream); + offset += BIT_readBitsFast(&seqState->DStream, extraBits); + } else { + offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); } + seqState->prevOffset[2] = seqState->prevOffset[1]; + seqState->prevOffset[1] = seqState->prevOffset[0]; + seqState->prevOffset[0] = offset; } else { - offset = ofBase + ll0 + BIT_readBitsFast(&seqState->DStream, 1); - { size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset]; - temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */ - if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1]; - seqState->prevOffset[1] = seqState->prevOffset[0]; - seqState->prevOffset[0] = offset = temp; - } } } - seq.offset = offset; - } + U32 const ll0 = (llDInfo->baseValue == 0); + if (LIKELY((ofBits == 0))) { + offset = seqState->prevOffset[ll0]; + seqState->prevOffset[1] = seqState->prevOffset[!ll0]; + seqState->prevOffset[0] = offset; + } else { + offset = ofBase + ll0 + BIT_readBitsFast(&seqState->DStream, 1); + { size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset]; + temp -= !temp; /* 0 is not valid: input corrupted => force offset to -1 => corruption detected at execSequence */ + if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1]; + seqState->prevOffset[1] = seqState->prevOffset[0]; + seqState->prevOffset[0] = offset = temp; + } } } + seq.offset = offset; + } - seq.matchLength = mlBase; - if (mlBits > 0) - seq.matchLength += BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/); + if (mlBits > 0) + seq.matchLength += BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/); - if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32)) - BIT_reloadDStream(&seqState->DStream); - if (MEM_64bits() && UNLIKELY(totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog))) - BIT_reloadDStream(&seqState->DStream); - /* Ensure there are enough bits to read the rest of data in 64-bit mode. */ - ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64); + if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32)) + BIT_reloadDStream(&seqState->DStream); + if (MEM_64bits() && UNLIKELY(totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog))) + BIT_reloadDStream(&seqState->DStream); + /* Ensure there are enough bits to read the rest of data in 64-bit mode. */ + ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64); - seq.litLength = llBase; - if (llBits > 0) - seq.litLength += BIT_readBitsFast(&seqState->DStream, llBits/*>0*/); + if (llBits > 0) + seq.litLength += BIT_readBitsFast(&seqState->DStream, llBits/*>0*/); - if (MEM_32bits()) - BIT_reloadDStream(&seqState->DStream); + if (MEM_32bits()) + BIT_reloadDStream(&seqState->DStream); - DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u", - (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); + DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u", + (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); - if (prefetch == ZSTD_p_prefetch) { - size_t const pos = seqState->pos + seq.litLength; - const BYTE* const matchBase = (seq.offset > pos) ? seqState->dictEnd : seqState->prefixStart; - seq.match = matchBase + pos - seq.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted. - * No consequence though : no memory access will occur, offset is only used for prefetching */ - seqState->pos = pos + seq.matchLength; - } - - /* ANS state update - * gcc-9.0.0 does 2.5% worse with ZSTD_updateFseStateWithDInfo(). - * clang-9.2.0 does 7% worse with ZSTD_updateFseState(). - * Naturally it seems like ZSTD_updateFseStateWithDInfo() should be the - * better option, so it is the default for other compilers. But, if you - * measure that it is worse, please put up a pull request. - */ - { -#if defined(__GNUC__) && !defined(__clang__) - const int kUseUpdateFseState = 1; -#else - const int kUseUpdateFseState = 0; -#endif - if (kUseUpdateFseState) { - ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */ - ZSTD_updateFseState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */ + if (!isLastSeq) { + /* don't update FSE state for last Sequence */ + ZSTD_updateFseStateWithDInfo(&seqState->stateLL, &seqState->DStream, llNext, llnbBits); /* <= 9 bits */ + ZSTD_updateFseStateWithDInfo(&seqState->stateML, &seqState->DStream, mlNext, mlnbBits); /* <= 9 bits */ if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ - ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */ - } else { - ZSTD_updateFseStateWithDInfo(&seqState->stateLL, &seqState->DStream, llDInfo); /* <= 9 bits */ - ZSTD_updateFseStateWithDInfo(&seqState->stateML, &seqState->DStream, mlDInfo); /* <= 9 bits */ - if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ - ZSTD_updateFseStateWithDInfo(&seqState->stateOffb, &seqState->DStream, ofDInfo); /* <= 8 bits */ + ZSTD_updateFseStateWithDInfo(&seqState->stateOffb, &seqState->DStream, ofNext, ofnbBits); /* <= 8 bits */ + BIT_reloadDStream(&seqState->DStream); } } return seq; } -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) +#if DEBUGLEVEL >= 1 static int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStart, BYTE const* oLitEnd) { size_t const windowSize = dctx->fParams.windowSize; @@ -961,59 +1362,65 @@ static int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStar /* Dictionary is active. */ return 1; } +#endif -MEM_STATIC void ZSTD_assertValidSequence( +static void ZSTD_assertValidSequence( ZSTD_DCtx const* dctx, BYTE const* op, BYTE const* oend, seq_t const seq, BYTE const* prefixStart, BYTE const* virtualStart) { - size_t const windowSize = dctx->fParams.windowSize; - size_t const sequenceSize = seq.litLength + seq.matchLength; - BYTE const* const oLitEnd = op + seq.litLength; - DEBUGLOG(6, "Checking sequence: litL=%u matchL=%u offset=%u", - (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); - assert(op <= oend); - assert((size_t)(oend - op) >= sequenceSize); - assert(sequenceSize <= ZSTD_BLOCKSIZE_MAX); - if (ZSTD_dictionaryIsActive(dctx, prefixStart, oLitEnd)) { - size_t const dictSize = (size_t)((char const*)dctx->dictContentEndForFuzzing - (char const*)dctx->dictContentBeginForFuzzing); - /* Offset must be within the dictionary. */ - assert(seq.offset <= (size_t)(oLitEnd - virtualStart)); - assert(seq.offset <= windowSize + dictSize); - } else { - /* Offset must be within our window. */ - assert(seq.offset <= windowSize); +#if DEBUGLEVEL >= 1 + if (dctx->isFrameDecompression) { + size_t const windowSize = dctx->fParams.windowSize; + size_t const sequenceSize = seq.litLength + seq.matchLength; + BYTE const* const oLitEnd = op + seq.litLength; + DEBUGLOG(6, "Checking sequence: litL=%u matchL=%u offset=%u", + (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); + assert(op <= oend); + assert((size_t)(oend - op) >= sequenceSize); + assert(sequenceSize <= ZSTD_blockSizeMax(dctx)); + if (ZSTD_dictionaryIsActive(dctx, prefixStart, oLitEnd)) { + size_t const dictSize = (size_t)((char const*)dctx->dictContentEndForFuzzing - (char const*)dctx->dictContentBeginForFuzzing); + /* Offset must be within the dictionary. */ + assert(seq.offset <= (size_t)(oLitEnd - virtualStart)); + assert(seq.offset <= windowSize + dictSize); + } else { + /* Offset must be within our window. */ + assert(seq.offset <= windowSize); + } } +#else + (void)dctx, (void)op, (void)oend, (void)seq, (void)prefixStart, (void)virtualStart; +#endif } #endif #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG + + FORCE_INLINE_TEMPLATE size_t DONT_VECTORIZE -ZSTD_decompressSequences_body( ZSTD_DCtx* dctx, +ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) + const ZSTD_longOffset_e isLongOffset) { const BYTE* ip = (const BYTE*)seqStart; const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE* const)dst; - BYTE* const oend = ostart + maxDstSize; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = ZSTD_maybeNullPtrAdd(ostart, maxDstSize); BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; - const BYTE* const litEnd = litPtr + dctx->litSize; + const BYTE* litBufferEnd = dctx->litBufferEnd; const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart); const BYTE* const vBase = (const BYTE*) (dctx->virtualStart); const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); - DEBUGLOG(5, "ZSTD_decompressSequences_body"); - (void)frame; + DEBUGLOG(5, "ZSTD_decompressSequences_bodySplitLitBuffer (%i seqs)", nbSeq); - /* Regen sequences */ + /* Literals are split between internal buffer & output buffer */ if (nbSeq) { seqState_t seqState; - size_t error = 0; dctx->fseEntropy = 1; { U32 i; for (i=0; ientropy.rep[i]; } RETURN_ERROR_IF( @@ -1029,134 +1436,331 @@ ZSTD_decompressSequences_body( ZSTD_DCtx* dctx, BIT_DStream_endOfBuffer < BIT_DStream_completed && BIT_DStream_completed < BIT_DStream_overflow); + /* decompress without overrunning litPtr begins */ + { seq_t sequence = {0,0,0}; /* some static analyzer believe that @sequence is not initialized (it necessarily is, since for(;;) loop as at least one iteration) */ + /* Align the decompression loop to 32 + 16 bytes. + * + * zstd compiled with gcc-9 on an Intel i9-9900k shows 10% decompression + * speed swings based on the alignment of the decompression loop. This + * performance swing is caused by parts of the decompression loop falling + * out of the DSB. The entire decompression loop should fit in the DSB, + * when it can't we get much worse performance. You can measure if you've + * hit the good case or the bad case with this perf command for some + * compressed file test.zst: + * + * perf stat -e cycles -e instructions -e idq.all_dsb_cycles_any_uops \ + * -e idq.all_mite_cycles_any_uops -- ./zstd -tq test.zst + * + * If you see most cycles served out of the MITE you've hit the bad case. + * If you see most cycles served out of the DSB you've hit the good case. + * If it is pretty even then you may be in an okay case. + * + * This issue has been reproduced on the following CPUs: + * - Kabylake: Macbook Pro (15-inch, 2019) 2.4 GHz Intel Core i9 + * Use Instruments->Counters to get DSB/MITE cycles. + * I never got performance swings, but I was able to + * go from the good case of mostly DSB to half of the + * cycles served from MITE. + * - Coffeelake: Intel i9-9900k + * - Coffeelake: Intel i7-9700k + * + * I haven't been able to reproduce the instability or DSB misses on any + * of the following CPUS: + * - Haswell + * - Broadwell: Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GH + * - Skylake + * + * Alignment is done for each of the three major decompression loops: + * - ZSTD_decompressSequences_bodySplitLitBuffer - presplit section of the literal buffer + * - ZSTD_decompressSequences_bodySplitLitBuffer - postsplit section of the literal buffer + * - ZSTD_decompressSequences_body + * Alignment choices are made to minimize large swings on bad cases and influence on performance + * from changes external to this code, rather than to overoptimize on the current commit. + * + * If you are seeing performance stability this script can help test. + * It tests on 4 commits in zstd where I saw performance change. + * + * https://gist.github.com/terrelln/9889fc06a423fd5ca6e99351564473f4 + */ #if defined(__GNUC__) && defined(__x86_64__) - /* Align the decompression loop to 32 + 16 bytes. - * - * zstd compiled with gcc-9 on an Intel i9-9900k shows 10% decompression - * speed swings based on the alignment of the decompression loop. This - * performance swing is caused by parts of the decompression loop falling - * out of the DSB. The entire decompression loop should fit in the DSB, - * when it can't we get much worse performance. You can measure if you've - * hit the good case or the bad case with this perf command for some - * compressed file test.zst: - * - * perf stat -e cycles -e instructions -e idq.all_dsb_cycles_any_uops \ - * -e idq.all_mite_cycles_any_uops -- ./zstd -tq test.zst - * - * If you see most cycles served out of the MITE you've hit the bad case. - * If you see most cycles served out of the DSB you've hit the good case. - * If it is pretty even then you may be in an okay case. - * - * I've been able to reproduce this issue on the following CPUs: - * - Kabylake: Macbook Pro (15-inch, 2019) 2.4 GHz Intel Core i9 - * Use Instruments->Counters to get DSB/MITE cycles. - * I never got performance swings, but I was able to - * go from the good case of mostly DSB to half of the - * cycles served from MITE. - * - Coffeelake: Intel i9-9900k - * - * I haven't been able to reproduce the instability or DSB misses on any - * of the following CPUS: - * - Haswell - * - Broadwell: Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GH - * - Skylake - * - * If you are seeing performance stability this script can help test. - * It tests on 4 commits in zstd where I saw performance change. - * - * https://gist.github.com/terrelln/9889fc06a423fd5ca6e99351564473f4 - */ - __asm__(".p2align 5"); - __asm__("nop"); - __asm__(".p2align 4"); + __asm__(".p2align 6"); +# if __GNUC__ >= 7 + /* good for gcc-7, gcc-9, and gcc-11 */ + __asm__("nop"); + __asm__(".p2align 5"); + __asm__("nop"); + __asm__(".p2align 4"); +# if __GNUC__ == 8 || __GNUC__ == 10 + /* good for gcc-8 and gcc-10 */ + __asm__("nop"); + __asm__(".p2align 3"); +# endif +# endif #endif - for ( ; ; ) { - seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_noPrefetch); - size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd); + + /* Handle the initial state where litBuffer is currently split between dst and litExtraBuffer */ + for ( ; nbSeq; nbSeq--) { + sequence = ZSTD_decodeSequence(&seqState, isLongOffset, nbSeq==1); + if (litPtr + sequence.litLength > dctx->litBufferEnd) break; + { size_t const oneSeqSize = ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequence.litLength - WILDCOPY_OVERLENGTH, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); + assert(!ZSTD_isError(oneSeqSize)); + ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); #endif - DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); - BIT_reloadDStream(&(seqState.DStream)); - /* gcc and clang both don't like early returns in this loop. - * gcc doesn't like early breaks either. - * Instead save an error and report it at the end. - * When there is an error, don't increment op, so we don't - * overwrite. - */ - if (UNLIKELY(ZSTD_isError(oneSeqSize))) error = oneSeqSize; - else op += oneSeqSize; - if (UNLIKELY(!--nbSeq)) break; + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + } } + DEBUGLOG(6, "reached: (litPtr + sequence.litLength > dctx->litBufferEnd)"); + + /* If there are more sequences, they will need to read literals from litExtraBuffer; copy over the remainder from dst and update litPtr and litEnd */ + if (nbSeq > 0) { + const size_t leftoverLit = dctx->litBufferEnd - litPtr; + DEBUGLOG(6, "There are %i sequences left, and %zu/%zu literals left in buffer", nbSeq, leftoverLit, sequence.litLength); + if (leftoverLit) { + RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); + ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); + sequence.litLength -= leftoverLit; + op += leftoverLit; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + { size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + } + nbSeq--; + } + } + + if (nbSeq > 0) { + /* there is remaining lit from extra buffer */ + +#if defined(__GNUC__) && defined(__x86_64__) + __asm__(".p2align 6"); + __asm__("nop"); +# if __GNUC__ != 7 + /* worse for gcc-7 better for gcc-8, gcc-9, and gcc-10 and clang */ + __asm__(".p2align 4"); + __asm__("nop"); + __asm__(".p2align 3"); +# elif __GNUC__ >= 11 + __asm__(".p2align 3"); +# else + __asm__(".p2align 5"); + __asm__("nop"); + __asm__(".p2align 3"); +# endif +#endif + + for ( ; nbSeq ; nbSeq--) { + seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, nbSeq==1); + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + } } /* check if reached exact end */ - DEBUGLOG(5, "ZSTD_decompressSequences_body: after decode loop, remaining nbSeq : %i", nbSeq); - if (ZSTD_isError(error)) return error; + DEBUGLOG(5, "ZSTD_decompressSequences_bodySplitLitBuffer: after decode loop, remaining nbSeq : %i", nbSeq); RETURN_ERROR_IF(nbSeq, corruption_detected, ""); - RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, ""); + DEBUGLOG(5, "bitStream : start=%p, ptr=%p, bitsConsumed=%u", seqState.DStream.start, seqState.DStream.ptr, seqState.DStream.bitsConsumed); + RETURN_ERROR_IF(!BIT_endOfDStream(&seqState.DStream), corruption_detected, ""); /* save reps for next block */ { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } } /* last literal segment */ - { size_t const lastLLSize = litEnd - litPtr; + if (dctx->litBufferLocation == ZSTD_split) { + /* split hasn't been reached yet, first get dst then copy litExtraBuffer */ + size_t const lastLLSize = (size_t)(litBufferEnd - litPtr); + DEBUGLOG(6, "copy last literals from segment : %u", (U32)lastLLSize); + RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + } + /* copy last literals from internal buffer */ + { size_t const lastLLSize = (size_t)(litBufferEnd - litPtr); + DEBUGLOG(6, "copy last literals from internal buffer : %u", (U32)lastLLSize); RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); if (op != NULL) { - memcpy(op, litPtr, lastLLSize); + ZSTD_memcpy(op, litPtr, lastLLSize); op += lastLLSize; + } } + + DEBUGLOG(6, "decoded block of size %u bytes", (U32)(op - ostart)); + return (size_t)(op - ostart); +} + +FORCE_INLINE_TEMPLATE size_t +DONT_VECTORIZE +ZSTD_decompressSequences_body(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset) +{ + const BYTE* ip = (const BYTE*)seqStart; + const BYTE* const iend = ip + seqSize; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = dctx->litBufferLocation == ZSTD_not_in_dst ? ZSTD_maybeNullPtrAdd(ostart, maxDstSize) : dctx->litBuffer; + BYTE* op = ostart; + const BYTE* litPtr = dctx->litPtr; + const BYTE* const litEnd = litPtr + dctx->litSize; + const BYTE* const prefixStart = (const BYTE*)(dctx->prefixStart); + const BYTE* const vBase = (const BYTE*)(dctx->virtualStart); + const BYTE* const dictEnd = (const BYTE*)(dctx->dictEnd); + DEBUGLOG(5, "ZSTD_decompressSequences_body: nbSeq = %d", nbSeq); + + /* Regen sequences */ + if (nbSeq) { + seqState_t seqState; + dctx->fseEntropy = 1; + { U32 i; for (i = 0; i < ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; } + RETURN_ERROR_IF( + ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend - ip)), + corruption_detected, ""); + ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); + ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); + ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); + assert(dst != NULL); + +#if defined(__GNUC__) && defined(__x86_64__) + __asm__(".p2align 6"); + __asm__("nop"); +# if __GNUC__ >= 7 + __asm__(".p2align 5"); + __asm__("nop"); + __asm__(".p2align 3"); +# else + __asm__(".p2align 4"); + __asm__("nop"); + __asm__(".p2align 3"); +# endif +#endif + + for ( ; nbSeq ; nbSeq--) { + seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, nbSeq==1); + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; } + + /* check if reached exact end */ + assert(nbSeq == 0); + RETURN_ERROR_IF(!BIT_endOfDStream(&seqState.DStream), corruption_detected, ""); + /* save reps for next block */ + { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } } - return op-ostart; + /* last literal segment */ + { size_t const lastLLSize = (size_t)(litEnd - litPtr); + DEBUGLOG(6, "copy last literals : %u", (U32)lastLLSize); + RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memcpy(op, litPtr, lastLLSize); + op += lastLLSize; + } } + + DEBUGLOG(6, "decoded block of size %u bytes", (U32)(op - ostart)); + return (size_t)(op - ostart); } static size_t ZSTD_decompressSequences_default(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) + const ZSTD_longOffset_e isLongOffset) { - return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); +} + +static size_t +ZSTD_decompressSequencesSplitLitBuffer_default(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset) +{ + return ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT + +FORCE_INLINE_TEMPLATE + +size_t ZSTD_prefetchMatch(size_t prefetchPos, seq_t const sequence, + const BYTE* const prefixStart, const BYTE* const dictEnd) +{ + prefetchPos += sequence.litLength; + { const BYTE* const matchBase = (sequence.offset > prefetchPos) ? dictEnd : prefixStart; + /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted. + * No consequence though : memory address is only used for prefetching, not for dereferencing */ + const BYTE* const match = ZSTD_wrappedPtrSub(ZSTD_wrappedPtrAdd(matchBase, prefetchPos), sequence.offset); + PREFETCH_L1(match); PREFETCH_L1(match+CACHELINE_SIZE); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */ + } + return prefetchPos + sequence.matchLength; +} + +/* This decoding function employs prefetching + * to reduce latency impact of cache misses. + * It's generally employed when block contains a significant portion of long-distance matches + * or when coupled with a "cold" dictionary */ FORCE_INLINE_TEMPLATE size_t ZSTD_decompressSequencesLong_body( ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) + const ZSTD_longOffset_e isLongOffset) { const BYTE* ip = (const BYTE*)seqStart; const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE* const)dst; - BYTE* const oend = ostart + maxDstSize; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = dctx->litBufferLocation == ZSTD_in_dst ? dctx->litBuffer : ZSTD_maybeNullPtrAdd(ostart, maxDstSize); BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; - const BYTE* const litEnd = litPtr + dctx->litSize; + const BYTE* litBufferEnd = dctx->litBufferEnd; const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart); const BYTE* const dictStart = (const BYTE*) (dctx->virtualStart); const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); - (void)frame; /* Regen sequences */ if (nbSeq) { -#define STORED_SEQS 4 +#define STORED_SEQS 8 #define STORED_SEQS_MASK (STORED_SEQS-1) -#define ADVANCED_SEQS 4 +#define ADVANCED_SEQS STORED_SEQS seq_t sequences[STORED_SEQS]; int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS); seqState_t seqState; int seqNb; + size_t prefetchPos = (size_t)(op-prefixStart); /* track position relative to prefixStart */ + dctx->fseEntropy = 1; { int i; for (i=0; ientropy.rep[i]; } - seqState.prefixStart = prefixStart; - seqState.pos = (size_t)(op-prefixStart); - seqState.dictEnd = dictEnd; assert(dst != NULL); assert(iend >= ip); RETURN_ERROR_IF( @@ -1167,37 +1771,95 @@ ZSTD_decompressSequencesLong_body( ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); /* prepare in advance */ - for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && (seqNblitBufferLocation == ZSTD_split && litPtr + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength > dctx->litBufferEnd) { + /* lit buffer is reaching split point, empty out the first buffer and transition to litExtraBuffer */ + const size_t leftoverLit = dctx->litBufferEnd - litPtr; + if (leftoverLit) + { + RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); + ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength -= leftoverLit; + op += leftoverLit; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + { size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb-ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart); + assert(!ZSTD_isError(oneSeqSize)); + ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart); #endif - if (ZSTD_isError(oneSeqSize)) return oneSeqSize; - PREFETCH_L1(sequence.match); PREFETCH_L1(sequence.match + sequence.matchLength - 1); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */ - sequences[seqNb & STORED_SEQS_MASK] = sequence; - op += oneSeqSize; + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + + prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd); + sequences[seqNb & STORED_SEQS_MASK] = sequence; + op += oneSeqSize; + } } + else + { + /* lit buffer is either wholly contained in first or second split, or not split at all*/ + size_t const oneSeqSize = dctx->litBufferLocation == ZSTD_split ? + ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength - WILDCOPY_OVERLENGTH, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd) : + ZSTD_execSequence(op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + + prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd); + sequences[seqNb & STORED_SEQS_MASK] = sequence; + op += oneSeqSize; + } } - RETURN_ERROR_IF(seqNblitBufferLocation == ZSTD_split && litPtr + sequence->litLength > dctx->litBufferEnd) { + const size_t leftoverLit = dctx->litBufferEnd - litPtr; + if (leftoverLit) { + RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); + ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); + sequence->litLength -= leftoverLit; + op += leftoverLit; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + { size_t const oneSeqSize = ZSTD_execSequence(op, oend, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart); + assert(!ZSTD_isError(oneSeqSize)); + ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart); #endif - if (ZSTD_isError(oneSeqSize)) return oneSeqSize; - op += oneSeqSize; + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + op += oneSeqSize; + } + } + else + { + size_t const oneSeqSize = dctx->litBufferLocation == ZSTD_split ? + ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequence->litLength - WILDCOPY_OVERLENGTH, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd) : + ZSTD_execSequence(op, oend, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + op += oneSeqSize; + } } /* save reps for next block */ @@ -1205,25 +1867,34 @@ ZSTD_decompressSequencesLong_body( } /* last literal segment */ - { size_t const lastLLSize = litEnd - litPtr; + if (dctx->litBufferLocation == ZSTD_split) { /* first deplete literal buffer in dst, then copy litExtraBuffer */ + size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + } + { size_t const lastLLSize = litBufferEnd - litPtr; RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); if (op != NULL) { - memcpy(op, litPtr, lastLLSize); + ZSTD_memmove(op, litPtr, lastLLSize); op += lastLLSize; } } - return op-ostart; + return (size_t)(op - ostart); } static size_t ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) + const ZSTD_longOffset_e isLongOffset) { - return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ @@ -1232,17 +1903,34 @@ ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx, #if DYNAMIC_BMI2 #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG +static BMI2_TARGET_ATTRIBUTE size_t +DONT_VECTORIZE +ZSTD_decompressSequences_bmi2(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset) +{ + return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); +} +static BMI2_TARGET_ATTRIBUTE size_t +DONT_VECTORIZE +ZSTD_decompressSequencesSplitLitBuffer_bmi2(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset) +{ + return ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); +} #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT -static TARGET_ATTRIBUTE("bmi2") size_t +static BMI2_TARGET_ATTRIBUTE size_t ZSTD_decompressSequencesLong_bmi2(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) + const ZSTD_longOffset_e isLongOffset) { - return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ @@ -1252,18 +1940,34 @@ typedef size_t (*ZSTD_decompressSequences_t)( ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame); + const ZSTD_longOffset_e isLongOffset); #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG static size_t ZSTD_decompressSequences(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) + const ZSTD_longOffset_e isLongOffset) { DEBUGLOG(5, "ZSTD_decompressSequences"); - return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +#if DYNAMIC_BMI2 + if (ZSTD_DCtx_get_bmi2(dctx)) { + return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); + } +#endif + return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); +} +static size_t +ZSTD_decompressSequencesSplitLitBuffer(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset) +{ + DEBUGLOG(5, "ZSTD_decompressSequencesSplitLitBuffer"); +#if DYNAMIC_BMI2 + if (ZSTD_DCtx_get_bmi2(dctx)) { + return ZSTD_decompressSequencesSplitLitBuffer_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); + } +#endif + return ZSTD_decompressSequencesSplitLitBuffer_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ @@ -1278,69 +1982,114 @@ static size_t ZSTD_decompressSequencesLong(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset, - const int frame) + const ZSTD_longOffset_e isLongOffset) { DEBUGLOG(5, "ZSTD_decompressSequencesLong"); #if DYNAMIC_BMI2 - if (dctx->bmi2) { - return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + if (ZSTD_DCtx_get_bmi2(dctx)) { + return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); } #endif - return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ +/** + * @returns The total size of the history referenceable by zstd, including + * both the prefix and the extDict. At @p op any offset larger than this + * is invalid. + */ +static size_t ZSTD_totalHistorySize(BYTE* op, BYTE const* virtualStart) +{ + return (size_t)(op - virtualStart); +} -#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ - !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) -/* ZSTD_getLongOffsetsShare() : +typedef struct { + unsigned longOffsetShare; + unsigned maxNbAdditionalBits; +} ZSTD_OffsetInfo; + +/* ZSTD_getOffsetInfo() : * condition : offTable must be valid * @return : "share" of long offsets (arbitrarily defined as > (1<<23)) - * compared to maximum possible of (1< 22) total += 1; + ZSTD_OffsetInfo info = {0, 0}; + /* If nbSeq == 0, then the offTable is uninitialized, but we have + * no sequences, so both values should be 0. + */ + if (nbSeq != 0) { + const void* ptr = offTable; + U32 const tableLog = ((const ZSTD_seqSymbol_header*)ptr)[0].tableLog; + const ZSTD_seqSymbol* table = offTable + 1; + U32 const max = 1 << tableLog; + U32 u; + DEBUGLOG(5, "ZSTD_getLongOffsetsShare: (tableLog=%u)", tableLog); + + assert(max <= (1 << OffFSELog)); /* max not too large */ + for (u=0; u 22) info.longOffsetShare += 1; + } + + assert(tableLog <= OffFSELog); + info.longOffsetShare <<= (OffFSELog - tableLog); /* scale to OffFSELog */ } - assert(tableLog <= OffFSELog); - total <<= (OffFSELog - tableLog); /* scale to OffFSELog */ + return info; +} - return total; +/** + * @returns The maximum offset we can decode in one read of our bitstream, without + * reloading more bits in the middle of the offset bits read. Any offsets larger + * than this must use the long offset decoder. + */ +static size_t ZSTD_maxShortOffset(void) +{ + if (MEM_64bits()) { + /* We can decode any offset without reloading bits. + * This might change if the max window size grows. + */ + ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); + return (size_t)-1; + } else { + /* The maximum offBase is (1 << (STREAM_ACCUMULATOR_MIN + 1)) - 1. + * This offBase would require STREAM_ACCUMULATOR_MIN extra bits. + * Then we have to subtract ZSTD_REP_NUM to get the maximum possible offset. + */ + size_t const maxOffbase = ((size_t)1 << (STREAM_ACCUMULATOR_MIN + 1)) - 1; + size_t const maxOffset = maxOffbase - ZSTD_REP_NUM; + assert(ZSTD_highbit32((U32)maxOffbase) == STREAM_ACCUMULATOR_MIN); + return maxOffset; + } } -#endif size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, - const void* src, size_t srcSize, const int frame) + const void* src, size_t srcSize, const streaming_operation streaming) { /* blockType == blockCompressed */ const BYTE* ip = (const BYTE*)src; - /* isLongOffset must be true if there are long offsets. - * Offsets are long if they are larger than 2^STREAM_ACCUMULATOR_MIN. - * We don't expect that to be the case in 64-bit mode. - * In block mode, window size is not known, so we have to be conservative. - * (note: but it could be evaluated from current-lowLimit) - */ - ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (!frame || (dctx->fParams.windowSize > (1ULL << STREAM_ACCUMULATOR_MIN)))); - DEBUGLOG(5, "ZSTD_decompressBlock_internal (size : %u)", (U32)srcSize); - - RETURN_ERROR_IF(srcSize >= ZSTD_BLOCKSIZE_MAX, srcSize_wrong, ""); + DEBUGLOG(5, "ZSTD_decompressBlock_internal (cSize : %u)", (unsigned)srcSize); + + /* Note : the wording of the specification + * allows compressed block to be sized exactly ZSTD_blockSizeMax(dctx). + * This generally does not happen, as it makes little sense, + * since an uncompressed block would feature same size and have no decompression cost. + * Also, note that decoder from reference libzstd before < v1.5.4 + * would consider this edge case as an error. + * As a consequence, avoid generating compressed blocks of size ZSTD_blockSizeMax(dctx) + * for broader compatibility with the deployed ecosystem of zstd decoders */ + RETURN_ERROR_IF(srcSize > ZSTD_blockSizeMax(dctx), srcSize_wrong, ""); /* Decode literals section */ - { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize); - DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : %u", (U32)litCSize); + { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize, dst, dstCapacity, streaming); + DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : cSize=%u, nbLiterals=%zu", (U32)litCSize, dctx->litSize); if (ZSTD_isError(litCSize)) return litCSize; ip += litCSize; srcSize -= litCSize; @@ -1348,6 +2097,23 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, /* Build Decoding Tables */ { + /* Compute the maximum block size, which must also work when !frame and fParams are unset. + * Additionally, take the min with dstCapacity to ensure that the totalHistorySize fits in a size_t. + */ + size_t const blockSizeMax = MIN(dstCapacity, ZSTD_blockSizeMax(dctx)); + size_t const totalHistorySize = ZSTD_totalHistorySize(ZSTD_maybeNullPtrAdd((BYTE*)dst, blockSizeMax), (BYTE const*)dctx->virtualStart); + /* isLongOffset must be true if there are long offsets. + * Offsets are long if they are larger than ZSTD_maxShortOffset(). + * We don't expect that to be the case in 64-bit mode. + * + * We check here to see if our history is large enough to allow long offsets. + * If it isn't, then we can't possible have (valid) long offsets. If the offset + * is invalid, then it is okay to read it incorrectly. + * + * If isLongOffsets is true, then we will later check our decoding table to see + * if it is even possible to generate long offsets. + */ + ZSTD_longOffset_e isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (totalHistorySize > ZSTD_maxShortOffset())); /* These macros control at build-time which decompressor implementation * we use. If neither is defined, we do some inspection and dispatch at * runtime. @@ -1355,6 +2121,11 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, #if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) int usePrefetchDecoder = dctx->ddictIsCold; +#else + /* Set to 1 to avoid computing offset info if we don't need to. + * Otherwise this value is ignored. + */ + int usePrefetchDecoder = 1; #endif int nbSeq; size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, srcSize); @@ -1362,40 +2133,58 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, ip += seqHSize; srcSize -= seqHSize; - RETURN_ERROR_IF(dst == NULL && nbSeq > 0, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF((dst == NULL || dstCapacity == 0) && nbSeq > 0, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(MEM_64bits() && sizeof(size_t) == sizeof(void*) && (size_t)(-1) - (size_t)dst < (size_t)(1 << 20), dstSize_tooSmall, + "invalid dst"); -#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ - !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) - if ( !usePrefetchDecoder - && (!frame || (dctx->fParams.windowSize > (1<<24))) - && (nbSeq>ADVANCED_SEQS) ) { /* could probably use a larger nbSeq limit */ - U32 const shareLongOffsets = ZSTD_getLongOffsetsShare(dctx->OFTptr); - U32 const minShare = MEM_64bits() ? 7 : 20; /* heuristic values, correspond to 2.73% and 7.81% */ - usePrefetchDecoder = (shareLongOffsets >= minShare); + /* If we could potentially have long offsets, or we might want to use the prefetch decoder, + * compute information about the share of long offsets, and the maximum nbAdditionalBits. + * NOTE: could probably use a larger nbSeq limit + */ + if (isLongOffset || (!usePrefetchDecoder && (totalHistorySize > (1u << 24)) && (nbSeq > 8))) { + ZSTD_OffsetInfo const info = ZSTD_getOffsetInfo(dctx->OFTptr, nbSeq); + if (isLongOffset && info.maxNbAdditionalBits <= STREAM_ACCUMULATOR_MIN) { + /* If isLongOffset, but the maximum number of additional bits that we see in our table is small + * enough, then we know it is impossible to have too long an offset in this block, so we can + * use the regular offset decoder. + */ + isLongOffset = ZSTD_lo_isRegularOffset; + } + if (!usePrefetchDecoder) { + U32 const minShare = MEM_64bits() ? 7 : 20; /* heuristic values, correspond to 2.73% and 7.81% */ + usePrefetchDecoder = (info.longOffsetShare >= minShare); + } } -#endif dctx->ddictIsCold = 0; #if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) - if (usePrefetchDecoder) + if (usePrefetchDecoder) { +#else + (void)usePrefetchDecoder; + { #endif #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT - return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); + return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset); #endif + } #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG /* else */ - return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); + if (dctx->litBufferLocation == ZSTD_split) + return ZSTD_decompressSequencesSplitLitBuffer(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset); + else + return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset); #endif } } -void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst) +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize) { - if (dst != dctx->previousDstEnd) { /* not contiguous */ + if (dst != dctx->previousDstEnd && dstSize > 0) { /* not contiguous */ dctx->dictEnd = dctx->previousDstEnd; dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart)); dctx->prefixStart = dst; @@ -1404,15 +2193,26 @@ void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst) } -size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) +size_t ZSTD_decompressBlock_deprecated(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize) { size_t dSize; - ZSTD_checkContinuity(dctx, dst); - dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0); + dctx->isFrameDecompression = 0; + ZSTD_checkContinuity(dctx, dst, dstCapacity); + dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, not_streaming); + FORWARD_IF_ERROR(dSize, ""); dctx->previousDstEnd = (char*)dst + dSize; return dSize; } + +/* NOTE: Must just wrap ZSTD_decompressBlock_deprecated() */ +size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize) +{ + return ZSTD_decompressBlock_deprecated(dctx, dst, dstCapacity, src, srcSize); } + +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/deprecated/zbuff_common.cpp b/src/duckdb/third_party/zstd/deprecated/zbuff_common.cpp new file mode 100644 index 000000000..489498ce4 --- /dev/null +++ b/src/duckdb/third_party/zstd/deprecated/zbuff_common.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/*-************************************* +* Dependencies +***************************************/ +#include "zstd/common/error_private.h" +#include "zstd/deprecated/zbuff.h" + +namespace duckdb_zstd { + +/*-**************************************** +* ZBUFF Error Management (deprecated) +******************************************/ + +/*! ZBUFF_isError() : +* tells if a return value is an error code */ +unsigned ZBUFF_isError(size_t errorCode) { return ERR_isError(errorCode); } +/*! ZBUFF_getErrorName() : +* provides error code string from function result (useful for debugging) */ +const char* ZBUFF_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); } + +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/deprecated/zbuff_compress.cpp b/src/duckdb/third_party/zstd/deprecated/zbuff_compress.cpp new file mode 100644 index 000000000..5c63dac49 --- /dev/null +++ b/src/duckdb/third_party/zstd/deprecated/zbuff_compress.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + + +/* ************************************* +* Dependencies +***************************************/ +#define ZBUFF_STATIC_LINKING_ONLY +#include "zstd/deprecated/zbuff.h" +#include "zstd/common/error_private.h" + + +/*-*********************************************************** +* Streaming compression +* +* A ZBUFF_CCtx object is required to track streaming operation. +* Use ZBUFF_createCCtx() and ZBUFF_freeCCtx() to create/release resources. +* Use ZBUFF_compressInit() to start a new compression operation. +* ZBUFF_CCtx objects can be reused multiple times. +* +* Use ZBUFF_compressContinue() repetitively to consume your input. +* *srcSizePtr and *dstCapacityPtr can be any size. +* The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr. +* Note that it may not consume the entire input, in which case it's up to the caller to call again the function with remaining input. +* The content of dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters or change dst . +* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency) +* or an error code, which can be tested using ZBUFF_isError(). +* +* ZBUFF_compressFlush() can be used to instruct ZBUFF to compress and output whatever remains within its buffer. +* Note that it will not output more than *dstCapacityPtr. +* Therefore, some content might still be left into its internal buffer if dst buffer is too small. +* @return : nb of bytes still present into internal buffer (0 if it's empty) +* or an error code, which can be tested using ZBUFF_isError(). +* +* ZBUFF_compressEnd() instructs to finish a frame. +* It will perform a flush and write frame epilogue. +* Similar to ZBUFF_compressFlush(), it may not be able to output the entire internal buffer content if *dstCapacityPtr is too small. +* @return : nb of bytes still present into internal buffer (0 if it's empty) +* or an error code, which can be tested using ZBUFF_isError(). +* +* Hint : recommended buffer sizes (not compulsory) +* input : ZSTD_BLOCKSIZE_MAX (128 KB), internal unit size, it improves latency to use this value. +* output : ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + ZBUFF_endFrameSize : ensures it's always possible to write/flush/end a full block at best speed. +* ***********************************************************/ + +namespace duckdb_zstd { + +ZBUFF_CCtx* ZBUFF_createCCtx(void) +{ + return ZSTD_createCStream(); +} + +ZBUFF_CCtx* ZBUFF_createCCtx_advanced(ZSTD_customMem customMem) +{ + return ZSTD_createCStream_advanced(customMem); +} + +size_t ZBUFF_freeCCtx(ZBUFF_CCtx* zbc) +{ + return ZSTD_freeCStream(zbc); +} + + +/* ====== Initialization ====== */ + +size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, + const void* dict, size_t dictSize, + ZSTD_parameters params, unsigned long long pledgedSrcSize) +{ + if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* preserve "0 == unknown" behavior */ + FORWARD_IF_ERROR(ZSTD_CCtx_reset(zbc, ZSTD_reset_session_only), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setPledgedSrcSize(zbc, pledgedSrcSize), ""); + + FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_windowLog, params.cParams.windowLog), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_hashLog, params.cParams.hashLog), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_chainLog, params.cParams.chainLog), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_searchLog, params.cParams.searchLog), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_minMatch, params.cParams.minMatch), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_targetLength, params.cParams.targetLength), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_strategy, params.cParams.strategy), ""); + + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_contentSizeFlag, params.fParams.contentSizeFlag), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_checksumFlag, params.fParams.checksumFlag), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_dictIDFlag, params.fParams.noDictIDFlag), ""); + + FORWARD_IF_ERROR(ZSTD_CCtx_loadDictionary(zbc, dict, dictSize), ""); + return 0; +} + +size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* zbc, const void* dict, size_t dictSize, int compressionLevel) +{ + FORWARD_IF_ERROR(ZSTD_CCtx_reset(zbc, ZSTD_reset_session_only), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_compressionLevel, compressionLevel), ""); + FORWARD_IF_ERROR(ZSTD_CCtx_loadDictionary(zbc, dict, dictSize), ""); + return 0; +} + +size_t ZBUFF_compressInit(ZBUFF_CCtx* zbc, int compressionLevel) +{ + return ZSTD_initCStream(zbc, compressionLevel); +} + +/* ====== Compression ====== */ + + +size_t ZBUFF_compressContinue(ZBUFF_CCtx* zbc, + void* dst, size_t* dstCapacityPtr, + const void* src, size_t* srcSizePtr) +{ + size_t result; + ZSTD_outBuffer outBuff; + ZSTD_inBuffer inBuff; + outBuff.dst = dst; + outBuff.pos = 0; + outBuff.size = *dstCapacityPtr; + inBuff.src = src; + inBuff.pos = 0; + inBuff.size = *srcSizePtr; + result = ZSTD_compressStream(zbc, &outBuff, &inBuff); + *dstCapacityPtr = outBuff.pos; + *srcSizePtr = inBuff.pos; + return result; +} + + + +/* ====== Finalize ====== */ + +size_t ZBUFF_compressFlush(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr) +{ + size_t result; + ZSTD_outBuffer outBuff; + outBuff.dst = dst; + outBuff.pos = 0; + outBuff.size = *dstCapacityPtr; + result = ZSTD_flushStream(zbc, &outBuff); + *dstCapacityPtr = outBuff.pos; + return result; +} + + +size_t ZBUFF_compressEnd(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr) +{ + size_t result; + ZSTD_outBuffer outBuff; + outBuff.dst = dst; + outBuff.pos = 0; + outBuff.size = *dstCapacityPtr; + result = ZSTD_endStream(zbc, &outBuff); + *dstCapacityPtr = outBuff.pos; + return result; +} + + + +/* ************************************* +* Tool functions +***************************************/ +size_t ZBUFF_recommendedCInSize(void) { return ZSTD_CStreamInSize(); } +size_t ZBUFF_recommendedCOutSize(void) { return ZSTD_CStreamOutSize(); } + +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/deprecated/zbuff_decompress.cpp b/src/duckdb/third_party/zstd/deprecated/zbuff_decompress.cpp new file mode 100644 index 000000000..c55fd5690 --- /dev/null +++ b/src/duckdb/third_party/zstd/deprecated/zbuff_decompress.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + + +/* ************************************* +* Dependencies +***************************************/ +#define ZSTD_DISABLE_DEPRECATE_WARNINGS /* suppress warning on ZSTD_initDStream_usingDict */ +#include "zstd.h" /* ZSTD_CStream, ZSTD_DStream, ZSTDLIB_API */ +#define ZBUFF_STATIC_LINKING_ONLY +#include "zstd/deprecated/zbuff.h" + +namespace duckdb_zstd { + +ZBUFF_DCtx* ZBUFF_createDCtx(void) +{ + return ZSTD_createDStream(); +} + +ZBUFF_DCtx* ZBUFF_createDCtx_advanced(ZSTD_customMem customMem) +{ + return ZSTD_createDStream_advanced(customMem); +} + +size_t ZBUFF_freeDCtx(ZBUFF_DCtx* zbd) +{ + return ZSTD_freeDStream(zbd); +} + + +/* *** Initialization *** */ + +size_t ZBUFF_decompressInitDictionary(ZBUFF_DCtx* zbd, const void* dict, size_t dictSize) +{ + return ZSTD_initDStream_usingDict(zbd, dict, dictSize); +} + +size_t ZBUFF_decompressInit(ZBUFF_DCtx* zbd) +{ + return ZSTD_initDStream(zbd); +} + + +/* *** Decompression *** */ + +size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbd, + void* dst, size_t* dstCapacityPtr, + const void* src, size_t* srcSizePtr) +{ + ZSTD_outBuffer outBuff; + ZSTD_inBuffer inBuff; + size_t result; + outBuff.dst = dst; + outBuff.pos = 0; + outBuff.size = *dstCapacityPtr; + inBuff.src = src; + inBuff.pos = 0; + inBuff.size = *srcSizePtr; + result = ZSTD_decompressStream(zbd, &outBuff, &inBuff); + *dstCapacityPtr = outBuff.pos; + *srcSizePtr = inBuff.pos; + return result; +} + + +/* ************************************* +* Tool functions +***************************************/ +size_t ZBUFF_recommendedDInSize(void) { return ZSTD_DStreamInSize(); } +size_t ZBUFF_recommendedDOutSize(void) { return ZSTD_DStreamOutSize(); } + +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/dict/cover.cpp b/src/duckdb/third_party/zstd/dict/cover.cpp new file mode 100644 index 000000000..935c96609 --- /dev/null +++ b/src/duckdb/third_party/zstd/dict/cover.cpp @@ -0,0 +1,1265 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* ***************************************************************************** + * Constructs a dictionary using a heuristic based on the following paper: + * + * Liao, Petri, Moffat, Wirth + * Effective Construction of Relative Lempel-Ziv Dictionaries + * Published in WWW 2016. + * + * Adapted from code originally written by @ot (Giuseppe Ottaviano). + ******************************************************************************/ + +/*-************************************* +* Dependencies +***************************************/ +#include /* fprintf */ +#include /* malloc, free, qsort */ +#include /* memset */ +#include /* clock */ + +#ifndef ZDICT_STATIC_LINKING_ONLY +# define ZDICT_STATIC_LINKING_ONLY +#endif + +#include "zstd/common/mem.h" /* read */ +#include "zstd/common/pool.h" /* POOL_ctx */ +#include "zstd/common/threading.h" /* ZSTD_pthread_mutex_t */ +#include "zstd/common/zstd_internal.h" /* includes zstd.h */ +#include "zstd/common/bits.h" /* ZSTD_highbit32 */ +#include "zdict.h" +#include "zstd/dict/cover.h" + +/*-************************************* +* Constants +***************************************/ +/** +* There are 32bit indexes used to ref samples, so limit samples size to 4GB +* on 64bit builds. +* For 32bit builds we choose 1 GB. +* Most 32bit platforms have 2GB user-mode addressable space and we allocate a large +* contiguous buffer, so 1GB is already a high limit. +*/ +#define COVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB)) +#define COVER_DEFAULT_SPLITPOINT 1.0 + +/*-************************************* +* Console display +***************************************/ +#ifndef LOCALDISPLAYLEVEL +static int g_displayLevel = 0; +#endif +#undef DISPLAY +#define DISPLAY(...) \ + { \ + fprintf(stderr, __VA_ARGS__); \ + fflush(stderr); \ + } +#undef LOCALDISPLAYLEVEL +#define LOCALDISPLAYLEVEL(displayLevel, l, ...) \ + if (displayLevel >= l) { \ + DISPLAY(__VA_ARGS__); \ + } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */ +#undef DISPLAYLEVEL +#define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__) + +#ifndef LOCALDISPLAYUPDATE +static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100; +static clock_t g_time = 0; +#endif +#undef LOCALDISPLAYUPDATE +#define LOCALDISPLAYUPDATE(displayLevel, l, ...) \ + if (displayLevel >= l) { \ + if ((clock() - g_time > g_refreshRate) || (displayLevel >= 4)) { \ + g_time = clock(); \ + DISPLAY(__VA_ARGS__); \ + } \ + } +#undef DISPLAYUPDATE +#define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__) + +namespace duckdb_zstd { + +/*-************************************* +* Hash table +*************************************** +* A small specialized hash map for storing activeDmers. +* The map does not resize, so if it becomes full it will loop forever. +* Thus, the map must be large enough to store every value. +* The map implements linear probing and keeps its load less than 0.5. +*/ + +#define MAP_EMPTY_VALUE ((U32)-1) +typedef struct COVER_map_pair_t_s { + U32 key; + U32 value; +} COVER_map_pair_t; + +typedef struct COVER_map_s { + COVER_map_pair_t *data; + U32 sizeLog; + U32 size; + U32 sizeMask; +} COVER_map_t; + +/** + * Clear the map. + */ +static void COVER_map_clear(COVER_map_t *map) { + memset(map->data, MAP_EMPTY_VALUE, map->size * sizeof(COVER_map_pair_t)); +} + +/** + * Initializes a map of the given size. + * Returns 1 on success and 0 on failure. + * The map must be destroyed with COVER_map_destroy(). + * The map is only guaranteed to be large enough to hold size elements. + */ +static int COVER_map_init(COVER_map_t *map, U32 size) { + map->sizeLog = ZSTD_highbit32(size) + 2; + map->size = (U32)1 << map->sizeLog; + map->sizeMask = map->size - 1; + map->data = (COVER_map_pair_t *)malloc(map->size * sizeof(COVER_map_pair_t)); + if (!map->data) { + map->sizeLog = 0; + map->size = 0; + return 0; + } + COVER_map_clear(map); + return 1; +} + +/** + * Internal hash function + */ +static const U32 COVER_prime4bytes = 2654435761U; +static U32 COVER_map_hash(COVER_map_t *map, U32 key) { + return (key * COVER_prime4bytes) >> (32 - map->sizeLog); +} + +/** + * Helper function that returns the index that a key should be placed into. + */ +static U32 COVER_map_index(COVER_map_t *map, U32 key) { + const U32 hash = COVER_map_hash(map, key); + U32 i; + for (i = hash;; i = (i + 1) & map->sizeMask) { + COVER_map_pair_t *pos = &map->data[i]; + if (pos->value == MAP_EMPTY_VALUE) { + return i; + } + if (pos->key == key) { + return i; + } + } +} + +/** + * Returns the pointer to the value for key. + * If key is not in the map, it is inserted and the value is set to 0. + * The map must not be full. + */ +static U32 *COVER_map_at(COVER_map_t *map, U32 key) { + COVER_map_pair_t *pos = &map->data[COVER_map_index(map, key)]; + if (pos->value == MAP_EMPTY_VALUE) { + pos->key = key; + pos->value = 0; + } + return &pos->value; +} + +/** + * Deletes key from the map if present. + */ +static void COVER_map_remove(COVER_map_t *map, U32 key) { + U32 i = COVER_map_index(map, key); + COVER_map_pair_t *del = &map->data[i]; + U32 shift = 1; + if (del->value == MAP_EMPTY_VALUE) { + return; + } + for (i = (i + 1) & map->sizeMask;; i = (i + 1) & map->sizeMask) { + COVER_map_pair_t *const pos = &map->data[i]; + /* If the position is empty we are done */ + if (pos->value == MAP_EMPTY_VALUE) { + del->value = MAP_EMPTY_VALUE; + return; + } + /* If pos can be moved to del do so */ + if (((i - COVER_map_hash(map, pos->key)) & map->sizeMask) >= shift) { + del->key = pos->key; + del->value = pos->value; + del = pos; + shift = 1; + } else { + ++shift; + } + } +} + +/** + * Destroys a map that is inited with COVER_map_init(). + */ +static void COVER_map_destroy(COVER_map_t *map) { + if (map->data) { + free(map->data); + } + map->data = NULL; + map->size = 0; +} + +/*-************************************* +* Context +***************************************/ + +typedef struct { + const BYTE *samples; + size_t *offsets; + const size_t *samplesSizes; + size_t nbSamples; + size_t nbTrainSamples; + size_t nbTestSamples; + U32 *suffix; + size_t suffixSize; + U32 *freqs; + U32 *dmerAt; + unsigned d; +} COVER_ctx_t; + +/* We need a global context for qsort... */ +static COVER_ctx_t *g_coverCtx = NULL; + +/*-************************************* +* Helper functions +***************************************/ + +/** + * Returns the sum of the sample sizes. + */ +size_t COVER_sum(const size_t *samplesSizes, unsigned nbSamples) { + size_t sum = 0; + unsigned i; + for (i = 0; i < nbSamples; ++i) { + sum += samplesSizes[i]; + } + return sum; +} + +/** + * Returns -1 if the dmer at lp is less than the dmer at rp. + * Return 0 if the dmers at lp and rp are equal. + * Returns 1 if the dmer at lp is greater than the dmer at rp. + */ +static int COVER_cmp(COVER_ctx_t *ctx, const void *lp, const void *rp) { + U32 const lhs = *(U32 const *)lp; + U32 const rhs = *(U32 const *)rp; + return memcmp(ctx->samples + lhs, ctx->samples + rhs, ctx->d); +} +/** + * Faster version for d <= 8. + */ +static int COVER_cmp8(COVER_ctx_t *ctx, const void *lp, const void *rp) { + U64 const mask = (ctx->d == 8) ? (U64)-1 : (((U64)1 << (8 * ctx->d)) - 1); + U64 const lhs = MEM_readLE64(ctx->samples + *(U32 const *)lp) & mask; + U64 const rhs = MEM_readLE64(ctx->samples + *(U32 const *)rp) & mask; + if (lhs < rhs) { + return -1; + } + return (lhs > rhs); +} + +/** + * Same as COVER_cmp() except ties are broken by pointer value + * NOTE: g_coverCtx must be set to call this function. A global is required because + * qsort doesn't take an opaque pointer. + */ +static int WIN_CDECL COVER_strict_cmp(const void *lp, const void *rp) { + int result = COVER_cmp(g_coverCtx, lp, rp); + if (result == 0) { + result = lp < rp ? -1 : 1; + } + return result; +} +/** + * Faster version for d <= 8. + */ +static int WIN_CDECL COVER_strict_cmp8(const void *lp, const void *rp) { + int result = COVER_cmp8(g_coverCtx, lp, rp); + if (result == 0) { + result = lp < rp ? -1 : 1; + } + return result; +} + +/** + * Returns the first pointer in [first, last) whose element does not compare + * less than value. If no such element exists it returns last. + */ +static const size_t *COVER_lower_bound(const size_t* first, const size_t* last, + size_t value) { + size_t count = (size_t)(last - first); + assert(last >= first); + while (count != 0) { + size_t step = count / 2; + const size_t *ptr = first; + ptr += step; + if (*ptr < value) { + first = ++ptr; + count -= step + 1; + } else { + count = step; + } + } + return first; +} + +/** + * Generic groupBy function. + * Groups an array sorted by cmp into groups with equivalent values. + * Calls grp for each group. + */ +static void +COVER_groupBy(const void *data, size_t count, size_t size, COVER_ctx_t *ctx, + int (*cmp)(COVER_ctx_t *, const void *, const void *), + void (*grp)(COVER_ctx_t *, const void *, const void *)) { + const BYTE *ptr = (const BYTE *)data; + size_t num = 0; + while (num < count) { + const BYTE *grpEnd = ptr + size; + ++num; + while (num < count && cmp(ctx, ptr, grpEnd) == 0) { + grpEnd += size; + ++num; + } + grp(ctx, ptr, grpEnd); + ptr = grpEnd; + } +} + +/*-************************************* +* Cover functions +***************************************/ + +/** + * Called on each group of positions with the same dmer. + * Counts the frequency of each dmer and saves it in the suffix array. + * Fills `ctx->dmerAt`. + */ +static void COVER_group(COVER_ctx_t *ctx, const void *group, + const void *groupEnd) { + /* The group consists of all the positions with the same first d bytes. */ + const U32 *grpPtr = (const U32 *)group; + const U32 *grpEnd = (const U32 *)groupEnd; + /* The dmerId is how we will reference this dmer. + * This allows us to map the whole dmer space to a much smaller space, the + * size of the suffix array. + */ + const U32 dmerId = (U32)(grpPtr - ctx->suffix); + /* Count the number of samples this dmer shows up in */ + U32 freq = 0; + /* Details */ + const size_t *curOffsetPtr = ctx->offsets; + const size_t *offsetsEnd = ctx->offsets + ctx->nbSamples; + /* Once *grpPtr >= curSampleEnd this occurrence of the dmer is in a + * different sample than the last. + */ + size_t curSampleEnd = ctx->offsets[0]; + for (; grpPtr != grpEnd; ++grpPtr) { + /* Save the dmerId for this position so we can get back to it. */ + ctx->dmerAt[*grpPtr] = dmerId; + /* Dictionaries only help for the first reference to the dmer. + * After that zstd can reference the match from the previous reference. + * So only count each dmer once for each sample it is in. + */ + if (*grpPtr < curSampleEnd) { + continue; + } + freq += 1; + /* Binary search to find the end of the sample *grpPtr is in. + * In the common case that grpPtr + 1 == grpEnd we can skip the binary + * search because the loop is over. + */ + if (grpPtr + 1 != grpEnd) { + const size_t *sampleEndPtr = + COVER_lower_bound(curOffsetPtr, offsetsEnd, *grpPtr); + curSampleEnd = *sampleEndPtr; + curOffsetPtr = sampleEndPtr + 1; + } + } + /* At this point we are never going to look at this segment of the suffix + * array again. We take advantage of this fact to save memory. + * We store the frequency of the dmer in the first position of the group, + * which is dmerId. + */ + ctx->suffix[dmerId] = freq; +} + + +/** + * Selects the best segment in an epoch. + * Segments of are scored according to the function: + * + * Let F(d) be the frequency of dmer d. + * Let S_i be the dmer at position i of segment S which has length k. + * + * Score(S) = F(S_1) + F(S_2) + ... + F(S_{k-d+1}) + * + * Once the dmer d is in the dictionary we set F(d) = 0. + */ +static COVER_segment_t COVER_selectSegment(const COVER_ctx_t *ctx, U32 *freqs, + COVER_map_t *activeDmers, U32 begin, + U32 end, + ZDICT_cover_params_t parameters) { + /* Constants */ + const U32 k = parameters.k; + const U32 d = parameters.d; + const U32 dmersInK = k - d + 1; + /* Try each segment (activeSegment) and save the best (bestSegment) */ + COVER_segment_t bestSegment = {0, 0, 0}; + COVER_segment_t activeSegment; + /* Reset the activeDmers in the segment */ + COVER_map_clear(activeDmers); + /* The activeSegment starts at the beginning of the epoch. */ + activeSegment.begin = begin; + activeSegment.end = begin; + activeSegment.score = 0; + /* Slide the activeSegment through the whole epoch. + * Save the best segment in bestSegment. + */ + while (activeSegment.end < end) { + /* The dmerId for the dmer at the next position */ + U32 newDmer = ctx->dmerAt[activeSegment.end]; + /* The entry in activeDmers for this dmerId */ + U32 *newDmerOcc = COVER_map_at(activeDmers, newDmer); + /* If the dmer isn't already present in the segment add its score. */ + if (*newDmerOcc == 0) { + /* The paper suggest using the L-0.5 norm, but experiments show that it + * doesn't help. + */ + activeSegment.score += freqs[newDmer]; + } + /* Add the dmer to the segment */ + activeSegment.end += 1; + *newDmerOcc += 1; + + /* If the window is now too large, drop the first position */ + if (activeSegment.end - activeSegment.begin == dmersInK + 1) { + U32 delDmer = ctx->dmerAt[activeSegment.begin]; + U32 *delDmerOcc = COVER_map_at(activeDmers, delDmer); + activeSegment.begin += 1; + *delDmerOcc -= 1; + /* If this is the last occurrence of the dmer, subtract its score */ + if (*delDmerOcc == 0) { + COVER_map_remove(activeDmers, delDmer); + activeSegment.score -= freqs[delDmer]; + } + } + + /* If this segment is the best so far save it */ + if (activeSegment.score > bestSegment.score) { + bestSegment = activeSegment; + } + } + { + /* Trim off the zero frequency head and tail from the segment. */ + U32 newBegin = bestSegment.end; + U32 newEnd = bestSegment.begin; + U32 pos; + for (pos = bestSegment.begin; pos != bestSegment.end; ++pos) { + U32 freq = freqs[ctx->dmerAt[pos]]; + if (freq != 0) { + newBegin = MIN(newBegin, pos); + newEnd = pos + 1; + } + } + bestSegment.begin = newBegin; + bestSegment.end = newEnd; + } + { + /* Zero out the frequency of each dmer covered by the chosen segment. */ + U32 pos; + for (pos = bestSegment.begin; pos != bestSegment.end; ++pos) { + freqs[ctx->dmerAt[pos]] = 0; + } + } + return bestSegment; +} + +/** + * Check the validity of the parameters. + * Returns non-zero if the parameters are valid and 0 otherwise. + */ +static int COVER_checkParameters(ZDICT_cover_params_t parameters, + size_t maxDictSize) { + /* k and d are required parameters */ + if (parameters.d == 0 || parameters.k == 0) { + return 0; + } + /* k <= maxDictSize */ + if (parameters.k > maxDictSize) { + return 0; + } + /* d <= k */ + if (parameters.d > parameters.k) { + return 0; + } + /* 0 < splitPoint <= 1 */ + if (parameters.splitPoint <= 0 || parameters.splitPoint > 1){ + return 0; + } + return 1; +} + +/** + * Clean up a context initialized with `COVER_ctx_init()`. + */ +static void COVER_ctx_destroy(COVER_ctx_t *ctx) { + if (!ctx) { + return; + } + if (ctx->suffix) { + free(ctx->suffix); + ctx->suffix = NULL; + } + if (ctx->freqs) { + free(ctx->freqs); + ctx->freqs = NULL; + } + if (ctx->dmerAt) { + free(ctx->dmerAt); + ctx->dmerAt = NULL; + } + if (ctx->offsets) { + free(ctx->offsets); + ctx->offsets = NULL; + } +} + +/** + * Prepare a context for dictionary building. + * The context is only dependent on the parameter `d` and can be used multiple + * times. + * Returns 0 on success or error code on error. + * The context must be destroyed with `COVER_ctx_destroy()`. + */ +static size_t COVER_ctx_init(COVER_ctx_t *ctx, const void *samplesBuffer, + const size_t *samplesSizes, unsigned nbSamples, + unsigned d, double splitPoint) +{ + const BYTE *const samples = (const BYTE *)samplesBuffer; + const size_t totalSamplesSize = COVER_sum(samplesSizes, nbSamples); + /* Split samples into testing and training sets */ + const unsigned nbTrainSamples = splitPoint < 1.0 ? (unsigned)((double)nbSamples * splitPoint) : nbSamples; + const unsigned nbTestSamples = splitPoint < 1.0 ? nbSamples - nbTrainSamples : nbSamples; + const size_t trainingSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes, nbTrainSamples) : totalSamplesSize; + const size_t testSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes + nbTrainSamples, nbTestSamples) : totalSamplesSize; + /* Checks */ + if (totalSamplesSize < MAX(d, sizeof(U64)) || + totalSamplesSize >= (size_t)COVER_MAX_SAMPLES_SIZE) { + DISPLAYLEVEL(1, "Total samples size is too large (%u MB), maximum size is %u MB\n", + (unsigned)(totalSamplesSize>>20), (COVER_MAX_SAMPLES_SIZE >> 20)); + return ERROR(srcSize_wrong); + } + /* Check if there are at least 5 training samples */ + if (nbTrainSamples < 5) { + DISPLAYLEVEL(1, "Total number of training samples is %u and is invalid.", nbTrainSamples); + return ERROR(srcSize_wrong); + } + /* Check if there's testing sample */ + if (nbTestSamples < 1) { + DISPLAYLEVEL(1, "Total number of testing samples is %u and is invalid.", nbTestSamples); + return ERROR(srcSize_wrong); + } + /* Zero the context */ + memset(ctx, 0, sizeof(*ctx)); + DISPLAYLEVEL(2, "Training on %u samples of total size %u\n", nbTrainSamples, + (unsigned)trainingSamplesSize); + DISPLAYLEVEL(2, "Testing on %u samples of total size %u\n", nbTestSamples, + (unsigned)testSamplesSize); + ctx->samples = samples; + ctx->samplesSizes = samplesSizes; + ctx->nbSamples = nbSamples; + ctx->nbTrainSamples = nbTrainSamples; + ctx->nbTestSamples = nbTestSamples; + /* Partial suffix array */ + ctx->suffixSize = trainingSamplesSize - MAX(d, sizeof(U64)) + 1; + ctx->suffix = (U32 *)malloc(ctx->suffixSize * sizeof(U32)); + /* Maps index to the dmerID */ + ctx->dmerAt = (U32 *)malloc(ctx->suffixSize * sizeof(U32)); + /* The offsets of each file */ + ctx->offsets = (size_t *)malloc((nbSamples + 1) * sizeof(size_t)); + if (!ctx->suffix || !ctx->dmerAt || !ctx->offsets) { + DISPLAYLEVEL(1, "Failed to allocate scratch buffers\n"); + COVER_ctx_destroy(ctx); + return ERROR(memory_allocation); + } + ctx->freqs = NULL; + ctx->d = d; + + /* Fill offsets from the samplesSizes */ + { + U32 i; + ctx->offsets[0] = 0; + for (i = 1; i <= nbSamples; ++i) { + ctx->offsets[i] = ctx->offsets[i - 1] + samplesSizes[i - 1]; + } + } + DISPLAYLEVEL(2, "Constructing partial suffix array\n"); + { + /* suffix is a partial suffix array. + * It only sorts suffixes by their first parameters.d bytes. + * The sort is stable, so each dmer group is sorted by position in input. + */ + U32 i; + for (i = 0; i < ctx->suffixSize; ++i) { + ctx->suffix[i] = i; + } + /* qsort doesn't take an opaque pointer, so pass as a global. + * On OpenBSD qsort() is not guaranteed to be stable, their mergesort() is. + */ + g_coverCtx = ctx; +#if defined(__OpenBSD__) + mergesort(ctx->suffix, ctx->suffixSize, sizeof(U32), + (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp)); +#else + qsort(ctx->suffix, ctx->suffixSize, sizeof(U32), + (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp)); +#endif + } + DISPLAYLEVEL(2, "Computing frequencies\n"); + /* For each dmer group (group of positions with the same first d bytes): + * 1. For each position we set dmerAt[position] = dmerID. The dmerID is + * (groupBeginPtr - suffix). This allows us to go from position to + * dmerID so we can look up values in freq. + * 2. We calculate how many samples the dmer occurs in and save it in + * freqs[dmerId]. + */ + COVER_groupBy(ctx->suffix, ctx->suffixSize, sizeof(U32), ctx, + (ctx->d <= 8 ? &COVER_cmp8 : &COVER_cmp), &COVER_group); + ctx->freqs = ctx->suffix; + ctx->suffix = NULL; + return 0; +} + +void COVER_warnOnSmallCorpus(size_t maxDictSize, size_t nbDmers, int displayLevel) +{ + const double ratio = (double)nbDmers / (double)maxDictSize; + if (ratio >= 10) { + return; + } + LOCALDISPLAYLEVEL(displayLevel, 1, + "WARNING: The maximum dictionary size %u is too large " + "compared to the source size %u! " + "size(source)/size(dictionary) = %f, but it should be >= " + "10! This may lead to a subpar dictionary! We recommend " + "training on sources at least 10x, and preferably 100x " + "the size of the dictionary! \n", (U32)maxDictSize, + (U32)nbDmers, ratio); +} + +COVER_epoch_info_t COVER_computeEpochs(U32 maxDictSize, + U32 nbDmers, U32 k, U32 passes) +{ + const U32 minEpochSize = k * 10; + COVER_epoch_info_t epochs; + epochs.num = MAX(1, maxDictSize / k / passes); + epochs.size = nbDmers / epochs.num; + if (epochs.size >= minEpochSize) { + assert(epochs.size * epochs.num <= nbDmers); + return epochs; + } + epochs.size = MIN(minEpochSize, nbDmers); + epochs.num = nbDmers / epochs.size; + assert(epochs.size * epochs.num <= nbDmers); + return epochs; +} + +/** + * Given the prepared context build the dictionary. + */ +static size_t COVER_buildDictionary(const COVER_ctx_t *ctx, U32 *freqs, + COVER_map_t *activeDmers, void *dictBuffer, + size_t dictBufferCapacity, + ZDICT_cover_params_t parameters) { + BYTE *const dict = (BYTE *)dictBuffer; + size_t tail = dictBufferCapacity; + /* Divide the data into epochs. We will select one segment from each epoch. */ + const COVER_epoch_info_t epochs = COVER_computeEpochs( + (U32)dictBufferCapacity, (U32)ctx->suffixSize, parameters.k, 4); + const size_t maxZeroScoreRun = MAX(10, MIN(100, epochs.num >> 3)); + size_t zeroScoreRun = 0; + size_t epoch; + DISPLAYLEVEL(2, "Breaking content into %u epochs of size %u\n", + (U32)epochs.num, (U32)epochs.size); + /* Loop through the epochs until there are no more segments or the dictionary + * is full. + */ + for (epoch = 0; tail > 0; epoch = (epoch + 1) % epochs.num) { + const U32 epochBegin = (U32)(epoch * epochs.size); + const U32 epochEnd = epochBegin + epochs.size; + size_t segmentSize; + /* Select a segment */ + COVER_segment_t segment = COVER_selectSegment( + ctx, freqs, activeDmers, epochBegin, epochEnd, parameters); + /* If the segment covers no dmers, then we are out of content. + * There may be new content in other epochs, for continue for some time. + */ + if (segment.score == 0) { + if (++zeroScoreRun >= maxZeroScoreRun) { + break; + } + continue; + } + zeroScoreRun = 0; + /* Trim the segment if necessary and if it is too small then we are done */ + segmentSize = MIN(segment.end - segment.begin + parameters.d - 1, tail); + if (segmentSize < parameters.d) { + break; + } + /* We fill the dictionary from the back to allow the best segments to be + * referenced with the smallest offsets. + */ + tail -= segmentSize; + memcpy(dict + tail, ctx->samples + segment.begin, segmentSize); + DISPLAYUPDATE( + 2, "\r%u%% ", + (unsigned)(((dictBufferCapacity - tail) * 100) / dictBufferCapacity)); + } + DISPLAYLEVEL(2, "\r%79s\r", ""); + return tail; +} + +ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_cover( + void *dictBuffer, size_t dictBufferCapacity, + const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples, + ZDICT_cover_params_t parameters) +{ + BYTE* const dict = (BYTE*)dictBuffer; + COVER_ctx_t ctx; + COVER_map_t activeDmers; + parameters.splitPoint = 1.0; + /* Initialize global data */ + g_displayLevel = (int)parameters.zParams.notificationLevel; + /* Checks */ + if (!COVER_checkParameters(parameters, dictBufferCapacity)) { + DISPLAYLEVEL(1, "Cover parameters incorrect\n"); + return ERROR(parameter_outOfBound); + } + if (nbSamples == 0) { + DISPLAYLEVEL(1, "Cover must have at least one input file\n"); + return ERROR(srcSize_wrong); + } + if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) { + DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n", + ZDICT_DICTSIZE_MIN); + return ERROR(dstSize_tooSmall); + } + /* Initialize context and activeDmers */ + { + size_t const initVal = COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, + parameters.d, parameters.splitPoint); + if (ZSTD_isError(initVal)) { + return initVal; + } + } + COVER_warnOnSmallCorpus(dictBufferCapacity, ctx.suffixSize, g_displayLevel); + if (!COVER_map_init(&activeDmers, parameters.k - parameters.d + 1)) { + DISPLAYLEVEL(1, "Failed to allocate dmer map: out of memory\n"); + COVER_ctx_destroy(&ctx); + return ERROR(memory_allocation); + } + + DISPLAYLEVEL(2, "Building dictionary\n"); + { + const size_t tail = + COVER_buildDictionary(&ctx, ctx.freqs, &activeDmers, dictBuffer, + dictBufferCapacity, parameters); + const size_t dictionarySize = ZDICT_finalizeDictionary( + dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail, + samplesBuffer, samplesSizes, nbSamples, parameters.zParams); + if (!ZSTD_isError(dictionarySize)) { + DISPLAYLEVEL(2, "Constructed dictionary of size %u\n", + (unsigned)dictionarySize); + } + COVER_ctx_destroy(&ctx); + COVER_map_destroy(&activeDmers); + return dictionarySize; + } +} + + + +size_t COVER_checkTotalCompressedSize(const ZDICT_cover_params_t parameters, + const size_t *samplesSizes, const BYTE *samples, + size_t *offsets, + size_t nbTrainSamples, size_t nbSamples, + BYTE *const dict, size_t dictBufferCapacity) { + size_t totalCompressedSize = ERROR(GENERIC); + /* Pointers */ + ZSTD_CCtx *cctx; + ZSTD_CDict *cdict; + void *dst; + /* Local variables */ + size_t dstCapacity; + size_t i; + /* Allocate dst with enough space to compress the maximum sized sample */ + { + size_t maxSampleSize = 0; + i = parameters.splitPoint < 1.0 ? nbTrainSamples : 0; + for (; i < nbSamples; ++i) { + maxSampleSize = MAX(samplesSizes[i], maxSampleSize); + } + dstCapacity = ZSTD_compressBound(maxSampleSize); + dst = malloc(dstCapacity); + } + /* Create the cctx and cdict */ + cctx = ZSTD_createCCtx(); + cdict = ZSTD_createCDict(dict, dictBufferCapacity, + parameters.zParams.compressionLevel); + if (!dst || !cctx || !cdict) { + goto _compressCleanup; + } + /* Compress each sample and sum their sizes (or error) */ + totalCompressedSize = dictBufferCapacity; + i = parameters.splitPoint < 1.0 ? nbTrainSamples : 0; + for (; i < nbSamples; ++i) { + const size_t size = ZSTD_compress_usingCDict( + cctx, dst, dstCapacity, samples + offsets[i], + samplesSizes[i], cdict); + if (ZSTD_isError(size)) { + totalCompressedSize = size; + goto _compressCleanup; + } + totalCompressedSize += size; + } +_compressCleanup: + ZSTD_freeCCtx(cctx); + ZSTD_freeCDict(cdict); + if (dst) { + free(dst); + } + return totalCompressedSize; +} + + +/** + * Initialize the `COVER_best_t`. + */ +void COVER_best_init(COVER_best_t *best) { + if (best==NULL) return; /* compatible with init on NULL */ + (void)ZSTD_pthread_mutex_init(&best->mutex, NULL); + (void)ZSTD_pthread_cond_init(&best->cond, NULL); + best->liveJobs = 0; + best->dict = NULL; + best->dictSize = 0; + best->compressedSize = (size_t)-1; + memset(&best->parameters, 0, sizeof(best->parameters)); +} + +/** + * Wait until liveJobs == 0. + */ +void COVER_best_wait(COVER_best_t *best) { + if (!best) { + return; + } + ZSTD_pthread_mutex_lock(&best->mutex); + while (best->liveJobs != 0) { + ZSTD_pthread_cond_wait(&best->cond, &best->mutex); + } + ZSTD_pthread_mutex_unlock(&best->mutex); +} + +/** + * Call COVER_best_wait() and then destroy the COVER_best_t. + */ +void COVER_best_destroy(COVER_best_t *best) { + if (!best) { + return; + } + COVER_best_wait(best); + if (best->dict) { + free(best->dict); + } + ZSTD_pthread_mutex_destroy(&best->mutex); + ZSTD_pthread_cond_destroy(&best->cond); +} + +/** + * Called when a thread is about to be launched. + * Increments liveJobs. + */ +void COVER_best_start(COVER_best_t *best) { + if (!best) { + return; + } + ZSTD_pthread_mutex_lock(&best->mutex); + ++best->liveJobs; + ZSTD_pthread_mutex_unlock(&best->mutex); +} + +/** + * Called when a thread finishes executing, both on error or success. + * Decrements liveJobs and signals any waiting threads if liveJobs == 0. + * If this dictionary is the best so far save it and its parameters. + */ +void COVER_best_finish(COVER_best_t* best, + ZDICT_cover_params_t parameters, + COVER_dictSelection_t selection) +{ + void* dict = selection.dictContent; + size_t compressedSize = selection.totalCompressedSize; + size_t dictSize = selection.dictSize; + if (!best) { + return; + } + { + size_t liveJobs; + ZSTD_pthread_mutex_lock(&best->mutex); + --best->liveJobs; + liveJobs = best->liveJobs; + /* If the new dictionary is better */ + if (compressedSize < best->compressedSize) { + /* Allocate space if necessary */ + if (!best->dict || best->dictSize < dictSize) { + if (best->dict) { + free(best->dict); + } + best->dict = malloc(dictSize); + if (!best->dict) { + best->compressedSize = ERROR(GENERIC); + best->dictSize = 0; + ZSTD_pthread_cond_signal(&best->cond); + ZSTD_pthread_mutex_unlock(&best->mutex); + return; + } + } + /* Save the dictionary, parameters, and size */ + if (dict) { + memcpy(best->dict, dict, dictSize); + best->dictSize = dictSize; + best->parameters = parameters; + best->compressedSize = compressedSize; + } + } + if (liveJobs == 0) { + ZSTD_pthread_cond_broadcast(&best->cond); + } + ZSTD_pthread_mutex_unlock(&best->mutex); + } +} + +static COVER_dictSelection_t setDictSelection(BYTE* buf, size_t s, size_t csz) +{ + COVER_dictSelection_t ds; + ds.dictContent = buf; + ds.dictSize = s; + ds.totalCompressedSize = csz; + return ds; +} + +COVER_dictSelection_t COVER_dictSelectionError(size_t error) { + return setDictSelection(NULL, 0, error); +} + +unsigned COVER_dictSelectionIsError(COVER_dictSelection_t selection) { + return (ZSTD_isError(selection.totalCompressedSize) || !selection.dictContent); +} + +void COVER_dictSelectionFree(COVER_dictSelection_t selection){ + free(selection.dictContent); +} + +COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBufferCapacity, + size_t dictContentSize, const BYTE* samplesBuffer, const size_t* samplesSizes, unsigned nbFinalizeSamples, + size_t nbCheckSamples, size_t nbSamples, ZDICT_cover_params_t params, size_t* offsets, size_t totalCompressedSize) { + + size_t largestDict = 0; + size_t largestCompressed = 0; + BYTE* customDictContentEnd = customDictContent + dictContentSize; + + BYTE* largestDictbuffer = (BYTE*)malloc(dictBufferCapacity); + BYTE* candidateDictBuffer = (BYTE*)malloc(dictBufferCapacity); + double regressionTolerance = ((double)params.shrinkDictMaxRegression / 100.0) + 1.00; + + if (!largestDictbuffer || !candidateDictBuffer) { + free(largestDictbuffer); + free(candidateDictBuffer); + return COVER_dictSelectionError(dictContentSize); + } + + /* Initial dictionary size and compressed size */ + memcpy(largestDictbuffer, customDictContent, dictContentSize); + dictContentSize = ZDICT_finalizeDictionary( + largestDictbuffer, dictBufferCapacity, customDictContent, dictContentSize, + samplesBuffer, samplesSizes, nbFinalizeSamples, params.zParams); + + if (ZDICT_isError(dictContentSize)) { + free(largestDictbuffer); + free(candidateDictBuffer); + return COVER_dictSelectionError(dictContentSize); + } + + totalCompressedSize = COVER_checkTotalCompressedSize(params, samplesSizes, + samplesBuffer, offsets, + nbCheckSamples, nbSamples, + largestDictbuffer, dictContentSize); + + if (ZSTD_isError(totalCompressedSize)) { + free(largestDictbuffer); + free(candidateDictBuffer); + return COVER_dictSelectionError(totalCompressedSize); + } + + if (params.shrinkDict == 0) { + free(candidateDictBuffer); + return setDictSelection(largestDictbuffer, dictContentSize, totalCompressedSize); + } + + largestDict = dictContentSize; + largestCompressed = totalCompressedSize; + dictContentSize = ZDICT_DICTSIZE_MIN; + + /* Largest dict is initially at least ZDICT_DICTSIZE_MIN */ + while (dictContentSize < largestDict) { + memcpy(candidateDictBuffer, largestDictbuffer, largestDict); + dictContentSize = ZDICT_finalizeDictionary( + candidateDictBuffer, dictBufferCapacity, customDictContentEnd - dictContentSize, dictContentSize, + samplesBuffer, samplesSizes, nbFinalizeSamples, params.zParams); + + if (ZDICT_isError(dictContentSize)) { + free(largestDictbuffer); + free(candidateDictBuffer); + return COVER_dictSelectionError(dictContentSize); + + } + + totalCompressedSize = COVER_checkTotalCompressedSize(params, samplesSizes, + samplesBuffer, offsets, + nbCheckSamples, nbSamples, + candidateDictBuffer, dictContentSize); + + if (ZSTD_isError(totalCompressedSize)) { + free(largestDictbuffer); + free(candidateDictBuffer); + return COVER_dictSelectionError(totalCompressedSize); + } + + if ((double)totalCompressedSize <= (double)largestCompressed * regressionTolerance) { + free(largestDictbuffer); + return setDictSelection( candidateDictBuffer, dictContentSize, totalCompressedSize ); + } + dictContentSize *= 2; + } + dictContentSize = largestDict; + totalCompressedSize = largestCompressed; + free(candidateDictBuffer); + return setDictSelection( largestDictbuffer, dictContentSize, totalCompressedSize ); +} + +/** + * Parameters for COVER_tryParameters(). + */ +typedef struct COVER_tryParameters_data_s { + const COVER_ctx_t *ctx; + COVER_best_t *best; + size_t dictBufferCapacity; + ZDICT_cover_params_t parameters; +} COVER_tryParameters_data_t; + +/** + * Tries a set of parameters and updates the COVER_best_t with the results. + * This function is thread safe if zstd is compiled with multithreaded support. + * It takes its parameters as an *OWNING* opaque pointer to support threading. + */ +static void COVER_tryParameters(void *opaque) +{ + /* Save parameters as local variables */ + COVER_tryParameters_data_t *const data = (COVER_tryParameters_data_t*)opaque; + const COVER_ctx_t *const ctx = data->ctx; + const ZDICT_cover_params_t parameters = data->parameters; + size_t dictBufferCapacity = data->dictBufferCapacity; + size_t totalCompressedSize = ERROR(GENERIC); + /* Allocate space for hash table, dict, and freqs */ + COVER_map_t activeDmers; + BYTE* const dict = (BYTE*)malloc(dictBufferCapacity); + COVER_dictSelection_t selection = COVER_dictSelectionError(ERROR(GENERIC)); + U32* const freqs = (U32*)malloc(ctx->suffixSize * sizeof(U32)); + if (!COVER_map_init(&activeDmers, parameters.k - parameters.d + 1)) { + DISPLAYLEVEL(1, "Failed to allocate dmer map: out of memory\n"); + goto _cleanup; + } + if (!dict || !freqs) { + DISPLAYLEVEL(1, "Failed to allocate buffers: out of memory\n"); + goto _cleanup; + } + /* Copy the frequencies because we need to modify them */ + memcpy(freqs, ctx->freqs, ctx->suffixSize * sizeof(U32)); + /* Build the dictionary */ + { + const size_t tail = COVER_buildDictionary(ctx, freqs, &activeDmers, dict, + dictBufferCapacity, parameters); + selection = COVER_selectDict(dict + tail, dictBufferCapacity, dictBufferCapacity - tail, + ctx->samples, ctx->samplesSizes, (unsigned)ctx->nbTrainSamples, ctx->nbTrainSamples, ctx->nbSamples, parameters, ctx->offsets, + totalCompressedSize); + + if (COVER_dictSelectionIsError(selection)) { + DISPLAYLEVEL(1, "Failed to select dictionary\n"); + goto _cleanup; + } + } +_cleanup: + free(dict); + COVER_best_finish(data->best, parameters, selection); + free(data); + COVER_map_destroy(&activeDmers); + COVER_dictSelectionFree(selection); + free(freqs); +} + +ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_cover( + void* dictBuffer, size_t dictBufferCapacity, const void* samplesBuffer, + const size_t* samplesSizes, unsigned nbSamples, + ZDICT_cover_params_t* parameters) +{ + /* constants */ + const unsigned nbThreads = parameters->nbThreads; + const double splitPoint = + parameters->splitPoint <= 0.0 ? COVER_DEFAULT_SPLITPOINT : parameters->splitPoint; + const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d; + const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d; + const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k; + const unsigned kMaxK = parameters->k == 0 ? 2000 : parameters->k; + const unsigned kSteps = parameters->steps == 0 ? 40 : parameters->steps; + const unsigned kStepSize = MAX((kMaxK - kMinK) / kSteps, 1); + const unsigned kIterations = + (1 + (kMaxD - kMinD) / 2) * (1 + (kMaxK - kMinK) / kStepSize); + const unsigned shrinkDict = 0; + /* Local variables */ + const int displayLevel = parameters->zParams.notificationLevel; + unsigned iteration = 1; + unsigned d; + unsigned k; + COVER_best_t best; + POOL_ctx *pool = NULL; + int warned = 0; + + /* Checks */ + if (splitPoint <= 0 || splitPoint > 1) { + LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect parameters\n"); + return ERROR(parameter_outOfBound); + } + if (kMinK < kMaxD || kMaxK < kMinK) { + LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect parameters\n"); + return ERROR(parameter_outOfBound); + } + if (nbSamples == 0) { + DISPLAYLEVEL(1, "Cover must have at least one input file\n"); + return ERROR(srcSize_wrong); + } + if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) { + DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n", + ZDICT_DICTSIZE_MIN); + return ERROR(dstSize_tooSmall); + } + if (nbThreads > 1) { + pool = POOL_create(nbThreads, 1); + if (!pool) { + return ERROR(memory_allocation); + } + } + /* Initialization */ + COVER_best_init(&best); + /* Turn down global display level to clean up display at level 2 and below */ + g_displayLevel = displayLevel == 0 ? 0 : displayLevel - 1; + /* Loop through d first because each new value needs a new context */ + LOCALDISPLAYLEVEL(displayLevel, 2, "Trying %u different sets of parameters\n", + kIterations); + for (d = kMinD; d <= kMaxD; d += 2) { + /* Initialize the context for this value of d */ + COVER_ctx_t ctx; + LOCALDISPLAYLEVEL(displayLevel, 3, "d=%u\n", d); + { + const size_t initVal = COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, d, splitPoint); + if (ZSTD_isError(initVal)) { + LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to initialize context\n"); + COVER_best_destroy(&best); + POOL_free(pool); + return initVal; + } + } + if (!warned) { + COVER_warnOnSmallCorpus(dictBufferCapacity, ctx.suffixSize, displayLevel); + warned = 1; + } + /* Loop through k reusing the same context */ + for (k = kMinK; k <= kMaxK; k += kStepSize) { + /* Prepare the arguments */ + COVER_tryParameters_data_t *data = (COVER_tryParameters_data_t *)malloc( + sizeof(COVER_tryParameters_data_t)); + LOCALDISPLAYLEVEL(displayLevel, 3, "k=%u\n", k); + if (!data) { + LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to allocate parameters\n"); + COVER_best_destroy(&best); + COVER_ctx_destroy(&ctx); + POOL_free(pool); + return ERROR(memory_allocation); + } + data->ctx = &ctx; + data->best = &best; + data->dictBufferCapacity = dictBufferCapacity; + data->parameters = *parameters; + data->parameters.k = k; + data->parameters.d = d; + data->parameters.splitPoint = splitPoint; + data->parameters.steps = kSteps; + data->parameters.shrinkDict = shrinkDict; + data->parameters.zParams.notificationLevel = g_displayLevel; + /* Check the parameters */ + if (!COVER_checkParameters(data->parameters, dictBufferCapacity)) { + DISPLAYLEVEL(1, "Cover parameters incorrect\n"); + free(data); + continue; + } + /* Call the function and pass ownership of data to it */ + COVER_best_start(&best); + if (pool) { + POOL_add(pool, &COVER_tryParameters, data); + } else { + COVER_tryParameters(data); + } + /* Print status */ + LOCALDISPLAYUPDATE(displayLevel, 2, "\r%u%% ", + (unsigned)((iteration * 100) / kIterations)); + ++iteration; + } + COVER_best_wait(&best); + COVER_ctx_destroy(&ctx); + } + LOCALDISPLAYLEVEL(displayLevel, 2, "\r%79s\r", ""); + /* Fill the output buffer and parameters with output of the best parameters */ + { + const size_t dictSize = best.dictSize; + if (ZSTD_isError(best.compressedSize)) { + const size_t compressedSize = best.compressedSize; + COVER_best_destroy(&best); + POOL_free(pool); + return compressedSize; + } + *parameters = best.parameters; + memcpy(dictBuffer, best.dict, dictSize); + COVER_best_destroy(&best); + POOL_free(pool); + return dictSize; + } +} + +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/dict/divsufsort.cpp b/src/duckdb/third_party/zstd/dict/divsufsort.cpp new file mode 100644 index 000000000..b40901734 --- /dev/null +++ b/src/duckdb/third_party/zstd/dict/divsufsort.cpp @@ -0,0 +1,1916 @@ +/* + * divsufsort.c for libdivsufsort-lite + * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/*- Compiler specifics -*/ +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif + +#if defined(_MSC_VER) +# pragma warning(disable : 4244) +# pragma warning(disable : 4127) /* C4127 : Condition expression is constant */ +#endif + + +/*- Dependencies -*/ +#include +#include +#include + +#include "zstd/dict/divsufsort.h" + +/*- Constants -*/ +#if defined(INLINE) +# undef INLINE +#endif +#if !defined(INLINE) +# define INLINE __inline +#endif +#if defined(ALPHABET_SIZE) && (ALPHABET_SIZE < 1) +# undef ALPHABET_SIZE +#endif +#if !defined(ALPHABET_SIZE) +# define ALPHABET_SIZE (256) +#endif +#define BUCKET_A_SIZE (ALPHABET_SIZE) +#define BUCKET_B_SIZE (ALPHABET_SIZE * ALPHABET_SIZE) +#if defined(SS_INSERTIONSORT_THRESHOLD) +# if SS_INSERTIONSORT_THRESHOLD < 1 +# undef SS_INSERTIONSORT_THRESHOLD +# define SS_INSERTIONSORT_THRESHOLD (1) +# endif +#else +# define SS_INSERTIONSORT_THRESHOLD (8) +#endif +#if defined(SS_BLOCKSIZE) +# if SS_BLOCKSIZE < 0 +# undef SS_BLOCKSIZE +# define SS_BLOCKSIZE (0) +# elif 32768 <= SS_BLOCKSIZE +# undef SS_BLOCKSIZE +# define SS_BLOCKSIZE (32767) +# endif +#else +# define SS_BLOCKSIZE (1024) +#endif +/* minstacksize = log(SS_BLOCKSIZE) / log(3) * 2 */ +#if SS_BLOCKSIZE == 0 +# define SS_MISORT_STACKSIZE (96) +#elif SS_BLOCKSIZE <= 4096 +# define SS_MISORT_STACKSIZE (16) +#else +# define SS_MISORT_STACKSIZE (24) +#endif +#define SS_SMERGE_STACKSIZE (32) +#define TR_INSERTIONSORT_THRESHOLD (8) +#define TR_STACKSIZE (64) + + +/*- Macros -*/ +#ifndef SWAP +# define SWAP(_a, _b) do { t = (_a); (_a) = (_b); (_b) = t; } while(0) +#endif /* SWAP */ +#ifndef MIN +# define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) +#endif /* MIN */ +#ifndef MAX +# define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) +#endif /* MAX */ +#define STACK_PUSH(_a, _b, _c, _d)\ + do {\ + assert(ssize < STACK_SIZE);\ + stack[ssize].a = (_a), stack[ssize].b = (_b),\ + stack[ssize].c = (_c), stack[ssize++].d = (_d);\ + } while(0) +#define STACK_PUSH5(_a, _b, _c, _d, _e)\ + do {\ + assert(ssize < STACK_SIZE);\ + stack[ssize].a = (_a), stack[ssize].b = (_b),\ + stack[ssize].c = (_c), stack[ssize].d = (_d), stack[ssize++].e = (_e);\ + } while(0) +#define STACK_POP(_a, _b, _c, _d)\ + do {\ + assert(0 <= ssize);\ + if(ssize == 0) { return; }\ + (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\ + (_c) = stack[ssize].c, (_d) = stack[ssize].d;\ + } while(0) +#define STACK_POP5(_a, _b, _c, _d, _e)\ + do {\ + assert(0 <= ssize);\ + if(ssize == 0) { return; }\ + (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\ + (_c) = stack[ssize].c, (_d) = stack[ssize].d, (_e) = stack[ssize].e;\ + } while(0) +#define BUCKET_A(_c0) bucket_A[(_c0)] +#if ALPHABET_SIZE == 256 +#define BUCKET_B(_c0, _c1) (bucket_B[((_c1) << 8) | (_c0)]) +#define BUCKET_BSTAR(_c0, _c1) (bucket_B[((_c0) << 8) | (_c1)]) +#else +#define BUCKET_B(_c0, _c1) (bucket_B[(_c1) * ALPHABET_SIZE + (_c0)]) +#define BUCKET_BSTAR(_c0, _c1) (bucket_B[(_c0) * ALPHABET_SIZE + (_c1)]) +#endif + +namespace duckdb_zstd { + +/*- Private Functions -*/ + +static const int lg_table[256]= { + -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; + +#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) + +static INLINE +int +ss_ilg(int n) { +#if SS_BLOCKSIZE == 0 + return (n & 0xffff0000) ? + ((n & 0xff000000) ? + 24 + lg_table[(n >> 24) & 0xff] : + 16 + lg_table[(n >> 16) & 0xff]) : + ((n & 0x0000ff00) ? + 8 + lg_table[(n >> 8) & 0xff] : + 0 + lg_table[(n >> 0) & 0xff]); +#elif SS_BLOCKSIZE < 256 + return lg_table[n]; +#else + return (n & 0xff00) ? + 8 + lg_table[(n >> 8) & 0xff] : + 0 + lg_table[(n >> 0) & 0xff]; +#endif +} + +#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */ + +#if SS_BLOCKSIZE != 0 + +static const int sqq_table[256] = { + 0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57, 59, 61, + 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83, 84, 86, 87, 89, + 90, 91, 93, 94, 96, 97, 98, 99, 101, 102, 103, 104, 106, 107, 108, 109, +110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, +128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, +143, 144, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, +156, 157, 158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168, +169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178, 179, 180, +181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191, +192, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201, +202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211, +212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 221, +221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230, +230, 231, 231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, +239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, +247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255 +}; + +static INLINE +int +ss_isqrt(int x) { + int y, e; + + if(x >= (SS_BLOCKSIZE * SS_BLOCKSIZE)) { return SS_BLOCKSIZE; } + e = (x & 0xffff0000) ? + ((x & 0xff000000) ? + 24 + lg_table[(x >> 24) & 0xff] : + 16 + lg_table[(x >> 16) & 0xff]) : + ((x & 0x0000ff00) ? + 8 + lg_table[(x >> 8) & 0xff] : + 0 + lg_table[(x >> 0) & 0xff]); + + if(e >= 16) { + y = sqq_table[x >> ((e - 6) - (e & 1))] << ((e >> 1) - 7); + if(e >= 24) { y = (y + 1 + x / y) >> 1; } + y = (y + 1 + x / y) >> 1; + } else if(e >= 8) { + y = (sqq_table[x >> ((e - 6) - (e & 1))] >> (7 - (e >> 1))) + 1; + } else { + return sqq_table[x] >> 4; + } + + return (x < (y * y)) ? y - 1 : y; +} + +#endif /* SS_BLOCKSIZE != 0 */ + + +/*---------------------------------------------------------------------------*/ + +/* Compares two suffixes. */ +static INLINE +int +ss_compare(const unsigned char *T, + const int *p1, const int *p2, + int depth) { + const unsigned char *U1, *U2, *U1n, *U2n; + + for(U1 = T + depth + *p1, + U2 = T + depth + *p2, + U1n = T + *(p1 + 1) + 2, + U2n = T + *(p2 + 1) + 2; + (U1 < U1n) && (U2 < U2n) && (*U1 == *U2); + ++U1, ++U2) { + } + + return U1 < U1n ? + (U2 < U2n ? *U1 - *U2 : 1) : + (U2 < U2n ? -1 : 0); +} + + +/*---------------------------------------------------------------------------*/ + +#if (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) + +/* Insertionsort for small size groups */ +static +void +ss_insertionsort(const unsigned char *T, const int *PA, + int *first, int *last, int depth) { + int *i, *j; + int t; + int r; + + for(i = last - 2; first <= i; --i) { + for(t = *i, j = i + 1; 0 < (r = ss_compare(T, PA + t, PA + *j, depth));) { + do { *(j - 1) = *j; } while((++j < last) && (*j < 0)); + if(last <= j) { break; } + } + if(r == 0) { *j = ~*j; } + *(j - 1) = t; + } +} + +#endif /* (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) */ + + +/*---------------------------------------------------------------------------*/ + +#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) + +static INLINE +void +ss_fixdown(const unsigned char *Td, const int *PA, + int *SA, int i, int size) { + int j, k; + int v; + int c, d, e; + + for(v = SA[i], c = Td[PA[v]]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) { + d = Td[PA[SA[k = j++]]]; + if(d < (e = Td[PA[SA[j]]])) { k = j; d = e; } + if(d <= c) { break; } + } + SA[i] = v; +} + +/* Simple top-down heapsort. */ +static +void +ss_heapsort(const unsigned char *Td, const int *PA, int *SA, int size) { + int i, m; + int t; + + m = size; + if((size % 2) == 0) { + m--; + if(Td[PA[SA[m / 2]]] < Td[PA[SA[m]]]) { SWAP(SA[m], SA[m / 2]); } + } + + for(i = m / 2 - 1; 0 <= i; --i) { ss_fixdown(Td, PA, SA, i, m); } + if((size % 2) == 0) { SWAP(SA[0], SA[m]); ss_fixdown(Td, PA, SA, 0, m); } + for(i = m - 1; 0 < i; --i) { + t = SA[0], SA[0] = SA[i]; + ss_fixdown(Td, PA, SA, 0, i); + SA[i] = t; + } +} + + +/*---------------------------------------------------------------------------*/ + +/* Returns the median of three elements. */ +static INLINE +int * +ss_median3(const unsigned char *Td, const int *PA, + int *v1, int *v2, int *v3) { + int *t; + if(Td[PA[*v1]] > Td[PA[*v2]]) { SWAP(v1, v2); } + if(Td[PA[*v2]] > Td[PA[*v3]]) { + if(Td[PA[*v1]] > Td[PA[*v3]]) { return v1; } + else { return v3; } + } + return v2; +} + +/* Returns the median of five elements. */ +static INLINE +int * +ss_median5(const unsigned char *Td, const int *PA, + int *v1, int *v2, int *v3, int *v4, int *v5) { + int *t; + if(Td[PA[*v2]] > Td[PA[*v3]]) { SWAP(v2, v3); } + if(Td[PA[*v4]] > Td[PA[*v5]]) { SWAP(v4, v5); } + if(Td[PA[*v2]] > Td[PA[*v4]]) { SWAP(v2, v4); SWAP(v3, v5); } + if(Td[PA[*v1]] > Td[PA[*v3]]) { SWAP(v1, v3); } + if(Td[PA[*v1]] > Td[PA[*v4]]) { SWAP(v1, v4); SWAP(v3, v5); } + if(Td[PA[*v3]] > Td[PA[*v4]]) { return v4; } + return v3; +} + +/* Returns the pivot element. */ +static INLINE +int * +ss_pivot(const unsigned char *Td, const int *PA, int *first, int *last) { + int *middle; + int t; + + t = last - first; + middle = first + t / 2; + + if(t <= 512) { + if(t <= 32) { + return ss_median3(Td, PA, first, middle, last - 1); + } else { + t >>= 2; + return ss_median5(Td, PA, first, first + t, middle, last - 1 - t, last - 1); + } + } + t >>= 3; + first = ss_median3(Td, PA, first, first + t, first + (t << 1)); + middle = ss_median3(Td, PA, middle - t, middle, middle + t); + last = ss_median3(Td, PA, last - 1 - (t << 1), last - 1 - t, last - 1); + return ss_median3(Td, PA, first, middle, last); +} + + +/*---------------------------------------------------------------------------*/ + +/* Binary partition for substrings. */ +static INLINE +int * +ss_partition(const int *PA, + int *first, int *last, int depth) { + int *a, *b; + int t; + for(a = first - 1, b = last;;) { + for(; (++a < b) && ((PA[*a] + depth) >= (PA[*a + 1] + 1));) { *a = ~*a; } + for(; (a < --b) && ((PA[*b] + depth) < (PA[*b + 1] + 1));) { } + if(b <= a) { break; } + t = ~*b; + *b = *a; + *a = t; + } + if(first < a) { *first = ~*first; } + return a; +} + +/* Multikey introsort for medium size groups. */ +static +void +ss_mintrosort(const unsigned char *T, const int *PA, + int *first, int *last, + int depth) { +#define STACK_SIZE SS_MISORT_STACKSIZE + struct { int *a, *b, c; int d; } stack[STACK_SIZE]; + const unsigned char *Td; + int *a, *b, *c, *d, *e, *f; + int s, t; + int ssize; + int limit; + int v, x = 0; + + for(ssize = 0, limit = ss_ilg(last - first);;) { + + if((last - first) <= SS_INSERTIONSORT_THRESHOLD) { +#if 1 < SS_INSERTIONSORT_THRESHOLD + if(1 < (last - first)) { ss_insertionsort(T, PA, first, last, depth); } +#endif + STACK_POP(first, last, depth, limit); + continue; + } + + Td = T + depth; + if(limit-- == 0) { ss_heapsort(Td, PA, first, last - first); } + if(limit < 0) { + for(a = first + 1, v = Td[PA[*first]]; a < last; ++a) { + if((x = Td[PA[*a]]) != v) { + if(1 < (a - first)) { break; } + v = x; + first = a; + } + } + if(Td[PA[*first] - 1] < v) { + first = ss_partition(PA, first, a, depth); + } + if((a - first) <= (last - a)) { + if(1 < (a - first)) { + STACK_PUSH(a, last, depth, -1); + last = a, depth += 1, limit = ss_ilg(a - first); + } else { + first = a, limit = -1; + } + } else { + if(1 < (last - a)) { + STACK_PUSH(first, a, depth + 1, ss_ilg(a - first)); + first = a, limit = -1; + } else { + last = a, depth += 1, limit = ss_ilg(a - first); + } + } + continue; + } + + /* choose pivot */ + a = ss_pivot(Td, PA, first, last); + v = Td[PA[*a]]; + SWAP(*first, *a); + + /* partition */ + for(b = first; (++b < last) && ((x = Td[PA[*b]]) == v);) { } + if(((a = b) < last) && (x < v)) { + for(; (++b < last) && ((x = Td[PA[*b]]) <= v);) { + if(x == v) { SWAP(*b, *a); ++a; } + } + } + for(c = last; (b < --c) && ((x = Td[PA[*c]]) == v);) { } + if((b < (d = c)) && (x > v)) { + for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) { + if(x == v) { SWAP(*c, *d); --d; } + } + } + for(; b < c;) { + SWAP(*b, *c); + for(; (++b < c) && ((x = Td[PA[*b]]) <= v);) { + if(x == v) { SWAP(*b, *a); ++a; } + } + for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) { + if(x == v) { SWAP(*c, *d); --d; } + } + } + + if(a <= d) { + c = b - 1; + + if((s = a - first) > (t = b - a)) { s = t; } + for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } + if((s = d - c) > (t = last - d - 1)) { s = t; } + for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } + + a = first + (b - a), c = last - (d - c); + b = (v <= Td[PA[*a] - 1]) ? a : ss_partition(PA, a, c, depth); + + if((a - first) <= (last - c)) { + if((last - c) <= (c - b)) { + STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); + STACK_PUSH(c, last, depth, limit); + last = a; + } else if((a - first) <= (c - b)) { + STACK_PUSH(c, last, depth, limit); + STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); + last = a; + } else { + STACK_PUSH(c, last, depth, limit); + STACK_PUSH(first, a, depth, limit); + first = b, last = c, depth += 1, limit = ss_ilg(c - b); + } + } else { + if((a - first) <= (c - b)) { + STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); + STACK_PUSH(first, a, depth, limit); + first = c; + } else if((last - c) <= (c - b)) { + STACK_PUSH(first, a, depth, limit); + STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); + first = c; + } else { + STACK_PUSH(first, a, depth, limit); + STACK_PUSH(c, last, depth, limit); + first = b, last = c, depth += 1, limit = ss_ilg(c - b); + } + } + } else { + limit += 1; + if(Td[PA[*first] - 1] < v) { + first = ss_partition(PA, first, last, depth); + limit = ss_ilg(last - first); + } + depth += 1; + } + } +#undef STACK_SIZE +} + +#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */ + + +/*---------------------------------------------------------------------------*/ + +#if SS_BLOCKSIZE != 0 + +static INLINE +void +ss_blockswap(int *a, int *b, int n) { + int t; + for(; 0 < n; --n, ++a, ++b) { + t = *a, *a = *b, *b = t; + } +} + +static INLINE +void +ss_rotate(int *first, int *middle, int *last) { + int *a, *b, t; + int l, r; + l = middle - first, r = last - middle; + for(; (0 < l) && (0 < r);) { + if(l == r) { ss_blockswap(first, middle, l); break; } + if(l < r) { + a = last - 1, b = middle - 1; + t = *a; + do { + *a-- = *b, *b-- = *a; + if(b < first) { + *a = t; + last = a; + if((r -= l + 1) <= l) { break; } + a -= 1, b = middle - 1; + t = *a; + } + } while(1); + } else { + a = first, b = middle; + t = *a; + do { + *a++ = *b, *b++ = *a; + if(last <= b) { + *a = t; + first = a + 1; + if((l -= r + 1) <= r) { break; } + a += 1, b = middle; + t = *a; + } + } while(1); + } + } +} + + +/*---------------------------------------------------------------------------*/ + +static +void +ss_inplacemerge(const unsigned char *T, const int *PA, + int *first, int *middle, int *last, + int depth) { + const int *p; + int *a, *b; + int len, half; + int q, r; + int x; + + for(;;) { + if(*(last - 1) < 0) { x = 1; p = PA + ~*(last - 1); } + else { x = 0; p = PA + *(last - 1); } + for(a = first, len = middle - first, half = len >> 1, r = -1; + 0 < len; + len = half, half >>= 1) { + b = a + half; + q = ss_compare(T, PA + ((0 <= *b) ? *b : ~*b), p, depth); + if(q < 0) { + a = b + 1; + half -= (len & 1) ^ 1; + } else { + r = q; + } + } + if(a < middle) { + if(r == 0) { *a = ~*a; } + ss_rotate(a, middle, last); + last -= middle - a; + middle = a; + if(first == middle) { break; } + } + --last; + if(x != 0) { while(*--last < 0) { } } + if(middle == last) { break; } + } +} + + +/*---------------------------------------------------------------------------*/ + +/* Merge-forward with internal buffer. */ +static +void +ss_mergeforward(const unsigned char *T, const int *PA, + int *first, int *middle, int *last, + int *buf, int depth) { + int *a, *b, *c, *bufend; + int t; + int r; + + bufend = buf + (middle - first) - 1; + ss_blockswap(buf, first, middle - first); + + for(t = *(a = first), b = buf, c = middle;;) { + r = ss_compare(T, PA + *b, PA + *c, depth); + if(r < 0) { + do { + *a++ = *b; + if(bufend <= b) { *bufend = t; return; } + *b++ = *a; + } while(*b < 0); + } else if(r > 0) { + do { + *a++ = *c, *c++ = *a; + if(last <= c) { + while(b < bufend) { *a++ = *b, *b++ = *a; } + *a = *b, *b = t; + return; + } + } while(*c < 0); + } else { + *c = ~*c; + do { + *a++ = *b; + if(bufend <= b) { *bufend = t; return; } + *b++ = *a; + } while(*b < 0); + + do { + *a++ = *c, *c++ = *a; + if(last <= c) { + while(b < bufend) { *a++ = *b, *b++ = *a; } + *a = *b, *b = t; + return; + } + } while(*c < 0); + } + } +} + +/* Merge-backward with internal buffer. */ +static +void +ss_mergebackward(const unsigned char *T, const int *PA, + int *first, int *middle, int *last, + int *buf, int depth) { + const int *p1, *p2; + int *a, *b, *c, *bufend; + int t; + int r; + int x; + + bufend = buf + (last - middle) - 1; + ss_blockswap(buf, middle, last - middle); + + x = 0; + if(*bufend < 0) { p1 = PA + ~*bufend; x |= 1; } + else { p1 = PA + *bufend; } + if(*(middle - 1) < 0) { p2 = PA + ~*(middle - 1); x |= 2; } + else { p2 = PA + *(middle - 1); } + for(t = *(a = last - 1), b = bufend, c = middle - 1;;) { + r = ss_compare(T, p1, p2, depth); + if(0 < r) { + if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; } + *a-- = *b; + if(b <= buf) { *buf = t; break; } + *b-- = *a; + if(*b < 0) { p1 = PA + ~*b; x |= 1; } + else { p1 = PA + *b; } + } else if(r < 0) { + if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; } + *a-- = *c, *c-- = *a; + if(c < first) { + while(buf < b) { *a-- = *b, *b-- = *a; } + *a = *b, *b = t; + break; + } + if(*c < 0) { p2 = PA + ~*c; x |= 2; } + else { p2 = PA + *c; } + } else { + if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; } + *a-- = ~*b; + if(b <= buf) { *buf = t; break; } + *b-- = *a; + if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; } + *a-- = *c, *c-- = *a; + if(c < first) { + while(buf < b) { *a-- = *b, *b-- = *a; } + *a = *b, *b = t; + break; + } + if(*b < 0) { p1 = PA + ~*b; x |= 1; } + else { p1 = PA + *b; } + if(*c < 0) { p2 = PA + ~*c; x |= 2; } + else { p2 = PA + *c; } + } + } +} + +/* D&C based merge. */ +static +void +ss_swapmerge(const unsigned char *T, const int *PA, + int *first, int *middle, int *last, + int *buf, int bufsize, int depth) { +#define STACK_SIZE SS_SMERGE_STACKSIZE +#define GETIDX(a) ((0 <= (a)) ? (a) : (~(a))) +#define MERGE_CHECK(a, b, c)\ + do {\ + if(((c) & 1) ||\ + (((c) & 2) && (ss_compare(T, PA + GETIDX(*((a) - 1)), PA + *(a), depth) == 0))) {\ + *(a) = ~*(a);\ + }\ + if(((c) & 4) && ((ss_compare(T, PA + GETIDX(*((b) - 1)), PA + *(b), depth) == 0))) {\ + *(b) = ~*(b);\ + }\ + } while(0) + struct { int *a, *b, *c; int d; } stack[STACK_SIZE]; + int *l, *r, *lm, *rm; + int m, len, half; + int ssize; + int check, next; + + for(check = 0, ssize = 0;;) { + if((last - middle) <= bufsize) { + if((first < middle) && (middle < last)) { + ss_mergebackward(T, PA, first, middle, last, buf, depth); + } + MERGE_CHECK(first, last, check); + STACK_POP(first, middle, last, check); + continue; + } + + if((middle - first) <= bufsize) { + if(first < middle) { + ss_mergeforward(T, PA, first, middle, last, buf, depth); + } + MERGE_CHECK(first, last, check); + STACK_POP(first, middle, last, check); + continue; + } + + for(m = 0, len = MIN(middle - first, last - middle), half = len >> 1; + 0 < len; + len = half, half >>= 1) { + if(ss_compare(T, PA + GETIDX(*(middle + m + half)), + PA + GETIDX(*(middle - m - half - 1)), depth) < 0) { + m += half + 1; + half -= (len & 1) ^ 1; + } + } + + if(0 < m) { + lm = middle - m, rm = middle + m; + ss_blockswap(lm, middle, m); + l = r = middle, next = 0; + if(rm < last) { + if(*rm < 0) { + *rm = ~*rm; + if(first < lm) { for(; *--l < 0;) { } next |= 4; } + next |= 1; + } else if(first < lm) { + for(; *r < 0; ++r) { } + next |= 2; + } + } + + if((l - first) <= (last - r)) { + STACK_PUSH(r, rm, last, (next & 3) | (check & 4)); + middle = lm, last = l, check = (check & 3) | (next & 4); + } else { + if((next & 2) && (r == middle)) { next ^= 6; } + STACK_PUSH(first, lm, l, (check & 3) | (next & 4)); + first = r, middle = rm, check = (next & 3) | (check & 4); + } + } else { + if(ss_compare(T, PA + GETIDX(*(middle - 1)), PA + *middle, depth) == 0) { + *middle = ~*middle; + } + MERGE_CHECK(first, last, check); + STACK_POP(first, middle, last, check); + } + } +#undef STACK_SIZE +} + +#endif /* SS_BLOCKSIZE != 0 */ + + +/*---------------------------------------------------------------------------*/ + +/* Substring sort */ +static +void +sssort(const unsigned char *T, const int *PA, + int *first, int *last, + int *buf, int bufsize, + int depth, int n, int lastsuffix) { + int *a; +#if SS_BLOCKSIZE != 0 + int *b, *middle, *curbuf; + int j, k, curbufsize, limit; +#endif + int i; + + if(lastsuffix != 0) { ++first; } + +#if SS_BLOCKSIZE == 0 + ss_mintrosort(T, PA, first, last, depth); +#else + if((bufsize < SS_BLOCKSIZE) && + (bufsize < (last - first)) && + (bufsize < (limit = ss_isqrt(last - first)))) { + if(SS_BLOCKSIZE < limit) { limit = SS_BLOCKSIZE; } + buf = middle = last - limit, bufsize = limit; + } else { + middle = last, limit = 0; + } + for(a = first, i = 0; SS_BLOCKSIZE < (middle - a); a += SS_BLOCKSIZE, ++i) { +#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE + ss_mintrosort(T, PA, a, a + SS_BLOCKSIZE, depth); +#elif 1 < SS_BLOCKSIZE + ss_insertionsort(T, PA, a, a + SS_BLOCKSIZE, depth); +#endif + curbufsize = last - (a + SS_BLOCKSIZE); + curbuf = a + SS_BLOCKSIZE; + if(curbufsize <= bufsize) { curbufsize = bufsize, curbuf = buf; } + for(b = a, k = SS_BLOCKSIZE, j = i; j & 1; b -= k, k <<= 1, j >>= 1) { + ss_swapmerge(T, PA, b - k, b, b + k, curbuf, curbufsize, depth); + } + } +#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE + ss_mintrosort(T, PA, a, middle, depth); +#elif 1 < SS_BLOCKSIZE + ss_insertionsort(T, PA, a, middle, depth); +#endif + for(k = SS_BLOCKSIZE; i != 0; k <<= 1, i >>= 1) { + if(i & 1) { + ss_swapmerge(T, PA, a - k, a, middle, buf, bufsize, depth); + a -= k; + } + } + if(limit != 0) { +#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE + ss_mintrosort(T, PA, middle, last, depth); +#elif 1 < SS_BLOCKSIZE + ss_insertionsort(T, PA, middle, last, depth); +#endif + ss_inplacemerge(T, PA, first, middle, last, depth); + } +#endif + + if(lastsuffix != 0) { + /* Insert last type B* suffix. */ + int PAi[2]; PAi[0] = PA[*(first - 1)], PAi[1] = n - 2; + for(a = first, i = *(first - 1); + (a < last) && ((*a < 0) || (0 < ss_compare(T, &(PAi[0]), PA + *a, depth))); + ++a) { + *(a - 1) = *a; + } + *(a - 1) = i; + } +} + + +/*---------------------------------------------------------------------------*/ + +static INLINE +int +tr_ilg(int n) { + return (n & 0xffff0000) ? + ((n & 0xff000000) ? + 24 + lg_table[(n >> 24) & 0xff] : + 16 + lg_table[(n >> 16) & 0xff]) : + ((n & 0x0000ff00) ? + 8 + lg_table[(n >> 8) & 0xff] : + 0 + lg_table[(n >> 0) & 0xff]); +} + + +/*---------------------------------------------------------------------------*/ + +/* Simple insertionsort for small size groups. */ +static +void +tr_insertionsort(const int *ISAd, int *first, int *last) { + int *a, *b; + int t, r; + + for(a = first + 1; a < last; ++a) { + for(t = *a, b = a - 1; 0 > (r = ISAd[t] - ISAd[*b]);) { + do { *(b + 1) = *b; } while((first <= --b) && (*b < 0)); + if(b < first) { break; } + } + if(r == 0) { *b = ~*b; } + *(b + 1) = t; + } +} + + +/*---------------------------------------------------------------------------*/ + +static INLINE +void +tr_fixdown(const int *ISAd, int *SA, int i, int size) { + int j, k; + int v; + int c, d, e; + + for(v = SA[i], c = ISAd[v]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) { + d = ISAd[SA[k = j++]]; + if(d < (e = ISAd[SA[j]])) { k = j; d = e; } + if(d <= c) { break; } + } + SA[i] = v; +} + +/* Simple top-down heapsort. */ +static +void +tr_heapsort(const int *ISAd, int *SA, int size) { + int i, m; + int t; + + m = size; + if((size % 2) == 0) { + m--; + if(ISAd[SA[m / 2]] < ISAd[SA[m]]) { SWAP(SA[m], SA[m / 2]); } + } + + for(i = m / 2 - 1; 0 <= i; --i) { tr_fixdown(ISAd, SA, i, m); } + if((size % 2) == 0) { SWAP(SA[0], SA[m]); tr_fixdown(ISAd, SA, 0, m); } + for(i = m - 1; 0 < i; --i) { + t = SA[0], SA[0] = SA[i]; + tr_fixdown(ISAd, SA, 0, i); + SA[i] = t; + } +} + + +/*---------------------------------------------------------------------------*/ + +/* Returns the median of three elements. */ +static INLINE +int * +tr_median3(const int *ISAd, int *v1, int *v2, int *v3) { + int *t; + if(ISAd[*v1] > ISAd[*v2]) { SWAP(v1, v2); } + if(ISAd[*v2] > ISAd[*v3]) { + if(ISAd[*v1] > ISAd[*v3]) { return v1; } + else { return v3; } + } + return v2; +} + +/* Returns the median of five elements. */ +static INLINE +int * +tr_median5(const int *ISAd, + int *v1, int *v2, int *v3, int *v4, int *v5) { + int *t; + if(ISAd[*v2] > ISAd[*v3]) { SWAP(v2, v3); } + if(ISAd[*v4] > ISAd[*v5]) { SWAP(v4, v5); } + if(ISAd[*v2] > ISAd[*v4]) { SWAP(v2, v4); SWAP(v3, v5); } + if(ISAd[*v1] > ISAd[*v3]) { SWAP(v1, v3); } + if(ISAd[*v1] > ISAd[*v4]) { SWAP(v1, v4); SWAP(v3, v5); } + if(ISAd[*v3] > ISAd[*v4]) { return v4; } + return v3; +} + +/* Returns the pivot element. */ +static INLINE +int * +tr_pivot(const int *ISAd, int *first, int *last) { + int *middle; + int t; + + t = last - first; + middle = first + t / 2; + + if(t <= 512) { + if(t <= 32) { + return tr_median3(ISAd, first, middle, last - 1); + } else { + t >>= 2; + return tr_median5(ISAd, first, first + t, middle, last - 1 - t, last - 1); + } + } + t >>= 3; + first = tr_median3(ISAd, first, first + t, first + (t << 1)); + middle = tr_median3(ISAd, middle - t, middle, middle + t); + last = tr_median3(ISAd, last - 1 - (t << 1), last - 1 - t, last - 1); + return tr_median3(ISAd, first, middle, last); +} + + +/*---------------------------------------------------------------------------*/ + +typedef struct _trbudget_t trbudget_t; +struct _trbudget_t { + int chance; + int remain; + int incval; + int count; +}; + +static INLINE +void +trbudget_init(trbudget_t *budget, int chance, int incval) { + budget->chance = chance; + budget->remain = budget->incval = incval; +} + +static INLINE +int +trbudget_check(trbudget_t *budget, int size) { + if(size <= budget->remain) { budget->remain -= size; return 1; } + if(budget->chance == 0) { budget->count += size; return 0; } + budget->remain += budget->incval - size; + budget->chance -= 1; + return 1; +} + + +/*---------------------------------------------------------------------------*/ + +static INLINE +void +tr_partition(const int *ISAd, + int *first, int *middle, int *last, + int **pa, int **pb, int v) { + int *a, *b, *c, *d, *e, *f; + int t, s; + int x = 0; + + for(b = middle - 1; (++b < last) && ((x = ISAd[*b]) == v);) { } + if(((a = b) < last) && (x < v)) { + for(; (++b < last) && ((x = ISAd[*b]) <= v);) { + if(x == v) { SWAP(*b, *a); ++a; } + } + } + for(c = last; (b < --c) && ((x = ISAd[*c]) == v);) { } + if((b < (d = c)) && (x > v)) { + for(; (b < --c) && ((x = ISAd[*c]) >= v);) { + if(x == v) { SWAP(*c, *d); --d; } + } + } + for(; b < c;) { + SWAP(*b, *c); + for(; (++b < c) && ((x = ISAd[*b]) <= v);) { + if(x == v) { SWAP(*b, *a); ++a; } + } + for(; (b < --c) && ((x = ISAd[*c]) >= v);) { + if(x == v) { SWAP(*c, *d); --d; } + } + } + + if(a <= d) { + c = b - 1; + if((s = a - first) > (t = b - a)) { s = t; } + for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } + if((s = d - c) > (t = last - d - 1)) { s = t; } + for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } + first += (b - a), last -= (d - c); + } + *pa = first, *pb = last; +} + +static +void +tr_copy(int *ISA, const int *SA, + int *first, int *a, int *b, int *last, + int depth) { + /* sort suffixes of middle partition + by using sorted order of suffixes of left and right partition. */ + int *c, *d, *e; + int s, v; + + v = b - SA - 1; + for(c = first, d = a - 1; c <= d; ++c) { + if((0 <= (s = *c - depth)) && (ISA[s] == v)) { + *++d = s; + ISA[s] = d - SA; + } + } + for(c = last - 1, e = d + 1, d = b; e < d; --c) { + if((0 <= (s = *c - depth)) && (ISA[s] == v)) { + *--d = s; + ISA[s] = d - SA; + } + } +} + +static +void +tr_partialcopy(int *ISA, const int *SA, + int *first, int *a, int *b, int *last, + int depth) { + int *c, *d, *e; + int s, v; + int rank, lastrank, newrank = -1; + + v = b - SA - 1; + lastrank = -1; + for(c = first, d = a - 1; c <= d; ++c) { + if((0 <= (s = *c - depth)) && (ISA[s] == v)) { + *++d = s; + rank = ISA[s + depth]; + if(lastrank != rank) { lastrank = rank; newrank = d - SA; } + ISA[s] = newrank; + } + } + + lastrank = -1; + for(e = d; first <= e; --e) { + rank = ISA[*e]; + if(lastrank != rank) { lastrank = rank; newrank = e - SA; } + if(newrank != rank) { ISA[*e] = newrank; } + } + + lastrank = -1; + for(c = last - 1, e = d + 1, d = b; e < d; --c) { + if((0 <= (s = *c - depth)) && (ISA[s] == v)) { + *--d = s; + rank = ISA[s + depth]; + if(lastrank != rank) { lastrank = rank; newrank = d - SA; } + ISA[s] = newrank; + } + } +} + +static +void +tr_introsort(int *ISA, const int *ISAd, + int *SA, int *first, int *last, + trbudget_t *budget) { +#define STACK_SIZE TR_STACKSIZE + struct { const int *a; int *b, *c; int d, e; }stack[STACK_SIZE]; + int *a, *b, *c; + int t; + int v, x = 0; + int incr = ISAd - ISA; + int limit, next; + int ssize, trlink = -1; + + for(ssize = 0, limit = tr_ilg(last - first);;) { + + if(limit < 0) { + if(limit == -1) { + /* tandem repeat partition */ + tr_partition(ISAd - incr, first, first, last, &a, &b, last - SA - 1); + + /* update ranks */ + if(a < last) { + for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; } + } + if(b < last) { + for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } + } + + /* push */ + if(1 < (b - a)) { + STACK_PUSH5(NULL, a, b, 0, 0); + STACK_PUSH5(ISAd - incr, first, last, -2, trlink); + trlink = ssize - 2; + } + if((a - first) <= (last - b)) { + if(1 < (a - first)) { + STACK_PUSH5(ISAd, b, last, tr_ilg(last - b), trlink); + last = a, limit = tr_ilg(a - first); + } else if(1 < (last - b)) { + first = b, limit = tr_ilg(last - b); + } else { + STACK_POP5(ISAd, first, last, limit, trlink); + } + } else { + if(1 < (last - b)) { + STACK_PUSH5(ISAd, first, a, tr_ilg(a - first), trlink); + first = b, limit = tr_ilg(last - b); + } else if(1 < (a - first)) { + last = a, limit = tr_ilg(a - first); + } else { + STACK_POP5(ISAd, first, last, limit, trlink); + } + } + } else if(limit == -2) { + /* tandem repeat copy */ + a = stack[--ssize].b, b = stack[ssize].c; + if(stack[ssize].d == 0) { + tr_copy(ISA, SA, first, a, b, last, ISAd - ISA); + } else { + if(0 <= trlink) { stack[trlink].d = -1; } + tr_partialcopy(ISA, SA, first, a, b, last, ISAd - ISA); + } + STACK_POP5(ISAd, first, last, limit, trlink); + } else { + /* sorted partition */ + if(0 <= *first) { + a = first; + do { ISA[*a] = a - SA; } while((++a < last) && (0 <= *a)); + first = a; + } + if(first < last) { + a = first; do { *a = ~*a; } while(*++a < 0); + next = (ISA[*a] != ISAd[*a]) ? tr_ilg(a - first + 1) : -1; + if(++a < last) { for(b = first, v = a - SA - 1; b < a; ++b) { ISA[*b] = v; } } + + /* push */ + if(trbudget_check(budget, a - first)) { + if((a - first) <= (last - a)) { + STACK_PUSH5(ISAd, a, last, -3, trlink); + ISAd += incr, last = a, limit = next; + } else { + if(1 < (last - a)) { + STACK_PUSH5(ISAd + incr, first, a, next, trlink); + first = a, limit = -3; + } else { + ISAd += incr, last = a, limit = next; + } + } + } else { + if(0 <= trlink) { stack[trlink].d = -1; } + if(1 < (last - a)) { + first = a, limit = -3; + } else { + STACK_POP5(ISAd, first, last, limit, trlink); + } + } + } else { + STACK_POP5(ISAd, first, last, limit, trlink); + } + } + continue; + } + + if((last - first) <= TR_INSERTIONSORT_THRESHOLD) { + tr_insertionsort(ISAd, first, last); + limit = -3; + continue; + } + + if(limit-- == 0) { + tr_heapsort(ISAd, first, last - first); + for(a = last - 1; first < a; a = b) { + for(x = ISAd[*a], b = a - 1; (first <= b) && (ISAd[*b] == x); --b) { *b = ~*b; } + } + limit = -3; + continue; + } + + /* choose pivot */ + a = tr_pivot(ISAd, first, last); + SWAP(*first, *a); + v = ISAd[*first]; + + /* partition */ + tr_partition(ISAd, first, first + 1, last, &a, &b, v); + if((last - first) != (b - a)) { + next = (ISA[*a] != v) ? tr_ilg(b - a) : -1; + + /* update ranks */ + for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; } + if(b < last) { for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } } + + /* push */ + if((1 < (b - a)) && (trbudget_check(budget, b - a))) { + if((a - first) <= (last - b)) { + if((last - b) <= (b - a)) { + if(1 < (a - first)) { + STACK_PUSH5(ISAd + incr, a, b, next, trlink); + STACK_PUSH5(ISAd, b, last, limit, trlink); + last = a; + } else if(1 < (last - b)) { + STACK_PUSH5(ISAd + incr, a, b, next, trlink); + first = b; + } else { + ISAd += incr, first = a, last = b, limit = next; + } + } else if((a - first) <= (b - a)) { + if(1 < (a - first)) { + STACK_PUSH5(ISAd, b, last, limit, trlink); + STACK_PUSH5(ISAd + incr, a, b, next, trlink); + last = a; + } else { + STACK_PUSH5(ISAd, b, last, limit, trlink); + ISAd += incr, first = a, last = b, limit = next; + } + } else { + STACK_PUSH5(ISAd, b, last, limit, trlink); + STACK_PUSH5(ISAd, first, a, limit, trlink); + ISAd += incr, first = a, last = b, limit = next; + } + } else { + if((a - first) <= (b - a)) { + if(1 < (last - b)) { + STACK_PUSH5(ISAd + incr, a, b, next, trlink); + STACK_PUSH5(ISAd, first, a, limit, trlink); + first = b; + } else if(1 < (a - first)) { + STACK_PUSH5(ISAd + incr, a, b, next, trlink); + last = a; + } else { + ISAd += incr, first = a, last = b, limit = next; + } + } else if((last - b) <= (b - a)) { + if(1 < (last - b)) { + STACK_PUSH5(ISAd, first, a, limit, trlink); + STACK_PUSH5(ISAd + incr, a, b, next, trlink); + first = b; + } else { + STACK_PUSH5(ISAd, first, a, limit, trlink); + ISAd += incr, first = a, last = b, limit = next; + } + } else { + STACK_PUSH5(ISAd, first, a, limit, trlink); + STACK_PUSH5(ISAd, b, last, limit, trlink); + ISAd += incr, first = a, last = b, limit = next; + } + } + } else { + if((1 < (b - a)) && (0 <= trlink)) { stack[trlink].d = -1; } + if((a - first) <= (last - b)) { + if(1 < (a - first)) { + STACK_PUSH5(ISAd, b, last, limit, trlink); + last = a; + } else if(1 < (last - b)) { + first = b; + } else { + STACK_POP5(ISAd, first, last, limit, trlink); + } + } else { + if(1 < (last - b)) { + STACK_PUSH5(ISAd, first, a, limit, trlink); + first = b; + } else if(1 < (a - first)) { + last = a; + } else { + STACK_POP5(ISAd, first, last, limit, trlink); + } + } + } + } else { + if(trbudget_check(budget, last - first)) { + limit = tr_ilg(last - first), ISAd += incr; + } else { + if(0 <= trlink) { stack[trlink].d = -1; } + STACK_POP5(ISAd, first, last, limit, trlink); + } + } + } +#undef STACK_SIZE +} + + + +/*---------------------------------------------------------------------------*/ + +/* Tandem repeat sort */ +static +void +trsort(int *ISA, int *SA, int n, int depth) { + int *ISAd; + int *first, *last; + trbudget_t budget; + int t, skip, unsorted; + + trbudget_init(&budget, tr_ilg(n) * 2 / 3, n); +/* trbudget_init(&budget, tr_ilg(n) * 3 / 4, n); */ + for(ISAd = ISA + depth; -n < *SA; ISAd += ISAd - ISA) { + first = SA; + skip = 0; + unsorted = 0; + do { + if((t = *first) < 0) { first -= t; skip += t; } + else { + if(skip != 0) { *(first + skip) = skip; skip = 0; } + last = SA + ISA[t] + 1; + if(1 < (last - first)) { + budget.count = 0; + tr_introsort(ISA, ISAd, SA, first, last, &budget); + if(budget.count != 0) { unsorted += budget.count; } + else { skip = first - last; } + } else if((last - first) == 1) { + skip = -1; + } + first = last; + } + } while(first < (SA + n)); + if(skip != 0) { *(first + skip) = skip; } + if(unsorted == 0) { break; } + } +} + + +/*---------------------------------------------------------------------------*/ + +/* Sorts suffixes of type B*. */ +static +int +sort_typeBstar(const unsigned char *T, int *SA, + int *bucket_A, int *bucket_B, + int n, int openMP) { + int *PAb, *ISAb, *buf; +#ifdef LIBBSC_OPENMP + int *curbuf; + int l; +#endif + int i, j, k, t, m, bufsize; + int c0, c1; +#ifdef LIBBSC_OPENMP + int d0, d1; +#endif + (void)openMP; + + /* Initialize bucket arrays. */ + for(i = 0; i < BUCKET_A_SIZE; ++i) { bucket_A[i] = 0; } + for(i = 0; i < BUCKET_B_SIZE; ++i) { bucket_B[i] = 0; } + + /* Count the number of occurrences of the first one or two characters of each + type A, B and B* suffix. Moreover, store the beginning position of all + type B* suffixes into the array SA. */ + for(i = n - 1, m = n, c0 = T[n - 1]; 0 <= i;) { + /* type A suffix. */ + do { ++BUCKET_A(c1 = c0); } while((0 <= --i) && ((c0 = T[i]) >= c1)); + if(0 <= i) { + /* type B* suffix. */ + ++BUCKET_BSTAR(c0, c1); + SA[--m] = i; + /* type B suffix. */ + for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) { + ++BUCKET_B(c0, c1); + } + } + } + m = n - m; +/* +note: + A type B* suffix is lexicographically smaller than a type B suffix that + begins with the same first two characters. +*/ + + /* Calculate the index of start/end point of each bucket. */ + for(c0 = 0, i = 0, j = 0; c0 < ALPHABET_SIZE; ++c0) { + t = i + BUCKET_A(c0); + BUCKET_A(c0) = i + j; /* start point */ + i = t + BUCKET_B(c0, c0); + for(c1 = c0 + 1; c1 < ALPHABET_SIZE; ++c1) { + j += BUCKET_BSTAR(c0, c1); + BUCKET_BSTAR(c0, c1) = j; /* end point */ + i += BUCKET_B(c0, c1); + } + } + + if(0 < m) { + /* Sort the type B* suffixes by their first two characters. */ + PAb = SA + n - m; ISAb = SA + m; + for(i = m - 2; 0 <= i; --i) { + t = PAb[i], c0 = T[t], c1 = T[t + 1]; + SA[--BUCKET_BSTAR(c0, c1)] = i; + } + t = PAb[m - 1], c0 = T[t], c1 = T[t + 1]; + SA[--BUCKET_BSTAR(c0, c1)] = m - 1; + + /* Sort the type B* substrings using sssort. */ +#ifdef LIBBSC_OPENMP + if (openMP) + { + buf = SA + m; + c0 = ALPHABET_SIZE - 2, c1 = ALPHABET_SIZE - 1, j = m; +#pragma omp parallel default(shared) private(bufsize, curbuf, k, l, d0, d1) + { + bufsize = (n - (2 * m)) / omp_get_num_threads(); + curbuf = buf + omp_get_thread_num() * bufsize; + k = 0; + for(;;) { + #pragma omp critical(sssort_lock) + { + if(0 < (l = j)) { + d0 = c0, d1 = c1; + do { + k = BUCKET_BSTAR(d0, d1); + if(--d1 <= d0) { + d1 = ALPHABET_SIZE - 1; + if(--d0 < 0) { break; } + } + } while(((l - k) <= 1) && (0 < (l = k))); + c0 = d0, c1 = d1, j = k; + } + } + if(l == 0) { break; } + sssort(T, PAb, SA + k, SA + l, + curbuf, bufsize, 2, n, *(SA + k) == (m - 1)); + } + } + } + else + { + buf = SA + m, bufsize = n - (2 * m); + for(c0 = ALPHABET_SIZE - 2, j = m; 0 < j; --c0) { + for(c1 = ALPHABET_SIZE - 1; c0 < c1; j = i, --c1) { + i = BUCKET_BSTAR(c0, c1); + if(1 < (j - i)) { + sssort(T, PAb, SA + i, SA + j, + buf, bufsize, 2, n, *(SA + i) == (m - 1)); + } + } + } + } +#else + buf = SA + m, bufsize = n - (2 * m); + for(c0 = ALPHABET_SIZE - 2, j = m; 0 < j; --c0) { + for(c1 = ALPHABET_SIZE - 1; c0 < c1; j = i, --c1) { + i = BUCKET_BSTAR(c0, c1); + if(1 < (j - i)) { + sssort(T, PAb, SA + i, SA + j, + buf, bufsize, 2, n, *(SA + i) == (m - 1)); + } + } + } +#endif + + /* Compute ranks of type B* substrings. */ + for(i = m - 1; 0 <= i; --i) { + if(0 <= SA[i]) { + j = i; + do { ISAb[SA[i]] = i; } while((0 <= --i) && (0 <= SA[i])); + SA[i + 1] = i - j; + if(i <= 0) { break; } + } + j = i; + do { ISAb[SA[i] = ~SA[i]] = j; } while(SA[--i] < 0); + ISAb[SA[i]] = j; + } + + /* Construct the inverse suffix array of type B* suffixes using trsort. */ + trsort(ISAb, SA, m, 1); + + /* Set the sorted order of type B* suffixes. */ + for(i = n - 1, j = m, c0 = T[n - 1]; 0 <= i;) { + for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) >= c1); --i, c1 = c0) { } + if(0 <= i) { + t = i; + for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) { } + SA[ISAb[--j]] = ((t == 0) || (1 < (t - i))) ? t : ~t; + } + } + + /* Calculate the index of start/end point of each bucket. */ + BUCKET_B(ALPHABET_SIZE - 1, ALPHABET_SIZE - 1) = n; /* end point */ + for(c0 = ALPHABET_SIZE - 2, k = m - 1; 0 <= c0; --c0) { + i = BUCKET_A(c0 + 1) - 1; + for(c1 = ALPHABET_SIZE - 1; c0 < c1; --c1) { + t = i - BUCKET_B(c0, c1); + BUCKET_B(c0, c1) = i; /* end point */ + + /* Move all type B* suffixes to the correct position. */ + for(i = t, j = BUCKET_BSTAR(c0, c1); + j <= k; + --i, --k) { SA[i] = SA[k]; } + } + BUCKET_BSTAR(c0, c0 + 1) = i - BUCKET_B(c0, c0) + 1; /* start point */ + BUCKET_B(c0, c0) = i; /* end point */ + } + } + + return m; +} + +/* Constructs the suffix array by using the sorted order of type B* suffixes. */ +static +void +construct_SA(const unsigned char *T, int *SA, + int *bucket_A, int *bucket_B, + int n, int m) { + int *i, *j, *k; + int s; + int c0, c1, c2; + + if(0 < m) { + /* Construct the sorted order of type B suffixes by using + the sorted order of type B* suffixes. */ + for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) { + /* Scan the suffix array from right to left. */ + for(i = SA + BUCKET_BSTAR(c1, c1 + 1), + j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1; + i <= j; + --j) { + if(0 < (s = *j)) { + assert(T[s] == c1); + assert(((s + 1) < n) && (T[s] <= T[s + 1])); + assert(T[s - 1] <= T[s]); + *j = ~s; + c0 = T[--s]; + if((0 < s) && (T[s - 1] > c0)) { s = ~s; } + if(c0 != c2) { + if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } + k = SA + BUCKET_B(c2 = c0, c1); + } + assert(k < j); assert(k != NULL); + *k-- = s; + } else { + assert(((s == 0) && (T[s] == c1)) || (s < 0)); + *j = ~s; + } + } + } + } + + /* Construct the suffix array by using + the sorted order of type B suffixes. */ + k = SA + BUCKET_A(c2 = T[n - 1]); + *k++ = (T[n - 2] < c2) ? ~(n - 1) : (n - 1); + /* Scan the suffix array from left to right. */ + for(i = SA, j = SA + n; i < j; ++i) { + if(0 < (s = *i)) { + assert(T[s - 1] >= T[s]); + c0 = T[--s]; + if((s == 0) || (T[s - 1] < c0)) { s = ~s; } + if(c0 != c2) { + BUCKET_A(c2) = k - SA; + k = SA + BUCKET_A(c2 = c0); + } + assert(i < k); + *k++ = s; + } else { + assert(s < 0); + *i = ~s; + } + } +} + +/* Constructs the burrows-wheeler transformed string directly + by using the sorted order of type B* suffixes. */ +static +int +construct_BWT(const unsigned char *T, int *SA, + int *bucket_A, int *bucket_B, + int n, int m) { + int *i, *j, *k, *orig; + int s; + int c0, c1, c2; + + if(0 < m) { + /* Construct the sorted order of type B suffixes by using + the sorted order of type B* suffixes. */ + for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) { + /* Scan the suffix array from right to left. */ + for(i = SA + BUCKET_BSTAR(c1, c1 + 1), + j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1; + i <= j; + --j) { + if(0 < (s = *j)) { + assert(T[s] == c1); + assert(((s + 1) < n) && (T[s] <= T[s + 1])); + assert(T[s - 1] <= T[s]); + c0 = T[--s]; + *j = ~((int)c0); + if((0 < s) && (T[s - 1] > c0)) { s = ~s; } + if(c0 != c2) { + if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } + k = SA + BUCKET_B(c2 = c0, c1); + } + assert(k < j); assert(k != NULL); + *k-- = s; + } else if(s != 0) { + *j = ~s; +#ifndef NDEBUG + } else { + assert(T[s] == c1); +#endif + } + } + } + } + + /* Construct the BWTed string by using + the sorted order of type B suffixes. */ + k = SA + BUCKET_A(c2 = T[n - 1]); + *k++ = (T[n - 2] < c2) ? ~((int)T[n - 2]) : (n - 1); + /* Scan the suffix array from left to right. */ + for(i = SA, j = SA + n, orig = SA; i < j; ++i) { + if(0 < (s = *i)) { + assert(T[s - 1] >= T[s]); + c0 = T[--s]; + *i = c0; + if((0 < s) && (T[s - 1] < c0)) { s = ~((int)T[s - 1]); } + if(c0 != c2) { + BUCKET_A(c2) = k - SA; + k = SA + BUCKET_A(c2 = c0); + } + assert(i < k); + *k++ = s; + } else if(s != 0) { + *i = ~s; + } else { + orig = i; + } + } + + return orig - SA; +} + +/* Constructs the burrows-wheeler transformed string directly + by using the sorted order of type B* suffixes. */ +static +int +construct_BWT_indexes(const unsigned char *T, int *SA, + int *bucket_A, int *bucket_B, + int n, int m, + unsigned char * num_indexes, int * indexes) { + int *i, *j, *k, *orig; + int s; + int c0, c1, c2; + + int mod = n / 8; + { + mod |= mod >> 1; mod |= mod >> 2; + mod |= mod >> 4; mod |= mod >> 8; + mod |= mod >> 16; mod >>= 1; + + *num_indexes = (unsigned char)((n - 1) / (mod + 1)); + } + + if(0 < m) { + /* Construct the sorted order of type B suffixes by using + the sorted order of type B* suffixes. */ + for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) { + /* Scan the suffix array from right to left. */ + for(i = SA + BUCKET_BSTAR(c1, c1 + 1), + j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1; + i <= j; + --j) { + if(0 < (s = *j)) { + assert(T[s] == c1); + assert(((s + 1) < n) && (T[s] <= T[s + 1])); + assert(T[s - 1] <= T[s]); + + if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = j - SA; + + c0 = T[--s]; + *j = ~((int)c0); + if((0 < s) && (T[s - 1] > c0)) { s = ~s; } + if(c0 != c2) { + if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } + k = SA + BUCKET_B(c2 = c0, c1); + } + assert(k < j); assert(k != NULL); + *k-- = s; + } else if(s != 0) { + *j = ~s; +#ifndef NDEBUG + } else { + assert(T[s] == c1); +#endif + } + } + } + } + + /* Construct the BWTed string by using + the sorted order of type B suffixes. */ + k = SA + BUCKET_A(c2 = T[n - 1]); + if (T[n - 2] < c2) { + if (((n - 1) & mod) == 0) indexes[(n - 1) / (mod + 1) - 1] = k - SA; + *k++ = ~((int)T[n - 2]); + } + else { + *k++ = n - 1; + } + + /* Scan the suffix array from left to right. */ + for(i = SA, j = SA + n, orig = SA; i < j; ++i) { + if(0 < (s = *i)) { + assert(T[s - 1] >= T[s]); + + if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = i - SA; + + c0 = T[--s]; + *i = c0; + if(c0 != c2) { + BUCKET_A(c2) = k - SA; + k = SA + BUCKET_A(c2 = c0); + } + assert(i < k); + if((0 < s) && (T[s - 1] < c0)) { + if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = k - SA; + *k++ = ~((int)T[s - 1]); + } else + *k++ = s; + } else if(s != 0) { + *i = ~s; + } else { + orig = i; + } + } + + return orig - SA; +} + + +/*---------------------------------------------------------------------------*/ + +/*- Function -*/ + +int +divsufsort(const unsigned char *T, int *SA, int n, int openMP) { + int *bucket_A, *bucket_B; + int m; + int err = 0; + + /* Check arguments. */ + if((T == NULL) || (SA == NULL) || (n < 0)) { return -1; } + else if(n == 0) { return 0; } + else if(n == 1) { SA[0] = 0; return 0; } + else if(n == 2) { m = (T[0] < T[1]); SA[m ^ 1] = 0, SA[m] = 1; return 0; } + + bucket_A = (int *)malloc(BUCKET_A_SIZE * sizeof(int)); + bucket_B = (int *)malloc(BUCKET_B_SIZE * sizeof(int)); + + /* Suffixsort. */ + if((bucket_A != NULL) && (bucket_B != NULL)) { + m = sort_typeBstar(T, SA, bucket_A, bucket_B, n, openMP); + construct_SA(T, SA, bucket_A, bucket_B, n, m); + } else { + err = -2; + } + + free(bucket_B); + free(bucket_A); + + return err; +} + +int +divbwt(const unsigned char *T, unsigned char *U, int *A, int n, unsigned char * num_indexes, int * indexes, int openMP) { + int *B; + int *bucket_A, *bucket_B; + int m, pidx, i; + + /* Check arguments. */ + if((T == NULL) || (U == NULL) || (n < 0)) { return -1; } + else if(n <= 1) { if(n == 1) { U[0] = T[0]; } return n; } + + if((B = A) == NULL) { B = (int *)malloc((size_t)(n + 1) * sizeof(int)); } + bucket_A = (int *)malloc(BUCKET_A_SIZE * sizeof(int)); + bucket_B = (int *)malloc(BUCKET_B_SIZE * sizeof(int)); + + /* Burrows-Wheeler Transform. */ + if((B != NULL) && (bucket_A != NULL) && (bucket_B != NULL)) { + m = sort_typeBstar(T, B, bucket_A, bucket_B, n, openMP); + + if (num_indexes == NULL || indexes == NULL) { + pidx = construct_BWT(T, B, bucket_A, bucket_B, n, m); + } else { + pidx = construct_BWT_indexes(T, B, bucket_A, bucket_B, n, m, num_indexes, indexes); + } + + /* Copy to output string. */ + U[0] = T[n - 1]; + for(i = 0; i < pidx; ++i) { U[i + 1] = (unsigned char)B[i]; } + for(i += 1; i < n; ++i) { U[i] = (unsigned char)B[i]; } + pidx += 1; + } else { + pidx = -2; + } + + free(bucket_B); + free(bucket_A); + if(A == NULL) { free(B); } + + return pidx; +} + +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/dict/fastcover.cpp b/src/duckdb/third_party/zstd/dict/fastcover.cpp new file mode 100644 index 000000000..b3d103125 --- /dev/null +++ b/src/duckdb/third_party/zstd/dict/fastcover.cpp @@ -0,0 +1,769 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/*-************************************* +* Dependencies +***************************************/ +#include /* fprintf */ +#include /* malloc, free, qsort */ +#include /* memset */ +#include /* clock */ + +#ifndef ZDICT_STATIC_LINKING_ONLY +# define ZDICT_STATIC_LINKING_ONLY +#endif + +#include "zstd/common/mem.h" /* read */ +#include "zstd/common/pool.h" +#include "zstd/common/threading.h" +#include "zstd/common/zstd_internal.h" /* includes zstd.h */ +#include "zstd/compress/zstd_compress_internal.h" /* ZSTD_hash*() */ +#include "zdict.h" +#include "zstd/dict/cover.h" + + +/*-************************************* +* Constants +***************************************/ +/** +* There are 32bit indexes used to ref samples, so limit samples size to 4GB +* on 64bit builds. +* For 32bit builds we choose 1 GB. +* Most 32bit platforms have 2GB user-mode addressable space and we allocate a large +* contiguous buffer, so 1GB is already a high limit. +*/ +#define FASTCOVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB)) +#define FASTCOVER_MAX_F 31 +#define FASTCOVER_MAX_ACCEL 10 +#define FASTCOVER_DEFAULT_SPLITPOINT 0.75 +#define DEFAULT_F 20 +#define DEFAULT_ACCEL 1 + +namespace duckdb_zstd { + +/*-************************************* +* Console display +***************************************/ +#ifndef LOCALDISPLAYLEVEL +static int g_displayLevel = 0; +#endif +#undef DISPLAY +#define DISPLAY(...) \ + { \ + fprintf(stderr, __VA_ARGS__); \ + fflush(stderr); \ + } +#undef LOCALDISPLAYLEVEL +#define LOCALDISPLAYLEVEL(displayLevel, l, ...) \ + if (displayLevel >= l) { \ + DISPLAY(__VA_ARGS__); \ + } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */ +#undef DISPLAYLEVEL +#define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__) + +#ifndef LOCALDISPLAYUPDATE +static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100; +static clock_t g_time = 0; +#endif +#undef LOCALDISPLAYUPDATE +#define LOCALDISPLAYUPDATE(displayLevel, l, ...) \ + if (displayLevel >= l) { \ + if ((clock() - g_time > g_refreshRate) || (displayLevel >= 4)) { \ + g_time = clock(); \ + DISPLAY(__VA_ARGS__); \ + } \ + } +#undef DISPLAYUPDATE +#define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__) + + +/*-************************************* +* Hash Functions +***************************************/ +/** + * Hash the d-byte value pointed to by p and mod 2^f into the frequency vector + */ +static size_t FASTCOVER_hashPtrToIndex(const void* p, U32 f, unsigned d) { + if (d == 6) { + return ZSTD_hash6Ptr(p, f); + } + return ZSTD_hash8Ptr(p, f); +} + + +/*-************************************* +* Acceleration +***************************************/ +typedef struct { + unsigned finalize; /* Percentage of training samples used for ZDICT_finalizeDictionary */ + unsigned skip; /* Number of dmer skipped between each dmer counted in computeFrequency */ +} FASTCOVER_accel_t; + + +static const FASTCOVER_accel_t FASTCOVER_defaultAccelParameters[FASTCOVER_MAX_ACCEL+1] = { + { 100, 0 }, /* accel = 0, should not happen because accel = 0 defaults to accel = 1 */ + { 100, 0 }, /* accel = 1 */ + { 50, 1 }, /* accel = 2 */ + { 34, 2 }, /* accel = 3 */ + { 25, 3 }, /* accel = 4 */ + { 20, 4 }, /* accel = 5 */ + { 17, 5 }, /* accel = 6 */ + { 14, 6 }, /* accel = 7 */ + { 13, 7 }, /* accel = 8 */ + { 11, 8 }, /* accel = 9 */ + { 10, 9 }, /* accel = 10 */ +}; + + +/*-************************************* +* Context +***************************************/ +typedef struct { + const BYTE *samples; + size_t *offsets; + const size_t *samplesSizes; + size_t nbSamples; + size_t nbTrainSamples; + size_t nbTestSamples; + size_t nbDmers; + U32 *freqs; + unsigned d; + unsigned f; + FASTCOVER_accel_t accelParams; +} FASTCOVER_ctx_t; + + +/*-************************************* +* Helper functions +***************************************/ +/** + * Selects the best segment in an epoch. + * Segments of are scored according to the function: + * + * Let F(d) be the frequency of all dmers with hash value d. + * Let S_i be hash value of the dmer at position i of segment S which has length k. + * + * Score(S) = F(S_1) + F(S_2) + ... + F(S_{k-d+1}) + * + * Once the dmer with hash value d is in the dictionary we set F(d) = 0. + */ +static COVER_segment_t FASTCOVER_selectSegment(const FASTCOVER_ctx_t *ctx, + U32 *freqs, U32 begin, U32 end, + ZDICT_cover_params_t parameters, + U16* segmentFreqs) { + /* Constants */ + const U32 k = parameters.k; + const U32 d = parameters.d; + const U32 f = ctx->f; + const U32 dmersInK = k - d + 1; + + /* Try each segment (activeSegment) and save the best (bestSegment) */ + COVER_segment_t bestSegment = {0, 0, 0}; + COVER_segment_t activeSegment; + + /* Reset the activeDmers in the segment */ + /* The activeSegment starts at the beginning of the epoch. */ + activeSegment.begin = begin; + activeSegment.end = begin; + activeSegment.score = 0; + + /* Slide the activeSegment through the whole epoch. + * Save the best segment in bestSegment. + */ + while (activeSegment.end < end) { + /* Get hash value of current dmer */ + const size_t idx = FASTCOVER_hashPtrToIndex(ctx->samples + activeSegment.end, f, d); + + /* Add frequency of this index to score if this is the first occurrence of index in active segment */ + if (segmentFreqs[idx] == 0) { + activeSegment.score += freqs[idx]; + } + /* Increment end of segment and segmentFreqs*/ + activeSegment.end += 1; + segmentFreqs[idx] += 1; + /* If the window is now too large, drop the first position */ + if (activeSegment.end - activeSegment.begin == dmersInK + 1) { + /* Get hash value of the dmer to be eliminated from active segment */ + const size_t delIndex = FASTCOVER_hashPtrToIndex(ctx->samples + activeSegment.begin, f, d); + segmentFreqs[delIndex] -= 1; + /* Subtract frequency of this index from score if this is the last occurrence of this index in active segment */ + if (segmentFreqs[delIndex] == 0) { + activeSegment.score -= freqs[delIndex]; + } + /* Increment start of segment */ + activeSegment.begin += 1; + } + + /* If this segment is the best so far save it */ + if (activeSegment.score > bestSegment.score) { + bestSegment = activeSegment; + } + } + + /* Zero out rest of segmentFreqs array */ + while (activeSegment.begin < end) { + const size_t delIndex = FASTCOVER_hashPtrToIndex(ctx->samples + activeSegment.begin, f, d); + segmentFreqs[delIndex] -= 1; + activeSegment.begin += 1; + } + + { + /* Zero the frequency of hash value of each dmer covered by the chosen segment. */ + U32 pos; + for (pos = bestSegment.begin; pos != bestSegment.end; ++pos) { + const size_t i = FASTCOVER_hashPtrToIndex(ctx->samples + pos, f, d); + freqs[i] = 0; + } + } + + return bestSegment; +} + + +static int FASTCOVER_checkParameters(ZDICT_cover_params_t parameters, + size_t maxDictSize, unsigned f, + unsigned accel) { + /* k, d, and f are required parameters */ + if (parameters.d == 0 || parameters.k == 0) { + return 0; + } + /* d has to be 6 or 8 */ + if (parameters.d != 6 && parameters.d != 8) { + return 0; + } + /* k <= maxDictSize */ + if (parameters.k > maxDictSize) { + return 0; + } + /* d <= k */ + if (parameters.d > parameters.k) { + return 0; + } + /* 0 < f <= FASTCOVER_MAX_F*/ + if (f > FASTCOVER_MAX_F || f == 0) { + return 0; + } + /* 0 < splitPoint <= 1 */ + if (parameters.splitPoint <= 0 || parameters.splitPoint > 1) { + return 0; + } + /* 0 < accel <= 10 */ + if (accel > 10 || accel == 0) { + return 0; + } + return 1; +} + + +/** + * Clean up a context initialized with `FASTCOVER_ctx_init()`. + */ +static void +FASTCOVER_ctx_destroy(FASTCOVER_ctx_t* ctx) +{ + if (!ctx) return; + + free(ctx->freqs); + ctx->freqs = NULL; + + free(ctx->offsets); + ctx->offsets = NULL; +} + + +/** + * Calculate for frequency of hash value of each dmer in ctx->samples + */ +static void +FASTCOVER_computeFrequency(U32* freqs, const FASTCOVER_ctx_t* ctx) +{ + const unsigned f = ctx->f; + const unsigned d = ctx->d; + const unsigned skip = ctx->accelParams.skip; + const unsigned readLength = MAX(d, 8); + size_t i; + assert(ctx->nbTrainSamples >= 5); + assert(ctx->nbTrainSamples <= ctx->nbSamples); + for (i = 0; i < ctx->nbTrainSamples; i++) { + size_t start = ctx->offsets[i]; /* start of current dmer */ + size_t const currSampleEnd = ctx->offsets[i+1]; + while (start + readLength <= currSampleEnd) { + const size_t dmerIndex = FASTCOVER_hashPtrToIndex(ctx->samples + start, f, d); + freqs[dmerIndex]++; + start = start + skip + 1; + } + } +} + + +/** + * Prepare a context for dictionary building. + * The context is only dependent on the parameter `d` and can be used multiple + * times. + * Returns 0 on success or error code on error. + * The context must be destroyed with `FASTCOVER_ctx_destroy()`. + */ +static size_t +FASTCOVER_ctx_init(FASTCOVER_ctx_t* ctx, + const void* samplesBuffer, + const size_t* samplesSizes, unsigned nbSamples, + unsigned d, double splitPoint, unsigned f, + FASTCOVER_accel_t accelParams) +{ + const BYTE* const samples = (const BYTE*)samplesBuffer; + const size_t totalSamplesSize = COVER_sum(samplesSizes, nbSamples); + /* Split samples into testing and training sets */ + const unsigned nbTrainSamples = splitPoint < 1.0 ? (unsigned)((double)nbSamples * splitPoint) : nbSamples; + const unsigned nbTestSamples = splitPoint < 1.0 ? nbSamples - nbTrainSamples : nbSamples; + const size_t trainingSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes, nbTrainSamples) : totalSamplesSize; + const size_t testSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes + nbTrainSamples, nbTestSamples) : totalSamplesSize; + + /* Checks */ + if (totalSamplesSize < MAX(d, sizeof(U64)) || + totalSamplesSize >= (size_t)FASTCOVER_MAX_SAMPLES_SIZE) { + DISPLAYLEVEL(1, "Total samples size is too large (%u MB), maximum size is %u MB\n", + (unsigned)(totalSamplesSize >> 20), (FASTCOVER_MAX_SAMPLES_SIZE >> 20)); + return ERROR(srcSize_wrong); + } + + /* Check if there are at least 5 training samples */ + if (nbTrainSamples < 5) { + DISPLAYLEVEL(1, "Total number of training samples is %u and is invalid\n", nbTrainSamples); + return ERROR(srcSize_wrong); + } + + /* Check if there's testing sample */ + if (nbTestSamples < 1) { + DISPLAYLEVEL(1, "Total number of testing samples is %u and is invalid.\n", nbTestSamples); + return ERROR(srcSize_wrong); + } + + /* Zero the context */ + memset(ctx, 0, sizeof(*ctx)); + DISPLAYLEVEL(2, "Training on %u samples of total size %u\n", nbTrainSamples, + (unsigned)trainingSamplesSize); + DISPLAYLEVEL(2, "Testing on %u samples of total size %u\n", nbTestSamples, + (unsigned)testSamplesSize); + + ctx->samples = samples; + ctx->samplesSizes = samplesSizes; + ctx->nbSamples = nbSamples; + ctx->nbTrainSamples = nbTrainSamples; + ctx->nbTestSamples = nbTestSamples; + ctx->nbDmers = trainingSamplesSize - MAX(d, sizeof(U64)) + 1; + ctx->d = d; + ctx->f = f; + ctx->accelParams = accelParams; + + /* The offsets of each file */ + ctx->offsets = (size_t*)calloc((nbSamples + 1), sizeof(size_t)); + if (ctx->offsets == NULL) { + DISPLAYLEVEL(1, "Failed to allocate scratch buffers \n"); + FASTCOVER_ctx_destroy(ctx); + return ERROR(memory_allocation); + } + + /* Fill offsets from the samplesSizes */ + { U32 i; + ctx->offsets[0] = 0; + assert(nbSamples >= 5); + for (i = 1; i <= nbSamples; ++i) { + ctx->offsets[i] = ctx->offsets[i - 1] + samplesSizes[i - 1]; + } + } + + /* Initialize frequency array of size 2^f */ + ctx->freqs = (U32*)calloc(((U64)1 << f), sizeof(U32)); + if (ctx->freqs == NULL) { + DISPLAYLEVEL(1, "Failed to allocate frequency table \n"); + FASTCOVER_ctx_destroy(ctx); + return ERROR(memory_allocation); + } + + DISPLAYLEVEL(2, "Computing frequencies\n"); + FASTCOVER_computeFrequency(ctx->freqs, ctx); + + return 0; +} + + +/** + * Given the prepared context build the dictionary. + */ +static size_t +FASTCOVER_buildDictionary(const FASTCOVER_ctx_t* ctx, + U32* freqs, + void* dictBuffer, size_t dictBufferCapacity, + ZDICT_cover_params_t parameters, + U16* segmentFreqs) +{ + BYTE *const dict = (BYTE *)dictBuffer; + size_t tail = dictBufferCapacity; + /* Divide the data into epochs. We will select one segment from each epoch. */ + const COVER_epoch_info_t epochs = COVER_computeEpochs( + (U32)dictBufferCapacity, (U32)ctx->nbDmers, parameters.k, 1); + const size_t maxZeroScoreRun = 10; + size_t zeroScoreRun = 0; + size_t epoch; + DISPLAYLEVEL(2, "Breaking content into %u epochs of size %u\n", + (U32)epochs.num, (U32)epochs.size); + /* Loop through the epochs until there are no more segments or the dictionary + * is full. + */ + for (epoch = 0; tail > 0; epoch = (epoch + 1) % epochs.num) { + const U32 epochBegin = (U32)(epoch * epochs.size); + const U32 epochEnd = epochBegin + epochs.size; + size_t segmentSize; + /* Select a segment */ + COVER_segment_t segment = FASTCOVER_selectSegment( + ctx, freqs, epochBegin, epochEnd, parameters, segmentFreqs); + + /* If the segment covers no dmers, then we are out of content. + * There may be new content in other epochs, for continue for some time. + */ + if (segment.score == 0) { + if (++zeroScoreRun >= maxZeroScoreRun) { + break; + } + continue; + } + zeroScoreRun = 0; + + /* Trim the segment if necessary and if it is too small then we are done */ + segmentSize = MIN(segment.end - segment.begin + parameters.d - 1, tail); + if (segmentSize < parameters.d) { + break; + } + + /* We fill the dictionary from the back to allow the best segments to be + * referenced with the smallest offsets. + */ + tail -= segmentSize; + memcpy(dict + tail, ctx->samples + segment.begin, segmentSize); + DISPLAYUPDATE( + 2, "\r%u%% ", + (unsigned)(((dictBufferCapacity - tail) * 100) / dictBufferCapacity)); + } + DISPLAYLEVEL(2, "\r%79s\r", ""); + return tail; +} + +/** + * Parameters for FASTCOVER_tryParameters(). + */ +typedef struct FASTCOVER_tryParameters_data_s { + const FASTCOVER_ctx_t* ctx; + COVER_best_t* best; + size_t dictBufferCapacity; + ZDICT_cover_params_t parameters; +} FASTCOVER_tryParameters_data_t; + + +/** + * Tries a set of parameters and updates the COVER_best_t with the results. + * This function is thread safe if zstd is compiled with multithreaded support. + * It takes its parameters as an *OWNING* opaque pointer to support threading. + */ +static void FASTCOVER_tryParameters(void* opaque) +{ + /* Save parameters as local variables */ + FASTCOVER_tryParameters_data_t *const data = (FASTCOVER_tryParameters_data_t*)opaque; + const FASTCOVER_ctx_t *const ctx = data->ctx; + const ZDICT_cover_params_t parameters = data->parameters; + size_t dictBufferCapacity = data->dictBufferCapacity; + size_t totalCompressedSize = ERROR(GENERIC); + /* Initialize array to keep track of frequency of dmer within activeSegment */ + U16* segmentFreqs = (U16*)calloc(((U64)1 << ctx->f), sizeof(U16)); + /* Allocate space for hash table, dict, and freqs */ + BYTE *const dict = (BYTE*)malloc(dictBufferCapacity); + COVER_dictSelection_t selection = COVER_dictSelectionError(ERROR(GENERIC)); + U32* freqs = (U32*) malloc(((U64)1 << ctx->f) * sizeof(U32)); + if (!segmentFreqs || !dict || !freqs) { + DISPLAYLEVEL(1, "Failed to allocate buffers: out of memory\n"); + goto _cleanup; + } + /* Copy the frequencies because we need to modify them */ + memcpy(freqs, ctx->freqs, ((U64)1 << ctx->f) * sizeof(U32)); + /* Build the dictionary */ + { const size_t tail = FASTCOVER_buildDictionary(ctx, freqs, dict, dictBufferCapacity, + parameters, segmentFreqs); + + const unsigned nbFinalizeSamples = (unsigned)(ctx->nbTrainSamples * ctx->accelParams.finalize / 100); + selection = COVER_selectDict(dict + tail, dictBufferCapacity, dictBufferCapacity - tail, + ctx->samples, ctx->samplesSizes, nbFinalizeSamples, ctx->nbTrainSamples, ctx->nbSamples, parameters, ctx->offsets, + totalCompressedSize); + + if (COVER_dictSelectionIsError(selection)) { + DISPLAYLEVEL(1, "Failed to select dictionary\n"); + goto _cleanup; + } + } +_cleanup: + free(dict); + COVER_best_finish(data->best, parameters, selection); + free(data); + free(segmentFreqs); + COVER_dictSelectionFree(selection); + free(freqs); +} + + +static void +FASTCOVER_convertToCoverParams(ZDICT_fastCover_params_t fastCoverParams, + ZDICT_cover_params_t* coverParams) +{ + coverParams->k = fastCoverParams.k; + coverParams->d = fastCoverParams.d; + coverParams->steps = fastCoverParams.steps; + coverParams->nbThreads = fastCoverParams.nbThreads; + coverParams->splitPoint = fastCoverParams.splitPoint; + coverParams->zParams = fastCoverParams.zParams; + coverParams->shrinkDict = fastCoverParams.shrinkDict; +} + + +static void +FASTCOVER_convertToFastCoverParams(ZDICT_cover_params_t coverParams, + ZDICT_fastCover_params_t* fastCoverParams, + unsigned f, unsigned accel) +{ + fastCoverParams->k = coverParams.k; + fastCoverParams->d = coverParams.d; + fastCoverParams->steps = coverParams.steps; + fastCoverParams->nbThreads = coverParams.nbThreads; + fastCoverParams->splitPoint = coverParams.splitPoint; + fastCoverParams->f = f; + fastCoverParams->accel = accel; + fastCoverParams->zParams = coverParams.zParams; + fastCoverParams->shrinkDict = coverParams.shrinkDict; +} + + +ZDICTLIB_STATIC_API size_t +ZDICT_trainFromBuffer_fastCover(void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, + const size_t* samplesSizes, unsigned nbSamples, + ZDICT_fastCover_params_t parameters) +{ + BYTE* const dict = (BYTE*)dictBuffer; + FASTCOVER_ctx_t ctx; + ZDICT_cover_params_t coverParams; + FASTCOVER_accel_t accelParams; + /* Initialize global data */ + g_displayLevel = (int)parameters.zParams.notificationLevel; + /* Assign splitPoint and f if not provided */ + parameters.splitPoint = 1.0; + parameters.f = parameters.f == 0 ? DEFAULT_F : parameters.f; + parameters.accel = parameters.accel == 0 ? DEFAULT_ACCEL : parameters.accel; + /* Convert to cover parameter */ + memset(&coverParams, 0 , sizeof(coverParams)); + FASTCOVER_convertToCoverParams(parameters, &coverParams); + /* Checks */ + if (!FASTCOVER_checkParameters(coverParams, dictBufferCapacity, parameters.f, + parameters.accel)) { + DISPLAYLEVEL(1, "FASTCOVER parameters incorrect\n"); + return ERROR(parameter_outOfBound); + } + if (nbSamples == 0) { + DISPLAYLEVEL(1, "FASTCOVER must have at least one input file\n"); + return ERROR(srcSize_wrong); + } + if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) { + DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n", + ZDICT_DICTSIZE_MIN); + return ERROR(dstSize_tooSmall); + } + /* Assign corresponding FASTCOVER_accel_t to accelParams*/ + accelParams = FASTCOVER_defaultAccelParameters[parameters.accel]; + /* Initialize context */ + { + size_t const initVal = FASTCOVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, + coverParams.d, parameters.splitPoint, parameters.f, + accelParams); + if (ZSTD_isError(initVal)) { + DISPLAYLEVEL(1, "Failed to initialize context\n"); + return initVal; + } + } + COVER_warnOnSmallCorpus(dictBufferCapacity, ctx.nbDmers, g_displayLevel); + /* Build the dictionary */ + DISPLAYLEVEL(2, "Building dictionary\n"); + { + /* Initialize array to keep track of frequency of dmer within activeSegment */ + U16* segmentFreqs = (U16 *)calloc(((U64)1 << parameters.f), sizeof(U16)); + const size_t tail = FASTCOVER_buildDictionary(&ctx, ctx.freqs, dictBuffer, + dictBufferCapacity, coverParams, segmentFreqs); + const unsigned nbFinalizeSamples = (unsigned)(ctx.nbTrainSamples * ctx.accelParams.finalize / 100); + const size_t dictionarySize = ZDICT_finalizeDictionary( + dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail, + samplesBuffer, samplesSizes, nbFinalizeSamples, coverParams.zParams); + if (!ZSTD_isError(dictionarySize)) { + DISPLAYLEVEL(2, "Constructed dictionary of size %u\n", + (unsigned)dictionarySize); + } + FASTCOVER_ctx_destroy(&ctx); + free(segmentFreqs); + return dictionarySize; + } +} + + +ZDICTLIB_STATIC_API size_t +ZDICT_optimizeTrainFromBuffer_fastCover( + void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, + const size_t* samplesSizes, unsigned nbSamples, + ZDICT_fastCover_params_t* parameters) +{ + ZDICT_cover_params_t coverParams; + FASTCOVER_accel_t accelParams; + /* constants */ + const unsigned nbThreads = parameters->nbThreads; + const double splitPoint = + parameters->splitPoint <= 0.0 ? FASTCOVER_DEFAULT_SPLITPOINT : parameters->splitPoint; + const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d; + const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d; + const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k; + const unsigned kMaxK = parameters->k == 0 ? 2000 : parameters->k; + const unsigned kSteps = parameters->steps == 0 ? 40 : parameters->steps; + const unsigned kStepSize = MAX((kMaxK - kMinK) / kSteps, 1); + const unsigned kIterations = + (1 + (kMaxD - kMinD) / 2) * (1 + (kMaxK - kMinK) / kStepSize); + const unsigned f = parameters->f == 0 ? DEFAULT_F : parameters->f; + const unsigned accel = parameters->accel == 0 ? DEFAULT_ACCEL : parameters->accel; + const unsigned shrinkDict = 0; + /* Local variables */ + const int displayLevel = (int)parameters->zParams.notificationLevel; + unsigned iteration = 1; + unsigned d; + unsigned k; + COVER_best_t best; + POOL_ctx *pool = NULL; + int warned = 0; + /* Checks */ + if (splitPoint <= 0 || splitPoint > 1) { + LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect splitPoint\n"); + return ERROR(parameter_outOfBound); + } + if (accel == 0 || accel > FASTCOVER_MAX_ACCEL) { + LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect accel\n"); + return ERROR(parameter_outOfBound); + } + if (kMinK < kMaxD || kMaxK < kMinK) { + LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect k\n"); + return ERROR(parameter_outOfBound); + } + if (nbSamples == 0) { + LOCALDISPLAYLEVEL(displayLevel, 1, "FASTCOVER must have at least one input file\n"); + return ERROR(srcSize_wrong); + } + if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) { + LOCALDISPLAYLEVEL(displayLevel, 1, "dictBufferCapacity must be at least %u\n", + ZDICT_DICTSIZE_MIN); + return ERROR(dstSize_tooSmall); + } + if (nbThreads > 1) { + pool = POOL_create(nbThreads, 1); + if (!pool) { + return ERROR(memory_allocation); + } + } + /* Initialization */ + COVER_best_init(&best); + memset(&coverParams, 0 , sizeof(coverParams)); + FASTCOVER_convertToCoverParams(*parameters, &coverParams); + accelParams = FASTCOVER_defaultAccelParameters[accel]; + /* Turn down global display level to clean up display at level 2 and below */ + g_displayLevel = displayLevel == 0 ? 0 : displayLevel - 1; + /* Loop through d first because each new value needs a new context */ + LOCALDISPLAYLEVEL(displayLevel, 2, "Trying %u different sets of parameters\n", + kIterations); + for (d = kMinD; d <= kMaxD; d += 2) { + /* Initialize the context for this value of d */ + FASTCOVER_ctx_t ctx; + LOCALDISPLAYLEVEL(displayLevel, 3, "d=%u\n", d); + { + size_t const initVal = FASTCOVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, d, splitPoint, f, accelParams); + if (ZSTD_isError(initVal)) { + LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to initialize context\n"); + COVER_best_destroy(&best); + POOL_free(pool); + return initVal; + } + } + if (!warned) { + COVER_warnOnSmallCorpus(dictBufferCapacity, ctx.nbDmers, displayLevel); + warned = 1; + } + /* Loop through k reusing the same context */ + for (k = kMinK; k <= kMaxK; k += kStepSize) { + /* Prepare the arguments */ + FASTCOVER_tryParameters_data_t *data = (FASTCOVER_tryParameters_data_t *)malloc( + sizeof(FASTCOVER_tryParameters_data_t)); + LOCALDISPLAYLEVEL(displayLevel, 3, "k=%u\n", k); + if (!data) { + LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to allocate parameters\n"); + COVER_best_destroy(&best); + FASTCOVER_ctx_destroy(&ctx); + POOL_free(pool); + return ERROR(memory_allocation); + } + data->ctx = &ctx; + data->best = &best; + data->dictBufferCapacity = dictBufferCapacity; + data->parameters = coverParams; + data->parameters.k = k; + data->parameters.d = d; + data->parameters.splitPoint = splitPoint; + data->parameters.steps = kSteps; + data->parameters.shrinkDict = shrinkDict; + data->parameters.zParams.notificationLevel = (unsigned)g_displayLevel; + /* Check the parameters */ + if (!FASTCOVER_checkParameters(data->parameters, dictBufferCapacity, + data->ctx->f, accel)) { + DISPLAYLEVEL(1, "FASTCOVER parameters incorrect\n"); + free(data); + continue; + } + /* Call the function and pass ownership of data to it */ + COVER_best_start(&best); + if (pool) { + POOL_add(pool, &FASTCOVER_tryParameters, data); + } else { + FASTCOVER_tryParameters(data); + } + /* Print status */ + LOCALDISPLAYUPDATE(displayLevel, 2, "\r%u%% ", + (unsigned)((iteration * 100) / kIterations)); + ++iteration; + } + COVER_best_wait(&best); + FASTCOVER_ctx_destroy(&ctx); + } + LOCALDISPLAYLEVEL(displayLevel, 2, "\r%79s\r", ""); + /* Fill the output buffer and parameters with output of the best parameters */ + { + const size_t dictSize = best.dictSize; + if (ZSTD_isError(best.compressedSize)) { + const size_t compressedSize = best.compressedSize; + COVER_best_destroy(&best); + POOL_free(pool); + return compressedSize; + } + FASTCOVER_convertToFastCoverParams(best.parameters, parameters, f, accel); + memcpy(dictBuffer, best.dict, dictSize); + COVER_best_destroy(&best); + POOL_free(pool); + return dictSize; + } + +} + +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/dict/zdict.cpp b/src/duckdb/third_party/zstd/dict/zdict.cpp new file mode 100644 index 000000000..7381e505d --- /dev/null +++ b/src/duckdb/third_party/zstd/dict/zdict.cpp @@ -0,0 +1,1136 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +/*-************************************** +* Tuning parameters +****************************************/ +#define MINRATIO 4 /* minimum nb of apparition to be selected in dictionary */ +#define ZDICT_MAX_SAMPLES_SIZE (2000U << 20) +#define ZDICT_MIN_SAMPLES_SIZE (ZDICT_CONTENTSIZE_MIN * MINRATIO) + + +/*-************************************** +* Compiler Options +****************************************/ +/* Unix Large Files support (>4GB) */ +#define _FILE_OFFSET_BITS 64 +#if (defined(__sun__) && (!defined(__LP64__))) /* Sun Solaris 32-bits requires specific definitions */ +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE +# endif +#elif ! defined(__LP64__) /* No point defining Large file for 64 bit */ +# ifndef _LARGEFILE64_SOURCE +# define _LARGEFILE64_SOURCE +# endif +#endif + + +/*-************************************* +* Dependencies +***************************************/ +#include /* malloc, free */ +#include /* memset */ +#include /* fprintf, fopen, ftello64 */ +#include /* clock */ + +#ifndef ZDICT_STATIC_LINKING_ONLY +# define ZDICT_STATIC_LINKING_ONLY +#endif + +#include "zstd/common/mem.h" /* read */ +#include "zstd/common/fse.h" /* FSE_normalizeCount, FSE_writeNCount */ +#include "zstd/common/huf.h" /* HUF_buildCTable, HUF_writeCTable */ +#include "zstd/common/zstd_internal.h" /* includes zstd.h */ +#include "zstd/common/xxhash.hpp" /* XXH64 */ +#include "zstd/compress/zstd_compress_internal.h" /* ZSTD_loadCEntropy() */ +#include "zdict.h" +#include "zstd/dict/divsufsort.h" +#include "zstd/common/bits.h" /* ZSTD_NbCommonBytes */ + +namespace duckdb_zstd { + +/*-************************************* +* Constants +***************************************/ +#define KB *(1 <<10) +#define MB *(1 <<20) +#define GB *(1U<<30) + +#define DICTLISTSIZE_DEFAULT 10000 + +#define NOISELENGTH 32 + +static const U32 g_selectivity_default = 9; + + +/*-************************************* +* Console display +***************************************/ +#undef DISPLAY +#define DISPLAY(...) do { fprintf(stderr, __VA_ARGS__); fflush( stderr ); } while (0) +#undef DISPLAYLEVEL +#define DISPLAYLEVEL(l, ...) do { if (notificationLevel>=l) { DISPLAY(__VA_ARGS__); } } while (0) /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */ + +static clock_t ZDICT_clockSpan(clock_t nPrevious) { return clock() - nPrevious; } + +static void ZDICT_printHex(const void* ptr, size_t length) +{ + const BYTE* const b = (const BYTE*)ptr; + size_t u; + for (u=0; u126) c = '.'; /* non-printable char */ + DISPLAY("%c", c); + } +} + + +/*-******************************************************** +* Helper functions +**********************************************************/ +unsigned ZDICT_isError(size_t errorCode) { return ERR_isError(errorCode); } + +const char* ZDICT_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); } + +unsigned ZDICT_getDictID(const void* dictBuffer, size_t dictSize) +{ + if (dictSize < 8) return 0; + if (MEM_readLE32(dictBuffer) != ZSTD_MAGIC_DICTIONARY) return 0; + return MEM_readLE32((const char*)dictBuffer + 4); +} + +size_t ZDICT_getDictHeaderSize(const void* dictBuffer, size_t dictSize) +{ + size_t headerSize; + if (dictSize <= 8 || MEM_readLE32(dictBuffer) != ZSTD_MAGIC_DICTIONARY) return ERROR(dictionary_corrupted); + + { ZSTD_compressedBlockState_t* bs = (ZSTD_compressedBlockState_t*)malloc(sizeof(ZSTD_compressedBlockState_t)); + U32* wksp = (U32*)malloc(HUF_WORKSPACE_SIZE); + if (!bs || !wksp) { + headerSize = ERROR(memory_allocation); + } else { + ZSTD_reset_compressedBlockState(bs); + headerSize = ZSTD_loadCEntropy(bs, wksp, dictBuffer, dictSize); + } + + free(bs); + free(wksp); + } + + return headerSize; +} + +/*-******************************************************** +* Dictionary training functions +**********************************************************/ +/*! ZDICT_count() : + Count the nb of common bytes between 2 pointers. + Note : this function presumes end of buffer followed by noisy guard band. +*/ +static size_t ZDICT_count(const void* pIn, const void* pMatch) +{ + const char* const pStart = (const char*)pIn; + for (;;) { + size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn); + if (!diff) { + pIn = (const char*)pIn+sizeof(size_t); + pMatch = (const char*)pMatch+sizeof(size_t); + continue; + } + pIn = (const char*)pIn+ZSTD_NbCommonBytes(diff); + return (size_t)((const char*)pIn - pStart); + } +} + + +typedef struct { + U32 pos; + U32 length; + U32 savings; +} dictItem; + +static void ZDICT_initDictItem(dictItem* d) +{ + d->pos = 1; + d->length = 0; + d->savings = (U32)(-1); +} + + +#define LLIMIT 64 /* heuristic determined experimentally */ +#define MINMATCHLENGTH 7 /* heuristic determined experimentally */ +static dictItem ZDICT_analyzePos( + BYTE* doneMarks, + const int* suffix, U32 start, + const void* buffer, U32 minRatio, U32 notificationLevel) +{ + U32 lengthList[LLIMIT] = {0}; + U32 cumulLength[LLIMIT] = {0}; + U32 savings[LLIMIT] = {0}; + const BYTE* b = (const BYTE*)buffer; + size_t maxLength = LLIMIT; + size_t pos = (size_t)suffix[start]; + U32 end = start; + dictItem solution; + + /* init */ + memset(&solution, 0, sizeof(solution)); + doneMarks[pos] = 1; + + /* trivial repetition cases */ + if ( (MEM_read16(b+pos+0) == MEM_read16(b+pos+2)) + ||(MEM_read16(b+pos+1) == MEM_read16(b+pos+3)) + ||(MEM_read16(b+pos+2) == MEM_read16(b+pos+4)) ) { + /* skip and mark segment */ + U16 const pattern16 = MEM_read16(b+pos+4); + U32 u, patternEnd = 6; + while (MEM_read16(b+pos+patternEnd) == pattern16) patternEnd+=2 ; + if (b[pos+patternEnd] == b[pos+patternEnd-1]) patternEnd++; + for (u=1; u= MINMATCHLENGTH); + } + + /* look backward */ + { size_t length; + do { + length = ZDICT_count(b + pos, b + *(suffix+start-1)); + if (length >=MINMATCHLENGTH) start--; + } while(length >= MINMATCHLENGTH); + } + + /* exit if not found a minimum nb of repetitions */ + if (end-start < minRatio) { + U32 idx; + for(idx=start; idx= %i at pos %7u ", (unsigned)(end-start), MINMATCHLENGTH, (unsigned)pos); + DISPLAYLEVEL(4, "\n"); + + for (mml = MINMATCHLENGTH ; ; mml++) { + BYTE currentChar = 0; + U32 currentCount = 0; + U32 currentID = refinedStart; + U32 id; + U32 selectedCount = 0; + U32 selectedID = currentID; + for (id =refinedStart; id < refinedEnd; id++) { + if (b[suffix[id] + mml] != currentChar) { + if (currentCount > selectedCount) { + selectedCount = currentCount; + selectedID = currentID; + } + currentID = id; + currentChar = b[ suffix[id] + mml]; + currentCount = 0; + } + currentCount ++; + } + if (currentCount > selectedCount) { /* for last */ + selectedCount = currentCount; + selectedID = currentID; + } + + if (selectedCount < minRatio) + break; + refinedStart = selectedID; + refinedEnd = refinedStart + selectedCount; + } + + /* evaluate gain based on new dict */ + start = refinedStart; + pos = suffix[refinedStart]; + end = start; + memset(lengthList, 0, sizeof(lengthList)); + + /* look forward */ + { size_t length; + do { + end++; + length = ZDICT_count(b + pos, b + suffix[end]); + if (length >= LLIMIT) length = LLIMIT-1; + lengthList[length]++; + } while (length >=MINMATCHLENGTH); + } + + /* look backward */ + { size_t length = MINMATCHLENGTH; + while ((length >= MINMATCHLENGTH) & (start > 0)) { + length = ZDICT_count(b + pos, b + suffix[start - 1]); + if (length >= LLIMIT) length = LLIMIT - 1; + lengthList[length]++; + if (length >= MINMATCHLENGTH) start--; + } + } + + /* largest useful length */ + memset(cumulLength, 0, sizeof(cumulLength)); + cumulLength[maxLength-1] = lengthList[maxLength-1]; + for (i=(int)(maxLength-2); i>=0; i--) + cumulLength[i] = cumulLength[i+1] + lengthList[i]; + + for (i=LLIMIT-1; i>=MINMATCHLENGTH; i--) if (cumulLength[i]>=minRatio) break; + maxLength = i; + + /* reduce maxLength in case of final into repetitive data */ + { U32 l = (U32)maxLength; + BYTE const c = b[pos + maxLength-1]; + while (b[pos+l-2]==c) l--; + maxLength = l; + } + if (maxLength < MINMATCHLENGTH) return solution; /* skip : no long-enough solution */ + + /* calculate savings */ + savings[5] = 0; + for (i=MINMATCHLENGTH; i<=(int)maxLength; i++) + savings[i] = savings[i-1] + (lengthList[i] * (i-3)); + + DISPLAYLEVEL(4, "Selected dict at position %u, of length %u : saves %u (ratio: %.2f) \n", + (unsigned)pos, (unsigned)maxLength, (unsigned)savings[maxLength], (double)savings[maxLength] / (double)maxLength); + + solution.pos = (U32)pos; + solution.length = (U32)maxLength; + solution.savings = savings[maxLength]; + + /* mark positions done */ + { U32 id; + for (id=start; id solution.length) length = solution.length; + } + pEnd = (U32)(testedPos + length); + for (p=testedPos; ppos; + const U32 eltEnd = elt.pos + elt.length; + const char* const buf = (const char*) buffer; + + /* tail overlap */ + U32 u; for (u=1; u elt.pos) && (table[u].pos <= eltEnd)) { /* overlap, existing > new */ + /* append */ + U32 const addedLength = table[u].pos - elt.pos; + table[u].length += addedLength; + table[u].pos = elt.pos; + table[u].savings += elt.savings * addedLength / elt.length; /* rough approx */ + table[u].savings += elt.length / 8; /* rough approx bonus */ + elt = table[u]; + /* sort : improve rank */ + while ((u>1) && (table[u-1].savings < elt.savings)) + table[u] = table[u-1], u--; + table[u] = elt; + return u; + } } + + /* front overlap */ + for (u=1; u= elt.pos) && (table[u].pos < elt.pos)) { /* overlap, existing < new */ + /* append */ + int const addedLength = (int)eltEnd - (int)(table[u].pos + table[u].length); + table[u].savings += elt.length / 8; /* rough approx bonus */ + if (addedLength > 0) { /* otherwise, elt fully included into existing */ + table[u].length += addedLength; + table[u].savings += elt.savings * addedLength / elt.length; /* rough approx */ + } + /* sort : improve rank */ + elt = table[u]; + while ((u>1) && (table[u-1].savings < elt.savings)) + table[u] = table[u-1], u--; + table[u] = elt; + return u; + } + + if (MEM_read64(buf + table[u].pos) == MEM_read64(buf + elt.pos + 1)) { + if (isIncluded(buf + table[u].pos, buf + elt.pos + 1, table[u].length)) { + size_t const addedLength = MAX( (int)elt.length - (int)table[u].length , 1 ); + table[u].pos = elt.pos; + table[u].savings += (U32)(elt.savings * addedLength / elt.length); + table[u].length = MIN(elt.length, table[u].length + 1); + return u; + } + } + } + + return 0; +} + + +static void ZDICT_removeDictItem(dictItem* table, U32 id) +{ + /* convention : table[0].pos stores nb of elts */ + U32 const max = table[0].pos; + U32 u; + if (!id) return; /* protection, should never happen */ + for (u=id; upos--; +} + + +static void ZDICT_insertDictItem(dictItem* table, U32 maxSize, dictItem elt, const void* buffer) +{ + /* merge if possible */ + U32 mergeId = ZDICT_tryMerge(table, elt, 0, buffer); + if (mergeId) { + U32 newMerge = 1; + while (newMerge) { + newMerge = ZDICT_tryMerge(table, table[mergeId], mergeId, buffer); + if (newMerge) ZDICT_removeDictItem(table, mergeId); + mergeId = newMerge; + } + return; + } + + /* insert */ + { U32 current; + U32 nextElt = table->pos; + if (nextElt >= maxSize) nextElt = maxSize-1; + current = nextElt-1; + while (table[current].savings < elt.savings) { + table[current+1] = table[current]; + current--; + } + table[current+1] = elt; + table->pos = nextElt+1; + } +} + + +static U32 ZDICT_dictSize(const dictItem* dictList) +{ + U32 u, dictSize = 0; + for (u=1; u=l) { \ + if (ZDICT_clockSpan(displayClock) > refreshRate) { \ + displayClock = clock(); \ + DISPLAY(__VA_ARGS__); \ + } \ + if (notificationLevel>=4) fflush(stderr); \ + } \ + } while (0) + + /* init */ + DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */ + if (!suffix0 || !reverseSuffix || !doneMarks || !filePos) { + result = ERROR(memory_allocation); + goto _cleanup; + } + if (minRatio < MINRATIO) minRatio = MINRATIO; + memset(doneMarks, 0, bufferSize+16); + + /* limit sample set size (divsufsort limitation)*/ + if (bufferSize > ZDICT_MAX_SAMPLES_SIZE) DISPLAYLEVEL(3, "sample set too large : reduced to %u MB ...\n", (unsigned)(ZDICT_MAX_SAMPLES_SIZE>>20)); + while (bufferSize > ZDICT_MAX_SAMPLES_SIZE) bufferSize -= fileSizes[--nbFiles]; + + /* sort */ + DISPLAYLEVEL(2, "sorting %u files of total size %u MB ...\n", nbFiles, (unsigned)(bufferSize>>20)); + { int const divSuftSortResult = divsufsort((const unsigned char*)buffer, suffix, (int)bufferSize, 0); + if (divSuftSortResult != 0) { result = ERROR(GENERIC); goto _cleanup; } + } + suffix[bufferSize] = (int)bufferSize; /* leads into noise */ + suffix0[0] = (int)bufferSize; /* leads into noise */ + /* build reverse suffix sort */ + { size_t pos; + for (pos=0; pos < bufferSize; pos++) + reverseSuffix[suffix[pos]] = (U32)pos; + /* note filePos tracks borders between samples. + It's not used at this stage, but planned to become useful in a later update */ + filePos[0] = 0; + for (pos=1; pos> 21); + } +} + + +typedef struct +{ + ZSTD_CDict* dict; /* dictionary */ + ZSTD_CCtx* zc; /* working context */ + void* workPlace; /* must be ZSTD_BLOCKSIZE_MAX allocated */ +} EStats_ress_t; + +#define MAXREPOFFSET 1024 + +static void ZDICT_countEStats(EStats_ress_t esr, const ZSTD_parameters* params, + unsigned* countLit, unsigned* offsetcodeCount, unsigned* matchlengthCount, unsigned* litlengthCount, U32* repOffsets, + const void* src, size_t srcSize, + U32 notificationLevel) +{ + size_t const blockSizeMax = MIN (ZSTD_BLOCKSIZE_MAX, 1 << params->cParams.windowLog); + size_t cSize; + + if (srcSize > blockSizeMax) srcSize = blockSizeMax; /* protection vs large samples */ + { size_t const errorCode = ZSTD_compressBegin_usingCDict_deprecated(esr.zc, esr.dict); + if (ZSTD_isError(errorCode)) { DISPLAYLEVEL(1, "warning : ZSTD_compressBegin_usingCDict failed \n"); return; } + + } + cSize = ZSTD_compressBlock_deprecated(esr.zc, esr.workPlace, ZSTD_BLOCKSIZE_MAX, src, srcSize); + if (ZSTD_isError(cSize)) { DISPLAYLEVEL(3, "warning : could not compress sample size %u \n", (unsigned)srcSize); return; } + + if (cSize) { /* if == 0; block is not compressible */ + const seqStore_t* const seqStorePtr = ZSTD_getSeqStore(esr.zc); + + /* literals stats */ + { const BYTE* bytePtr; + for(bytePtr = seqStorePtr->litStart; bytePtr < seqStorePtr->lit; bytePtr++) + countLit[*bytePtr]++; + } + + /* seqStats */ + { U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); + ZSTD_seqToCodes(seqStorePtr); + + { const BYTE* codePtr = seqStorePtr->ofCode; + U32 u; + for (u=0; umlCode; + U32 u; + for (u=0; ullCode; + U32 u; + for (u=0; u= 2) { /* rep offsets */ + const seqDef* const seq = seqStorePtr->sequencesStart; + U32 offset1 = seq[0].offBase - ZSTD_REP_NUM; + U32 offset2 = seq[1].offBase - ZSTD_REP_NUM; + if (offset1 >= MAXREPOFFSET) offset1 = 0; + if (offset2 >= MAXREPOFFSET) offset2 = 0; + repOffsets[offset1] += 3; + repOffsets[offset2] += 1; + } } } +} + +static size_t ZDICT_totalSampleSize(const size_t* fileSizes, unsigned nbFiles) +{ + size_t total=0; + unsigned u; + for (u=0; u0; u--) { + offsetCount_t tmp; + if (table[u-1].count >= table[u].count) break; + tmp = table[u-1]; + table[u-1] = table[u]; + table[u] = tmp; + } +} + +/* ZDICT_flatLit() : + * rewrite `countLit` to contain a mostly flat but still compressible distribution of literals. + * necessary to avoid generating a non-compressible distribution that HUF_writeCTable() cannot encode. + */ +static void ZDICT_flatLit(unsigned* countLit) +{ + int u; + for (u=1; u<256; u++) countLit[u] = 2; + countLit[0] = 4; + countLit[253] = 1; + countLit[254] = 1; +} + +#define OFFCODE_MAX 30 /* only applicable to first block */ +static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, + int compressionLevel, + const void* srcBuffer, const size_t* fileSizes, unsigned nbFiles, + const void* dictBuffer, size_t dictBufferSize, + unsigned notificationLevel) +{ + unsigned countLit[256]; + HUF_CREATE_STATIC_CTABLE(hufTable, 255); + unsigned offcodeCount[OFFCODE_MAX+1]; + short offcodeNCount[OFFCODE_MAX+1]; + U32 offcodeMax = ZSTD_highbit32((U32)(dictBufferSize + 128 KB)); + unsigned matchLengthCount[MaxML+1]; + short matchLengthNCount[MaxML+1]; + unsigned litLengthCount[MaxLL+1]; + short litLengthNCount[MaxLL+1]; + U32 repOffset[MAXREPOFFSET]; + offsetCount_t bestRepOffset[ZSTD_REP_NUM+1]; + EStats_ress_t esr = { NULL, NULL, NULL }; + ZSTD_parameters params; + U32 u, huffLog = 11, Offlog = OffFSELog, mlLog = MLFSELog, llLog = LLFSELog, total; + size_t pos = 0, errorCode; + size_t eSize = 0; + size_t const totalSrcSize = ZDICT_totalSampleSize(fileSizes, nbFiles); + size_t const averageSampleSize = totalSrcSize / (nbFiles + !nbFiles); + BYTE* dstPtr = (BYTE*)dstBuffer; + U32 wksp[HUF_CTABLE_WORKSPACE_SIZE_U32]; + + /* init */ + DEBUGLOG(4, "ZDICT_analyzeEntropy"); + if (offcodeMax>OFFCODE_MAX) { eSize = ERROR(dictionaryCreation_failed); goto _cleanup; } /* too large dictionary */ + for (u=0; u<256; u++) countLit[u] = 1; /* any character must be described */ + for (u=0; u<=offcodeMax; u++) offcodeCount[u] = 1; + for (u=0; u<=MaxML; u++) matchLengthCount[u] = 1; + for (u=0; u<=MaxLL; u++) litLengthCount[u] = 1; + memset(repOffset, 0, sizeof(repOffset)); + repOffset[1] = repOffset[4] = repOffset[8] = 1; + memset(bestRepOffset, 0, sizeof(bestRepOffset)); + if (compressionLevel==0) compressionLevel = ZSTD_CLEVEL_DEFAULT; + params = ZSTD_getParams(compressionLevel, averageSampleSize, dictBufferSize); + + esr.dict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, ZSTD_dlm_byRef, ZSTD_dct_rawContent, params.cParams, ZSTD_defaultCMem); + esr.zc = ZSTD_createCCtx(); + esr.workPlace = malloc(ZSTD_BLOCKSIZE_MAX); + if (!esr.dict || !esr.zc || !esr.workPlace) { + eSize = ERROR(memory_allocation); + DISPLAYLEVEL(1, "Not enough memory \n"); + goto _cleanup; + } + + /* collect stats on all samples */ + for (u=0; u= 4) { + /* writeStats */ + DISPLAYLEVEL(4, "Offset Code Frequencies : \n"); + for (u=0; u<=offcodeMax; u++) { + DISPLAYLEVEL(4, "%2u :%7u \n", u, offcodeCount[u]); + } } + + /* analyze, build stats, starting with literals */ + { size_t maxNbBits = HUF_buildCTable_wksp(hufTable, countLit, 255, huffLog, wksp, sizeof(wksp)); + if (HUF_isError(maxNbBits)) { + eSize = maxNbBits; + DISPLAYLEVEL(1, " HUF_buildCTable error \n"); + goto _cleanup; + } + if (maxNbBits==8) { /* not compressible : will fail on HUF_writeCTable() */ + DISPLAYLEVEL(2, "warning : pathological dataset : literals are not compressible : samples are noisy or too regular \n"); + ZDICT_flatLit(countLit); /* replace distribution by a fake "mostly flat but still compressible" distribution, that HUF_writeCTable() can encode */ + maxNbBits = HUF_buildCTable_wksp(hufTable, countLit, 255, huffLog, wksp, sizeof(wksp)); + assert(maxNbBits==9); + } + huffLog = (U32)maxNbBits; + } + + /* looking for most common first offsets */ + { U32 offset; + for (offset=1; offset dictBufferCapacity) { + dictContentSize = dictBufferCapacity - hSize; + } + + /* Pad the dictionary content with zeros if it is too small */ + if (dictContentSize < minContentSize) { + RETURN_ERROR_IF(hSize + minContentSize > dictBufferCapacity, dstSize_tooSmall, + "dictBufferCapacity too small to fit max repcode"); + paddingSize = minContentSize - dictContentSize; + } else { + paddingSize = 0; + } + + { + size_t const dictSize = hSize + paddingSize + dictContentSize; + + /* The dictionary consists of the header, optional padding, and the content. + * The padding comes before the content because the "best" position in the + * dictionary is the last byte. + */ + BYTE* const outDictHeader = (BYTE*)dictBuffer; + BYTE* const outDictPadding = outDictHeader + hSize; + BYTE* const outDictContent = outDictPadding + paddingSize; + + assert(dictSize <= dictBufferCapacity); + assert(outDictContent + dictContentSize == (BYTE*)dictBuffer + dictSize); + + /* First copy the customDictContent into its final location. + * `customDictContent` and `dictBuffer` may overlap, so we must + * do this before any other writes into the output buffer. + * Then copy the header & padding into the output buffer. + */ + memmove(outDictContent, customDictContent, dictContentSize); + memcpy(outDictHeader, header, hSize); + memset(outDictPadding, 0, paddingSize); + + return dictSize; + } +} + + +static size_t ZDICT_addEntropyTablesFromBuffer_advanced( + void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_params_t params) +{ + int const compressionLevel = (params.compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : params.compressionLevel; + U32 const notificationLevel = params.notificationLevel; + size_t hSize = 8; + + /* calculate entropy tables */ + DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */ + DISPLAYLEVEL(2, "statistics ... \n"); + { size_t const eSize = ZDICT_analyzeEntropy((char*)dictBuffer+hSize, dictBufferCapacity-hSize, + compressionLevel, + samplesBuffer, samplesSizes, nbSamples, + (char*)dictBuffer + dictBufferCapacity - dictContentSize, dictContentSize, + notificationLevel); + if (ZDICT_isError(eSize)) return eSize; + hSize += eSize; + } + + /* add dictionary header (after entropy tables) */ + MEM_writeLE32(dictBuffer, ZSTD_MAGIC_DICTIONARY); + { U64 const randomID = XXH64((char*)dictBuffer + dictBufferCapacity - dictContentSize, dictContentSize, 0); + U32 const compliantID = (randomID % ((1U<<31)-32768)) + 32768; + U32 const dictID = params.dictID ? params.dictID : compliantID; + MEM_writeLE32((char*)dictBuffer+4, dictID); + } + + if (hSize + dictContentSize < dictBufferCapacity) + memmove((char*)dictBuffer + hSize, (char*)dictBuffer + dictBufferCapacity - dictContentSize, dictContentSize); + return MIN(dictBufferCapacity, hSize+dictContentSize); +} + +/*! ZDICT_trainFromBuffer_unsafe_legacy() : +* Warning : `samplesBuffer` must be followed by noisy guard band !!! +* @return : size of dictionary, or an error code which can be tested with ZDICT_isError() +*/ +static size_t ZDICT_trainFromBuffer_unsafe_legacy( + void* dictBuffer, size_t maxDictSize, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_legacy_params_t params) +{ + U32 const dictListSize = MAX(MAX(DICTLISTSIZE_DEFAULT, nbSamples), (U32)(maxDictSize/16)); + dictItem* const dictList = (dictItem*)malloc(dictListSize * sizeof(*dictList)); + unsigned const selectivity = params.selectivityLevel == 0 ? g_selectivity_default : params.selectivityLevel; + unsigned const minRep = (selectivity > 30) ? MINRATIO : nbSamples >> selectivity; + size_t const targetDictSize = maxDictSize; + size_t const samplesBuffSize = ZDICT_totalSampleSize(samplesSizes, nbSamples); + size_t dictSize = 0; + U32 const notificationLevel = params.zParams.notificationLevel; + + /* checks */ + if (!dictList) return ERROR(memory_allocation); + if (maxDictSize < ZDICT_DICTSIZE_MIN) { free(dictList); return ERROR(dstSize_tooSmall); } /* requested dictionary size is too small */ + if (samplesBuffSize < ZDICT_MIN_SAMPLES_SIZE) { free(dictList); return ERROR(dictionaryCreation_failed); } /* not enough source to create dictionary */ + + /* init */ + ZDICT_initDictItem(dictList); + + /* build dictionary */ + ZDICT_trainBuffer_legacy(dictList, dictListSize, + samplesBuffer, samplesBuffSize, + samplesSizes, nbSamples, + minRep, notificationLevel); + + /* display best matches */ + if (params.zParams.notificationLevel>= 3) { + unsigned const nb = MIN(25, dictList[0].pos); + unsigned const dictContentSize = ZDICT_dictSize(dictList); + unsigned u; + DISPLAYLEVEL(3, "\n %u segments found, of total size %u \n", (unsigned)dictList[0].pos-1, dictContentSize); + DISPLAYLEVEL(3, "list %u best segments \n", nb-1); + for (u=1; u samplesBuffSize) || ((pos + length) > samplesBuffSize)) { + free(dictList); + return ERROR(GENERIC); /* should never happen */ + } + DISPLAYLEVEL(3, "%3u:%3u bytes at pos %8u, savings %7u bytes |", + u, length, pos, (unsigned)dictList[u].savings); + ZDICT_printHex((const char*)samplesBuffer+pos, printedLength); + DISPLAYLEVEL(3, "| \n"); + } } + + + /* create dictionary */ + { unsigned dictContentSize = ZDICT_dictSize(dictList); + if (dictContentSize < ZDICT_CONTENTSIZE_MIN) { free(dictList); return ERROR(dictionaryCreation_failed); } /* dictionary content too small */ + if (dictContentSize < targetDictSize/4) { + DISPLAYLEVEL(2, "! warning : selected content significantly smaller than requested (%u < %u) \n", dictContentSize, (unsigned)maxDictSize); + if (samplesBuffSize < 10 * targetDictSize) + DISPLAYLEVEL(2, "! consider increasing the number of samples (total size : %u MB)\n", (unsigned)(samplesBuffSize>>20)); + if (minRep > MINRATIO) { + DISPLAYLEVEL(2, "! consider increasing selectivity to produce larger dictionary (-s%u) \n", selectivity+1); + DISPLAYLEVEL(2, "! note : larger dictionaries are not necessarily better, test its efficiency on samples \n"); + } + } + + if ((dictContentSize > targetDictSize*3) && (nbSamples > 2*MINRATIO) && (selectivity>1)) { + unsigned proposedSelectivity = selectivity-1; + while ((nbSamples >> proposedSelectivity) <= MINRATIO) { proposedSelectivity--; } + DISPLAYLEVEL(2, "! note : calculated dictionary significantly larger than requested (%u > %u) \n", dictContentSize, (unsigned)maxDictSize); + DISPLAYLEVEL(2, "! consider increasing dictionary size, or produce denser dictionary (-s%u) \n", proposedSelectivity); + DISPLAYLEVEL(2, "! always test dictionary efficiency on real samples \n"); + } + + /* limit dictionary size */ + { U32 const max = dictList->pos; /* convention : nb of useful elts within dictList */ + U32 currentSize = 0; + U32 n; for (n=1; n targetDictSize) { currentSize -= dictList[n].length; break; } + } + dictList->pos = n; + dictContentSize = currentSize; + } + + /* build dict content */ + { U32 u; + BYTE* ptr = (BYTE*)dictBuffer + maxDictSize; + for (u=1; upos; u++) { + U32 l = dictList[u].length; + ptr -= l; + if (ptr<(BYTE*)dictBuffer) { free(dictList); return ERROR(GENERIC); } /* should not happen */ + memcpy(ptr, (const char*)samplesBuffer+dictList[u].pos, l); + } } + + dictSize = ZDICT_addEntropyTablesFromBuffer_advanced(dictBuffer, dictContentSize, maxDictSize, + samplesBuffer, samplesSizes, nbSamples, + params.zParams); + } + + /* clean up */ + free(dictList); + return dictSize; +} + + +/* ZDICT_trainFromBuffer_legacy() : + * issue : samplesBuffer need to be followed by a noisy guard band. + * work around : duplicate the buffer, and add the noise */ +size_t ZDICT_trainFromBuffer_legacy(void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_legacy_params_t params) +{ + size_t result; + void* newBuff; + size_t const sBuffSize = ZDICT_totalSampleSize(samplesSizes, nbSamples); + if (sBuffSize < ZDICT_MIN_SAMPLES_SIZE) return 0; /* not enough content => no dictionary */ + + newBuff = malloc(sBuffSize + NOISELENGTH); + if (!newBuff) return ERROR(memory_allocation); + + memcpy(newBuff, samplesBuffer, sBuffSize); + ZDICT_fillNoise((char*)newBuff + sBuffSize, NOISELENGTH); /* guard band, for end of buffer condition */ + + result = + ZDICT_trainFromBuffer_unsafe_legacy(dictBuffer, dictBufferCapacity, newBuff, + samplesSizes, nbSamples, params); + free(newBuff); + return result; +} + + +size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples) +{ + ZDICT_fastCover_params_t params; + DEBUGLOG(3, "ZDICT_trainFromBuffer"); + memset(¶ms, 0, sizeof(params)); + params.d = 8; + params.steps = 4; + /* Use default level since no compression level information is available */ + params.zParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; +#if defined(DEBUGLEVEL) && (DEBUGLEVEL>=1) + params.zParams.notificationLevel = DEBUGLEVEL; +#endif + return ZDICT_optimizeTrainFromBuffer_fastCover(dictBuffer, dictBufferCapacity, + samplesBuffer, samplesSizes, nbSamples, + ¶ms); +} + +size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples) +{ + ZDICT_params_t params; + memset(¶ms, 0, sizeof(params)); + return ZDICT_addEntropyTablesFromBuffer_advanced(dictBuffer, dictContentSize, dictBufferCapacity, + samplesBuffer, samplesSizes, nbSamples, + params); +} + +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/include/zdict.h b/src/duckdb/third_party/zstd/include/zdict.h new file mode 100644 index 000000000..eaf877270 --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zdict.h @@ -0,0 +1,473 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +#ifndef ZSTD_ZDICT_H +#define ZSTD_ZDICT_H + +/*====== Dependencies ======*/ +#include /* size_t */ + +namespace duckdb_zstd { + +/* ===== ZDICTLIB_API : control library symbols visibility ===== */ +#ifndef ZDICTLIB_VISIBLE + /* Backwards compatibility with old macro name */ +# ifdef ZDICTLIB_VISIBILITY +# define ZDICTLIB_VISIBLE ZDICTLIB_VISIBILITY +# elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) +# define ZDICTLIB_VISIBLE __attribute__ ((visibility ("default"))) +# else +# define ZDICTLIB_VISIBLE +# endif +#endif + +#ifndef ZDICTLIB_HIDDEN +# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) +# define ZDICTLIB_HIDDEN __attribute__ ((visibility ("hidden"))) +# else +# define ZDICTLIB_HIDDEN +# endif +#endif + +#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZDICTLIB_API __declspec(dllexport) ZDICTLIB_VISIBLE +#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZDICTLIB_API __declspec(dllimport) ZDICTLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define ZDICTLIB_API ZDICTLIB_VISIBLE +#endif + +/******************************************************************************* + * Zstd dictionary builder + * + * FAQ + * === + * Why should I use a dictionary? + * ------------------------------ + * + * Zstd can use dictionaries to improve compression ratio of small data. + * Traditionally small files don't compress well because there is very little + * repetition in a single sample, since it is small. But, if you are compressing + * many similar files, like a bunch of JSON records that share the same + * structure, you can train a dictionary on ahead of time on some samples of + * these files. Then, zstd can use the dictionary to find repetitions that are + * present across samples. This can vastly improve compression ratio. + * + * When is a dictionary useful? + * ---------------------------- + * + * Dictionaries are useful when compressing many small files that are similar. + * The larger a file is, the less benefit a dictionary will have. Generally, + * we don't expect dictionary compression to be effective past 100KB. And the + * smaller a file is, the more we would expect the dictionary to help. + * + * How do I use a dictionary? + * -------------------------- + * + * Simply pass the dictionary to the zstd compressor with + * `ZSTD_CCtx_loadDictionary()`. The same dictionary must then be passed to + * the decompressor, using `ZSTD_DCtx_loadDictionary()`. There are other + * more advanced functions that allow selecting some options, see zstd.h for + * complete documentation. + * + * What is a zstd dictionary? + * -------------------------- + * + * A zstd dictionary has two pieces: Its header, and its content. The header + * contains a magic number, the dictionary ID, and entropy tables. These + * entropy tables allow zstd to save on header costs in the compressed file, + * which really matters for small data. The content is just bytes, which are + * repeated content that is common across many samples. + * + * What is a raw content dictionary? + * --------------------------------- + * + * A raw content dictionary is just bytes. It doesn't have a zstd dictionary + * header, a dictionary ID, or entropy tables. Any buffer is a valid raw + * content dictionary. + * + * How do I train a dictionary? + * ---------------------------- + * + * Gather samples from your use case. These samples should be similar to each + * other. If you have several use cases, you could try to train one dictionary + * per use case. + * + * Pass those samples to `ZDICT_trainFromBuffer()` and that will train your + * dictionary. There are a few advanced versions of this function, but this + * is a great starting point. If you want to further tune your dictionary + * you could try `ZDICT_optimizeTrainFromBuffer_cover()`. If that is too slow + * you can try `ZDICT_optimizeTrainFromBuffer_fastCover()`. + * + * If the dictionary training function fails, that is likely because you + * either passed too few samples, or a dictionary would not be effective + * for your data. Look at the messages that the dictionary trainer printed, + * if it doesn't say too few samples, then a dictionary would not be effective. + * + * How large should my dictionary be? + * ---------------------------------- + * + * A reasonable dictionary size, the `dictBufferCapacity`, is about 100KB. + * The zstd CLI defaults to a 110KB dictionary. You likely don't need a + * dictionary larger than that. But, most use cases can get away with a + * smaller dictionary. The advanced dictionary builders can automatically + * shrink the dictionary for you, and select the smallest size that doesn't + * hurt compression ratio too much. See the `shrinkDict` parameter. + * A smaller dictionary can save memory, and potentially speed up + * compression. + * + * How many samples should I provide to the dictionary builder? + * ------------------------------------------------------------ + * + * We generally recommend passing ~100x the size of the dictionary + * in samples. A few thousand should suffice. Having too few samples + * can hurt the dictionaries effectiveness. Having more samples will + * only improve the dictionaries effectiveness. But having too many + * samples can slow down the dictionary builder. + * + * How do I determine if a dictionary will be effective? + * ----------------------------------------------------- + * + * Simply train a dictionary and try it out. You can use zstd's built in + * benchmarking tool to test the dictionary effectiveness. + * + * # Benchmark levels 1-3 without a dictionary + * zstd -b1e3 -r /path/to/my/files + * # Benchmark levels 1-3 with a dictionary + * zstd -b1e3 -r /path/to/my/files -D /path/to/my/dictionary + * + * When should I retrain a dictionary? + * ----------------------------------- + * + * You should retrain a dictionary when its effectiveness drops. Dictionary + * effectiveness drops as the data you are compressing changes. Generally, we do + * expect dictionaries to "decay" over time, as your data changes, but the rate + * at which they decay depends on your use case. Internally, we regularly + * retrain dictionaries, and if the new dictionary performs significantly + * better than the old dictionary, we will ship the new dictionary. + * + * I have a raw content dictionary, how do I turn it into a zstd dictionary? + * ------------------------------------------------------------------------- + * + * If you have a raw content dictionary, e.g. by manually constructing it, or + * using a third-party dictionary builder, you can turn it into a zstd + * dictionary by using `ZDICT_finalizeDictionary()`. You'll also have to + * provide some samples of the data. It will add the zstd header to the + * raw content, which contains a dictionary ID and entropy tables, which + * will improve compression ratio, and allow zstd to write the dictionary ID + * into the frame, if you so choose. + * + * Do I have to use zstd's dictionary builder? + * ------------------------------------------- + * + * No! You can construct dictionary content however you please, it is just + * bytes. It will always be valid as a raw content dictionary. If you want + * a zstd dictionary, which can improve compression ratio, use + * `ZDICT_finalizeDictionary()`. + * + * What is the attack surface of a zstd dictionary? + * ------------------------------------------------ + * + * Zstd is heavily fuzz tested, including loading fuzzed dictionaries, so + * zstd should never crash, or access out-of-bounds memory no matter what + * the dictionary is. However, if an attacker can control the dictionary + * during decompression, they can cause zstd to generate arbitrary bytes, + * just like if they controlled the compressed data. + * + ******************************************************************************/ + + +/*! ZDICT_trainFromBuffer(): + * Train a dictionary from an array of samples. + * Redirect towards ZDICT_optimizeTrainFromBuffer_fastCover() single-threaded, with d=8, steps=4, + * f=20, and accel=1. + * Samples must be stored concatenated in a single flat buffer `samplesBuffer`, + * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order. + * The resulting dictionary will be saved into `dictBuffer`. + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * Note: Dictionary training will fail if there are not enough samples to construct a + * dictionary, or if most of the samples are too small (< 8 bytes being the lower limit). + * If dictionary training fails, you should use zstd without a dictionary, as the dictionary + * would've been ineffective anyways. If you believe your samples would benefit from a dictionary + * please open an issue with details, and we can look into it. + * Note: ZDICT_trainFromBuffer()'s memory usage is about 6 MB. + * Tips: In general, a reasonable dictionary has a size of ~ 100 KB. + * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`. + * In general, it's recommended to provide a few thousands samples, though this can vary a lot. + * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. + */ +ZDICTLIB_API size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, + const size_t* samplesSizes, unsigned nbSamples); + +typedef struct { + int compressionLevel; /**< optimize for a specific zstd compression level; 0 means default */ + unsigned notificationLevel; /**< Write log to stderr; 0 = none (default); 1 = errors; 2 = progression; 3 = details; 4 = debug; */ + unsigned dictID; /**< force dictID value; 0 means auto mode (32-bits random value) + * NOTE: The zstd format reserves some dictionary IDs for future use. + * You may use them in private settings, but be warned that they + * may be used by zstd in a public dictionary registry in the future. + * These dictionary IDs are: + * - low range : <= 32767 + * - high range : >= (2^31) + */ +} ZDICT_params_t; + +/*! ZDICT_finalizeDictionary(): + * Given a custom content as a basis for dictionary, and a set of samples, + * finalize dictionary by adding headers and statistics according to the zstd + * dictionary format. + * + * Samples must be stored concatenated in a flat buffer `samplesBuffer`, + * supplied with an array of sizes `samplesSizes`, providing the size of each + * sample in order. The samples are used to construct the statistics, so they + * should be representative of what you will compress with this dictionary. + * + * The compression level can be set in `parameters`. You should pass the + * compression level you expect to use in production. The statistics for each + * compression level differ, so tuning the dictionary for the compression level + * can help quite a bit. + * + * You can set an explicit dictionary ID in `parameters`, or allow us to pick + * a random dictionary ID for you, but we can't guarantee no collisions. + * + * The dstDictBuffer and the dictContent may overlap, and the content will be + * appended to the end of the header. If the header + the content doesn't fit in + * maxDictSize the beginning of the content is truncated to make room, since it + * is presumed that the most profitable content is at the end of the dictionary, + * since that is the cheapest to reference. + * + * `maxDictSize` must be >= max(dictContentSize, ZSTD_DICTSIZE_MIN). + * + * @return: size of dictionary stored into `dstDictBuffer` (<= `maxDictSize`), + * or an error code, which can be tested by ZDICT_isError(). + * Note: ZDICT_finalizeDictionary() will push notifications into stderr if + * instructed to, using notificationLevel>0. + * NOTE: This function currently may fail in several edge cases including: + * * Not enough samples + * * Samples are uncompressible + * * Samples are all exactly the same + */ +ZDICTLIB_API size_t ZDICT_finalizeDictionary(void* dstDictBuffer, size_t maxDictSize, + const void* dictContent, size_t dictContentSize, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_params_t parameters); + + +/*====== Helper functions ======*/ +ZDICTLIB_API unsigned ZDICT_getDictID(const void* dictBuffer, size_t dictSize); /**< extracts dictID; @return zero if error (not a valid dictionary) */ +ZDICTLIB_API size_t ZDICT_getDictHeaderSize(const void* dictBuffer, size_t dictSize); /* returns dict header size; returns a ZSTD error code on failure */ +ZDICTLIB_API unsigned ZDICT_isError(size_t errorCode); +ZDICTLIB_API const char* ZDICT_getErrorName(size_t errorCode); + +} // namespace duckdb_zstd + +#endif /* ZSTD_ZDICT_H */ + +#if defined(ZDICT_STATIC_LINKING_ONLY) && !defined(ZSTD_ZDICT_H_STATIC) +#define ZSTD_ZDICT_H_STATIC + +namespace duckdb_zstd { + +/* This can be overridden externally to hide static symbols. */ +#ifndef ZDICTLIB_STATIC_API +# if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZDICTLIB_STATIC_API __declspec(dllexport) ZDICTLIB_VISIBLE +# elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZDICTLIB_STATIC_API __declspec(dllimport) ZDICTLIB_VISIBLE +# else +# define ZDICTLIB_STATIC_API ZDICTLIB_VISIBLE +# endif +#endif + +/* ==================================================================================== + * The definitions in this section are considered experimental. + * They should never be used with a dynamic library, as they may change in the future. + * They are provided for advanced usages. + * Use them only in association with static linking. + * ==================================================================================== */ + +#define ZDICT_DICTSIZE_MIN 256 +/* Deprecated: Remove in v1.6.0 */ +#define ZDICT_CONTENTSIZE_MIN 128 + +/*! ZDICT_cover_params_t: + * k and d are the only required parameters. + * For others, value 0 means default. + */ +typedef struct { + unsigned k; /* Segment size : constraint: 0 < k : Reasonable range [16, 2048+] */ + unsigned d; /* dmer size : constraint: 0 < d <= k : Reasonable range [6, 16] */ + unsigned steps; /* Number of steps : Only used for optimization : 0 means default (40) : Higher means more parameters checked */ + unsigned nbThreads; /* Number of threads : constraint: 0 < nbThreads : 1 means single-threaded : Only used for optimization : Ignored if ZSTD_MULTITHREAD is not defined */ + double splitPoint; /* Percentage of samples used for training: Only used for optimization : the first nbSamples * splitPoint samples will be used to training, the last nbSamples * (1 - splitPoint) samples will be used for testing, 0 means default (1.0), 1.0 when all samples are used for both training and testing */ + unsigned shrinkDict; /* Train dictionaries to shrink in size starting from the minimum size and selects the smallest dictionary that is shrinkDictMaxRegression% worse than the largest dictionary. 0 means no shrinking and 1 means shrinking */ + unsigned shrinkDictMaxRegression; /* Sets shrinkDictMaxRegression so that a smaller dictionary can be at worse shrinkDictMaxRegression% worse than the max dict size dictionary. */ + ZDICT_params_t zParams; +} ZDICT_cover_params_t; + +typedef struct { + unsigned k; /* Segment size : constraint: 0 < k : Reasonable range [16, 2048+] */ + unsigned d; /* dmer size : constraint: 0 < d <= k : Reasonable range [6, 16] */ + unsigned f; /* log of size of frequency array : constraint: 0 < f <= 31 : 1 means default(20)*/ + unsigned steps; /* Number of steps : Only used for optimization : 0 means default (40) : Higher means more parameters checked */ + unsigned nbThreads; /* Number of threads : constraint: 0 < nbThreads : 1 means single-threaded : Only used for optimization : Ignored if ZSTD_MULTITHREAD is not defined */ + double splitPoint; /* Percentage of samples used for training: Only used for optimization : the first nbSamples * splitPoint samples will be used to training, the last nbSamples * (1 - splitPoint) samples will be used for testing, 0 means default (0.75), 1.0 when all samples are used for both training and testing */ + unsigned accel; /* Acceleration level: constraint: 0 < accel <= 10, higher means faster and less accurate, 0 means default(1) */ + unsigned shrinkDict; /* Train dictionaries to shrink in size starting from the minimum size and selects the smallest dictionary that is shrinkDictMaxRegression% worse than the largest dictionary. 0 means no shrinking and 1 means shrinking */ + unsigned shrinkDictMaxRegression; /* Sets shrinkDictMaxRegression so that a smaller dictionary can be at worse shrinkDictMaxRegression% worse than the max dict size dictionary. */ + + ZDICT_params_t zParams; +} ZDICT_fastCover_params_t; + +/*! ZDICT_trainFromBuffer_cover(): + * Train a dictionary from an array of samples using the COVER algorithm. + * Samples must be stored concatenated in a single flat buffer `samplesBuffer`, + * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order. + * The resulting dictionary will be saved into `dictBuffer`. + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * See ZDICT_trainFromBuffer() for details on failure modes. + * Note: ZDICT_trainFromBuffer_cover() requires about 9 bytes of memory for each input byte. + * Tips: In general, a reasonable dictionary has a size of ~ 100 KB. + * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`. + * In general, it's recommended to provide a few thousands samples, though this can vary a lot. + * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. + */ +ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_cover( + void *dictBuffer, size_t dictBufferCapacity, + const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples, + ZDICT_cover_params_t parameters); + +/*! ZDICT_optimizeTrainFromBuffer_cover(): + * The same requirements as above hold for all the parameters except `parameters`. + * This function tries many parameter combinations and picks the best parameters. + * `*parameters` is filled with the best parameters found, + * dictionary constructed with those parameters is stored in `dictBuffer`. + * + * All of the parameters d, k, steps are optional. + * If d is non-zero then we don't check multiple values of d, otherwise we check d = {6, 8}. + * if steps is zero it defaults to its default value. + * If k is non-zero then we don't check multiple values of k, otherwise we check steps values in [50, 2000]. + * + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * On success `*parameters` contains the parameters selected. + * See ZDICT_trainFromBuffer() for details on failure modes. + * Note: ZDICT_optimizeTrainFromBuffer_cover() requires about 8 bytes of memory for each input byte and additionally another 5 bytes of memory for each byte of memory for each thread. + */ +ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_cover( + void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_cover_params_t* parameters); + +/*! ZDICT_trainFromBuffer_fastCover(): + * Train a dictionary from an array of samples using a modified version of COVER algorithm. + * Samples must be stored concatenated in a single flat buffer `samplesBuffer`, + * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order. + * d and k are required. + * All other parameters are optional, will use default values if not provided + * The resulting dictionary will be saved into `dictBuffer`. + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * See ZDICT_trainFromBuffer() for details on failure modes. + * Note: ZDICT_trainFromBuffer_fastCover() requires 6 * 2^f bytes of memory. + * Tips: In general, a reasonable dictionary has a size of ~ 100 KB. + * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`. + * In general, it's recommended to provide a few thousands samples, though this can vary a lot. + * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. + */ +ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_fastCover(void *dictBuffer, + size_t dictBufferCapacity, const void *samplesBuffer, + const size_t *samplesSizes, unsigned nbSamples, + ZDICT_fastCover_params_t parameters); + +/*! ZDICT_optimizeTrainFromBuffer_fastCover(): + * The same requirements as above hold for all the parameters except `parameters`. + * This function tries many parameter combinations (specifically, k and d combinations) + * and picks the best parameters. `*parameters` is filled with the best parameters found, + * dictionary constructed with those parameters is stored in `dictBuffer`. + * All of the parameters d, k, steps, f, and accel are optional. + * If d is non-zero then we don't check multiple values of d, otherwise we check d = {6, 8}. + * if steps is zero it defaults to its default value. + * If k is non-zero then we don't check multiple values of k, otherwise we check steps values in [50, 2000]. + * If f is zero, default value of 20 is used. + * If accel is zero, default value of 1 is used. + * + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * On success `*parameters` contains the parameters selected. + * See ZDICT_trainFromBuffer() for details on failure modes. + * Note: ZDICT_optimizeTrainFromBuffer_fastCover() requires about 6 * 2^f bytes of memory for each thread. + */ +ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_fastCover(void* dictBuffer, + size_t dictBufferCapacity, const void* samplesBuffer, + const size_t* samplesSizes, unsigned nbSamples, + ZDICT_fastCover_params_t* parameters); + +typedef struct { + unsigned selectivityLevel; /* 0 means default; larger => select more => larger dictionary */ + ZDICT_params_t zParams; +} ZDICT_legacy_params_t; + +/*! ZDICT_trainFromBuffer_legacy(): + * Train a dictionary from an array of samples. + * Samples must be stored concatenated in a single flat buffer `samplesBuffer`, + * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order. + * The resulting dictionary will be saved into `dictBuffer`. + * `parameters` is optional and can be provided with values set to 0 to mean "default". + * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + * or an error code, which can be tested with ZDICT_isError(). + * See ZDICT_trainFromBuffer() for details on failure modes. + * Tips: In general, a reasonable dictionary has a size of ~ 100 KB. + * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`. + * In general, it's recommended to provide a few thousands samples, though this can vary a lot. + * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. + * Note: ZDICT_trainFromBuffer_legacy() will send notifications into stderr if instructed to, using notificationLevel>0. + */ +ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_legacy( + void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_legacy_params_t parameters); + + +/* Deprecation warnings */ +/* It is generally possible to disable deprecation warnings from compiler, + for example with -Wno-deprecated-declarations for gcc + or _CRT_SECURE_NO_WARNINGS in Visual. + Otherwise, it's also possible to manually define ZDICT_DISABLE_DEPRECATE_WARNINGS */ +#ifdef ZDICT_DISABLE_DEPRECATE_WARNINGS +# define ZDICT_DEPRECATED(message) /* disable deprecation warnings */ +#else +# define ZDICT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ +# define ZDICT_DEPRECATED(message) [[deprecated(message)]] +# elif defined(__clang__) || (ZDICT_GCC_VERSION >= 405) +# define ZDICT_DEPRECATED(message) __attribute__((deprecated(message))) +# elif (ZDICT_GCC_VERSION >= 301) +# define ZDICT_DEPRECATED(message) __attribute__((deprecated)) +# elif defined(_MSC_VER) +# define ZDICT_DEPRECATED(message) __declspec(deprecated(message)) +# else +# pragma message("WARNING: You need to implement ZDICT_DEPRECATED for this compiler") +# define ZDICT_DEPRECATED(message) +# endif +#endif /* ZDICT_DISABLE_DEPRECATE_WARNINGS */ + +ZDICT_DEPRECATED("use ZDICT_finalizeDictionary() instead") +ZDICTLIB_STATIC_API +size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples); + +} // namespace duckdb_zstd + +#endif /* ZSTD_ZDICT_H_STATIC */ diff --git a/src/duckdb/third_party/zstd/include/zstd.h b/src/duckdb/third_party/zstd/include/zstd.h index ade94c2d5..8b40c366e 100644 --- a/src/duckdb/third_party/zstd/include/zstd.h +++ b/src/duckdb/third_party/zstd/include/zstd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -7,31 +7,71 @@ * in the COPYING file in the root directory of this source tree). * You may select, at your option, one of the above-listed licenses. */ + #ifndef ZSTD_H_235446 #define ZSTD_H_235446 -/* ====== Dependency ======*/ +// DuckDB: just enable everything for amalgamation +#ifdef DUCKDB_AMALGAMATION +#define ZSTD_STATIC_LINKING_ONLY +#endif + +/* ====== Dependencies ======*/ #include /* INT_MAX */ #include /* size_t */ +namespace duckdb_zstd { /* ===== ZSTDLIB_API : control library symbols visibility ===== */ -#ifndef ZSTDLIB_VISIBILITY -# if defined(__GNUC__) && (__GNUC__ >= 4) -# define ZSTDLIB_VISIBILITY __attribute__ ((visibility ("default"))) +#ifndef ZSTDLIB_VISIBLE + /* Backwards compatibility with old macro name */ +# ifdef ZSTDLIB_VISIBILITY +# define ZSTDLIB_VISIBLE ZSTDLIB_VISIBILITY +# elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) +# define ZSTDLIB_VISIBLE __attribute__ ((visibility ("default"))) +# else +# define ZSTDLIB_VISIBLE +# endif +#endif + +#ifndef ZSTDLIB_HIDDEN +# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) +# define ZSTDLIB_HIDDEN __attribute__ ((visibility ("hidden"))) # else -# define ZSTDLIB_VISIBILITY +# define ZSTDLIB_HIDDEN # endif #endif + #if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) -# define ZSTDLIB_API __declspec(dllexport) ZSTDLIB_VISIBILITY +# define ZSTDLIB_API __declspec(dllexport) ZSTDLIB_VISIBLE #elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) -# define ZSTDLIB_API __declspec(dllimport) ZSTDLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +# define ZSTDLIB_API __declspec(dllimport) ZSTDLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ #else -# define ZSTDLIB_API ZSTDLIB_VISIBILITY +# define ZSTDLIB_API ZSTDLIB_VISIBLE #endif -namespace duckdb_zstd { +/* Deprecation warnings : + * Should these warnings be a problem, it is generally possible to disable them, + * typically with -Wno-deprecated-declarations for gcc or _CRT_SECURE_NO_WARNINGS in Visual. + * Otherwise, it's also possible to define ZSTD_DISABLE_DEPRECATE_WARNINGS. + */ +#ifdef ZSTD_DISABLE_DEPRECATE_WARNINGS +# define ZSTD_DEPRECATED(message) /* disable deprecation warnings */ +#else +# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ +# define ZSTD_DEPRECATED(message) [[deprecated(message)]] +# elif (defined(GNUC) && (GNUC > 4 || (GNUC == 4 && GNUC_MINOR >= 5))) || defined(__clang__) +# define ZSTD_DEPRECATED(message) __attribute__((deprecated(message))) +# elif defined(__GNUC__) && (__GNUC__ >= 3) +# define ZSTD_DEPRECATED(message) __attribute__((deprecated)) +# elif defined(_MSC_VER) +# define ZSTD_DEPRECATED(message) __declspec(deprecated(message)) +# else +# pragma message("WARNING: You need to implement ZSTD_DEPRECATED for this compiler") +# define ZSTD_DEPRECATED(message) +# endif +#endif /* ZSTD_DISABLE_DEPRECATE_WARNINGS */ + /******************************************************************************* Introduction @@ -68,17 +108,22 @@ namespace duckdb_zstd { /*------ Version ------*/ #define ZSTD_VERSION_MAJOR 1 -#define ZSTD_VERSION_MINOR 4 -#define ZSTD_VERSION_RELEASE 5 - +#define ZSTD_VERSION_MINOR 5 +#define ZSTD_VERSION_RELEASE 6 #define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) -ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< to check runtime library version */ + +/*! ZSTD_versionNumber() : + * Return runtime library version, the value is (MAJOR*100*100 + MINOR*100 + RELEASE). */ +ZSTDLIB_API unsigned ZSTD_versionNumber(void); #define ZSTD_LIB_VERSION ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE #define ZSTD_QUOTE(str) #str #define ZSTD_EXPAND_AND_QUOTE(str) ZSTD_QUOTE(str) #define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION) -ZSTDLIB_API const char* ZSTD_versionString(void); /* requires v1.3.0+ */ + +/*! ZSTD_versionString() : + * Return runtime library version, like "1.4.5". Requires v1.3.0+. */ +ZSTDLIB_API const char* ZSTD_versionString(void); /* ************************************* * Default constant @@ -101,13 +146,13 @@ ZSTDLIB_API const char* ZSTD_versionString(void); /* requires v1.3.0+ */ #define ZSTD_BLOCKSIZE_MAX (1<= `ZSTD_compressBound(srcSize)`. + * NOTE: Providing `dstCapacity >= ZSTD_compressBound(srcSize)` guarantees that zstd will have + * enough space to successfully compress the data. * @return : compressed size written into `dst` (<= `dstCapacity), * or an error code if it fails (which can be tested using ZSTD_isError()). */ ZSTDLIB_API size_t ZSTD_compress( void* dst, size_t dstCapacity, @@ -156,9 +201,11 @@ ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t * "empty", "unknown" and "error" results to the same return value (0), * while ZSTD_getFrameContentSize() gives them separate return values. * @return : decompressed size of `src` frame content _if known and not empty_, 0 otherwise. */ -ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize); +ZSTD_DEPRECATED("Replaced by ZSTD_getFrameContentSize") +ZSTDLIB_API +unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize); -/*! ZSTD_findFrameCompressedSize() : +/*! ZSTD_findFrameCompressedSize() : Requires v1.4.0+ * `src` should point to the start of a ZSTD frame or skippable frame. * `srcSize` must be >= first frame size * @return : the compressed size of the first frame starting at `src`, @@ -168,12 +215,35 @@ ZSTDLIB_API size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize) /*====== Helper functions ======*/ -#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */ -ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case single-pass scenario */ +/* ZSTD_compressBound() : + * maximum compressed size in worst case single-pass scenario. + * When invoking `ZSTD_compress()` or any other one-pass compression function, + * it's recommended to provide @dstCapacity >= ZSTD_compressBound(srcSize) + * as it eliminates one potential failure scenario, + * aka not enough room in dst buffer to write the compressed frame. + * Note : ZSTD_compressBound() itself can fail, if @srcSize > ZSTD_MAX_INPUT_SIZE . + * In which case, ZSTD_compressBound() will return an error code + * which can be tested using ZSTD_isError(). + * + * ZSTD_COMPRESSBOUND() : + * same as ZSTD_compressBound(), but as a macro. + * It can be used to produce constants, which can be useful for static allocation, + * for example to size a static array on stack. + * Will produce constant value 0 if srcSize too large. + */ +#define ZSTD_MAX_INPUT_SIZE ((sizeof(size_t)==8) ? 0xFF00FF00FF00FF00ULL : 0xFF00FF00U) +#define ZSTD_COMPRESSBOUND(srcSize) (((size_t)(srcSize) >= ZSTD_MAX_INPUT_SIZE) ? 0 : (srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */ +ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case single-pass scenario */ +/* ZSTD_isError() : + * Most ZSTD_* functions returning a size_t value can be tested for error, + * using ZSTD_isError(). + * @return 1 if error, 0 otherwise + */ ZSTDLIB_API unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */ ZSTDLIB_API const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */ -ZSTDLIB_API int ZSTD_minCLevel(void); /*!< minimum negative compression level allowed */ +ZSTDLIB_API int ZSTD_minCLevel(void); /*!< minimum negative compression level allowed, requires v1.4.0+ */ ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */ +ZSTDLIB_API int ZSTD_defaultCLevel(void); /*!< default compression level, specified by ZSTD_CLEVEL_DEFAULT, requires v1.5.0+ */ /*************************************** @@ -182,7 +252,7 @@ ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compres /*= Compression context * When compressing many times, * it is recommended to allocate a context just once, - * and re-use it for each successive compression operation. + * and reuse it for each successive compression operation. * This will make workload friendlier for system's memory. * Note : re-using context is just a speed / resource optimization. * It doesn't change the compression ratio, which remains identical. @@ -191,13 +261,13 @@ ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compres */ typedef struct ZSTD_CCtx_s ZSTD_CCtx; ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx(void); -ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx); +ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx); /* accept NULL pointer */ /*! ZSTD_compressCCtx() : * Same as ZSTD_compress(), using an explicit ZSTD_CCtx. - * Important : in order to behave similarly to `ZSTD_compress()`, - * this function compresses at requested compression level, - * __ignoring any other parameter__ . + * Important : in order to mirror `ZSTD_compress()` behavior, + * this function compresses at the requested compression level, + * __ignoring any other advanced parameter__ . * If any advanced parameter was set using the advanced API, * they will all be reset. Only `compressionLevel` remains. */ @@ -209,38 +279,38 @@ ZSTDLIB_API size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, /*= Decompression context * When decompressing many times, * it is recommended to allocate a context only once, - * and re-use it for each successive compression operation. + * and reuse it for each successive compression operation. * This will make workload friendlier for system's memory. * Use one context per thread for parallel execution. */ typedef struct ZSTD_DCtx_s ZSTD_DCtx; ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx(void); -ZSTDLIB_API size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); +ZSTDLIB_API size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); /* accept NULL pointer */ /*! ZSTD_decompressDCtx() : * Same as ZSTD_decompress(), * requires an allocated ZSTD_DCtx. - * Compatible with sticky parameters. + * Compatible with sticky parameters (see below). */ ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -/*************************************** -* Advanced compression API -***************************************/ +/********************************************* +* Advanced compression API (Requires v1.4.0+) +**********************************************/ /* API design : * Parameters are pushed one by one into an existing context, * using ZSTD_CCtx_set*() functions. * Pushed parameters are sticky : they are valid for next compressed frame, and any subsequent frame. * "sticky" parameters are applicable to `ZSTD_compress2()` and `ZSTD_compressStream*()` ! - * __They do not apply to "simple" one-shot variants such as ZSTD_compressCCtx()__ . + * __They do not apply to one-shot variants such as ZSTD_compressCCtx()__ . * * It's possible to reset all parameters to "default" using ZSTD_CCtx_reset(). * - * This API supercedes all other "advanced" API entry points in the experimental section. - * In the future, we expect to remove from experimental API entry points which are redundant with this API. + * This API supersedes all other "advanced" API entry points in the experimental section. + * In the future, we expect to remove API entry points from experimental which are redundant with this API. */ @@ -258,7 +328,6 @@ typedef enum { ZSTD_fast=1, Only the order (from fast to strong) is guaranteed */ } ZSTD_strategy; - typedef enum { /* compression parameters @@ -325,13 +394,27 @@ typedef enum { * resulting in stronger and slower compression. * Special: value 0 means "use default strategy". */ + ZSTD_c_targetCBlockSize=130, /* v1.5.6+ + * Attempts to fit compressed block size into approximatively targetCBlockSize. + * Bound by ZSTD_TARGETCBLOCKSIZE_MIN and ZSTD_TARGETCBLOCKSIZE_MAX. + * Note that it's not a guarantee, just a convergence target (default:0). + * No target when targetCBlockSize == 0. + * This is helpful in low bandwidth streaming environments to improve end-to-end latency, + * when a client can make use of partial documents (a prominent example being Chrome). + * Note: this parameter is stable since v1.5.6. + * It was present as an experimental parameter in earlier versions, + * but it's not recommended using it with earlier library versions + * due to massive performance regressions. + */ /* LDM mode parameters */ ZSTD_c_enableLongDistanceMatching=160, /* Enable long distance matching. * This parameter is designed to improve compression ratio * for large inputs, by finding large matches at long distance. * It increases memory usage and window size. * Note: enabling this parameter increases default ZSTD_c_windowLog to 128 MB - * except when expressly set to a different value. */ + * except when expressly set to a different value. + * Note: will be enabled by default if ZSTD_c_windowLog >= 128 MB and + * compression strategy >= ZSTD_btopt (== compression level 16+) */ ZSTD_c_ldmHashLog=161, /* Size of the table for long distance matching, as a power of 2. * Larger values increase memory usage and compression ratio, * but decrease compression speed. @@ -362,20 +445,24 @@ typedef enum { ZSTD_c_dictIDFlag=202, /* When applicable, dictionary's ID is written into frame header (default:1) */ /* multi-threading parameters */ - /* These parameters are only useful if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD). - * They return an error otherwise. */ + /* These parameters are only active if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD). + * Otherwise, trying to set any other value than default (0) will be a no-op and return an error. + * In a situation where it's unknown if the linked library supports multi-threading or not, + * setting ZSTD_c_nbWorkers to any value >= 1 and consulting the return value provides a quick way to check this property. + */ ZSTD_c_nbWorkers=400, /* Select how many threads will be spawned to compress in parallel. - * When nbWorkers >= 1, triggers asynchronous mode when used with ZSTD_compressStream*() : + * When nbWorkers >= 1, triggers asynchronous mode when invoking ZSTD_compressStream*() : * ZSTD_compressStream*() consumes input and flush output if possible, but immediately gives back control to caller, - * while compression work is performed in parallel, within worker threads. + * while compression is performed in parallel, within worker thread(s). * (note : a strong exception to this rule is when first invocation of ZSTD_compressStream2() sets ZSTD_e_end : * in which case, ZSTD_compressStream2() delegates to ZSTD_compress2(), which is always a blocking call). * More workers improve speed, but also increase memory usage. - * Default value is `0`, aka "single-threaded mode" : no worker is spawned, compression is performed inside Caller's thread, all invocations are blocking */ + * Default value is `0`, aka "single-threaded mode" : no worker is spawned, + * compression is performed inside Caller's thread, and all invocations are blocking */ ZSTD_c_jobSize=401, /* Size of a compression job. This value is enforced only when nbWorkers >= 1. * Each compression job is completed in parallel, so this value can indirectly impact the nb of active threads. * 0 means default, which is dynamically determined based on compression parameters. - * Job size must be a minimum of overlap size, or 1 MB, whichever is largest. + * Job size must be a minimum of overlap size, or ZSTDMT_JOBSIZE_MIN (= 512 KB), whichever is largest. * The minimum size is automatically and transparently enforced. */ ZSTD_c_overlapLog=402, /* Control the overlap size, as a fraction of window size. * The overlap size is an amount of data reloaded from previous job at the beginning of a new job. @@ -398,8 +485,17 @@ typedef enum { * ZSTD_c_forceMaxWindow * ZSTD_c_forceAttachDict * ZSTD_c_literalCompressionMode - * ZSTD_c_targetCBlockSize * ZSTD_c_srcSizeHint + * ZSTD_c_enableDedicatedDictSearch + * ZSTD_c_stableInBuffer + * ZSTD_c_stableOutBuffer + * ZSTD_c_blockDelimiters + * ZSTD_c_validateSequences + * ZSTD_c_useBlockSplitter + * ZSTD_c_useRowMatchFinder + * ZSTD_c_prefetchCDictTables + * ZSTD_c_enableSeqProducerFallback + * ZSTD_c_maxBlockSize * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. * note : never ever use experimentalParam? names directly; * also, the enums values themselves are unstable and can still change. @@ -409,8 +505,20 @@ typedef enum { ZSTD_c_experimentalParam3=1000, ZSTD_c_experimentalParam4=1001, ZSTD_c_experimentalParam5=1002, - ZSTD_c_experimentalParam6=1003, - ZSTD_c_experimentalParam7=1004 + /* was ZSTD_c_experimentalParam6=1003; is now ZSTD_c_targetCBlockSize */ + ZSTD_c_experimentalParam7=1004, + ZSTD_c_experimentalParam8=1005, + ZSTD_c_experimentalParam9=1006, + ZSTD_c_experimentalParam10=1007, + ZSTD_c_experimentalParam11=1008, + ZSTD_c_experimentalParam12=1009, + ZSTD_c_experimentalParam13=1010, + ZSTD_c_experimentalParam14=1011, + ZSTD_c_experimentalParam15=1012, + ZSTD_c_experimentalParam16=1013, + ZSTD_c_experimentalParam17=1014, + ZSTD_c_experimentalParam18=1015, + ZSTD_c_experimentalParam19=1016 } ZSTD_cParameter; typedef struct { @@ -473,7 +581,7 @@ typedef enum { * They will be used to compress next frame. * Resetting session never fails. * - The parameters : changes all parameters back to "default". - * This removes any reference to any dictionary too. + * This also removes any reference to any dictionary or external sequence producer. * Parameters can only be changed between 2 sessions (i.e. no compression is currently ongoing) * otherwise the reset fails, and function returns an error value (which can be tested using ZSTD_isError()) * - Both : similar to resetting the session, followed by resetting parameters. @@ -482,11 +590,13 @@ ZSTDLIB_API size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset); /*! ZSTD_compress2() : * Behave the same as ZSTD_compressCCtx(), but compression parameters are set using the advanced API. + * (note that this entry point doesn't even expose a compression level parameter). * ZSTD_compress2() always starts a new frame. * Should cctx hold data from a previously unfinished frame, everything about it is forgotten. * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*() * - The function is always blocking, returns when compression is completed. - * Hint : compression runs faster if `dstCapacity` >= `ZSTD_compressBound(srcSize)`. + * NOTE: Providing `dstCapacity >= ZSTD_compressBound(srcSize)` guarantees that zstd will have + * enough space to successfully compress the data, though it is possible it fails for other reasons. * @return : compressed size written into `dst` (<= `dstCapacity), * or an error code if it fails (which can be tested using ZSTD_isError()). */ @@ -495,9 +605,9 @@ ZSTDLIB_API size_t ZSTD_compress2( ZSTD_CCtx* cctx, const void* src, size_t srcSize); -/*************************************** -* Advanced decompression API -***************************************/ +/*********************************************** +* Advanced decompression API (Requires v1.4.0+) +************************************************/ /* The advanced API pushes parameters one by one into an existing DCtx context. * Parameters are sticky, and remain valid for all following frames @@ -521,11 +631,19 @@ typedef enum { * At the time of this writing, they include : * ZSTD_d_format * ZSTD_d_stableOutBuffer + * ZSTD_d_forceIgnoreChecksum + * ZSTD_d_refMultipleDDicts + * ZSTD_d_disableHuffmanAssembly + * ZSTD_d_maxBlockSize * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. * note : never ever use experimentalParam? names directly */ ZSTD_d_experimentalParam1=1000, - ZSTD_d_experimentalParam2=1001 + ZSTD_d_experimentalParam2=1001, + ZSTD_d_experimentalParam3=1002, + ZSTD_d_experimentalParam4=1003, + ZSTD_d_experimentalParam5=1004, + ZSTD_d_experimentalParam6=1005 } ZSTD_dParameter; @@ -580,14 +698,14 @@ typedef struct ZSTD_outBuffer_s { * A ZSTD_CStream object is required to track streaming operation. * Use ZSTD_createCStream() and ZSTD_freeCStream() to create/release resources. * ZSTD_CStream objects can be reused multiple times on consecutive compression operations. -* It is recommended to re-use ZSTD_CStream since it will play nicer with system's memory, by re-using already allocated memory. +* It is recommended to reuse ZSTD_CStream since it will play nicer with system's memory, by re-using already allocated memory. * * For parallel execution, use one separate ZSTD_CStream per thread. * * note : since v1.3.0, ZSTD_CStream and ZSTD_CCtx are the same thing. * * Parameters are sticky : when starting a new compression on the same context, -* it will re-use the same sticky parameters as previous compression session. +* it will reuse the same sticky parameters as previous compression session. * When in doubt, it's recommended to fully initialize the context before usage. * Use ZSTD_CCtx_reset() to reset the context and ZSTD_CCtx_setParameter(), * ZSTD_CCtx_setPledgedSrcSize(), or ZSTD_CCtx_loadDictionary() and friends to @@ -639,7 +757,7 @@ typedef ZSTD_CCtx ZSTD_CStream; /**< CCtx and CStream are now effectively same /* Continue to distinguish them for compatibility with older versions <= v1.2.0 */ /*===== ZSTD_CStream management functions =====*/ ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream(void); -ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs); +ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs); /* accept NULL pointer */ /*===== Streaming compression functions =====*/ typedef enum { @@ -655,14 +773,15 @@ typedef enum { : note : multithreaded compression will block to flush as much output as possible. */ } ZSTD_EndDirective; -/*! ZSTD_compressStream2() : +/*! ZSTD_compressStream2() : Requires v1.4.0+ * Behaves about the same as ZSTD_compressStream, with additional control on end directive. * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*() * - Compression parameters cannot be changed once compression is started (save a list of exceptions in multi-threading mode) * - output->pos must be <= dstCapacity, input->pos must be <= srcSize * - output->pos and input->pos will be updated. They are guaranteed to remain below their respective limit. + * - endOp must be a valid directive * - When nbWorkers==0 (default), function is blocking : it completes its job before returning to caller. - * - When nbWorkers>=1, function is non-blocking : it just acquires a copy of input, and distributes jobs to internal worker threads, flush whatever is available, + * - When nbWorkers>=1, function is non-blocking : it copies a portion of input, distributes jobs to internal worker threads, flush to output whatever is available, * and then immediately returns, just indicating that there is some data remaining to be flushed. * The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte. * - Exception : if the first call requests a ZSTD_e_end directive and provides enough dstCapacity, the function delegates to ZSTD_compress2() which is always blocking. @@ -675,6 +794,11 @@ typedef enum { * only ZSTD_e_end or ZSTD_e_flush operations are allowed. * Before starting a new compression job, or changing compression parameters, * it is required to fully flush internal buffers. + * - note: if an operation ends with an error, it may leave @cctx in an undefined state. + * Therefore, it's UB to invoke ZSTD_compressStream2() of ZSTD_compressStream() on such a state. + * In order to be re-employed after an error, a state must be reset, + * which can be done explicitly (ZSTD_CCtx_reset()), + * or is sometimes implied by methods starting a new compression job (ZSTD_initCStream(), ZSTD_compressCCtx()) */ ZSTDLIB_API size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, ZSTD_outBuffer* output, @@ -700,11 +824,9 @@ ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output /* ***************************************************************************** - * This following is a legacy streaming API. + * This following is a legacy streaming API, available since v1.0+ . * It can be replaced by ZSTD_CCtx_reset() and ZSTD_compressStream2(). * It is redundant, but remains fully supported. - * Advanced parameters and dictionary compression can only be used through the - * new API. ******************************************************************************/ /*! @@ -713,6 +835,9 @@ ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any) * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); + * + * Note that ZSTD_initCStream() clears any previously set dictionary. Use the new API + * to compress with a dictionary. */ ZSTDLIB_API size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel); /*! @@ -733,7 +858,7 @@ ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output); * * A ZSTD_DStream object is required to track streaming operations. * Use ZSTD_createDStream() and ZSTD_freeDStream() to create/release resources. -* ZSTD_DStream objects can be re-used multiple times. +* ZSTD_DStream objects can be reused multiple times. * * Use ZSTD_initDStream() to start a new decompression operation. * @return : recommended first input size @@ -759,17 +884,41 @@ typedef ZSTD_DCtx ZSTD_DStream; /**< DCtx and DStream are now effectively same /* For compatibility with versions <= v1.2.0, prefer differentiating them. */ /*===== ZSTD_DStream management functions =====*/ ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void); -ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds); +ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds); /* accept NULL pointer */ /*===== Streaming decompression functions =====*/ -/* This function is redundant with the advanced API and equivalent to: +/*! ZSTD_initDStream() : + * Initialize/reset DStream state for new decompression operation. + * Call before new decompression operation using same DStream. * + * Note : This function is redundant with the advanced API and equivalent to: * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); * ZSTD_DCtx_refDDict(zds, NULL); */ ZSTDLIB_API size_t ZSTD_initDStream(ZSTD_DStream* zds); +/*! ZSTD_decompressStream() : + * Streaming decompression function. + * Call repetitively to consume full input updating it as necessary. + * Function will update both input and output `pos` fields exposing current state via these fields: + * - `input.pos < input.size`, some input remaining and caller should provide remaining input + * on the next call. + * - `output.pos < output.size`, decoder finished and flushed all remaining buffers. + * - `output.pos == output.size`, potentially uncflushed data present in the internal buffers, + * call ZSTD_decompressStream() again to flush remaining data to output. + * Note : with no additional input, amount of data flushed <= ZSTD_BLOCKSIZE_MAX. + * + * @return : 0 when a frame is completely decoded and fully flushed, + * or an error code, which can be tested using ZSTD_isError(), + * or any other value > 0, which means there is some decoding or flushing to do to complete current frame. + * + * Note: when an operation returns with an error code, the @zds state may be left in undefined state. + * It's UB to invoke `ZSTD_decompressStream()` on such a state. + * In order to re-use such a state, it must be first reset, + * which can be done explicitly (`ZSTD_DCtx_reset()`), + * or is implied for operations starting some new decompression job (`ZSTD_initDStream`, `ZSTD_decompressDCtx()`, `ZSTD_decompress_usingDict()`) + */ ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input); ZSTDLIB_API size_t ZSTD_DStreamInSize(void); /*!< recommended size for input buffer */ @@ -782,7 +931,7 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output /*! ZSTD_compress_usingDict() : * Compression at an explicit compression level using a Dictionary. * A dictionary can be any arbitrary data segment (also called a prefix), - * or a buffer with specified information (see dict/zdict.h). + * or a buffer with specified information (see zdict.h). * Note : This function loads the dictionary, resulting in significant startup delay. * It's intended for a dictionary used only once. * Note 2 : When `dict == NULL || dictSize < 8` no dictionary is used. */ @@ -825,7 +974,8 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize int compressionLevel); /*! ZSTD_freeCDict() : - * Function frees memory allocated by ZSTD_createCDict(). */ + * Function frees memory allocated by ZSTD_createCDict(). + * If a NULL pointer is passed, no operation is performed. */ ZSTDLIB_API size_t ZSTD_freeCDict(ZSTD_CDict* CDict); /*! ZSTD_compress_usingCDict() : @@ -847,7 +997,8 @@ typedef struct ZSTD_DDict_s ZSTD_DDict; ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict(const void* dictBuffer, size_t dictSize); /*! ZSTD_freeDDict() : - * Function frees memory allocated with ZSTD_createDDict() */ + * Function frees memory allocated with ZSTD_createDDict() + * If a NULL pointer is passed, no operation is performed. */ ZSTDLIB_API size_t ZSTD_freeDDict(ZSTD_DDict* ddict); /*! ZSTD_decompress_usingDDict() : @@ -863,24 +1014,30 @@ ZSTDLIB_API size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, * Dictionary helper functions *******************************/ -/*! ZSTD_getDictID_fromDict() : +/*! ZSTD_getDictID_fromDict() : Requires v1.4.0+ * Provides the dictID stored within dictionary. * if @return == 0, the dictionary is not conformant with Zstandard specification. * It can still be loaded, but as a content-only dictionary. */ ZSTDLIB_API unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize); -/*! ZSTD_getDictID_fromDDict() : +/*! ZSTD_getDictID_fromCDict() : Requires v1.5.0+ + * Provides the dictID of the dictionary loaded into `cdict`. + * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. + * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ +ZSTDLIB_API unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict); + +/*! ZSTD_getDictID_fromDDict() : Requires v1.4.0+ * Provides the dictID of the dictionary loaded into `ddict`. * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ ZSTDLIB_API unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict); -/*! ZSTD_getDictID_fromFrame() : +/*! ZSTD_getDictID_fromFrame() : Requires v1.4.0+ * Provides the dictID required to decompressed the frame stored within `src`. * If @return == 0, the dictID could not be decoded. * This could for one of the following reasons : * - The frame does not require a dictionary to be decoded (most common case). - * - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden information. + * - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden piece of information. * Note : this use case also happens when using a non-conformant dictionary. * - `srcSize` is too small, and as a result, the frame header could not be decoded (only possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`). * - This is not a Zstandard frame. @@ -889,23 +1046,26 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize); /******************************************************************************* - * Advanced dictionary and prefix API + * Advanced dictionary and prefix API (Requires v1.4.0+) * * This API allows dictionaries to be used with ZSTD_compress2(), - * ZSTD_compressStream2(), and ZSTD_decompress(). Dictionaries are sticky, and - * only reset with the context is reset with ZSTD_reset_parameters or - * ZSTD_reset_session_and_parameters. Prefixes are single-use. + * ZSTD_compressStream2(), and ZSTD_decompressDCtx(). + * Dictionaries are sticky, they remain valid when same context is reused, + * they only reset when the context is reset + * with ZSTD_reset_parameters or ZSTD_reset_session_and_parameters. + * In contrast, Prefixes are single-use. ******************************************************************************/ -/*! ZSTD_CCtx_loadDictionary() : +/*! ZSTD_CCtx_loadDictionary() : Requires v1.4.0+ * Create an internal CDict from `dict` buffer. * Decompression will have to use same dictionary. * @result : 0, or an error code (which can be tested with ZSTD_isError()). * Special: Loading a NULL (or 0-size) dictionary invalidates previous dictionary, * meaning "return to no-dictionary mode". - * Note 1 : Dictionary is sticky, it will be used for all future compressed frames. - * To return to "no-dictionary" situation, load a NULL dictionary (or reset parameters). + * Note 1 : Dictionary is sticky, it will be used for all future compressed frames, + * until parameters are reset, a new dictionary is loaded, or the dictionary + * is explicitly invalidated by loading a NULL dictionary. * Note 2 : Loading a dictionary involves building tables. * It's also a CPU consuming operation, with non-negligible impact on latency. * Tables are dependent on compression parameters, and for this reason, @@ -914,14 +1074,18 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize); * Use experimental ZSTD_CCtx_loadDictionary_byReference() to reference content instead. * In such a case, dictionary buffer must outlive its users. * Note 4 : Use ZSTD_CCtx_loadDictionary_advanced() - * to precisely select how dictionary content must be interpreted. */ + * to precisely select how dictionary content must be interpreted. + * Note 5 : This method does not benefit from LDM (long distance mode). + * If you want to employ LDM on some large dictionary content, + * prefer employing ZSTD_CCtx_refPrefix() described below. + */ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); -/*! ZSTD_CCtx_refCDict() : - * Reference a prepared dictionary, to be used for all next compressed frames. +/*! ZSTD_CCtx_refCDict() : Requires v1.4.0+ + * Reference a prepared dictionary, to be used for all future compressed frames. * Note that compression parameters are enforced from within CDict, * and supersede any compression parameter previously set within CCtx. - * The parameters ignored are labled as "superseded-by-cdict" in the ZSTD_cParameter enum docs. + * The parameters ignored are labelled as "superseded-by-cdict" in the ZSTD_cParameter enum docs. * The ignored parameters will be used again if the CCtx is returned to no-dictionary mode. * The dictionary will remain valid for future compressed frames using same CCtx. * @result : 0, or an error code (which can be tested with ZSTD_isError()). @@ -931,12 +1095,13 @@ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, s * Note 2 : CDict is just referenced, its lifetime must outlive its usage within CCtx. */ ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); -/*! ZSTD_CCtx_refPrefix() : +/*! ZSTD_CCtx_refPrefix() : Requires v1.4.0+ * Reference a prefix (single-usage dictionary) for next compressed frame. * A prefix is **only used once**. Tables are discarded at end of frame (ZSTD_e_end). * Decompression will need same prefix to properly regenerate data. * Compressing with a prefix is similar in outcome as performing a diff and compressing it, * but performs much faster, especially during decompression (compression speed is tunable with compression level). + * This method is compatible with LDM (long distance mode). * @result : 0, or an error code (which can be tested with ZSTD_isError()). * Special: Adding any prefix (including NULL) invalidates any previous prefix or dictionary * Note 1 : Prefix buffer is referenced. It **must** outlive compression. @@ -952,10 +1117,10 @@ ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize); -/*! ZSTD_DCtx_loadDictionary() : - * Create an internal DDict from dict buffer, - * to be used to decompress next frames. - * The dictionary remains valid for all future frames, until explicitly invalidated. +/*! ZSTD_DCtx_loadDictionary() : Requires v1.4.0+ + * Create an internal DDict from dict buffer, to be used to decompress all future frames. + * The dictionary remains valid for all future frames, until explicitly invalidated, or + * a new dictionary is loaded. * @result : 0, or an error code (which can be tested with ZSTD_isError()). * Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary, * meaning "return to no-dictionary mode". @@ -969,18 +1134,26 @@ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, */ ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); -/*! ZSTD_DCtx_refDDict() : +/*! ZSTD_DCtx_refDDict() : Requires v1.4.0+ * Reference a prepared dictionary, to be used to decompress next frames. * The dictionary remains active for decompression of future frames using same DCtx. + * + * If called with ZSTD_d_refMultipleDDicts enabled, repeated calls of this function + * will store the DDict references in a table, and the DDict used for decompression + * will be determined at decompression time, as per the dict ID in the frame. + * The memory for the table is allocated on the first call to refDDict, and can be + * freed with ZSTD_freeDCtx(). + * + * If called with ZSTD_d_refMultipleDDicts disabled (the default), only one dictionary + * will be managed, and referencing a dictionary effectively "discards" any previous one. + * * @result : 0, or an error code (which can be tested with ZSTD_isError()). - * Note 1 : Currently, only one dictionary can be managed. - * Referencing a new dictionary effectively "discards" any previous one. * Special: referencing a NULL DDict means "return to no-dictionary mode". * Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx. */ ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); -/*! ZSTD_DCtx_refPrefix() : +/*! ZSTD_DCtx_refPrefix() : Requires v1.4.0+ * Reference a prefix (single-usage dictionary) to decompress next frame. * This is the reverse operation of ZSTD_CCtx_refPrefix(), * and must use the same prefix as the one used during compression. @@ -1001,7 +1174,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, /* === Memory management === */ -/*! ZSTD_sizeof_*() : +/*! ZSTD_sizeof_*() : Requires v1.4.0+ * These functions give the _current_ memory usage of selected object. * Note that object memory usage can evolve (increase or decrease) over time. */ ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx); @@ -1011,5 +1184,1910 @@ ZSTDLIB_API size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds); ZSTDLIB_API size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict); ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); -} +} // namespace duckdb_zstd + #endif /* ZSTD_H_235446 */ + +namespace duckdb_zstd { + +/* ************************************************************************************** + * ADVANCED AND EXPERIMENTAL FUNCTIONS + **************************************************************************************** + * The definitions in the following section are considered experimental. + * They are provided for advanced scenarios. + * They should never be used with a dynamic library, as prototypes may change in the future. + * Use them only in association with static linking. + * ***************************************************************************************/ + +#if defined(ZSTD_STATIC_LINKING_ONLY) && !defined(ZSTD_H_ZSTD_STATIC_LINKING_ONLY) +#define ZSTD_H_ZSTD_STATIC_LINKING_ONLY + +/* This can be overridden externally to hide static symbols. */ +#ifndef ZSTDLIB_STATIC_API +# if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZSTDLIB_STATIC_API __declspec(dllexport) ZSTDLIB_VISIBLE +# elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZSTDLIB_STATIC_API __declspec(dllimport) ZSTDLIB_VISIBLE +# else +# define ZSTDLIB_STATIC_API ZSTDLIB_VISIBLE +# endif +#endif + +/**************************************************************************************** + * experimental API (static linking only) + **************************************************************************************** + * The following symbols and constants + * are not planned to join "stable API" status in the near future. + * They can still change in future versions. + * Some of them are planned to remain in the static_only section indefinitely. + * Some of them might be removed in the future (especially when redundant with existing stable functions) + * ***************************************************************************************/ + +#define ZSTD_FRAMEHEADERSIZE_PREFIX(format) ((format) == ZSTD_f_zstd1 ? 5 : 1) /* minimum input size required to query frame header size */ +#define ZSTD_FRAMEHEADERSIZE_MIN(format) ((format) == ZSTD_f_zstd1 ? 6 : 2) +#define ZSTD_FRAMEHEADERSIZE_MAX 18 /* can be useful for static allocation */ +#define ZSTD_SKIPPABLEHEADERSIZE 8 + +/* compression parameter bounds */ +#define ZSTD_WINDOWLOG_MAX_32 30 +#define ZSTD_WINDOWLOG_MAX_64 31 +#define ZSTD_WINDOWLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64)) +#define ZSTD_WINDOWLOG_MIN 10 +#define ZSTD_HASHLOG_MAX ((ZSTD_WINDOWLOG_MAX < 30) ? ZSTD_WINDOWLOG_MAX : 30) +#define ZSTD_HASHLOG_MIN 6 +#define ZSTD_CHAINLOG_MAX_32 29 +#define ZSTD_CHAINLOG_MAX_64 30 +#define ZSTD_CHAINLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_CHAINLOG_MAX_32 : ZSTD_CHAINLOG_MAX_64)) +#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN +#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1) +#define ZSTD_SEARCHLOG_MIN 1 +#define ZSTD_MINMATCH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */ +#define ZSTD_MINMATCH_MIN 3 /* only for ZSTD_btopt+, faster strategies are limited to 4 */ +#define ZSTD_TARGETLENGTH_MAX ZSTD_BLOCKSIZE_MAX +#define ZSTD_TARGETLENGTH_MIN 0 /* note : comparing this constant to an unsigned results in a tautological test */ +#define ZSTD_STRATEGY_MIN ZSTD_fast +#define ZSTD_STRATEGY_MAX ZSTD_btultra2 +#define ZSTD_BLOCKSIZE_MAX_MIN (1 << 10) /* The minimum valid max blocksize. Maximum blocksizes smaller than this make compressBound() inaccurate. */ + + +#define ZSTD_OVERLAPLOG_MIN 0 +#define ZSTD_OVERLAPLOG_MAX 9 + +#define ZSTD_WINDOWLOG_LIMIT_DEFAULT 27 /* by default, the streaming decoder will refuse any frame */ + /* requiring larger than (1< 0: + * If litLength != 0: + * rep == 1 --> offset == repeat_offset_1 + * rep == 2 --> offset == repeat_offset_2 + * rep == 3 --> offset == repeat_offset_3 + * If litLength == 0: + * rep == 1 --> offset == repeat_offset_2 + * rep == 2 --> offset == repeat_offset_3 + * rep == 3 --> offset == repeat_offset_1 - 1 + * + * Note: This field is optional. ZSTD_generateSequences() will calculate the value of + * 'rep', but repeat offsets do not necessarily need to be calculated from an external + * sequence provider's perspective. For example, ZSTD_compressSequences() does not + * use this 'rep' field at all (as of now). + */ +} ZSTD_Sequence; + +typedef struct { + unsigned windowLog; /**< largest match distance : larger == more compression, more memory needed during decompression */ + unsigned chainLog; /**< fully searched segment : larger == more compression, slower, more memory (useless for fast) */ + unsigned hashLog; /**< dispatch table : larger == faster, more memory */ + unsigned searchLog; /**< nb of searches : larger == more compression, slower */ + unsigned minMatch; /**< match length searched : larger == faster decompression, sometimes less compression */ + unsigned targetLength; /**< acceptable match size for optimal parser (only) : larger == more compression, slower */ + ZSTD_strategy strategy; /**< see ZSTD_strategy definition above */ +} ZSTD_compressionParameters; + +typedef struct { + int contentSizeFlag; /**< 1: content size will be in frame header (when known) */ + int checksumFlag; /**< 1: generate a 32-bits checksum using XXH64 algorithm at end of frame, for error detection */ + int noDictIDFlag; /**< 1: no dictID will be saved into frame header (dictID is only useful for dictionary compression) */ +} ZSTD_frameParameters; + +typedef struct { + ZSTD_compressionParameters cParams; + ZSTD_frameParameters fParams; +} ZSTD_parameters; + +typedef enum { + ZSTD_dct_auto = 0, /* dictionary is "full" when starting with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */ + ZSTD_dct_rawContent = 1, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */ + ZSTD_dct_fullDict = 2 /* refuses to load a dictionary if it does not respect Zstandard's specification, starting with ZSTD_MAGIC_DICTIONARY */ +} ZSTD_dictContentType_e; + +typedef enum { + ZSTD_dlm_byCopy = 0, /**< Copy dictionary content internally */ + ZSTD_dlm_byRef = 1 /**< Reference dictionary content -- the dictionary buffer must outlive its users. */ +} ZSTD_dictLoadMethod_e; + +typedef enum { + ZSTD_f_zstd1 = 0, /* zstd frame format, specified in zstd_compression_format.md (default) */ + ZSTD_f_zstd1_magicless = 1 /* Variant of zstd frame format, without initial 4-bytes magic number. + * Useful to save 4 bytes per generated frame. + * Decoder cannot recognise automatically this format, requiring this instruction. */ +} ZSTD_format_e; + +typedef enum { + /* Note: this enum controls ZSTD_d_forceIgnoreChecksum */ + ZSTD_d_validateChecksum = 0, + ZSTD_d_ignoreChecksum = 1 +} ZSTD_forceIgnoreChecksum_e; + +typedef enum { + /* Note: this enum controls ZSTD_d_refMultipleDDicts */ + ZSTD_rmd_refSingleDDict = 0, + ZSTD_rmd_refMultipleDDicts = 1 +} ZSTD_refMultipleDDicts_e; + +typedef enum { + /* Note: this enum and the behavior it controls are effectively internal + * implementation details of the compressor. They are expected to continue + * to evolve and should be considered only in the context of extremely + * advanced performance tuning. + * + * Zstd currently supports the use of a CDict in three ways: + * + * - The contents of the CDict can be copied into the working context. This + * means that the compression can search both the dictionary and input + * while operating on a single set of internal tables. This makes + * the compression faster per-byte of input. However, the initial copy of + * the CDict's tables incurs a fixed cost at the beginning of the + * compression. For small compressions (< 8 KB), that copy can dominate + * the cost of the compression. + * + * - The CDict's tables can be used in-place. In this model, compression is + * slower per input byte, because the compressor has to search two sets of + * tables. However, this model incurs no start-up cost (as long as the + * working context's tables can be reused). For small inputs, this can be + * faster than copying the CDict's tables. + * + * - The CDict's tables are not used at all, and instead we use the working + * context alone to reload the dictionary and use params based on the source + * size. See ZSTD_compress_insertDictionary() and ZSTD_compress_usingDict(). + * This method is effective when the dictionary sizes are very small relative + * to the input size, and the input size is fairly large to begin with. + * + * Zstd has a simple internal heuristic that selects which strategy to use + * at the beginning of a compression. However, if experimentation shows that + * Zstd is making poor choices, it is possible to override that choice with + * this enum. + */ + ZSTD_dictDefaultAttach = 0, /* Use the default heuristic. */ + ZSTD_dictForceAttach = 1, /* Never copy the dictionary. */ + ZSTD_dictForceCopy = 2, /* Always copy the dictionary. */ + ZSTD_dictForceLoad = 3 /* Always reload the dictionary */ +} ZSTD_dictAttachPref_e; + +typedef enum { + ZSTD_lcm_auto = 0, /**< Automatically determine the compression mode based on the compression level. + * Negative compression levels will be uncompressed, and positive compression + * levels will be compressed. */ + ZSTD_lcm_huffman = 1, /**< Always attempt Huffman compression. Uncompressed literals will still be + * emitted if Huffman compression is not profitable. */ + ZSTD_lcm_uncompressed = 2 /**< Always emit uncompressed literals. */ +} ZSTD_literalCompressionMode_e; + +typedef enum { + /* Note: This enum controls features which are conditionally beneficial. Zstd typically will make a final + * decision on whether or not to enable the feature (ZSTD_ps_auto), but setting the switch to ZSTD_ps_enable + * or ZSTD_ps_disable allow for a force enable/disable the feature. + */ + ZSTD_ps_auto = 0, /* Let the library automatically determine whether the feature shall be enabled */ + ZSTD_ps_enable = 1, /* Force-enable the feature */ + ZSTD_ps_disable = 2 /* Do not use the feature */ +} ZSTD_paramSwitch_e; + +/*************************************** +* Frame header and size functions +***************************************/ + +/*! ZSTD_findDecompressedSize() : + * `src` should point to the start of a series of ZSTD encoded and/or skippable frames + * `srcSize` must be the _exact_ size of this series + * (i.e. there should be a frame boundary at `src + srcSize`) + * @return : - decompressed size of all data in all successive frames + * - if the decompressed size cannot be determined: ZSTD_CONTENTSIZE_UNKNOWN + * - if an error occurred: ZSTD_CONTENTSIZE_ERROR + * + * note 1 : decompressed size is an optional field, that may not be present, especially in streaming mode. + * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size. + * In which case, it's necessary to use streaming mode to decompress data. + * note 2 : decompressed size is always present when compression is done with ZSTD_compress() + * note 3 : decompressed size can be very large (64-bits value), + * potentially larger than what local system can handle as a single memory segment. + * In which case, it's necessary to use streaming mode to decompress data. + * note 4 : If source is untrusted, decompressed size could be wrong or intentionally modified. + * Always ensure result fits within application's authorized limits. + * Each application can set its own limits. + * note 5 : ZSTD_findDecompressedSize handles multiple frames, and so it must traverse the input to + * read each contained frame header. This is fast as most of the data is skipped, + * however it does mean that all frame data must be present and valid. */ +ZSTDLIB_STATIC_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize); + +/*! ZSTD_decompressBound() : + * `src` should point to the start of a series of ZSTD encoded and/or skippable frames + * `srcSize` must be the _exact_ size of this series + * (i.e. there should be a frame boundary at `src + srcSize`) + * @return : - upper-bound for the decompressed size of all data in all successive frames + * - if an error occurred: ZSTD_CONTENTSIZE_ERROR + * + * note 1 : an error can occur if `src` contains an invalid or incorrectly formatted frame. + * note 2 : the upper-bound is exact when the decompressed size field is available in every ZSTD encoded frame of `src`. + * in this case, `ZSTD_findDecompressedSize` and `ZSTD_decompressBound` return the same value. + * note 3 : when the decompressed size field isn't available, the upper-bound for that frame is calculated by: + * upper-bound = # blocks * min(128 KB, Window_Size) + */ +ZSTDLIB_STATIC_API unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize); + +/*! ZSTD_frameHeaderSize() : + * srcSize must be >= ZSTD_FRAMEHEADERSIZE_PREFIX. + * @return : size of the Frame Header, + * or an error code (if srcSize is too small) */ +ZSTDLIB_STATIC_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize); + +typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e; +typedef struct { + unsigned long long frameContentSize; /* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */ + unsigned long long windowSize; /* can be very large, up to <= frameContentSize */ + unsigned blockSizeMax; + ZSTD_frameType_e frameType; /* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */ + unsigned headerSize; + unsigned dictID; + unsigned checksumFlag; + unsigned _reserved1; + unsigned _reserved2; +} ZSTD_frameHeader; + +/*! ZSTD_getFrameHeader() : + * decode Frame Header, or requires larger `srcSize`. + * @return : 0, `zfhPtr` is correctly filled, + * >0, `srcSize` is too small, value is wanted `srcSize` amount, + * or an error code, which can be tested using ZSTD_isError() */ +ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */ +/*! ZSTD_getFrameHeader_advanced() : + * same as ZSTD_getFrameHeader(), + * with added capability to select a format (like ZSTD_f_zstd1_magicless) */ +ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format); + +/*! ZSTD_decompressionMargin() : + * Zstd supports in-place decompression, where the input and output buffers overlap. + * In this case, the output buffer must be at least (Margin + Output_Size) bytes large, + * and the input buffer must be at the end of the output buffer. + * + * _______________________ Output Buffer ________________________ + * | | + * | ____ Input Buffer ____| + * | | | + * v v v + * |---------------------------------------|-----------|----------| + * ^ ^ ^ + * |___________________ Output_Size ___________________|_ Margin _| + * + * NOTE: See also ZSTD_DECOMPRESSION_MARGIN(). + * NOTE: This applies only to single-pass decompression through ZSTD_decompress() or + * ZSTD_decompressDCtx(). + * NOTE: This function supports multi-frame input. + * + * @param src The compressed frame(s) + * @param srcSize The size of the compressed frame(s) + * @returns The decompression margin or an error that can be checked with ZSTD_isError(). + */ +ZSTDLIB_STATIC_API size_t ZSTD_decompressionMargin(const void* src, size_t srcSize); + +/*! ZSTD_DECOMPRESS_MARGIN() : + * Similar to ZSTD_decompressionMargin(), but instead of computing the margin from + * the compressed frame, compute it from the original size and the blockSizeLog. + * See ZSTD_decompressionMargin() for details. + * + * WARNING: This macro does not support multi-frame input, the input must be a single + * zstd frame. If you need that support use the function, or implement it yourself. + * + * @param originalSize The original uncompressed size of the data. + * @param blockSize The block size == MIN(windowSize, ZSTD_BLOCKSIZE_MAX). + * Unless you explicitly set the windowLog smaller than + * ZSTD_BLOCKSIZELOG_MAX you can just use ZSTD_BLOCKSIZE_MAX. + */ +#define ZSTD_DECOMPRESSION_MARGIN(originalSize, blockSize) ((size_t)( \ + ZSTD_FRAMEHEADERSIZE_MAX /* Frame header */ + \ + 4 /* checksum */ + \ + ((originalSize) == 0 ? 0 : 3 * (((originalSize) + (blockSize) - 1) / blockSize)) /* 3 bytes per block */ + \ + (blockSize) /* One block of margin */ \ + )) + +typedef enum { + ZSTD_sf_noBlockDelimiters = 0, /* Representation of ZSTD_Sequence has no block delimiters, sequences only */ + ZSTD_sf_explicitBlockDelimiters = 1 /* Representation of ZSTD_Sequence contains explicit block delimiters */ +} ZSTD_sequenceFormat_e; + +/*! ZSTD_sequenceBound() : + * `srcSize` : size of the input buffer + * @return : upper-bound for the number of sequences that can be generated + * from a buffer of srcSize bytes + * + * note : returns number of sequences - to get bytes, multiply by sizeof(ZSTD_Sequence). + */ +ZSTDLIB_STATIC_API size_t ZSTD_sequenceBound(size_t srcSize); + +/*! ZSTD_generateSequences() : + * WARNING: This function is meant for debugging and informational purposes ONLY! + * Its implementation is flawed, and it will be deleted in a future version. + * It is not guaranteed to succeed, as there are several cases where it will give + * up and fail. You should NOT use this function in production code. + * + * This function is deprecated, and will be removed in a future version. + * + * Generate sequences using ZSTD_compress2(), given a source buffer. + * + * @param zc The compression context to be used for ZSTD_compress2(). Set any + * compression parameters you need on this context. + * @param outSeqs The output sequences buffer of size @p outSeqsSize + * @param outSeqsSize The size of the output sequences buffer. + * ZSTD_sequenceBound(srcSize) is an upper bound on the number + * of sequences that can be generated. + * @param src The source buffer to generate sequences from of size @p srcSize. + * @param srcSize The size of the source buffer. + * + * Each block will end with a dummy sequence + * with offset == 0, matchLength == 0, and litLength == length of last literals. + * litLength may be == 0, and if so, then the sequence of (of: 0 ml: 0 ll: 0) + * simply acts as a block delimiter. + * + * @returns The number of sequences generated, necessarily less than + * ZSTD_sequenceBound(srcSize), or an error code that can be checked + * with ZSTD_isError(). + */ +ZSTD_DEPRECATED("For debugging only, will be replaced by ZSTD_extractSequences()") +ZSTDLIB_STATIC_API size_t +ZSTD_generateSequences(ZSTD_CCtx* zc, + ZSTD_Sequence* outSeqs, size_t outSeqsSize, + const void* src, size_t srcSize); + +/*! ZSTD_mergeBlockDelimiters() : + * Given an array of ZSTD_Sequence, remove all sequences that represent block delimiters/last literals + * by merging them into the literals of the next sequence. + * + * As such, the final generated result has no explicit representation of block boundaries, + * and the final last literals segment is not represented in the sequences. + * + * The output of this function can be fed into ZSTD_compressSequences() with CCtx + * setting of ZSTD_c_blockDelimiters as ZSTD_sf_noBlockDelimiters + * @return : number of sequences left after merging + */ +ZSTDLIB_STATIC_API size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize); + +/*! ZSTD_compressSequences() : + * Compress an array of ZSTD_Sequence, associated with @src buffer, into dst. + * @src contains the entire input (not just the literals). + * If @srcSize > sum(sequence.length), the remaining bytes are considered all literals + * If a dictionary is included, then the cctx should reference the dict. (see: ZSTD_CCtx_refCDict(), ZSTD_CCtx_loadDictionary(), etc.) + * The entire source is compressed into a single frame. + * + * The compression behavior changes based on cctx params. In particular: + * If ZSTD_c_blockDelimiters == ZSTD_sf_noBlockDelimiters, the array of ZSTD_Sequence is expected to contain + * no block delimiters (defined in ZSTD_Sequence). Block boundaries are roughly determined based on + * the block size derived from the cctx, and sequences may be split. This is the default setting. + * + * If ZSTD_c_blockDelimiters == ZSTD_sf_explicitBlockDelimiters, the array of ZSTD_Sequence is expected to contain + * block delimiters (defined in ZSTD_Sequence). Behavior is undefined if no block delimiters are provided. + * + * If ZSTD_c_validateSequences == 0, this function will blindly accept the sequences provided. Invalid sequences cause undefined + * behavior. If ZSTD_c_validateSequences == 1, then if sequence is invalid (see doc/zstd_compression_format.md for + * specifics regarding offset/matchlength requirements) then the function will bail out and return an error. + * + * In addition to the two adjustable experimental params, there are other important cctx params. + * - ZSTD_c_minMatch MUST be set as less than or equal to the smallest match generated by the match finder. It has a minimum value of ZSTD_MINMATCH_MIN. + * - ZSTD_c_compressionLevel accordingly adjusts the strength of the entropy coder, as it would in typical compression. + * - ZSTD_c_windowLog affects offset validation: this function will return an error at higher debug levels if a provided offset + * is larger than what the spec allows for a given window log and dictionary (if present). See: doc/zstd_compression_format.md + * + * Note: Repcodes are, as of now, always re-calculated within this function, so ZSTD_Sequence::rep is unused. + * Note 2: Once we integrate ability to ingest repcodes, the explicit block delims mode must respect those repcodes exactly, + * and cannot emit an RLE block that disagrees with the repcode history + * @return : final compressed size, or a ZSTD error code. + */ +ZSTDLIB_STATIC_API size_t +ZSTD_compressSequences( ZSTD_CCtx* cctx, void* dst, size_t dstSize, + const ZSTD_Sequence* inSeqs, size_t inSeqsSize, + const void* src, size_t srcSize); + + +/*! ZSTD_writeSkippableFrame() : + * Generates a zstd skippable frame containing data given by src, and writes it to dst buffer. + * + * Skippable frames begin with a 4-byte magic number. There are 16 possible choices of magic number, + * ranging from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15. + * As such, the parameter magicVariant controls the exact skippable frame magic number variant used, so + * the magic number used will be ZSTD_MAGIC_SKIPPABLE_START + magicVariant. + * + * Returns an error if destination buffer is not large enough, if the source size is not representable + * with a 4-byte unsigned int, or if the parameter magicVariant is greater than 15 (and therefore invalid). + * + * @return : number of bytes written or a ZSTD error. + */ +ZSTDLIB_STATIC_API size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity, + const void* src, size_t srcSize, unsigned magicVariant); + +/*! ZSTD_readSkippableFrame() : + * Retrieves a zstd skippable frame containing data given by src, and writes it to dst buffer. + * + * The parameter magicVariant will receive the magicVariant that was supplied when the frame was written, + * i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested + * in the magicVariant. + * + * Returns an error if destination buffer is not large enough, or if the frame is not skippable. + * + * @return : number of bytes written or a ZSTD error. + */ +ZSTDLIB_API size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, unsigned* magicVariant, + const void* src, size_t srcSize); + +/*! ZSTD_isSkippableFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame. + */ +ZSTDLIB_API unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size); + + + +/*************************************** +* Memory management +***************************************/ + +/*! ZSTD_estimate*() : + * These functions make it possible to estimate memory usage + * of a future {D,C}Ctx, before its creation. + * This is useful in combination with ZSTD_initStatic(), + * which makes it possible to employ a static buffer for ZSTD_CCtx* state. + * + * ZSTD_estimateCCtxSize() will provide a memory budget large enough + * to compress data of any size using one-shot compression ZSTD_compressCCtx() or ZSTD_compress2() + * associated with any compression level up to max specified one. + * The estimate will assume the input may be arbitrarily large, + * which is the worst case. + * + * Note that the size estimation is specific for one-shot compression, + * it is not valid for streaming (see ZSTD_estimateCStreamSize*()) + * nor other potential ways of using a ZSTD_CCtx* state. + * + * When srcSize can be bound by a known and rather "small" value, + * this knowledge can be used to provide a tighter budget estimation + * because the ZSTD_CCtx* state will need less memory for small inputs. + * This tighter estimation can be provided by employing more advanced functions + * ZSTD_estimateCCtxSize_usingCParams(), which can be used in tandem with ZSTD_getCParams(), + * and ZSTD_estimateCCtxSize_usingCCtxParams(), which can be used in tandem with ZSTD_CCtxParams_setParameter(). + * Both can be used to estimate memory using custom compression parameters and arbitrary srcSize limits. + * + * Note : only single-threaded compression is supported. + * ZSTD_estimateCCtxSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. + */ +ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize(int maxCompressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDCtxSize(void); + +/*! ZSTD_estimateCStreamSize() : + * ZSTD_estimateCStreamSize() will provide a memory budget large enough for streaming compression + * using any compression level up to the max specified one. + * It will also consider src size to be arbitrarily "large", which is a worst case scenario. + * If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation. + * ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + * ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParams_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_c_nbWorkers is >= 1. + * Note : CStream size estimation is only correct for single-threaded compression. + * ZSTD_estimateCStreamSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. + * Note 2 : ZSTD_estimateCStreamSize* functions are not compatible with the Block-Level Sequence Producer API at this time. + * Size estimates assume that no external sequence producer is registered. + * + * ZSTD_DStream memory budget depends on frame's window Size. + * This information can be passed manually, using ZSTD_estimateDStreamSize, + * or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame(); + * Any frame requesting a window size larger than max specified one will be rejected. + * Note : if streaming is init with function ZSTD_init?Stream_usingDict(), + * an internal ?Dict will be created, which additional size is not estimated here. + * In this case, get total size by adding ZSTD_estimate?DictSize + */ +ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize(int maxCompressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize(size_t maxWindowSize); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); + +/*! ZSTD_estimate?DictSize() : + * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). + * ZSTD_estimateCDictSize_advanced() makes it possible to control compression parameters precisely, like ZSTD_createCDict_advanced(). + * Note : dictionaries created by reference (`ZSTD_dlm_byRef`) are logically smaller. + */ +ZSTDLIB_STATIC_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod); + +/*! ZSTD_initStatic*() : + * Initialize an object using a pre-allocated fixed-size buffer. + * workspace: The memory area to emplace the object into. + * Provided pointer *must be 8-bytes aligned*. + * Buffer must outlive object. + * workspaceSize: Use ZSTD_estimate*Size() to determine + * how large workspace must be to support target scenario. + * @return : pointer to object (same address as workspace, just different type), + * or NULL if error (size too small, incorrect alignment, etc.) + * Note : zstd will never resize nor malloc() when using a static buffer. + * If the object requires more memory than available, + * zstd will just error out (typically ZSTD_error_memory_allocation). + * Note 2 : there is no corresponding "free" function. + * Since workspace is allocated externally, it must be freed externally too. + * Note 3 : cParams : use ZSTD_getCParams() to convert a compression level + * into its associated cParams. + * Limitation 1 : currently not compatible with internal dictionary creation, triggered by + * ZSTD_CCtx_loadDictionary(), ZSTD_initCStream_usingDict() or ZSTD_initDStream_usingDict(). + * Limitation 2 : static cctx currently not compatible with multi-threading. + * Limitation 3 : static dctx is incompatible with legacy support. + */ +ZSTDLIB_STATIC_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize); +ZSTDLIB_STATIC_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */ + +ZSTDLIB_STATIC_API ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize); +ZSTDLIB_STATIC_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */ + +ZSTDLIB_STATIC_API const ZSTD_CDict* ZSTD_initStaticCDict( + void* workspace, size_t workspaceSize, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_compressionParameters cParams); + +ZSTDLIB_STATIC_API const ZSTD_DDict* ZSTD_initStaticDDict( + void* workspace, size_t workspaceSize, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType); + + +/*! Custom memory allocation : + * These prototypes make it possible to pass your own allocation/free functions. + * ZSTD_customMem is provided at creation time, using ZSTD_create*_advanced() variants listed below. + * All allocation/free operations will be completed using these custom variants instead of regular ones. + */ +typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size); +typedef void (*ZSTD_freeFunction) (void* opaque, void* address); +typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem; +static +#ifdef __GNUC__ +__attribute__((__unused__)) +#endif +ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL }; /**< this constant defers to stdlib's functions */ + +ZSTDLIB_STATIC_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem); +ZSTDLIB_STATIC_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); +ZSTDLIB_STATIC_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem); +ZSTDLIB_STATIC_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem); + +ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_compressionParameters cParams, + ZSTD_customMem customMem); + +/*! Thread pool : + * These prototypes make it possible to share a thread pool among multiple compression contexts. + * This can limit resources for applications with multiple threads where each one uses + * a threaded compression mode (via ZSTD_c_nbWorkers parameter). + * ZSTD_createThreadPool creates a new thread pool with a given number of threads. + * Note that the lifetime of such pool must exist while being used. + * ZSTD_CCtx_refThreadPool assigns a thread pool to a context (use NULL argument value + * to use an internal thread pool). + * ZSTD_freeThreadPool frees a thread pool, accepts NULL pointer. + */ +typedef struct POOL_ctx_s ZSTD_threadPool; +ZSTDLIB_STATIC_API ZSTD_threadPool* ZSTD_createThreadPool(size_t numThreads); +ZSTDLIB_STATIC_API void ZSTD_freeThreadPool (ZSTD_threadPool* pool); /* accept NULL pointer */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool); + + +/* + * This API is temporary and is expected to change or disappear in the future! + */ +ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_advanced2( + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + const ZSTD_CCtx_params* cctxParams, + ZSTD_customMem customMem); + +ZSTDLIB_STATIC_API ZSTD_DDict* ZSTD_createDDict_advanced( + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_customMem customMem); + + +/*************************************** +* Advanced compression functions +***************************************/ + +/*! ZSTD_createCDict_byReference() : + * Create a digested dictionary for compression + * Dictionary content is just referenced, not duplicated. + * As a consequence, `dictBuffer` **must** outlive CDict, + * and its content must remain unmodified throughout the lifetime of CDict. + * note: equivalent to ZSTD_createCDict_advanced(), with dictLoadMethod==ZSTD_dlm_byRef */ +ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel); + +/*! ZSTD_getCParams() : + * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. + * `estimatedSrcSize` value is optional, select 0 if not known */ +ZSTDLIB_STATIC_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); + +/*! ZSTD_getParams() : + * same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`. + * All fields of `ZSTD_frameParameters` are set to default : contentSize=1, checksum=0, noDictID=0 */ +ZSTDLIB_STATIC_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); + +/*! ZSTD_checkCParams() : + * Ensure param values remain within authorized range. + * @return 0 on success, or an error code (can be checked with ZSTD_isError()) */ +ZSTDLIB_STATIC_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params); + +/*! ZSTD_adjustCParams() : + * optimize params for a given `srcSize` and `dictSize`. + * `srcSize` can be unknown, in which case use ZSTD_CONTENTSIZE_UNKNOWN. + * `dictSize` must be `0` when there is no dictionary. + * cPar can be invalid : all parameters will be clamped within valid range in the @return struct. + * This function never fails (wide contract) */ +ZSTDLIB_STATIC_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize); + +/*! ZSTD_CCtx_setCParams() : + * Set all parameters provided within @p cparams into the working @p cctx. + * Note : if modifying parameters during compression (MT mode only), + * note that changes to the .windowLog parameter will be ignored. + * @return 0 on success, or an error code (can be checked with ZSTD_isError()). + * On failure, no parameters are updated. + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setCParams(ZSTD_CCtx* cctx, ZSTD_compressionParameters cparams); + +/*! ZSTD_CCtx_setFParams() : + * Set all parameters provided within @p fparams into the working @p cctx. + * @return 0 on success, or an error code (can be checked with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setFParams(ZSTD_CCtx* cctx, ZSTD_frameParameters fparams); + +/*! ZSTD_CCtx_setParams() : + * Set all parameters provided within @p params into the working @p cctx. + * @return 0 on success, or an error code (can be checked with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setParams(ZSTD_CCtx* cctx, ZSTD_parameters params); + +/*! ZSTD_compress_advanced() : + * Note : this function is now DEPRECATED. + * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_setParameter() and other parameter setters. + * This prototype will generate compilation warnings. */ +ZSTD_DEPRECATED("use ZSTD_compress2") +ZSTDLIB_STATIC_API +size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize, + ZSTD_parameters params); + +/*! ZSTD_compress_usingCDict_advanced() : + * Note : this function is now DEPRECATED. + * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_loadDictionary() and other parameter setters. + * This prototype will generate compilation warnings. */ +ZSTD_DEPRECATED("use ZSTD_compress2 with ZSTD_CCtx_loadDictionary") +ZSTDLIB_STATIC_API +size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict, + ZSTD_frameParameters fParams); + + +/*! ZSTD_CCtx_loadDictionary_byReference() : + * Same as ZSTD_CCtx_loadDictionary(), but dictionary content is referenced, instead of being copied into CCtx. + * It saves some memory, but also requires that `dict` outlives its usage within `cctx` */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); + +/*! ZSTD_CCtx_loadDictionary_advanced() : + * Same as ZSTD_CCtx_loadDictionary(), but gives finer control over + * how to load the dictionary (by copy ? by reference ?) + * and how to interpret it (automatic ? force raw mode ? full mode only ?) */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); + +/*! ZSTD_CCtx_refPrefix_advanced() : + * Same as ZSTD_CCtx_refPrefix(), but gives finer control over + * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); + +/* === experimental parameters === */ +/* these parameters can be used with ZSTD_setParameter() + * they are not guaranteed to remain supported in the future */ + + /* Enables rsyncable mode, + * which makes compressed files more rsync friendly + * by adding periodic synchronization points to the compressed data. + * The target average block size is ZSTD_c_jobSize / 2. + * It's possible to modify the job size to increase or decrease + * the granularity of the synchronization point. + * Once the jobSize is smaller than the window size, + * it will result in compression ratio degradation. + * NOTE 1: rsyncable mode only works when multithreading is enabled. + * NOTE 2: rsyncable performs poorly in combination with long range mode, + * since it will decrease the effectiveness of synchronization points, + * though mileage may vary. + * NOTE 3: Rsyncable mode limits maximum compression speed to ~400 MB/s. + * If the selected compression level is already running significantly slower, + * the overall speed won't be significantly impacted. + */ + #define ZSTD_c_rsyncable ZSTD_c_experimentalParam1 + +/* Select a compression format. + * The value must be of type ZSTD_format_e. + * See ZSTD_format_e enum definition for details */ +#define ZSTD_c_format ZSTD_c_experimentalParam2 + +/* Force back-reference distances to remain < windowSize, + * even when referencing into Dictionary content (default:0) */ +#define ZSTD_c_forceMaxWindow ZSTD_c_experimentalParam3 + +/* Controls whether the contents of a CDict + * are used in place, or copied into the working context. + * Accepts values from the ZSTD_dictAttachPref_e enum. + * See the comments on that enum for an explanation of the feature. */ +#define ZSTD_c_forceAttachDict ZSTD_c_experimentalParam4 + +/* Controlled with ZSTD_paramSwitch_e enum. + * Default is ZSTD_ps_auto. + * Set to ZSTD_ps_disable to never compress literals. + * Set to ZSTD_ps_enable to always compress literals. (Note: uncompressed literals + * may still be emitted if huffman is not beneficial to use.) + * + * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use + * literals compression based on the compression parameters - specifically, + * negative compression levels do not use literal compression. + */ +#define ZSTD_c_literalCompressionMode ZSTD_c_experimentalParam5 + +/* User's best guess of source size. + * Hint is not valid when srcSizeHint == 0. + * There is no guarantee that hint is close to actual source size, + * but compression ratio may regress significantly if guess considerably underestimates */ +#define ZSTD_c_srcSizeHint ZSTD_c_experimentalParam7 + +/* Controls whether the new and experimental "dedicated dictionary search + * structure" can be used. This feature is still rough around the edges, be + * prepared for surprising behavior! + * + * How to use it: + * + * When using a CDict, whether to use this feature or not is controlled at + * CDict creation, and it must be set in a CCtxParams set passed into that + * construction (via ZSTD_createCDict_advanced2()). A compression will then + * use the feature or not based on how the CDict was constructed; the value of + * this param, set in the CCtx, will have no effect. + * + * However, when a dictionary buffer is passed into a CCtx, such as via + * ZSTD_CCtx_loadDictionary(), this param can be set on the CCtx to control + * whether the CDict that is created internally can use the feature or not. + * + * What it does: + * + * Normally, the internal data structures of the CDict are analogous to what + * would be stored in a CCtx after compressing the contents of a dictionary. + * To an approximation, a compression using a dictionary can then use those + * data structures to simply continue what is effectively a streaming + * compression where the simulated compression of the dictionary left off. + * Which is to say, the search structures in the CDict are normally the same + * format as in the CCtx. + * + * It is possible to do better, since the CDict is not like a CCtx: the search + * structures are written once during CDict creation, and then are only read + * after that, while the search structures in the CCtx are both read and + * written as the compression goes along. This means we can choose a search + * structure for the dictionary that is read-optimized. + * + * This feature enables the use of that different structure. + * + * Note that some of the members of the ZSTD_compressionParameters struct have + * different semantics and constraints in the dedicated search structure. It is + * highly recommended that you simply set a compression level in the CCtxParams + * you pass into the CDict creation call, and avoid messing with the cParams + * directly. + * + * Effects: + * + * This will only have any effect when the selected ZSTD_strategy + * implementation supports this feature. Currently, that's limited to + * ZSTD_greedy, ZSTD_lazy, and ZSTD_lazy2. + * + * Note that this means that the CDict tables can no longer be copied into the + * CCtx, so the dict attachment mode ZSTD_dictForceCopy will no longer be + * usable. The dictionary can only be attached or reloaded. + * + * In general, you should expect compression to be faster--sometimes very much + * so--and CDict creation to be slightly slower. Eventually, we will probably + * make this mode the default. + */ +#define ZSTD_c_enableDedicatedDictSearch ZSTD_c_experimentalParam8 + +/* ZSTD_c_stableInBuffer + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable. + * + * Tells the compressor that input data presented with ZSTD_inBuffer + * will ALWAYS be the same between calls. + * Technically, the @src pointer must never be changed, + * and the @pos field can only be updated by zstd. + * However, it's possible to increase the @size field, + * allowing scenarios where more data can be appended after compressions starts. + * These conditions are checked by the compressor, + * and compression will fail if they are not respected. + * Also, data in the ZSTD_inBuffer within the range [src, src + pos) + * MUST not be modified during compression or it will result in data corruption. + * + * When this flag is enabled zstd won't allocate an input window buffer, + * because the user guarantees it can reference the ZSTD_inBuffer until + * the frame is complete. But, it will still allocate an output buffer + * large enough to fit a block (see ZSTD_c_stableOutBuffer). This will also + * avoid the memcpy() from the input buffer to the input window buffer. + * + * NOTE: So long as the ZSTD_inBuffer always points to valid memory, using + * this flag is ALWAYS memory safe, and will never access out-of-bounds + * memory. However, compression WILL fail if conditions are not respected. + * + * WARNING: The data in the ZSTD_inBuffer in the range [src, src + pos) MUST + * not be modified during compression or it will result in data corruption. + * This is because zstd needs to reference data in the ZSTD_inBuffer to find + * matches. Normally zstd maintains its own window buffer for this purpose, + * but passing this flag tells zstd to rely on user provided buffer instead. + */ +#define ZSTD_c_stableInBuffer ZSTD_c_experimentalParam9 + +/* ZSTD_c_stableOutBuffer + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable. + * + * Tells he compressor that the ZSTD_outBuffer will not be resized between + * calls. Specifically: (out.size - out.pos) will never grow. This gives the + * compressor the freedom to say: If the compressed data doesn't fit in the + * output buffer then return ZSTD_error_dstSizeTooSmall. This allows us to + * always decompress directly into the output buffer, instead of decompressing + * into an internal buffer and copying to the output buffer. + * + * When this flag is enabled zstd won't allocate an output buffer, because + * it can write directly to the ZSTD_outBuffer. It will still allocate the + * input window buffer (see ZSTD_c_stableInBuffer). + * + * Zstd will check that (out.size - out.pos) never grows and return an error + * if it does. While not strictly necessary, this should prevent surprises. + */ +#define ZSTD_c_stableOutBuffer ZSTD_c_experimentalParam10 + +/* ZSTD_c_blockDelimiters + * Default is 0 == ZSTD_sf_noBlockDelimiters. + * + * For use with sequence compression API: ZSTD_compressSequences(). + * + * Designates whether or not the given array of ZSTD_Sequence contains block delimiters + * and last literals, which are defined as sequences with offset == 0 and matchLength == 0. + * See the definition of ZSTD_Sequence for more specifics. + */ +#define ZSTD_c_blockDelimiters ZSTD_c_experimentalParam11 + +/* ZSTD_c_validateSequences + * Default is 0 == disabled. Set to 1 to enable sequence validation. + * + * For use with sequence compression API: ZSTD_compressSequences(). + * Designates whether or not we validate sequences provided to ZSTD_compressSequences() + * during function execution. + * + * Without validation, providing a sequence that does not conform to the zstd spec will cause + * undefined behavior, and may produce a corrupted block. + * + * With validation enabled, if sequence is invalid (see doc/zstd_compression_format.md for + * specifics regarding offset/matchlength requirements) then the function will bail out and + * return an error. + * + */ +#define ZSTD_c_validateSequences ZSTD_c_experimentalParam12 + +/* ZSTD_c_useBlockSplitter + * Controlled with ZSTD_paramSwitch_e enum. + * Default is ZSTD_ps_auto. + * Set to ZSTD_ps_disable to never use block splitter. + * Set to ZSTD_ps_enable to always use block splitter. + * + * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use + * block splitting based on the compression parameters. + */ +#define ZSTD_c_useBlockSplitter ZSTD_c_experimentalParam13 + +/* ZSTD_c_useRowMatchFinder + * Controlled with ZSTD_paramSwitch_e enum. + * Default is ZSTD_ps_auto. + * Set to ZSTD_ps_disable to never use row-based matchfinder. + * Set to ZSTD_ps_enable to force usage of row-based matchfinder. + * + * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use + * the row-based matchfinder based on support for SIMD instructions and the window log. + * Note that this only pertains to compression strategies: greedy, lazy, and lazy2 + */ +#define ZSTD_c_useRowMatchFinder ZSTD_c_experimentalParam14 + +/* ZSTD_c_deterministicRefPrefix + * Default is 0 == disabled. Set to 1 to enable. + * + * Zstd produces different results for prefix compression when the prefix is + * directly adjacent to the data about to be compressed vs. when it isn't. + * This is because zstd detects that the two buffers are contiguous and it can + * use a more efficient match finding algorithm. However, this produces different + * results than when the two buffers are non-contiguous. This flag forces zstd + * to always load the prefix in non-contiguous mode, even if it happens to be + * adjacent to the data, to guarantee determinism. + * + * If you really care about determinism when using a dictionary or prefix, + * like when doing delta compression, you should select this option. It comes + * at a speed penalty of about ~2.5% if the dictionary and data happened to be + * contiguous, and is free if they weren't contiguous. We don't expect that + * intentionally making the dictionary and data contiguous will be worth the + * cost to memcpy() the data. + */ +#define ZSTD_c_deterministicRefPrefix ZSTD_c_experimentalParam15 + +/* ZSTD_c_prefetchCDictTables + * Controlled with ZSTD_paramSwitch_e enum. Default is ZSTD_ps_auto. + * + * In some situations, zstd uses CDict tables in-place rather than copying them + * into the working context. (See docs on ZSTD_dictAttachPref_e above for details). + * In such situations, compression speed is seriously impacted when CDict tables are + * "cold" (outside CPU cache). This parameter instructs zstd to prefetch CDict tables + * when they are used in-place. + * + * For sufficiently small inputs, the cost of the prefetch will outweigh the benefit. + * For sufficiently large inputs, zstd will by default memcpy() CDict tables + * into the working context, so there is no need to prefetch. This parameter is + * targeted at a middle range of input sizes, where a prefetch is cheap enough to be + * useful but memcpy() is too expensive. The exact range of input sizes where this + * makes sense is best determined by careful experimentation. + * + * Note: for this parameter, ZSTD_ps_auto is currently equivalent to ZSTD_ps_disable, + * but in the future zstd may conditionally enable this feature via an auto-detection + * heuristic for cold CDicts. + * Use ZSTD_ps_disable to opt out of prefetching under any circumstances. + */ +#define ZSTD_c_prefetchCDictTables ZSTD_c_experimentalParam16 + +/* ZSTD_c_enableSeqProducerFallback + * Allowed values are 0 (disable) and 1 (enable). The default setting is 0. + * + * Controls whether zstd will fall back to an internal sequence producer if an + * external sequence producer is registered and returns an error code. This fallback + * is block-by-block: the internal sequence producer will only be called for blocks + * where the external sequence producer returns an error code. Fallback parsing will + * follow any other cParam settings, such as compression level, the same as in a + * normal (fully-internal) compression operation. + * + * The user is strongly encouraged to read the full Block-Level Sequence Producer API + * documentation (below) before setting this parameter. */ +#define ZSTD_c_enableSeqProducerFallback ZSTD_c_experimentalParam17 + +/* ZSTD_c_maxBlockSize + * Allowed values are between 1KB and ZSTD_BLOCKSIZE_MAX (128KB). + * The default is ZSTD_BLOCKSIZE_MAX, and setting to 0 will set to the default. + * + * This parameter can be used to set an upper bound on the blocksize + * that overrides the default ZSTD_BLOCKSIZE_MAX. It cannot be used to set upper + * bounds greater than ZSTD_BLOCKSIZE_MAX or bounds lower than 1KB (will make + * compressBound() inaccurate). Only currently meant to be used for testing. + * + */ +#define ZSTD_c_maxBlockSize ZSTD_c_experimentalParam18 + +/* ZSTD_c_searchForExternalRepcodes + * This parameter affects how zstd parses external sequences, such as sequences + * provided through the compressSequences() API or from an external block-level + * sequence producer. + * + * If set to ZSTD_ps_enable, the library will check for repeated offsets in + * external sequences, even if those repcodes are not explicitly indicated in + * the "rep" field. Note that this is the only way to exploit repcode matches + * while using compressSequences() or an external sequence producer, since zstd + * currently ignores the "rep" field of external sequences. + * + * If set to ZSTD_ps_disable, the library will not exploit repeated offsets in + * external sequences, regardless of whether the "rep" field has been set. This + * reduces sequence compression overhead by about 25% while sacrificing some + * compression ratio. + * + * The default value is ZSTD_ps_auto, for which the library will enable/disable + * based on compression level. + * + * Note: for now, this param only has an effect if ZSTD_c_blockDelimiters is + * set to ZSTD_sf_explicitBlockDelimiters. That may change in the future. + */ +#define ZSTD_c_searchForExternalRepcodes ZSTD_c_experimentalParam19 + +/*! ZSTD_CCtx_getParameter() : + * Get the requested compression parameter value, selected by enum ZSTD_cParameter, + * and store it into int* value. + * @return : 0, or an error code (which can be tested with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_getParameter(const ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value); + + +/*! ZSTD_CCtx_params : + * Quick howto : + * - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure + * - ZSTD_CCtxParams_setParameter() : Push parameters one by one into + * an existing ZSTD_CCtx_params structure. + * This is similar to + * ZSTD_CCtx_setParameter(). + * - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to + * an existing CCtx. + * These parameters will be applied to + * all subsequent frames. + * - ZSTD_compressStream2() : Do compression using the CCtx. + * - ZSTD_freeCCtxParams() : Free the memory, accept NULL pointer. + * + * This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams() + * for static allocation of CCtx for single-threaded compression. + */ +ZSTDLIB_STATIC_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); +ZSTDLIB_STATIC_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); /* accept NULL pointer */ + +/*! ZSTD_CCtxParams_reset() : + * Reset params to default values. + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params); + +/*! ZSTD_CCtxParams_init() : + * Initializes the compression parameters of cctxParams according to + * compression level. All other parameters are reset to their default values. + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel); + +/*! ZSTD_CCtxParams_init_advanced() : + * Initializes the compression and frame parameters of cctxParams according to + * params. All other parameters are reset to their default values. + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); + +/*! ZSTD_CCtxParams_setParameter() : Requires v1.4.0+ + * Similar to ZSTD_CCtx_setParameter. + * Set one compression parameter, selected by enum ZSTD_cParameter. + * Parameters must be applied to a ZSTD_CCtx using + * ZSTD_CCtx_setParametersUsingCCtxParams(). + * @result : a code representing success or failure (which can be tested with + * ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int value); + +/*! ZSTD_CCtxParams_getParameter() : + * Similar to ZSTD_CCtx_getParameter. + * Get the requested value of one compression parameter, selected by enum ZSTD_cParameter. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_getParameter(const ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value); + +/*! ZSTD_CCtx_setParametersUsingCCtxParams() : + * Apply a set of ZSTD_CCtx_params to the compression context. + * This can be done even after compression is started, + * if nbWorkers==0, this will have no impact until a new compression is started. + * if nbWorkers>=1, new parameters will be picked up at next job, + * with a few restrictions (windowLog, pledgedSrcSize, nbWorkers, jobSize, and overlapLog are not updated). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setParametersUsingCCtxParams( + ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params); + +/*! ZSTD_compressStream2_simpleArgs() : + * Same as ZSTD_compressStream2(), + * but using only integral types as arguments. + * This variant might be helpful for binders from dynamic languages + * which have troubles handling structures containing memory pointers. + */ +ZSTDLIB_STATIC_API size_t ZSTD_compressStream2_simpleArgs ( + ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos, + ZSTD_EndDirective endOp); + + +/*************************************** +* Advanced decompression functions +***************************************/ + +/*! ZSTD_isFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier. + * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. + * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled. + * Note 3 : Skippable Frame Identifiers are considered valid. */ +ZSTDLIB_STATIC_API unsigned ZSTD_isFrame(const void* buffer, size_t size); + +/*! ZSTD_createDDict_byReference() : + * Create a digested dictionary, ready to start decompression operation without startup delay. + * Dictionary content is referenced, and therefore stays in dictBuffer. + * It is important that dictBuffer outlives DDict, + * it must remain read accessible throughout the lifetime of DDict */ +ZSTDLIB_STATIC_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize); + +/*! ZSTD_DCtx_loadDictionary_byReference() : + * Same as ZSTD_DCtx_loadDictionary(), + * but references `dict` content instead of copying it into `dctx`. + * This saves memory if `dict` remains around., + * However, it's imperative that `dict` remains accessible (and unmodified) while being used, so it must outlive decompression. */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); + +/*! ZSTD_DCtx_loadDictionary_advanced() : + * Same as ZSTD_DCtx_loadDictionary(), + * but gives direct control over + * how to load the dictionary (by copy ? by reference ?) + * and how to interpret it (automatic ? force raw mode ? full mode only ?). */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); + +/*! ZSTD_DCtx_refPrefix_advanced() : + * Same as ZSTD_DCtx_refPrefix(), but gives finer control over + * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); + +/*! ZSTD_DCtx_setMaxWindowSize() : + * Refuses allocating internal buffers for frames requiring a window size larger than provided limit. + * This protects a decoder context from reserving too much memory for itself (potential attack scenario). + * This parameter is only useful in streaming mode, since no internal buffer is allocated in single-pass mode. + * By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + * @return : 0, or an error code (which can be tested using ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize); + +/*! ZSTD_DCtx_getParameter() : + * Get the requested decompression parameter value, selected by enum ZSTD_dParameter, + * and store it into int* value. + * @return : 0, or an error code (which can be tested with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value); + +/* ZSTD_d_format + * experimental parameter, + * allowing selection between ZSTD_format_e input compression formats + */ +#define ZSTD_d_format ZSTD_d_experimentalParam1 +/* ZSTD_d_stableOutBuffer + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable. + * + * Tells the decompressor that the ZSTD_outBuffer will ALWAYS be the same + * between calls, except for the modifications that zstd makes to pos (the + * caller must not modify pos). This is checked by the decompressor, and + * decompression will fail if it ever changes. Therefore the ZSTD_outBuffer + * MUST be large enough to fit the entire decompressed frame. This will be + * checked when the frame content size is known. The data in the ZSTD_outBuffer + * in the range [dst, dst + pos) MUST not be modified during decompression + * or you will get data corruption. + * + * When this flag is enabled zstd won't allocate an output buffer, because + * it can write directly to the ZSTD_outBuffer, but it will still allocate + * an input buffer large enough to fit any compressed block. This will also + * avoid the memcpy() from the internal output buffer to the ZSTD_outBuffer. + * If you need to avoid the input buffer allocation use the buffer-less + * streaming API. + * + * NOTE: So long as the ZSTD_outBuffer always points to valid memory, using + * this flag is ALWAYS memory safe, and will never access out-of-bounds + * memory. However, decompression WILL fail if you violate the preconditions. + * + * WARNING: The data in the ZSTD_outBuffer in the range [dst, dst + pos) MUST + * not be modified during decompression or you will get data corruption. This + * is because zstd needs to reference data in the ZSTD_outBuffer to regenerate + * matches. Normally zstd maintains its own buffer for this purpose, but passing + * this flag tells zstd to use the user provided buffer. + */ +#define ZSTD_d_stableOutBuffer ZSTD_d_experimentalParam2 + +/* ZSTD_d_forceIgnoreChecksum + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable + * + * Tells the decompressor to skip checksum validation during decompression, regardless + * of whether checksumming was specified during compression. This offers some + * slight performance benefits, and may be useful for debugging. + * Param has values of type ZSTD_forceIgnoreChecksum_e + */ +#define ZSTD_d_forceIgnoreChecksum ZSTD_d_experimentalParam3 + +/* ZSTD_d_refMultipleDDicts + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable + * + * If enabled and dctx is allocated on the heap, then additional memory will be allocated + * to store references to multiple ZSTD_DDict. That is, multiple calls of ZSTD_refDDict() + * using a given ZSTD_DCtx, rather than overwriting the previous DDict reference, will instead + * store all references. At decompression time, the appropriate dictID is selected + * from the set of DDicts based on the dictID in the frame. + * + * Usage is simply calling ZSTD_refDDict() on multiple dict buffers. + * + * Param has values of byte ZSTD_refMultipleDDicts_e + * + * WARNING: Enabling this parameter and calling ZSTD_DCtx_refDDict(), will trigger memory + * allocation for the hash table. ZSTD_freeDCtx() also frees this memory. + * Memory is allocated as per ZSTD_DCtx::customMem. + * + * Although this function allocates memory for the table, the user is still responsible for + * memory management of the underlying ZSTD_DDict* themselves. + */ +#define ZSTD_d_refMultipleDDicts ZSTD_d_experimentalParam4 + +/* ZSTD_d_disableHuffmanAssembly + * Set to 1 to disable the Huffman assembly implementation. + * The default value is 0, which allows zstd to use the Huffman assembly + * implementation if available. + * + * This parameter can be used to disable Huffman assembly at runtime. + * If you want to disable it at compile time you can define the macro + * ZSTD_DISABLE_ASM. + */ +#define ZSTD_d_disableHuffmanAssembly ZSTD_d_experimentalParam5 + +/* ZSTD_d_maxBlockSize + * Allowed values are between 1KB and ZSTD_BLOCKSIZE_MAX (128KB). + * The default is ZSTD_BLOCKSIZE_MAX, and setting to 0 will set to the default. + * + * Forces the decompressor to reject blocks whose content size is + * larger than the configured maxBlockSize. When maxBlockSize is + * larger than the windowSize, the windowSize is used instead. + * This saves memory on the decoder when you know all blocks are small. + * + * This option is typically used in conjunction with ZSTD_c_maxBlockSize. + * + * WARNING: This causes the decoder to reject otherwise valid frames + * that have block sizes larger than the configured maxBlockSize. + */ +#define ZSTD_d_maxBlockSize ZSTD_d_experimentalParam6 + + +/*! ZSTD_DCtx_setFormat() : + * This function is REDUNDANT. Prefer ZSTD_DCtx_setParameter(). + * Instruct the decoder context about what kind of data to decode next. + * This instruction is mandatory to decode data without a fully-formed header, + * such ZSTD_f_zstd1_magicless for example. + * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ +ZSTD_DEPRECATED("use ZSTD_DCtx_setParameter() instead") +ZSTDLIB_STATIC_API +size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); + +/*! ZSTD_decompressStream_simpleArgs() : + * Same as ZSTD_decompressStream(), + * but using only integral types as arguments. + * This can be helpful for binders from dynamic languages + * which have troubles handling structures containing memory pointers. + */ +ZSTDLIB_STATIC_API size_t ZSTD_decompressStream_simpleArgs ( + ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos); + + +/******************************************************************** +* Advanced streaming functions +* Warning : most of these functions are now redundant with the Advanced API. +* Once Advanced API reaches "stable" status, +* redundant functions will be deprecated, and then at some point removed. +********************************************************************/ + +/*===== Advanced Streaming compression functions =====*/ + +/*! ZSTD_initCStream_srcSize() : + * This function is DEPRECATED, and equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any) + * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * + * pledgedSrcSize must be correct. If it is not known at init time, use + * ZSTD_CONTENTSIZE_UNKNOWN. Note that, for compatibility with older programs, + * "0" also disables frame content size field. It may be enabled in the future. + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API +size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, + int compressionLevel, + unsigned long long pledgedSrcSize); + +/*! ZSTD_initCStream_usingDict() : + * This function is DEPRECATED, and is equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); + * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); + * + * Creates of an internal CDict (incompatible with static CCtx), except if + * dict == NULL or dictSize < 8, in which case no dict is used. + * Note: dict is loaded with ZSTD_dct_auto (treated as a full zstd dictionary if + * it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy. + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API +size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, + int compressionLevel); + +/*! ZSTD_initCStream_advanced() : + * This function is DEPRECATED, and is equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_setParams(zcs, params); + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); + * + * dict is loaded with ZSTD_dct_auto and ZSTD_dlm_byCopy. + * pledgedSrcSize must be correct. + * If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API +size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, + ZSTD_parameters params, + unsigned long long pledgedSrcSize); + +/*! ZSTD_initCStream_usingCDict() : + * This function is DEPRECATED, and equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_refCDict(zcs, cdict); + * + * note : cdict will just be referenced, and must outlive compression session + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API +size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); + +/*! ZSTD_initCStream_usingCDict_advanced() : + * This function is DEPRECATED, and is equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_setFParams(zcs, fParams); + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * ZSTD_CCtx_refCDict(zcs, cdict); + * + * same as ZSTD_initCStream_usingCDict(), with control over frame parameters. + * pledgedSrcSize must be correct. If srcSize is not known at init time, use + * value ZSTD_CONTENTSIZE_UNKNOWN. + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API +size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, + const ZSTD_CDict* cdict, + ZSTD_frameParameters fParams, + unsigned long long pledgedSrcSize); + +/*! ZSTD_resetCStream() : + * This function is DEPRECATED, and is equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * Note: ZSTD_resetCStream() interprets pledgedSrcSize == 0 as ZSTD_CONTENTSIZE_UNKNOWN, but + * ZSTD_CCtx_setPledgedSrcSize() does not do the same, so ZSTD_CONTENTSIZE_UNKNOWN must be + * explicitly specified. + * + * start a new frame, using same parameters from previous frame. + * This is typically useful to skip dictionary loading stage, since it will reuse it in-place. + * Note that zcs must be init at least once before using ZSTD_resetCStream(). + * If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN. + * If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end. + * For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs, + * but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead. + * @return : 0, or an error code (which can be tested using ZSTD_isError()) + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API +size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize); + + +typedef struct { + unsigned long long ingested; /* nb input bytes read and buffered */ + unsigned long long consumed; /* nb input bytes actually compressed */ + unsigned long long produced; /* nb of compressed bytes generated and buffered */ + unsigned long long flushed; /* nb of compressed bytes flushed : not provided; can be tracked from caller side */ + unsigned currentJobID; /* MT only : latest started job nb */ + unsigned nbActiveWorkers; /* MT only : nb of workers actively compressing at probe time */ +} ZSTD_frameProgression; + +/* ZSTD_getFrameProgression() : + * tells how much data has been ingested (read from input) + * consumed (input actually compressed) and produced (output) for current frame. + * Note : (ingested - consumed) is amount of input data buffered internally, not yet compressed. + * Aggregates progression inside active worker threads. + */ +ZSTDLIB_STATIC_API ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx); + +/*! ZSTD_toFlushNow() : + * Tell how many bytes are ready to be flushed immediately. + * Useful for multithreading scenarios (nbWorkers >= 1). + * Probe the oldest active job, defined as oldest job not yet entirely flushed, + * and check its output buffer. + * @return : amount of data stored in oldest job and ready to be flushed immediately. + * if @return == 0, it means either : + * + there is no active job (could be checked with ZSTD_frameProgression()), or + * + oldest job is still actively compressing data, + * but everything it has produced has also been flushed so far, + * therefore flush speed is limited by production speed of oldest job + * irrespective of the speed of concurrent (and newer) jobs. + */ +ZSTDLIB_STATIC_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx); + + +/*===== Advanced Streaming decompression functions =====*/ + +/*! + * This function is deprecated, and is equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * ZSTD_DCtx_loadDictionary(zds, dict, dictSize); + * + * note: no dictionary will be used if dict == NULL or dictSize < 8 + */ +ZSTD_DEPRECATED("use ZSTD_DCtx_reset + ZSTD_DCtx_loadDictionary, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); + +/*! + * This function is deprecated, and is equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * ZSTD_DCtx_refDDict(zds, ddict); + * + * note : ddict is referenced, it must outlive decompression session + */ +ZSTD_DEPRECATED("use ZSTD_DCtx_reset + ZSTD_DCtx_refDDict, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); + +/*! + * This function is deprecated, and is equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * + * reuse decompression parameters from previous init; saves dictionary loading + */ +ZSTD_DEPRECATED("use ZSTD_DCtx_reset, see zstd.h for detailed instructions") +ZSTDLIB_STATIC_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); + + +/* ********************* BLOCK-LEVEL SEQUENCE PRODUCER API ********************* + * + * *** OVERVIEW *** + * The Block-Level Sequence Producer API allows users to provide their own custom + * sequence producer which libzstd invokes to process each block. The produced list + * of sequences (literals and matches) is then post-processed by libzstd to produce + * valid compressed blocks. + * + * This block-level offload API is a more granular complement of the existing + * frame-level offload API compressSequences() (introduced in v1.5.1). It offers + * an easier migration story for applications already integrated with libzstd: the + * user application continues to invoke the same compression functions + * ZSTD_compress2() or ZSTD_compressStream2() as usual, and transparently benefits + * from the specific advantages of the external sequence producer. For example, + * the sequence producer could be tuned to take advantage of known characteristics + * of the input, to offer better speed / ratio, or could leverage hardware + * acceleration not available within libzstd itself. + * + * See contrib/externalSequenceProducer for an example program employing the + * Block-Level Sequence Producer API. + * + * *** USAGE *** + * The user is responsible for implementing a function of type + * ZSTD_sequenceProducer_F. For each block, zstd will pass the following + * arguments to the user-provided function: + * + * - sequenceProducerState: a pointer to a user-managed state for the sequence + * producer. + * + * - outSeqs, outSeqsCapacity: an output buffer for the sequence producer. + * outSeqsCapacity is guaranteed >= ZSTD_sequenceBound(srcSize). The memory + * backing outSeqs is managed by the CCtx. + * + * - src, srcSize: an input buffer for the sequence producer to parse. + * srcSize is guaranteed to be <= ZSTD_BLOCKSIZE_MAX. + * + * - dict, dictSize: a history buffer, which may be empty, which the sequence + * producer may reference as it parses the src buffer. Currently, zstd will + * always pass dictSize == 0 into external sequence producers, but this will + * change in the future. + * + * - compressionLevel: a signed integer representing the zstd compression level + * set by the user for the current operation. The sequence producer may choose + * to use this information to change its compression strategy and speed/ratio + * tradeoff. Note: the compression level does not reflect zstd parameters set + * through the advanced API. + * + * - windowSize: a size_t representing the maximum allowed offset for external + * sequences. Note that sequence offsets are sometimes allowed to exceed the + * windowSize if a dictionary is present, see doc/zstd_compression_format.md + * for details. + * + * The user-provided function shall return a size_t representing the number of + * sequences written to outSeqs. This return value will be treated as an error + * code if it is greater than outSeqsCapacity. The return value must be non-zero + * if srcSize is non-zero. The ZSTD_SEQUENCE_PRODUCER_ERROR macro is provided + * for convenience, but any value greater than outSeqsCapacity will be treated as + * an error code. + * + * If the user-provided function does not return an error code, the sequences + * written to outSeqs must be a valid parse of the src buffer. Data corruption may + * occur if the parse is not valid. A parse is defined to be valid if the + * following conditions hold: + * - The sum of matchLengths and literalLengths must equal srcSize. + * - All sequences in the parse, except for the final sequence, must have + * matchLength >= ZSTD_MINMATCH_MIN. The final sequence must have + * matchLength >= ZSTD_MINMATCH_MIN or matchLength == 0. + * - All offsets must respect the windowSize parameter as specified in + * doc/zstd_compression_format.md. + * - If the final sequence has matchLength == 0, it must also have offset == 0. + * + * zstd will only validate these conditions (and fail compression if they do not + * hold) if the ZSTD_c_validateSequences cParam is enabled. Note that sequence + * validation has a performance cost. + * + * If the user-provided function returns an error, zstd will either fall back + * to an internal sequence producer or fail the compression operation. The user can + * choose between the two behaviors by setting the ZSTD_c_enableSeqProducerFallback + * cParam. Fallback compression will follow any other cParam settings, such as + * compression level, the same as in a normal compression operation. + * + * The user shall instruct zstd to use a particular ZSTD_sequenceProducer_F + * function by calling + * ZSTD_registerSequenceProducer(cctx, + * sequenceProducerState, + * sequenceProducer) + * This setting will persist until the next parameter reset of the CCtx. + * + * The sequenceProducerState must be initialized by the user before calling + * ZSTD_registerSequenceProducer(). The user is responsible for destroying the + * sequenceProducerState. + * + * *** LIMITATIONS *** + * This API is compatible with all zstd compression APIs which respect advanced parameters. + * However, there are three limitations: + * + * First, the ZSTD_c_enableLongDistanceMatching cParam is not currently supported. + * COMPRESSION WILL FAIL if it is enabled and the user tries to compress with a block-level + * external sequence producer. + * - Note that ZSTD_c_enableLongDistanceMatching is auto-enabled by default in some + * cases (see its documentation for details). Users must explicitly set + * ZSTD_c_enableLongDistanceMatching to ZSTD_ps_disable in such cases if an external + * sequence producer is registered. + * - As of this writing, ZSTD_c_enableLongDistanceMatching is disabled by default + * whenever ZSTD_c_windowLog < 128MB, but that's subject to change. Users should + * check the docs on ZSTD_c_enableLongDistanceMatching whenever the Block-Level Sequence + * Producer API is used in conjunction with advanced settings (like ZSTD_c_windowLog). + * + * Second, history buffers are not currently supported. Concretely, zstd will always pass + * dictSize == 0 to the external sequence producer (for now). This has two implications: + * - Dictionaries are not currently supported. Compression will *not* fail if the user + * references a dictionary, but the dictionary won't have any effect. + * - Stream history is not currently supported. All advanced compression APIs, including + * streaming APIs, work with external sequence producers, but each block is treated as + * an independent chunk without history from previous blocks. + * + * Third, multi-threading within a single compression is not currently supported. In other words, + * COMPRESSION WILL FAIL if ZSTD_c_nbWorkers > 0 and an external sequence producer is registered. + * Multi-threading across compressions is fine: simply create one CCtx per thread. + * + * Long-term, we plan to overcome all three limitations. There is no technical blocker to + * overcoming them. It is purely a question of engineering effort. + */ + +#define ZSTD_SEQUENCE_PRODUCER_ERROR ((size_t)(-1)) + +typedef size_t (*ZSTD_sequenceProducer_F) ( + void* sequenceProducerState, + ZSTD_Sequence* outSeqs, size_t outSeqsCapacity, + const void* src, size_t srcSize, + const void* dict, size_t dictSize, + int compressionLevel, + size_t windowSize +); + +/*! ZSTD_registerSequenceProducer() : + * Instruct zstd to use a block-level external sequence producer function. + * + * The sequenceProducerState must be initialized by the caller, and the caller is + * responsible for managing its lifetime. This parameter is sticky across + * compressions. It will remain set until the user explicitly resets compression + * parameters. + * + * Sequence producer registration is considered to be an "advanced parameter", + * part of the "advanced API". This means it will only have an effect on compression + * APIs which respect advanced parameters, such as compress2() and compressStream2(). + * Older compression APIs such as compressCCtx(), which predate the introduction of + * "advanced parameters", will ignore any external sequence producer setting. + * + * The sequence producer can be "cleared" by registering a NULL function pointer. This + * removes all limitations described above in the "LIMITATIONS" section of the API docs. + * + * The user is strongly encouraged to read the full API documentation (above) before + * calling this function. */ +ZSTDLIB_STATIC_API void +ZSTD_registerSequenceProducer( + ZSTD_CCtx* cctx, + void* sequenceProducerState, + ZSTD_sequenceProducer_F sequenceProducer +); + +/*! ZSTD_CCtxParams_registerSequenceProducer() : + * Same as ZSTD_registerSequenceProducer(), but operates on ZSTD_CCtx_params. + * This is used for accurate size estimation with ZSTD_estimateCCtxSize_usingCCtxParams(), + * which is needed when creating a ZSTD_CCtx with ZSTD_initStaticCCtx(). + * + * If you are using the external sequence producer API in a scenario where ZSTD_initStaticCCtx() + * is required, then this function is for you. Otherwise, you probably don't need it. + * + * See tests/zstreamtest.c for example usage. */ +ZSTDLIB_STATIC_API void +ZSTD_CCtxParams_registerSequenceProducer( + ZSTD_CCtx_params* params, + void* sequenceProducerState, + ZSTD_sequenceProducer_F sequenceProducer +); + + +/********************************************************************* +* Buffer-less and synchronous inner streaming functions (DEPRECATED) +* +* This API is deprecated, and will be removed in a future version. +* It allows streaming (de)compression with user allocated buffers. +* However, it is hard to use, and not as well tested as the rest of +* our API. +* +* Please use the normal streaming API instead: ZSTD_compressStream2, +* and ZSTD_decompressStream. +* If there is functionality that you need, but it doesn't provide, +* please open an issue on our GitHub. +********************************************************************* */ + +/** + Buffer-less streaming compression (synchronous mode) + + A ZSTD_CCtx object is required to track streaming operations. + Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource. + ZSTD_CCtx object can be reused multiple times within successive compression operations. + + Start by initializing a context. + Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression. + + Then, consume your input using ZSTD_compressContinue(). + There are some important considerations to keep in mind when using this advanced function : + - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffers only. + - Interface is synchronous : input is consumed entirely and produces 1+ compressed blocks. + - Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario. + Worst case evaluation is provided by ZSTD_compressBound(). + ZSTD_compressContinue() doesn't guarantee recover after a failed compression. + - ZSTD_compressContinue() presumes prior input ***is still accessible and unmodified*** (up to maximum distance size, see WindowLog). + It remembers all previous contiguous blocks, plus one separated memory segment (which can itself consists of multiple contiguous blocks) + - ZSTD_compressContinue() detects that prior input has been overwritten when `src` buffer overlaps. + In which case, it will "discard" the relevant memory section from its history. + + Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum. + It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame. + Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders. + + `ZSTD_CCtx` object can be reused (ZSTD_compressBegin()) to compress again. +*/ + +/*===== Buffer-less streaming compression functions =====*/ +ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); +ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); +ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */ + +ZSTD_DEPRECATED("This function will likely be removed in a future release. It is misleading and has very limited utility.") +ZSTDLIB_STATIC_API +size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */ + +ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); + +/* The ZSTD_compressBegin_advanced() and ZSTD_compressBegin_usingCDict_advanced() are now DEPRECATED and will generate a compiler warning */ +ZSTD_DEPRECATED("use advanced API to access custom parameters") +ZSTDLIB_STATIC_API +size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */ +ZSTD_DEPRECATED("use advanced API to access custom parameters") +ZSTDLIB_STATIC_API +size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */ +/** + Buffer-less streaming decompression (synchronous mode) + + A ZSTD_DCtx object is required to track streaming operations. + Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it. + A ZSTD_DCtx object can be reused multiple times. + + First typical operation is to retrieve frame parameters, using ZSTD_getFrameHeader(). + Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough. + Data fragment must be large enough to ensure successful decoding. + `ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough. + result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled. + >0 : `srcSize` is too small, please provide at least result bytes on next attempt. + errorCode, which can be tested using ZSTD_isError(). + + It fills a ZSTD_frameHeader structure with important information to correctly decode the frame, + such as the dictionary ID, content size, or maximum back-reference distance (`windowSize`). + Note that these values could be wrong, either because of data corruption, or because a 3rd party deliberately spoofs false information. + As a consequence, check that values remain within valid application range. + For example, do not allocate memory blindly, check that `windowSize` is within expectation. + Each application can set its own limits, depending on local restrictions. + For extended interoperability, it is recommended to support `windowSize` of at least 8 MB. + + ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize` bytes. + ZSTD_decompressContinue() is very sensitive to contiguity, + if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place, + or that previous contiguous segment is large enough to properly handle maximum back-reference distance. + There are multiple ways to guarantee this condition. + + The most memory efficient way is to use a round buffer of sufficient size. + Sufficient size is determined by invoking ZSTD_decodingBufferSize_min(), + which can return an error code if required value is too large for current system (in 32-bits mode). + In a round buffer methodology, ZSTD_decompressContinue() decompresses each block next to previous one, + up to the moment there is not enough room left in the buffer to guarantee decoding another full block, + which maximum size is provided in `ZSTD_frameHeader` structure, field `blockSizeMax`. + At which point, decoding can resume from the beginning of the buffer. + Note that already decoded data stored in the buffer should be flushed before being overwritten. + + There are alternatives possible, for example using two or more buffers of size `windowSize` each, though they consume more memory. + + Finally, if you control the compression process, you can also ignore all buffer size rules, + as long as the encoder and decoder progress in "lock-step", + aka use exactly the same buffer sizes, break contiguity at the same place, etc. + + Once buffers are setup, start decompression, with ZSTD_decompressBegin(). + If decompression requires a dictionary, use ZSTD_decompressBegin_usingDict() or ZSTD_decompressBegin_usingDDict(). + + Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively. + ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize' to ZSTD_decompressContinue(). + ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will fail. + + result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity). + It can be zero : it just means ZSTD_decompressContinue() has decoded some metadata item. + It can also be an error code, which can be tested with ZSTD_isError(). + + A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero. + Context can then be reset to start a new decompression. + + Note : it's possible to know if next input to present is a header or a block, using ZSTD_nextInputType(). + This information is not required to properly decode a frame. + + == Special case : skippable frames == + + Skippable frames allow integration of user-defined data into a flow of concatenated frames. + Skippable frames will be ignored (skipped) by decompressor. + The format of skippable frames is as follows : + a) Skippable frame ID - 4 Bytes, Little endian format, any value from 0x184D2A50 to 0x184D2A5F + b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits + c) Frame Content - any content (User Data) of length equal to Frame Size + For skippable frames ZSTD_getFrameHeader() returns zfhPtr->frameType==ZSTD_skippableFrame. + For skippable frames ZSTD_decompressContinue() always returns 0 : it only skips the content. +*/ + +/*===== Buffer-less streaming decompression functions =====*/ + +ZSTDLIB_STATIC_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */ + +ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); +ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); +ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); + +ZSTDLIB_STATIC_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); +ZSTDLIB_STATIC_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); + +/* misc */ +ZSTD_DEPRECATED("This function will likely be removed in the next minor release. It is misleading and has very limited utility.") +ZSTDLIB_STATIC_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); +typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e; +ZSTDLIB_STATIC_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); + + + + +/* ========================================= */ +/** Block level API (DEPRECATED) */ +/* ========================================= */ + +/*! + + This API is deprecated in favor of the regular compression API. + You can get the frame header down to 2 bytes by setting: + - ZSTD_c_format = ZSTD_f_zstd1_magicless + - ZSTD_c_contentSizeFlag = 0 + - ZSTD_c_checksumFlag = 0 + - ZSTD_c_dictIDFlag = 0 + + This API is not as well tested as our normal API, so we recommend not using it. + We will be removing it in a future version. If the normal API doesn't provide + the functionality you need, please open a GitHub issue. + + Block functions produce and decode raw zstd blocks, without frame metadata. + Frame metadata cost is typically ~12 bytes, which can be non-negligible for very small blocks (< 100 bytes). + But users will have to take in charge needed metadata to regenerate data, such as compressed and content sizes. + + A few rules to respect : + - Compressing and decompressing require a context structure + + Use ZSTD_createCCtx() and ZSTD_createDCtx() + - It is necessary to init context before starting + + compression : any ZSTD_compressBegin*() variant, including with dictionary + + decompression : any ZSTD_decompressBegin*() variant, including with dictionary + - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB + + If input is larger than a block size, it's necessary to split input data into multiple blocks + + For inputs larger than a single block, consider using regular ZSTD_compress() instead. + Frame metadata is not that costly, and quickly becomes negligible as source size grows larger than a block. + - When a block is considered not compressible enough, ZSTD_compressBlock() result will be 0 (zero) ! + ===> In which case, nothing is produced into `dst` ! + + User __must__ test for such outcome and deal directly with uncompressed data + + A block cannot be declared incompressible if ZSTD_compressBlock() return value was != 0. + Doing so would mess up with statistics history, leading to potential data corruption. + + ZSTD_decompressBlock() _doesn't accept uncompressed data as input_ !! + + In case of multiple successive blocks, should some of them be uncompressed, + decoder must be informed of their existence in order to follow proper history. + Use ZSTD_insertBlock() for such a case. +*/ + +/*===== Raw zstd block functions =====*/ +ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx); +ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.") +ZSTDLIB_STATIC_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */ + +#endif /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */ + +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/include/zstd/common/allocations.h b/src/duckdb/third_party/zstd/include/zstd/common/allocations.h new file mode 100644 index 000000000..0bb1506b9 --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd/common/allocations.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* This file provides custom allocation primitives + */ +#ifndef ZSTD_ALLOCATIONS_H +#define ZSTD_ALLOCATIONS_H + +#define ZSTD_DEPS_NEED_MALLOC +#include "zstd/common/zstd_deps.h" /* ZSTD_malloc, ZSTD_calloc, ZSTD_free, ZSTD_memset */ + +#include "zstd/common/compiler.h" /* MEM_STATIC */ +#define ZSTD_STATIC_LINKING_ONLY +#include "zstd.h" /* ZSTD_customMem */ + +namespace duckdb_zstd { + +/* custom memory allocation functions */ + +MEM_STATIC void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem) +{ + if (customMem.customAlloc) + return customMem.customAlloc(customMem.opaque, size); + return ZSTD_malloc(size); +} + +MEM_STATIC void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem) +{ + if (customMem.customAlloc) { + /* calloc implemented as malloc+memset; + * not as efficient as calloc, but next best guess for custom malloc */ + void* const ptr = customMem.customAlloc(customMem.opaque, size); + ZSTD_memset(ptr, 0, size); + return ptr; + } + return ZSTD_calloc(1, size); +} + +MEM_STATIC void ZSTD_customFree(void* ptr, ZSTD_customMem customMem) +{ + if (ptr!=NULL) { + if (customMem.customFree) + customMem.customFree(customMem.opaque, ptr); + else + ZSTD_free(ptr); + } +} + +} // namespace duckdb_zstd + +#endif /* ZSTD_ALLOCATIONS_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/bits.h b/src/duckdb/third_party/zstd/include/zstd/common/bits.h new file mode 100644 index 000000000..ecdf916dc --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd/common/bits.h @@ -0,0 +1,204 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_BITS_H +#define ZSTD_BITS_H + +#include "zstd/common/mem.h" + +namespace duckdb_zstd { + +MEM_STATIC unsigned ZSTD_countTrailingZeros32_fallback(U32 val) +{ + assert(val != 0); + { + static const U32 DeBruijnBytePos[32] = {0, 1, 28, 2, 29, 14, 24, 3, + 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, + 26, 12, 18, 6, 11, 5, 10, 9}; + return DeBruijnBytePos[((U32) ((val & -(S32) val) * 0x077CB531U)) >> 27]; + } +} + +MEM_STATIC unsigned ZSTD_countTrailingZeros32(U32 val) +{ + assert(val != 0); +# if defined(_MSC_VER) +# if STATIC_BMI2 == 1 + return (unsigned)_tzcnt_u32(val); +# else + if (val != 0) { + unsigned long r; + _BitScanForward(&r, val); + return (unsigned)r; + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 4) + return (unsigned)__builtin_ctz(val); +# else + return ZSTD_countTrailingZeros32_fallback(val); +# endif +} + +MEM_STATIC unsigned ZSTD_countLeadingZeros32_fallback(U32 val) { + assert(val != 0); + { + static const U32 DeBruijnClz[32] = {0, 9, 1, 10, 13, 21, 2, 29, + 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, + 19, 27, 23, 6, 26, 5, 4, 31}; + val |= val >> 1; + val |= val >> 2; + val |= val >> 4; + val |= val >> 8; + val |= val >> 16; + return 31 - DeBruijnClz[(val * 0x07C4ACDDU) >> 27]; + } +} + +MEM_STATIC unsigned ZSTD_countLeadingZeros32(U32 val) +{ + assert(val != 0); +# if defined(_MSC_VER) +# if STATIC_BMI2 == 1 + return (unsigned)_lzcnt_u32(val); +# else + if (val != 0) { + unsigned long r; + _BitScanReverse(&r, val); + return (unsigned)(31 - r); + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 4) + return (unsigned)__builtin_clz(val); +# else + return ZSTD_countLeadingZeros32_fallback(val); +# endif +} + +MEM_STATIC unsigned ZSTD_countTrailingZeros64(U64 val) +{ + assert(val != 0); +# if defined(_MSC_VER) && defined(_WIN64) +# if STATIC_BMI2 == 1 + return (unsigned)_tzcnt_u64(val); +# else + if (val != 0) { + unsigned long r; + _BitScanForward64(&r, val); + return (unsigned)r; + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(__LP64__) + return (unsigned)__builtin_ctzll(val); +# else + { + U32 mostSignificantWord = (U32)(val >> 32); + U32 leastSignificantWord = (U32)val; + if (leastSignificantWord == 0) { + return 32 + ZSTD_countTrailingZeros32(mostSignificantWord); + } else { + return ZSTD_countTrailingZeros32(leastSignificantWord); + } + } +# endif +} + +MEM_STATIC unsigned ZSTD_countLeadingZeros64(U64 val) +{ + assert(val != 0); +# if defined(_MSC_VER) && defined(_WIN64) +# if STATIC_BMI2 == 1 + return (unsigned)_lzcnt_u64(val); +# else + if (val != 0) { + unsigned long r; + _BitScanReverse64(&r, val); + return (unsigned)(63 - r); + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 4) + return (unsigned)(__builtin_clzll(val)); +# else + { + U32 mostSignificantWord = (U32)(val >> 32); + U32 leastSignificantWord = (U32)val; + if (mostSignificantWord == 0) { + return 32 + ZSTD_countLeadingZeros32(leastSignificantWord); + } else { + return ZSTD_countLeadingZeros32(mostSignificantWord); + } + } +# endif +} + +MEM_STATIC unsigned ZSTD_NbCommonBytes(size_t val) +{ + if (MEM_isLittleEndian()) { + if (MEM_64bits()) { + return ZSTD_countTrailingZeros64((U64)val) >> 3; + } else { + return ZSTD_countTrailingZeros32((U32)val) >> 3; + } + } else { /* Big Endian CPU */ + if (MEM_64bits()) { + return ZSTD_countLeadingZeros64((U64)val) >> 3; + } else { + return ZSTD_countLeadingZeros32((U32)val) >> 3; + } + } +} + +MEM_STATIC unsigned ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */ +{ + assert(val != 0); + return 31 - ZSTD_countLeadingZeros32(val); +} + +/* ZSTD_rotateRight_*(): + * Rotates a bitfield to the right by "count" bits. + * https://en.wikipedia.org/w/index.php?title=Circular_shift&oldid=991635599#Implementing_circular_shifts + */ +MEM_STATIC +U64 ZSTD_rotateRight_U64(U64 const value, U32 count) { + assert(count < 64); + count &= 0x3F; /* for fickle pattern recognition */ + return (value >> count) | (U64)(value << ((0U - count) & 0x3F)); +} + +MEM_STATIC +U32 ZSTD_rotateRight_U32(U32 const value, U32 count) { + assert(count < 32); + count &= 0x1F; /* for fickle pattern recognition */ + return (value >> count) | (U32)(value << ((0U - count) & 0x1F)); +} + +MEM_STATIC +U16 ZSTD_rotateRight_U16(U16 const value, U32 count) { + assert(count < 16); + count &= 0x0F; /* for fickle pattern recognition */ + return (value >> count) | (U16)(value << ((0U - count) & 0x0F)); +} + +} // namespace duckdb_zstd + +#endif /* ZSTD_BITS_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/bitstream.h b/src/duckdb/third_party/zstd/include/zstd/common/bitstream.h index 653074666..2b1624295 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/bitstream.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/bitstream.h @@ -1,7 +1,7 @@ /* ****************************************************************** * bitstream * Part of FSE library - * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * You can contact the author at : * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -27,15 +27,17 @@ #include "zstd/common/compiler.h" /* UNLIKELY() */ #include "zstd/common/debug.h" /* assert(), DEBUGLOG(), RAWLOG() */ #include "zstd/common/error_private.h" /* error codes and messages */ - +#include "zstd/common/bits.h" /* ZSTD_highbit32 */ /*========================================= * Target specific =========================================*/ -#if defined(__BMI__) && defined(__GNUC__) -# include /* support for bextr (experimental) */ -#elif defined(__ICCARM__) -# include +#ifndef ZSTD_NO_INTRINSICS +# if (defined(__BMI__) || defined(__BMI2__)) && defined(__GNUC__) +# include /* support for bextr (experimental)/bzhi */ +# elif defined(__ICCARM__) +# include +# endif #endif #define STREAM_ACCUMULATOR_MIN_32 25 @@ -85,19 +87,20 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC); /*-******************************************** * bitStream decoding API (read backward) **********************************************/ +typedef size_t BitContainerType; typedef struct { - size_t bitContainer; + BitContainerType bitContainer; unsigned bitsConsumed; const char* ptr; const char* start; const char* limitPtr; } BIT_DStream_t; -typedef enum { BIT_DStream_unfinished = 0, - BIT_DStream_endOfBuffer = 1, - BIT_DStream_completed = 2, - BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */ - /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */ +typedef enum { BIT_DStream_unfinished = 0, /* fully refilled */ + BIT_DStream_endOfBuffer = 1, /* still some bits left in bitstream */ + BIT_DStream_completed = 2, /* bitstream entirely consumed, bit-exact */ + BIT_DStream_overflow = 3 /* user requested more bits than present in bitstream */ + } BIT_DStream_status; /* result of BIT_reloadDStream() */ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize); MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits); @@ -107,7 +110,7 @@ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD); /* Start by invoking BIT_initDStream(). * A chunk of the bitStream is then stored into a local register. -* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). +* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (BitContainerType). * You can then retrieve bitFields stored into the local register, **in reverse order**. * Local register is explicitly reloaded from memory by the BIT_reloadDStream() method. * A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished. @@ -128,38 +131,6 @@ MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC); MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); /* faster, but works only if nbBits >= 1 */ - - -/*-************************************************************** -* Internal functions -****************************************************************/ -MEM_STATIC unsigned BIT_highbit32 (U32 val) -{ - assert(val != 0); - { -# if defined(_MSC_VER) /* Visual */ - unsigned long r=0; - return _BitScanReverse ( &r, val ) ? (unsigned)r : 0; -# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ - return __builtin_clz (val) ^ 31; -# elif defined(__ICCARM__) /* IAR Intrinsic */ - return 31 - __CLZ(val); -# else /* Software version */ - static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, - 11, 14, 16, 18, 22, 25, 3, 30, - 8, 12, 20, 28, 15, 17, 24, 7, - 19, 27, 23, 6, 26, 5, 4, 31 }; - U32 v = val; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27]; -# endif - } -} - /*===== Local Constants =====*/ static const unsigned BIT_mask[] = { 0, 1, 3, 7, 0xF, 0x1F, @@ -189,16 +160,26 @@ MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, return 0; } +FORCE_INLINE_TEMPLATE size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) +{ +#if defined(STATIC_BMI2) && STATIC_BMI2 == 1 && !defined(ZSTD_NO_INTRINSICS) + return _bzhi_u64(bitContainer, nbBits); +#else + assert(nbBits < BIT_MASK_SIZE); + return bitContainer & BIT_mask[nbBits]; +#endif +} + /*! BIT_addBits() : * can add up to 31 bits into `bitC`. * Note : does not check for register overflow ! */ MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits) { - MEM_STATIC_ASSERT(BIT_MASK_SIZE == 32); + DEBUG_STATIC_ASSERT(BIT_MASK_SIZE == 32); assert(nbBits < BIT_MASK_SIZE); assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8); - bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos; + bitC->bitContainer |= BIT_getLowerBits(value, nbBits) << bitC->bitPos; bitC->bitPos += nbBits; } @@ -268,7 +249,7 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC) */ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize) { - if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } + if (srcSize < 1) { ZSTD_memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } bitD->start = (const char*)srcBuffer; bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer); @@ -277,35 +258,35 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer); bitD->bitContainer = MEM_readLEST(bitD->ptr); { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; - bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */ + bitD->bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */ if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ } } else { bitD->ptr = bitD->start; bitD->bitContainer = *(const BYTE*)(bitD->start); switch(srcSize) { - case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16); - /* fall-through */ + case 7: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16); + ZSTD_FALLTHROUGH; - case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24); - /* fall-through */ + case 6: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24); + ZSTD_FALLTHROUGH; - case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32); - /* fall-through */ + case 5: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32); + ZSTD_FALLTHROUGH; - case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24; - /* fall-through */ + case 4: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[3]) << 24; + ZSTD_FALLTHROUGH; - case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16; - /* fall-through */ + case 3: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[2]) << 16; + ZSTD_FALLTHROUGH; - case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8; - /* fall-through */ + case 2: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[1]) << 8; + ZSTD_FALLTHROUGH; default: break; } { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; - bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; + bitD->bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */ } bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8; @@ -314,23 +295,26 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si return srcSize; } -MEM_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start) +FORCE_INLINE_TEMPLATE size_t BIT_getUpperBits(BitContainerType bitContainer, U32 const start) { return bitContainer >> start; } -MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits) +FORCE_INLINE_TEMPLATE size_t BIT_getMiddleBits(BitContainerType bitContainer, U32 const start, U32 const nbBits) { U32 const regMask = sizeof(bitContainer)*8 - 1; /* if start > regMask, bitstream is corrupted, and result is undefined */ assert(nbBits < BIT_MASK_SIZE); + /* x86 transform & ((1 << nbBits) - 1) to bzhi instruction, it is better + * than accessing memory. When bmi2 instruction is not present, we consider + * such cpus old (pre-Haswell, 2013) and their performance is not of that + * importance. + */ +#if defined(__x86_64__) || defined(_M_X86) + return (bitContainer >> (start & regMask)) & ((((U64)1) << nbBits) - 1); +#else return (bitContainer >> (start & regMask)) & BIT_mask[nbBits]; -} - -MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) -{ - assert(nbBits < BIT_MASK_SIZE); - return bitContainer & BIT_mask[nbBits]; +#endif } /*! BIT_lookBits() : @@ -339,7 +323,7 @@ MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) * On 32-bits, maxNbBits==24. * On 64-bits, maxNbBits==56. * @return : value extracted */ -MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits) +FORCE_INLINE_TEMPLATE size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits) { /* arbitrate between double-shift and shift+mask */ #if 1 @@ -362,7 +346,7 @@ MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits) return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask); } -MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) +FORCE_INLINE_TEMPLATE void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) { bitD->bitsConsumed += nbBits; } @@ -371,7 +355,7 @@ MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) * Read (consume) next n bits from local register and update. * Pay attention to not read more than nbBits contained into local register. * @return : extracted value. */ -MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits) +FORCE_INLINE_TEMPLATE size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits) { size_t const value = BIT_lookBits(bitD, nbBits); BIT_skipBits(bitD, nbBits); @@ -379,7 +363,7 @@ MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits) } /*! BIT_readBitsFast() : - * unsafe version; only works only if nbBits >= 1 */ + * unsafe version; only works if nbBits >= 1 */ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits) { size_t const value = BIT_lookBitsFast(bitD, nbBits); @@ -388,6 +372,21 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits) return value; } +/*! BIT_reloadDStream_internal() : + * Simple variant of BIT_reloadDStream(), with two conditions: + * 1. bitstream is valid : bitsConsumed <= sizeof(bitD->bitContainer)*8 + * 2. look window is valid after shifted down : bitD->ptr >= bitD->start + */ +MEM_STATIC BIT_DStream_status BIT_reloadDStream_internal(BIT_DStream_t* bitD) +{ + assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8); + bitD->ptr -= bitD->bitsConsumed >> 3; + assert(bitD->ptr >= bitD->start); + bitD->bitsConsumed &= 7; + bitD->bitContainer = MEM_readLEST(bitD->ptr); + return BIT_DStream_unfinished; +} + /*! BIT_reloadDStreamFast() : * Similar to BIT_reloadDStream(), but with two differences: * 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold! @@ -398,31 +397,35 @@ MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD) { if (UNLIKELY(bitD->ptr < bitD->limitPtr)) return BIT_DStream_overflow; - assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8); - bitD->ptr -= bitD->bitsConsumed >> 3; - bitD->bitsConsumed &= 7; - bitD->bitContainer = MEM_readLEST(bitD->ptr); - return BIT_DStream_unfinished; + return BIT_reloadDStream_internal(bitD); } /*! BIT_reloadDStream() : * Refill `bitD` from buffer previously set in BIT_initDStream() . - * This function is safe, it guarantees it will not read beyond src buffer. + * This function is safe, it guarantees it will not never beyond src buffer. * @return : status of `BIT_DStream_t` internal register. * when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */ -MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD) +FORCE_INLINE_TEMPLATE BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD) { - if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */ + /* note : once in overflow mode, a bitstream remains in this mode until it's reset */ + if (UNLIKELY(bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8))) { + static const BitContainerType zeroFilled = 0; + bitD->ptr = (const char*)&zeroFilled; /* aliasing is allowed for char */ + /* overflow detected, erroneous scenario or end of stream: no update */ return BIT_DStream_overflow; + } + + assert(bitD->ptr >= bitD->start); if (bitD->ptr >= bitD->limitPtr) { - return BIT_reloadDStreamFast(bitD); + return BIT_reloadDStream_internal(bitD); } if (bitD->ptr == bitD->start) { + /* reached end of bitStream => no update */ if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer; return BIT_DStream_completed; } - /* start < ptr < limitPtr */ + /* start < ptr < limitPtr => cautious update */ { U32 nbBytes = bitD->bitsConsumed >> 3; BIT_DStream_status result = BIT_DStream_unfinished; if (bitD->ptr - nbBytes < bitD->start) { @@ -444,6 +447,6 @@ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream) return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8)); } -} +} // namespace duckdb_zstd #endif /* BITSTREAM_H_MODULE */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/compiler.h b/src/duckdb/third_party/zstd/include/zstd/common/compiler.h index b94dbad13..f880f0b11 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/compiler.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/compiler.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,6 +11,10 @@ #ifndef ZSTD_COMPILER_H #define ZSTD_COMPILER_H +#include + +#include "zstd/common/portability_macros.h" + /*-******************************************************* * Compiler specifics *********************************************************/ @@ -38,12 +42,30 @@ #endif +/** + On MSVC qsort requires that functions passed into it use the __cdecl calling conversion(CC). + This explicitly marks such functions as __cdecl so that the code will still compile + if a CC other than __cdecl has been made the default. +*/ +#if defined(_MSC_VER) +# define WIN_CDECL __cdecl +#else +# define WIN_CDECL +#endif + +/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */ +#if defined(__GNUC__) +# define UNUSED_ATTR __attribute__((unused)) +#else +# define UNUSED_ATTR +#endif + /** * FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant * parameters. They must be inlined for the compiler to eliminate the constant * branches. */ -#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR +#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR UNUSED_ATTR /** * HINT_INLINE is used to help the compiler generate better code. It is *not* * used for "templates", so it can be tweaked based on the compilers @@ -58,14 +80,28 @@ #if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5 # define HINT_INLINE static INLINE_KEYWORD #else -# define HINT_INLINE static INLINE_KEYWORD FORCE_INLINE_ATTR +# define HINT_INLINE FORCE_INLINE_TEMPLATE #endif -/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */ +/* "soft" inline : + * The compiler is free to select if it's a good idea to inline or not. + * The main objective is to silence compiler warnings + * when a defined function in included but not used. + * + * Note : this macro is prefixed `MEM_` because it used to be provided by `mem.h` unit. + * Updating the prefix is probably preferable, but requires a fairly large codemod, + * since this name is used everywhere. + */ +#ifndef MEM_STATIC /* already defined in Linux Kernel mem.h */ #if defined(__GNUC__) -# define UNUSED_ATTR __attribute__((unused)) +# define MEM_STATIC static __inline UNUSED_ATTR +#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define MEM_STATIC static inline +#elif defined(_MSC_VER) +# define MEM_STATIC static __inline #else -# define UNUSED_ATTR +# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ +#endif #endif /* force no inlining */ @@ -79,67 +115,58 @@ # endif #endif + /* target attribute */ -#ifndef __has_attribute - #define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ -#endif #if defined(__GNUC__) || defined(__ICCARM__) # define TARGET_ATTRIBUTE(target) __attribute__((__target__(target))) #else # define TARGET_ATTRIBUTE(target) #endif -/* Enable runtime BMI2 dispatch based on the CPU. - * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default. +/* Target attribute for BMI2 dynamic dispatch. + * Enable lzcnt, bmi, and bmi2. + * We test for bmi1 & bmi2. lzcnt is included in bmi1. */ -#ifndef DYNAMIC_BMI2 - #if ((defined(__clang__) && __has_attribute(__target__)) \ - || (defined(__GNUC__) \ - && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \ - && (defined(__x86_64__) || defined(_M_X86)) \ - && !defined(__BMI2__) - # define DYNAMIC_BMI2 1 - #else - # define DYNAMIC_BMI2 0 - #endif -#endif +#define BMI2_TARGET_ATTRIBUTE TARGET_ATTRIBUTE("lzcnt,bmi,bmi2") /* prefetch * can be disabled, by declaring NO_PREFETCH build macro */ #if defined(NO_PREFETCH) -# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */ -# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */ +# define PREFETCH_L1(ptr) do { (void)(ptr); } while (0) /* disabled */ +# define PREFETCH_L2(ptr) do { (void)(ptr); } while (0) /* disabled */ #else -# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */ +# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) && !defined(_M_ARM64EC) /* _mm_prefetch() is not defined outside of x86/x64 */ # include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ # define PREFETCH_L1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) # define PREFETCH_L2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1) -# elif defined(__aarch64__) -# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))) -# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))) # elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) # define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) # define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */) +# elif defined(__aarch64__) +# define PREFETCH_L1(ptr) do { __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))); } while (0) +# define PREFETCH_L2(ptr) do { __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))); } while (0) # else -# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */ -# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */ +# define PREFETCH_L1(ptr) do { (void)(ptr); } while (0) /* disabled */ +# define PREFETCH_L2(ptr) do { (void)(ptr); } while (0) /* disabled */ # endif #endif /* NO_PREFETCH */ #define CACHELINE_SIZE 64 -#define PREFETCH_AREA(p, s) { \ - const char* const _ptr = (const char*)(p); \ - size_t const _size = (size_t)(s); \ - size_t _pos; \ - for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \ - PREFETCH_L2(_ptr + _pos); \ - } \ -} +#define PREFETCH_AREA(p, s) \ + do { \ + const char* const _ptr = (const char*)(p); \ + size_t const _size = (size_t)(s); \ + size_t _pos; \ + for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \ + PREFETCH_L2(_ptr + _pos); \ + } \ + } while (0) /* vectorization - * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax */ -#if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__) + * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax, + * and some compilers, like Intel ICC and MCST LCC, do not support it at all. */ +#if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__) && !defined(__LCC__) # if (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || (__GNUC__ >= 5) # define DONT_VECTORIZE __attribute__((optimize("no-tree-vectorize"))) # else @@ -155,19 +182,188 @@ * and clang, please do. */ #if defined(__GNUC__) -#ifndef LIKELY #define LIKELY(x) (__builtin_expect((x), 1)) -#endif -#ifndef UNLIKELY #define UNLIKELY(x) (__builtin_expect((x), 0)) -#endif #else -#ifndef LIKELY #define LIKELY(x) (x) -#endif -#ifndef UNLIKELY #define UNLIKELY(x) (x) #endif + +#if __has_builtin(__builtin_unreachable) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))) +# define ZSTD_UNREACHABLE do { assert(0), __builtin_unreachable(); } while (0) +#else +# define ZSTD_UNREACHABLE do { assert(0); } while (0) +#endif + +/* disable warnings */ +#ifdef _MSC_VER /* Visual Studio */ +# include /* For Visual 2005 */ +# pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ +# pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ +# pragma warning(disable : 4324) /* disable: C4324: padded structure */ +#endif + +/*Like DYNAMIC_BMI2 but for compile time determination of BMI2 support*/ +#ifndef STATIC_BMI2 +# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) +# ifdef __AVX2__ //MSVC does not have a BMI2 specific flag, but every CPU that supports AVX2 also supports BMI2 +# define STATIC_BMI2 1 +# endif +# elif defined(__BMI2__) && defined(__x86_64__) && defined(__GNUC__) +# define STATIC_BMI2 1 +# endif +#endif + +#ifndef STATIC_BMI2 + #define STATIC_BMI2 0 +#endif + +/* compile time determination of SIMD support */ +#if !defined(ZSTD_NO_INTRINSICS) +# if defined(__SSE2__) || defined(_M_AMD64) || (defined (_M_IX86) && defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) +# define ZSTD_ARCH_X86_SSE2 +# endif +# if defined(__ARM_NEON) || defined(_M_ARM64) +# define ZSTD_ARCH_ARM_NEON +# endif +# +# if defined(ZSTD_ARCH_X86_SSE2) +# include +# elif defined(ZSTD_ARCH_ARM_NEON) +# include +# endif +#endif + +/* C-language Attributes are added in C23. */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute) +# define ZSTD_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) +#else +# define ZSTD_HAS_C_ATTRIBUTE(x) 0 #endif +/* Only use C++ attributes in C++. Some compilers report support for C++ + * attributes when compiling with C. + */ +#if defined(__cplusplus) && defined(__has_cpp_attribute) +# define ZSTD_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define ZSTD_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +/* Define ZSTD_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute. + * - C23: https://en.cppreference.com/w/c/language/attributes/fallthrough + * - CPP17: https://en.cppreference.com/w/cpp/language/attributes/fallthrough + * - Else: __attribute__((__fallthrough__)) + */ +#ifndef ZSTD_FALLTHROUGH +# define ZSTD_FALLTHROUGH +#endif + +/*-************************************************************** +* Alignment check +*****************************************************************/ + +/* this test was initially positioned in mem.h, + * but this file is removed (or replaced) for linux kernel + * so it's now hosted in compiler.h, + * which remains valid for both user & kernel spaces. + */ + +#ifndef ZSTD_ALIGNOF +# if defined(__GNUC__) || defined(_MSC_VER) +/* covers gcc, clang & MSVC */ +/* note : this section must come first, before C11, + * due to a limitation in the kernel source generator */ +# define ZSTD_ALIGNOF(T) __alignof(T) + +# elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +/* C11 support */ +# include +# define ZSTD_ALIGNOF(T) alignof(T) + +# else +/* No known support for alignof() - imperfect backup */ +# define ZSTD_ALIGNOF(T) (sizeof(void*) < sizeof(T) ? sizeof(void*) : sizeof(T)) + +# endif +#endif /* ZSTD_ALIGNOF */ + +/*-************************************************************** +* Sanitizer +*****************************************************************/ + +/** + * Zstd relies on pointer overflow in its decompressor. + * We add this attribute to functions that rely on pointer overflow. + */ +#ifndef ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +# if __has_attribute(no_sanitize) +# if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 8 + /* gcc < 8 only has signed-integer-overlow which triggers on pointer overflow */ +# define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR __attribute__((no_sanitize("signed-integer-overflow"))) +# else + /* older versions of clang [3.7, 5.0) will warn that pointer-overflow is ignored. */ +# define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR __attribute__((no_sanitize("pointer-overflow"))) +# endif +# else +# define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +# endif +#endif + +namespace duckdb_zstd { + +/** + * Helper function to perform a wrapped pointer difference without trigging + * UBSAN. + * + * @returns lhs - rhs with wrapping + */ +MEM_STATIC +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +ptrdiff_t ZSTD_wrappedPtrDiff(unsigned char const* lhs, unsigned char const* rhs) +{ + return lhs - rhs; +} + +/** + * Helper function to perform a wrapped pointer add without triggering UBSAN. + * + * @return ptr + add with wrapping + */ +MEM_STATIC +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +unsigned char const* ZSTD_wrappedPtrAdd(unsigned char const* ptr, ptrdiff_t add) +{ + return ptr + add; +} + +/** + * Helper function to perform a wrapped pointer subtraction without triggering + * UBSAN. + * + * @return ptr - sub with wrapping + */ +MEM_STATIC +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +unsigned char const* ZSTD_wrappedPtrSub(unsigned char const* ptr, ptrdiff_t sub) +{ + return ptr - sub; +} + +/** + * Helper function to add to a pointer that works around C's undefined behavior + * of adding 0 to NULL. + * + * @returns `ptr + add` except it defines `NULL + 0 == NULL`. + */ +MEM_STATIC +unsigned char* ZSTD_maybeNullPtrAdd(unsigned char* ptr, ptrdiff_t add) +{ + return add > 0 ? ptr + add : ptr; +} + +} // namespace duckdb_zstd + #endif /* ZSTD_COMPILER_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/cpu.h b/src/duckdb/third_party/zstd/include/zstd/common/cpu.h new file mode 100644 index 000000000..892f9851d --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd/common/cpu.h @@ -0,0 +1,253 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_COMMON_CPU_H +#define ZSTD_COMMON_CPU_H + +/** + * Implementation taken from folly/CpuId.h + * https://github.com/facebook/folly/blob/master/folly/CpuId.h + */ + +#include "zstd/common/mem.h" + +#ifdef _MSC_VER +#include +#endif + +namespace duckdb_zstd { + +typedef struct { + U32 f1c; + U32 f1d; + U32 f7b; + U32 f7c; +} ZSTD_cpuid_t; + +MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) { + U32 f1c = 0; + U32 f1d = 0; + U32 f7b = 0; + U32 f7c = 0; +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) +#if !defined(__clang__) + int reg[4]; + __cpuid((int*)reg, 0); + { + int const n = reg[0]; + if (n >= 1) { + __cpuid((int*)reg, 1); + f1c = (U32)reg[2]; + f1d = (U32)reg[3]; + } + if (n >= 7) { + __cpuidex((int*)reg, 7, 0); + f7b = (U32)reg[1]; + f7c = (U32)reg[2]; + } + } +#else + /* Clang compiler has a bug (fixed in https://reviews.llvm.org/D101338) in + * which the `__cpuid` intrinsic does not save and restore `rbx` as it needs + * to due to being a reserved register. So in that case, do the `cpuid` + * ourselves. Clang supports inline assembly anyway. + */ + U32 n; + __asm__( + "pushq %%rbx\n\t" + "cpuid\n\t" + "popq %%rbx\n\t" + : "=a"(n) + : "a"(0) + : "rcx", "rdx"); + if (n >= 1) { + U32 f1a; + __asm__( + "pushq %%rbx\n\t" + "cpuid\n\t" + "popq %%rbx\n\t" + : "=a"(f1a), "=c"(f1c), "=d"(f1d) + : "a"(1) + :); + } + if (n >= 7) { + __asm__( + "pushq %%rbx\n\t" + "cpuid\n\t" + "movq %%rbx, %%rax\n\t" + "popq %%rbx" + : "=a"(f7b), "=c"(f7c) + : "a"(7), "c"(0) + : "rdx"); + } +#endif +#elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__) + /* The following block like the normal cpuid branch below, but gcc + * reserves ebx for use of its pic register so we must specially + * handle the save and restore to avoid clobbering the register + */ + U32 n; + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "popl %%ebx\n\t" + : "=a"(n) + : "a"(0) + : "ecx", "edx"); + if (n >= 1) { + U32 f1a; + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "popl %%ebx\n\t" + : "=a"(f1a), "=c"(f1c), "=d"(f1d) + : "a"(1)); + } + if (n >= 7) { + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "movl %%ebx, %%eax\n\t" + "popl %%ebx" + : "=a"(f7b), "=c"(f7c) + : "a"(7), "c"(0) + : "edx"); + } +#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__) + U32 n; + __asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx"); + if (n >= 1) { + U32 f1a; + __asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx"); + } + if (n >= 7) { + U32 f7a; + __asm__("cpuid" + : "=a"(f7a), "=b"(f7b), "=c"(f7c) + : "a"(7), "c"(0) + : "edx"); + } +#endif + { + ZSTD_cpuid_t cpuid; + cpuid.f1c = f1c; + cpuid.f1d = f1d; + cpuid.f7b = f7b; + cpuid.f7c = f7c; + return cpuid; + } +} + +#define X(name, r, bit) \ + MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) { \ + return ((cpuid.r) & (1U << bit)) != 0; \ + } + +/* cpuid(1): Processor Info and Feature Bits. */ +#define C(name, bit) X(name, f1c, bit) + C(sse3, 0) + C(pclmuldq, 1) + C(dtes64, 2) + C(monitor, 3) + C(dscpl, 4) + C(vmx, 5) + C(smx, 6) + C(eist, 7) + C(tm2, 8) + C(ssse3, 9) + C(cnxtid, 10) + C(fma, 12) + C(cx16, 13) + C(xtpr, 14) + C(pdcm, 15) + C(pcid, 17) + C(dca, 18) + C(sse41, 19) + C(sse42, 20) + C(x2apic, 21) + C(movbe, 22) + C(popcnt, 23) + C(tscdeadline, 24) + C(aes, 25) + C(xsave, 26) + C(osxsave, 27) + C(avx, 28) + C(f16c, 29) + C(rdrand, 30) +#undef C +#define D(name, bit) X(name, f1d, bit) + D(fpu, 0) + D(vme, 1) + D(de, 2) + D(pse, 3) + D(tsc, 4) + D(msr, 5) + D(pae, 6) + D(mce, 7) + D(cx8, 8) + D(apic, 9) + D(sep, 11) + D(mtrr, 12) + D(pge, 13) + D(mca, 14) + D(cmov, 15) + D(pat, 16) + D(pse36, 17) + D(psn, 18) + D(clfsh, 19) + D(ds, 21) + D(acpi, 22) + D(mmx, 23) + D(fxsr, 24) + D(sse, 25) + D(sse2, 26) + D(ss, 27) + D(htt, 28) + D(tm, 29) + D(pbe, 31) +#undef D + +/* cpuid(7): Extended Features. */ +#define B(name, bit) X(name, f7b, bit) + B(bmi1, 3) + B(hle, 4) + B(avx2, 5) + B(smep, 7) + B(bmi2, 8) + B(erms, 9) + B(invpcid, 10) + B(rtm, 11) + B(mpx, 14) + B(avx512f, 16) + B(avx512dq, 17) + B(rdseed, 18) + B(adx, 19) + B(smap, 20) + B(avx512ifma, 21) + B(pcommit, 22) + B(clflushopt, 23) + B(clwb, 24) + B(avx512pf, 26) + B(avx512er, 27) + B(avx512cd, 28) + B(sha, 29) + B(avx512bw, 30) + B(avx512vl, 31) +#undef B +#define C(name, bit) X(name, f7c, bit) + C(prefetchwt1, 0) + C(avx512vbmi, 1) +#undef C + +#undef X + +} // namespace duckdb_zstd + +#endif /* ZSTD_COMMON_CPU_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/debug.h b/src/duckdb/third_party/zstd/include/zstd/common/debug.h index ac6224888..559897771 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/debug.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/debug.h @@ -1,7 +1,7 @@ /* ****************************************************************** * debug * Part of FSE library - * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * You can contact the author at : * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -32,10 +32,7 @@ #ifndef DEBUG_H_12987983217 #define DEBUG_H_12987983217 -#if defined (__cplusplus) -extern "C" { -#endif - +#include "zstd/common/zstd_deps.h" // DuckDB: added here /* static assert is triggered at compile time, leaving no runtime artefact. * static assert only works with compile-time constants. @@ -51,15 +48,6 @@ extern "C" { #endif -/* DEBUGFILE can be defined externally, - * typically through compiler command line. - * note : currently useless. - * Value must be stderr or stdout */ -#ifndef DEBUGFILE -# define DEBUGFILE stderr -#endif - - /* recommended values for DEBUGLEVEL : * 0 : release mode, no debug, all run-time checks disabled * 1 : enables assert() only, no display @@ -76,7 +64,8 @@ extern "C" { */ #if (DEBUGLEVEL>=1) -# include +# define ZSTD_DEPS_NEED_ASSERT +// # include "zstd/common/zstd_deps.h" // DuckDB: comment out otherwise amalgamation won't be happy #else # ifndef assert /* assert may be already defined, due to prior #include */ # define assert(condition) ((void)0) /* disable assert (default) */ @@ -84,7 +73,11 @@ extern "C" { #endif #if (DEBUGLEVEL>=2) -# include +# define ZSTD_DEPS_NEED_IO +// # include "zstd/common/zstd_deps.h" // DuckDB: comment out otherwise amalgamation won't be happy + +namespace duckdb_zstd { + extern int g_debuglevel; /* the variable is only declared, it actually lives in debug.c, and is shared by the whole process. @@ -92,23 +85,30 @@ extern int g_debuglevel; /* the variable is only declared, It's useful when enabling very verbose levels on selective conditions (such as position in src) */ -# define RAWLOG(l, ...) { \ - if (l<=g_debuglevel) { \ - fprintf(stderr, __VA_ARGS__); \ - } } -# define DEBUGLOG(l, ...) { \ - if (l<=g_debuglevel) { \ - fprintf(stderr, __FILE__ ": " __VA_ARGS__); \ - fprintf(stderr, " \n"); \ - } } -#else -# define RAWLOG(l, ...) {} /* disabled */ -# define DEBUGLOG(l, ...) {} /* disabled */ -#endif +# define RAWLOG(l, ...) \ + do { \ + if (l<=g_debuglevel) { \ + ZSTD_DEBUG_PRINT(__VA_ARGS__); \ + } \ + } while (0) +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) +#define LINE_AS_STRING TOSTRING(__LINE__) -#if defined (__cplusplus) -} +# define DEBUGLOG(l, ...) \ + do { \ + if (l<=g_debuglevel) { \ + ZSTD_DEBUG_PRINT(__FILE__ ":" LINE_AS_STRING ": " __VA_ARGS__); \ + ZSTD_DEBUG_PRINT(" \n"); \ + } \ + } while (0) + +} // namespace duckdb_zstd + +#else +# define RAWLOG(l, ...) do { } while (0) /* disabled */ +# define DEBUGLOG(l, ...) do { } while (0) /* disabled */ #endif #endif /* DEBUG_H_12987983217 */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/error_private.h b/src/duckdb/third_party/zstd/include/zstd/common/error_private.h index b1af95d12..7fe7701de 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/error_private.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/error_private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -16,10 +16,13 @@ /* **************************************** * Dependencies ******************************************/ -#include /* size_t */ -#include "zstd/common/zstd_errors.h" /* enum list */ +#include "zstd_errors.h" /* enum list */ +#include "zstd/common/compiler.h" +#include "zstd/common/debug.h" +#include "zstd/common/zstd_deps.h" /* size_t */ namespace duckdb_zstd { + /* **************************************** * Compiler-specific ******************************************/ @@ -33,7 +36,6 @@ namespace duckdb_zstd { # define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ #endif - /*-**************************************** * Customization (error_public.h) ******************************************/ @@ -53,8 +55,13 @@ ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); } /* check and forward error code */ -#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e -#define CHECK_F(f) { CHECK_V_F(_var_err__, f); } +#define CHECK_V_F(e, f) \ + size_t const e = f; \ + do { \ + if (ERR_isError(e)) \ + return e; \ + } while (0) +#define CHECK_F(f) do { CHECK_V_F(_var_err__, f); } while (0) /*-**************************************** @@ -68,6 +75,87 @@ ERR_STATIC const char* ERR_getErrorName(size_t code) return ERR_getErrorString(ERR_getErrorCode(code)); } +/** + * Ignore: this is an internal helper. + * + * This is a helper function to help force C99-correctness during compilation. + * Under strict compilation modes, variadic macro arguments can't be empty. + * However, variadic function arguments can be. Using a function therefore lets + * us statically check that at least one (string) argument was passed, + * independent of the compilation flags. + */ +static INLINE_KEYWORD UNUSED_ATTR +void _force_has_format_string(const char *format, ...) { + (void)format; } +/** + * Ignore: this is an internal helper. + * + * We want to force this function invocation to be syntactically correct, but + * we don't want to force runtime evaluation of its arguments. + */ +#define _FORCE_HAS_FORMAT_STRING(...) \ + do { \ + if (0) { \ + _force_has_format_string(__VA_ARGS__); \ + } \ + } while (0) + +#define ERR_QUOTE(str) #str + +/** + * Return the specified error if the condition evaluates to true. + * + * In debug modes, prints additional information. + * In order to do that (particularly, printing the conditional that failed), + * this can't just wrap RETURN_ERROR(). + */ +#define RETURN_ERROR_IF(cond, err, ...) \ + do { \ + if (cond) { \ + RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \ + __FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return ERROR(err); \ + } \ + } while (0) + +/** + * Unconditionally return the specified error. + * + * In debug modes, prints additional information. + */ +#define RETURN_ERROR(err, ...) \ + do { \ + RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \ + __FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return ERROR(err); \ + } while(0) + +/** + * If the provided expression evaluates to an error code, returns that error code. + * + * In debug modes, prints additional information. + */ +#define FORWARD_IF_ERROR(err, ...) \ + do { \ + size_t const err_code = (err); \ + if (ERR_isError(err_code)) { \ + RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \ + __FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return err_code; \ + } \ + } while(0) + +} // namespace duckdb_zstd + #endif /* ERROR_H_MODULE */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/fse.h b/src/duckdb/third_party/zstd/include/zstd/common/fse.h index 6600fee54..9df59ff14 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/fse.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/fse.h @@ -1,7 +1,7 @@ /* ****************************************************************** * FSE : Finite State Entropy codec * Public Prototypes declaration - * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * You can contact the author at : * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -12,6 +12,7 @@ * You may select, at your option, one of the above-listed licenses. ****************************************************************** */ + #ifndef FSE_H #define FSE_H @@ -19,10 +20,11 @@ /*-***************************************** * Dependencies ******************************************/ -#include /* size_t, ptrdiff_t */ +#include "zstd/common/zstd_deps.h" /* size_t, ptrdiff_t */ namespace duckdb_zstd { + /*-***************************************** * FSE_PUBLIC_API : control library symbols visibility ******************************************/ @@ -50,34 +52,6 @@ namespace duckdb_zstd { FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */ -/*-**************************************** -* FSE simple functions -******************************************/ -/*! FSE_compress() : - Compress content of buffer 'src', of size 'srcSize', into destination buffer 'dst'. - 'dst' buffer must be already allocated. Compression runs faster is dstCapacity >= FSE_compressBound(srcSize). - @return : size of compressed data (<= dstCapacity). - Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!! - if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression instead. - if FSE_isError(return), compression failed (more details using FSE_getErrorName()) -*/ -FSE_PUBLIC_API size_t FSE_compress(void* dst, size_t dstCapacity, - const void* src, size_t srcSize); - -/*! FSE_decompress(): - Decompress FSE data from buffer 'cSrc', of size 'cSrcSize', - into already allocated destination buffer 'dst', of size 'dstCapacity'. - @return : size of regenerated data (<= maxDstSize), - or an error code, which can be tested using FSE_isError() . - - ** Important ** : FSE_decompress() does not decompress non-compressible nor RLE data !!! - Why ? : making this distinction requires a header. - Header management is intentionally delegated to the user layer, which can better manage special cases. -*/ -FSE_PUBLIC_API size_t FSE_decompress(void* dst, size_t dstCapacity, - const void* cSrc, size_t cSrcSize); - - /*-***************************************** * Tool functions ******************************************/ @@ -88,20 +62,6 @@ FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return FSE_PUBLIC_API const char* FSE_getErrorName(size_t code); /* provides error code string (useful for debugging) */ -/*-***************************************** -* FSE advanced functions -******************************************/ -/*! FSE_compress2() : - Same as FSE_compress(), but allows the selection of 'maxSymbolValue' and 'tableLog' - Both parameters can be defined as '0' to mean : use default value - @return : size of compressed data - Special values : if return == 0, srcData is not compressible => Nothing is stored within cSrc !!! - if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression. - if FSE_isError(return), it's an error code. -*/ -FSE_PUBLIC_API size_t FSE_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog); - - /*-***************************************** * FSE detailed API ******************************************/ @@ -134,10 +94,16 @@ FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize /*! FSE_normalizeCount(): normalize counts so that sum(count[]) == Power_of_2 (2^tableLog) 'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1). + useLowProbCount is a boolean parameter which trades off compressed size for + faster header decoding. When it is set to 1, the compressed data will be slightly + smaller. And when it is set to 0, FSE_readNCount() and FSE_buildDTable() will be + faster. If you are compressing a small amount of data (< 2 KB) then useLowProbCount=0 + is a good default, since header deserialization makes a big speed difference. + Otherwise, useLowProbCount=1 is a good default, since the speed difference is small. @return : tableLog, or an errorCode, which can be tested using FSE_isError() */ FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog, - const unsigned* count, size_t srcSize, unsigned maxSymbolValue); + const unsigned* count, size_t srcSize, unsigned maxSymbolValue, unsigned useLowProbCount); /*! FSE_NCountWriteBound(): Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'. @@ -155,8 +121,6 @@ FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize, /*! Constructor and Destructor of FSE_CTable. Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */ typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */ -FSE_PUBLIC_API FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog); -FSE_PUBLIC_API void FSE_freeCTable (FSE_CTable* ct); /*! FSE_buildCTable(): Builds `ct`, which must be already allocated, using FSE_createCTable(). @@ -225,23 +189,14 @@ FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, const void* rBuffer, size_t rBuffSize); -/*! Constructor and Destructor of FSE_DTable. - Note that its size depends on 'tableLog' */ +/*! FSE_readNCount_bmi2(): + * Same as FSE_readNCount() but pass bmi2=1 when your CPU supports BMI2 and 0 otherwise. + */ +FSE_PUBLIC_API size_t FSE_readNCount_bmi2(short* normalizedCounter, + unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, + const void* rBuffer, size_t rBuffSize, int bmi2); + typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */ -FSE_PUBLIC_API FSE_DTable* FSE_createDTable(unsigned tableLog); -FSE_PUBLIC_API void FSE_freeDTable(FSE_DTable* dt); - -/*! FSE_buildDTable(): - Builds 'dt', which must be already allocated, using FSE_createDTable(). - return : 0, or an errorCode, which can be tested using FSE_isError() */ -FSE_PUBLIC_API size_t FSE_buildDTable (FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog); - -/*! FSE_decompress_usingDTable(): - Decompress compressed source `cSrc` of size `cSrcSize` using `dt` - into `dst` which must be already allocated. - @return : size of regenerated data (necessarily <= `dstCapacity`), - or an errorCode, which can be tested using FSE_isError() */ -FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt); /*! Tutorial : @@ -271,7 +226,412 @@ FSE_decompress_usingDTable() result will tell how many bytes were regenerated (< If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small) */ -} +} // namespace duckdb_zstd #endif /* FSE_H */ +#if defined(FSE_STATIC_LINKING_ONLY) && !defined(FSE_H_FSE_STATIC_LINKING_ONLY) +#define FSE_H_FSE_STATIC_LINKING_ONLY + +/* *** Dependency *** */ +#include "zstd/common/bitstream.h" + +namespace duckdb_zstd { + +/* ***************************************** +* Static allocation +*******************************************/ +/* FSE buffer bounds */ +#define FSE_NCOUNTBOUND 512 +#define FSE_BLOCKBOUND(size) ((size) + ((size)>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */) +#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ + +/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */ +#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<((maxTableLog)-1)) + (((maxSymbolValue)+1)*2)) +#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1<<(maxTableLog))) + +/* or use the size to malloc() space directly. Pay attention to alignment restrictions though */ +#define FSE_CTABLE_SIZE(maxTableLog, maxSymbolValue) (FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(FSE_CTable)) +#define FSE_DTABLE_SIZE(maxTableLog) (FSE_DTABLE_SIZE_U32(maxTableLog) * sizeof(FSE_DTable)) + + +/* ***************************************** + * FSE advanced API + ***************************************** */ + +unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus); +/**< same as FSE_optimalTableLog(), which used `minus==2` */ + +size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue); +/**< build a fake FSE_CTable, designed to compress always the same symbolValue */ + +/* FSE_buildCTable_wksp() : + * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`). + * `wkspSize` must be >= `FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)` of `unsigned`. + * See FSE_buildCTable_wksp() for breakdown of workspace usage. + */ +#define FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog) (((maxSymbolValue + 2) + (1ull << (tableLog)))/2 + sizeof(U64)/sizeof(U32) /* additional 8 bytes for potential table overwrite */) +#define FSE_BUILD_CTABLE_WORKSPACE_SIZE(maxSymbolValue, tableLog) (sizeof(unsigned) * FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)) +size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); + +#define FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) (sizeof(short) * (maxSymbolValue + 1) + (1ULL << maxTableLog) + 8) +#define FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ((FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) + sizeof(unsigned) - 1) / sizeof(unsigned)) +FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); +/**< Same as FSE_buildDTable(), using an externally allocated `workspace` produced with `FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxSymbolValue)` */ + +#define FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) (FSE_DTABLE_SIZE_U32(maxTableLog) + 1 + FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) + (FSE_MAX_SYMBOL_VALUE + 1) / 2 + 1) +#define FSE_DECOMPRESS_WKSP_SIZE(maxTableLog, maxSymbolValue) (FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(unsigned)) +size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2); +/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DECOMPRESS_WKSP_SIZE_U32(maxLog, maxSymbolValue)`. + * Set bmi2 to 1 if your CPU supports BMI2 or 0 if it doesn't */ + +typedef enum { + FSE_repeat_none, /**< Cannot use the previous table */ + FSE_repeat_check, /**< Can use the previous table but it must be checked */ + FSE_repeat_valid /**< Can use the previous table and it is assumed to be valid */ + } FSE_repeat; + +/* ***************************************** +* FSE symbol compression API +*******************************************/ +/*! + This API consists of small unitary functions, which highly benefit from being inlined. + Hence their body are included in next section. +*/ +typedef struct { + ptrdiff_t value; + const void* stateTable; + const void* symbolTT; + unsigned stateLog; +} FSE_CState_t; + +static void FSE_initCState(FSE_CState_t* CStatePtr, const FSE_CTable* ct); + +static void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* CStatePtr, unsigned symbol); + +static void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* CStatePtr); + +/**< +These functions are inner components of FSE_compress_usingCTable(). +They allow the creation of custom streams, mixing multiple tables and bit sources. + +A key property to keep in mind is that encoding and decoding are done **in reverse direction**. +So the first symbol you will encode is the last you will decode, like a LIFO stack. + +You will need a few variables to track your CStream. They are : + +FSE_CTable ct; // Provided by FSE_buildCTable() +BIT_CStream_t bitStream; // bitStream tracking structure +FSE_CState_t state; // State tracking structure (can have several) + + +The first thing to do is to init bitStream and state. + size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize); + FSE_initCState(&state, ct); + +Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError(); +You can then encode your input data, byte after byte. +FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time. +Remember decoding will be done in reverse direction. + FSE_encodeByte(&bitStream, &state, symbol); + +At any time, you can also add any bit sequence. +Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders + BIT_addBits(&bitStream, bitField, nbBits); + +The above methods don't commit data to memory, they just store it into local register, for speed. +Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). +Writing data to memory is a manual operation, performed by the flushBits function. + BIT_flushBits(&bitStream); + +Your last FSE encoding operation shall be to flush your last state value(s). + FSE_flushState(&bitStream, &state); + +Finally, you must close the bitStream. +The function returns the size of CStream in bytes. +If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible) +If there is an error, it returns an errorCode (which can be tested using FSE_isError()). + size_t size = BIT_closeCStream(&bitStream); +*/ + + +/* ***************************************** +* FSE symbol decompression API +*******************************************/ +typedef struct { + size_t state; + const void* table; /* precise table may vary, depending on U16 */ +} FSE_DState_t; + + +static void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt); + +static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD); + +static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr); + +/**< +Let's now decompose FSE_decompress_usingDTable() into its unitary components. +You will decode FSE-encoded symbols from the bitStream, +and also any other bitFields you put in, **in reverse order**. + +You will need a few variables to track your bitStream. They are : + +BIT_DStream_t DStream; // Stream context +FSE_DState_t DState; // State context. Multiple ones are possible +FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable() + +The first thing to do is to init the bitStream. + errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize); + +You should then retrieve your initial state(s) +(in reverse flushing order if you have several ones) : + errorCode = FSE_initDState(&DState, &DStream, DTablePtr); + +You can then decode your data, symbol after symbol. +For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'. +Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out). + unsigned char symbol = FSE_decodeSymbol(&DState, &DStream); + +You can retrieve any bitfield you eventually stored into the bitStream (in reverse order) +Note : maximum allowed nbBits is 25, for 32-bits compatibility + size_t bitField = BIT_readBits(&DStream, nbBits); + +All above operations only read from local register (which size depends on size_t). +Refueling the register from memory is manually performed by the reload method. + endSignal = FSE_reloadDStream(&DStream); + +BIT_reloadDStream() result tells if there is still some more data to read from DStream. +BIT_DStream_unfinished : there is still some data left into the DStream. +BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled. +BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed. +BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted. + +When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop, +to properly detect the exact end of stream. +After each decoded symbol, check if DStream is fully consumed using this simple test : + BIT_reloadDStream(&DStream) >= BIT_DStream_completed + +When it's done, verify decompression is fully completed, by checking both DStream and the relevant states. +Checking if DStream has reached its end is performed by : + BIT_endOfDStream(&DStream); +Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible. + FSE_endOfDState(&DState); +*/ + + +/* ***************************************** +* FSE unsafe API +*******************************************/ +static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD); +/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */ + + +/* ***************************************** +* Implementation of inlined functions +*******************************************/ +typedef struct { + int deltaFindState; + U32 deltaNbBits; +} FSE_symbolCompressionTransform; /* total 8 bytes */ + +MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct) +{ + const void* ptr = ct; + const U16* u16ptr = (const U16*) ptr; + const U32 tableLog = MEM_read16(ptr); + statePtr->value = (ptrdiff_t)1<stateTable = u16ptr+2; + statePtr->symbolTT = ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1); + statePtr->stateLog = tableLog; +} + + +/*! FSE_initCState2() : +* Same as FSE_initCState(), but the first symbol to include (which will be the last to be read) +* uses the smallest state value possible, saving the cost of this symbol */ +MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol) +{ + FSE_initCState(statePtr, ct); + { const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol]; + const U16* stateTable = (const U16*)(statePtr->stateTable); + U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16); + statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits; + statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState]; + } +} + +MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, unsigned symbol) +{ + FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol]; + const U16* const stateTable = (const U16*)(statePtr->stateTable); + U32 const nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16); + BIT_addBits(bitC, (size_t)statePtr->value, nbBitsOut); + statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState]; +} + +MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr) +{ + BIT_addBits(bitC, (size_t)statePtr->value, statePtr->stateLog); + BIT_flushBits(bitC); +} + + +/* FSE_getMaxNbBits() : + * Approximate maximum cost of a symbol, in bits. + * Fractional get rounded up (i.e. a symbol with a normalized frequency of 3 gives the same result as a frequency of 2) + * note 1 : assume symbolValue is valid (<= maxSymbolValue) + * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ +MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue) +{ + const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr; + return (symbolTT[symbolValue].deltaNbBits + ((1<<16)-1)) >> 16; +} + +/* FSE_bitCost() : + * Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits) + * note 1 : assume symbolValue is valid (<= maxSymbolValue) + * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ +MEM_STATIC U32 FSE_bitCost(const void* symbolTTPtr, U32 tableLog, U32 symbolValue, U32 accuracyLog) +{ + const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr; + U32 const minNbBits = symbolTT[symbolValue].deltaNbBits >> 16; + U32 const threshold = (minNbBits+1) << 16; + assert(tableLog < 16); + assert(accuracyLog < 31-tableLog); /* ensure enough room for renormalization double shift */ + { U32 const tableSize = 1 << tableLog; + U32 const deltaFromThreshold = threshold - (symbolTT[symbolValue].deltaNbBits + tableSize); + U32 const normalizedDeltaFromThreshold = (deltaFromThreshold << accuracyLog) >> tableLog; /* linear interpolation (very approximate) */ + U32 const bitMultiplier = 1 << accuracyLog; + assert(symbolTT[symbolValue].deltaNbBits + tableSize <= threshold); + assert(normalizedDeltaFromThreshold <= bitMultiplier); + return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold; + } +} + + +/* ====== Decompression ====== */ + +typedef struct { + U16 tableLog; + U16 fastMode; +} FSE_DTableHeader; /* sizeof U32 */ + +typedef struct +{ + unsigned short newState; + unsigned char symbol; + unsigned char nbBits; +} FSE_decode_t; /* size == U32 */ + +MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt) +{ + const void* ptr = dt; + const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr; + DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog); + BIT_reloadDStream(bitD); + DStatePtr->table = dt + 1; +} + +MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + return DInfo.symbol; +} + +MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + size_t const lowBits = BIT_readBits(bitD, nbBits); + DStatePtr->state = DInfo.newState + lowBits; +} + +MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + BYTE const symbol = DInfo.symbol; + size_t const lowBits = BIT_readBits(bitD, nbBits); + + DStatePtr->state = DInfo.newState + lowBits; + return symbol; +} + +/*! FSE_decodeSymbolFast() : + unsafe, only works if no symbol has a probability > 50% */ +MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + BYTE const symbol = DInfo.symbol; + size_t const lowBits = BIT_readBitsFast(bitD, nbBits); + + DStatePtr->state = DInfo.newState + lowBits; + return symbol; +} + +MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) +{ + return DStatePtr->state == 0; +} + + + +#ifndef FSE_COMMONDEFS_ONLY + +/* ************************************************************** +* Tuning parameters +****************************************************************/ +/*!MEMORY_USAGE : +* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) +* Increasing memory usage improves compression ratio +* Reduced memory usage can improve speed, due to cache effect +* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */ +#ifndef FSE_MAX_MEMORY_USAGE +# define FSE_MAX_MEMORY_USAGE 14 +#endif +#ifndef FSE_DEFAULT_MEMORY_USAGE +# define FSE_DEFAULT_MEMORY_USAGE 13 +#endif +#if (FSE_DEFAULT_MEMORY_USAGE > FSE_MAX_MEMORY_USAGE) +# error "FSE_DEFAULT_MEMORY_USAGE must be <= FSE_MAX_MEMORY_USAGE" +#endif + +/*!FSE_MAX_SYMBOL_VALUE : +* Maximum symbol value authorized. +* Required for proper stack allocation */ +#ifndef FSE_MAX_SYMBOL_VALUE +# define FSE_MAX_SYMBOL_VALUE 255 +#endif + +/* ************************************************************** +* template functions type & suffix +****************************************************************/ +#define FSE_FUNCTION_TYPE BYTE +#define FSE_FUNCTION_EXTENSION +#define FSE_DECODE_TYPE FSE_decode_t + + +#endif /* !FSE_COMMONDEFS_ONLY */ + + +/* *************************************************************** +* Constants +*****************************************************************/ +#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2) +#define FSE_MAX_TABLESIZE (1U< FSE_TABLELOG_ABSOLUTE_MAX +# error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported" +#endif + +#define FSE_TABLESTEP(tableSize) (((tableSize)>>1) + ((tableSize)>>3) + 3) + +} // namespace duckdb_zstd + +#endif /* FSE_STATIC_LINKING_ONLY */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/fse_static.h b/src/duckdb/third_party/zstd/include/zstd/common/fse_static.h deleted file mode 100644 index 7d8267e3e..000000000 --- a/src/duckdb/third_party/zstd/include/zstd/common/fse_static.h +++ /dev/null @@ -1,421 +0,0 @@ -/* ****************************************************************** - * FSE : Finite State Entropy codec - * Public Prototypes declaration - * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. - * - * You can contact the author at : - * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. -****************************************************************** */ - -#ifndef FSE_H_FSE_STATIC_LINKING_ONLY -#define FSE_H_FSE_STATIC_LINKING_ONLY - -/* *** Dependency *** */ -#include "zstd/common/bitstream.h" - -namespace duckdb_zstd { - -/* ***************************************** -* Static allocation -*******************************************/ -/* FSE buffer bounds */ -#define FSE_NCOUNTBOUND 512 -#define FSE_BLOCKBOUND(size) (size + (size>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */) -#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ - -/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */ -#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<(maxTableLog-1)) + ((maxSymbolValue+1)*2)) -#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1< 12) ? (1 << (maxTableLog - 2)) : 1024) ) -size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); - -size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits); -/**< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */ - -size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue); -/**< build a fake FSE_CTable, designed to compress always the same symbolValue */ - -/* FSE_buildCTable_wksp() : - * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`). - * `wkspSize` must be >= `(1<= BIT_DStream_completed - -When it's done, verify decompression is fully completed, by checking both DStream and the relevant states. -Checking if DStream has reached its end is performed by : - BIT_endOfDStream(&DStream); -Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible. - FSE_endOfDState(&DState); -*/ - - -/* ***************************************** -* FSE unsafe API -*******************************************/ -static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD); -/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */ - - -/* ***************************************** -* Implementation of inlined functions -*******************************************/ -typedef struct { - int deltaFindState; - U32 deltaNbBits; -} FSE_symbolCompressionTransform; /* total 8 bytes */ - -MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct) -{ - const void* ptr = ct; - const U16* u16ptr = (const U16*) ptr; - const U32 tableLog = MEM_read16(ptr); - statePtr->value = (ptrdiff_t)1<stateTable = u16ptr+2; - statePtr->symbolTT = ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1); - statePtr->stateLog = tableLog; -} - - -/*! FSE_initCState2() : -* Same as FSE_initCState(), but the first symbol to include (which will be the last to be read) -* uses the smallest state value possible, saving the cost of this symbol */ -MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol) -{ - FSE_initCState(statePtr, ct); - { const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol]; - const U16* stateTable = (const U16*)(statePtr->stateTable); - U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16); - statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits; - statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState]; - } -} - -MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, unsigned symbol) -{ - FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol]; - const U16* const stateTable = (const U16*)(statePtr->stateTable); - U32 const nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16); - BIT_addBits(bitC, statePtr->value, nbBitsOut); - statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState]; -} - -MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr) -{ - BIT_addBits(bitC, statePtr->value, statePtr->stateLog); - BIT_flushBits(bitC); -} - - -/* FSE_getMaxNbBits() : - * Approximate maximum cost of a symbol, in bits. - * Fractional get rounded up (i.e : a symbol with a normalized frequency of 3 gives the same result as a frequency of 2) - * note 1 : assume symbolValue is valid (<= maxSymbolValue) - * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ -MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue) -{ - const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr; - return (symbolTT[symbolValue].deltaNbBits + ((1<<16)-1)) >> 16; -} - -/* FSE_bitCost() : - * Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits) - * note 1 : assume symbolValue is valid (<= maxSymbolValue) - * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ -MEM_STATIC U32 FSE_bitCost(const void* symbolTTPtr, U32 tableLog, U32 symbolValue, U32 accuracyLog) -{ - const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr; - U32 const minNbBits = symbolTT[symbolValue].deltaNbBits >> 16; - U32 const threshold = (minNbBits+1) << 16; - assert(tableLog < 16); - assert(accuracyLog < 31-tableLog); /* ensure enough room for renormalization double shift */ - { U32 const tableSize = 1 << tableLog; - U32 const deltaFromThreshold = threshold - (symbolTT[symbolValue].deltaNbBits + tableSize); - U32 const normalizedDeltaFromThreshold = (deltaFromThreshold << accuracyLog) >> tableLog; /* linear interpolation (very approximate) */ - U32 const bitMultiplier = 1 << accuracyLog; - assert(symbolTT[symbolValue].deltaNbBits + tableSize <= threshold); - assert(normalizedDeltaFromThreshold <= bitMultiplier); - return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold; - } -} - - -/* ====== Decompression ====== */ - -typedef struct { - U16 tableLog; - U16 fastMode; -} FSE_DTableHeader; /* sizeof U32 */ - -typedef struct -{ - unsigned short newState; - unsigned char symbol; - unsigned char nbBits; -} FSE_decode_t; /* size == U32 */ - -MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt) -{ - const void* ptr = dt; - const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr; - DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog); - BIT_reloadDStream(bitD); - DStatePtr->table = dt + 1; -} - -MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr) -{ - FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; - return DInfo.symbol; -} - -MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) -{ - FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; - U32 const nbBits = DInfo.nbBits; - size_t const lowBits = BIT_readBits(bitD, nbBits); - DStatePtr->state = DInfo.newState + lowBits; -} - -MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) -{ - FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; - U32 const nbBits = DInfo.nbBits; - BYTE const symbol = DInfo.symbol; - size_t const lowBits = BIT_readBits(bitD, nbBits); - - DStatePtr->state = DInfo.newState + lowBits; - return symbol; -} - -/*! FSE_decodeSymbolFast() : - unsafe, only works if no symbol has a probability > 50% */ -MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) -{ - FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; - U32 const nbBits = DInfo.nbBits; - BYTE const symbol = DInfo.symbol; - size_t const lowBits = BIT_readBitsFast(bitD, nbBits); - - DStatePtr->state = DInfo.newState + lowBits; - return symbol; -} - -MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) -{ - return DStatePtr->state == 0; -} - - - -#ifndef FSE_COMMONDEFS_ONLY - -/* ************************************************************** -* Tuning parameters -****************************************************************/ -/*!MEMORY_USAGE : -* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) -* Increasing memory usage improves compression ratio -* Reduced memory usage can improve speed, due to cache effect -* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */ -#ifndef FSE_MAX_MEMORY_USAGE -# define FSE_MAX_MEMORY_USAGE 14 -#endif -#ifndef FSE_DEFAULT_MEMORY_USAGE -# define FSE_DEFAULT_MEMORY_USAGE 13 -#endif - -/*!FSE_MAX_SYMBOL_VALUE : -* Maximum symbol value authorized. -* Required for proper stack allocation */ -#ifndef FSE_MAX_SYMBOL_VALUE -# define FSE_MAX_SYMBOL_VALUE 255 -#endif - -/* ************************************************************** -* template functions type & suffix -****************************************************************/ -#define FSE_FUNCTION_TYPE BYTE -#define FSE_FUNCTION_EXTENSION -#define FSE_DECODE_TYPE FSE_decode_t - - -#endif /* !FSE_COMMONDEFS_ONLY */ - - -/* *************************************************************** -* Constants -*****************************************************************/ -#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2) -#define FSE_MAX_TABLESIZE (1U< FSE_TABLELOG_ABSOLUTE_MAX -# error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported" -#endif - -#define FSE_TABLESTEP(tableSize) ((tableSize>>1) + (tableSize>>3) + 3) - -} - -#endif /* FSE_H_FSE_STATIC_LINKING_ONLY */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/huf.h b/src/duckdb/third_party/zstd/include/zstd/common/huf.h index 4bba72729..a28595ce6 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/huf.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/huf.h @@ -1,7 +1,7 @@ /* ****************************************************************** * huff0 huffman codec, * part of Finite State Entropy library - * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * You can contact the author at : * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -12,86 +12,271 @@ * You may select, at your option, one of the above-listed licenses. ****************************************************************** */ + #ifndef HUF_H_298734234 #define HUF_H_298734234 /* *** Dependencies *** */ -#include /* size_t */ - - -/* *** library symbols visibility *** */ -/* Note : when linking with -fvisibility=hidden on gcc, or by default on Visual, - * HUF symbols remain "private" (internal symbols for library only). - * Set macro FSE_DLL_EXPORT to 1 if you want HUF symbols visible on DLL interface */ -#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4) -# define HUF_PUBLIC_API __attribute__ ((visibility ("default"))) -#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */ -# define HUF_PUBLIC_API __declspec(dllexport) -#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1) -# define HUF_PUBLIC_API __declspec(dllimport) /* not required, just to generate faster code (saves a function pointer load from IAT and an indirect jump) */ -#else -# define HUF_PUBLIC_API -#endif +#include "zstd/common/zstd_deps.h" /* size_t */ +#include "zstd/common/mem.h" /* U32 */ +#define FSE_STATIC_LINKING_ONLY +#include "zstd/common/fse.h" namespace duckdb_zstd { -/* ========================== */ -/* *** simple functions *** */ -/* ========================== */ - -/** HUF_compress() : - * Compress content from buffer 'src', of size 'srcSize', into buffer 'dst'. - * 'dst' buffer must be already allocated. - * Compression runs faster if `dstCapacity` >= HUF_compressBound(srcSize). - * `srcSize` must be <= `HUF_BLOCKSIZE_MAX` == 128 KB. - * @return : size of compressed data (<= `dstCapacity`). - * Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!! - * if HUF_isError(return), compression failed (more details using HUF_getErrorName()) +/* *** Tool functions *** */ +#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */ +size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */ + +/* Error Management */ +unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */ +const char* HUF_getErrorName(size_t code); /**< provides error code string (useful for debugging) */ + + +#define HUF_WORKSPACE_SIZE ((8 << 10) + 512 /* sorting scratch space */) +#define HUF_WORKSPACE_SIZE_U64 (HUF_WORKSPACE_SIZE / sizeof(U64)) + +/* *** Constants *** */ +#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_TABLELOG_ABSOLUTEMAX */ +#define HUF_TABLELOG_DEFAULT 11 /* default tableLog value when none specified */ +#define HUF_SYMBOLVALUE_MAX 255 + +#define HUF_TABLELOG_ABSOLUTEMAX 12 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */ +#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX) +# error "HUF_TABLELOG_MAX is too large !" +#endif + + +/* **************************************** +* Static allocation +******************************************/ +/* HUF buffer bounds */ +#define HUF_CTABLEBOUND 129 +#define HUF_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true when incompressible is pre-filtered with fast heuristic */ +#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ + +/* static allocation of HUF's Compression Table */ +/* this is a private definition, just exposed for allocation and strict aliasing purpose. never EVER access its members directly */ +typedef size_t HUF_CElt; /* consider it an incomplete type */ +#define HUF_CTABLE_SIZE_ST(maxSymbolValue) ((maxSymbolValue)+2) /* Use tables of size_t, for proper alignment */ +#define HUF_CTABLE_SIZE(maxSymbolValue) (HUF_CTABLE_SIZE_ST(maxSymbolValue) * sizeof(size_t)) +#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \ + HUF_CElt name[HUF_CTABLE_SIZE_ST(maxSymbolValue)] /* no final ; */ + +/* static allocation of HUF's DTable */ +typedef U32 HUF_DTable; +#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog))) +#define HUF_CREATE_STATIC_DTABLEX1(DTable, maxTableLog) \ + HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) } +#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \ + HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) } + + +/* **************************************** +* Advanced decompression functions +******************************************/ + +/** + * Huffman flags bitset. + * For all flags, 0 is the default value. */ -HUF_PUBLIC_API size_t HUF_compress(void* dst, size_t dstCapacity, - const void* src, size_t srcSize); - -/** HUF_decompress() : - * Decompress HUF data from buffer 'cSrc', of size 'cSrcSize', - * into already allocated buffer 'dst', of minimum size 'dstSize'. - * `originalSize` : **must** be the ***exact*** size of original (uncompressed) data. - * Note : in contrast with FSE, HUF_decompress can regenerate - * RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data, - * because it knows size to regenerate (originalSize). - * @return : size of regenerated data (== originalSize), - * or an error code, which can be tested using HUF_isError() +typedef enum { + /** + * If compiled with DYNAMIC_BMI2: Set flag only if the CPU supports BMI2 at runtime. + * Otherwise: Ignored. + */ + HUF_flags_bmi2 = (1 << 0), + /** + * If set: Test possible table depths to find the one that produces the smallest header + encoded size. + * If unset: Use heuristic to find the table depth. + */ + HUF_flags_optimalDepth = (1 << 1), + /** + * If set: If the previous table can encode the input, always reuse the previous table. + * If unset: If the previous table can encode the input, reuse the previous table if it results in a smaller output. + */ + HUF_flags_preferRepeat = (1 << 2), + /** + * If set: Sample the input and check if the sample is uncompressible, if it is then don't attempt to compress. + * If unset: Always histogram the entire input. + */ + HUF_flags_suspectUncompressible = (1 << 3), + /** + * If set: Don't use assembly implementations + * If unset: Allow using assembly implementations + */ + HUF_flags_disableAsm = (1 << 4), + /** + * If set: Don't use the fast decoding loop, always use the fallback decoding loop. + * If unset: Use the fast decoding loop when possible. + */ + HUF_flags_disableFast = (1 << 5) +} HUF_flags_e; + + +/* **************************************** + * HUF detailed API + * ****************************************/ +#define HUF_OPTIMAL_DEPTH_THRESHOLD ZSTD_btultra + +/*! HUF_compress() does the following: + * 1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "fse.h") + * 2. (optional) refine tableLog using HUF_optimalTableLog() + * 3. build Huffman table from count using HUF_buildCTable() + * 4. save Huffman table to memory buffer using HUF_writeCTable() + * 5. encode the data stream using HUF_compress4X_usingCTable() + * + * The following API allows targeting specific sub-functions for advanced tasks. + * For example, it's possible to compress several blocks using the same 'CTable', + * or to save and regenerate 'CTable' using external methods. */ -HUF_PUBLIC_API size_t HUF_decompress(void* dst, size_t originalSize, - const void* cSrc, size_t cSrcSize); +unsigned HUF_minTableLog(unsigned symbolCardinality); +unsigned HUF_cardinality(const unsigned* count, unsigned maxSymbolValue); +unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, void* workSpace, + size_t wkspSize, HUF_CElt* table, const unsigned* count, int flags); /* table is used as scratch space for building and testing tables, not a return value */ +size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, void* workspace, size_t workspaceSize); +size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags); +size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); +int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); +typedef enum { + HUF_repeat_none, /**< Cannot use the previous table */ + HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */ + HUF_repeat_valid /**< Can use the previous table and it is assumed to be valid */ + } HUF_repeat; -/* *** Tool functions *** */ -#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */ -HUF_PUBLIC_API size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */ +/** HUF_compress4X_repeat() : + * Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. + * If it uses hufTable it does not modify hufTable or repeat. + * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. + * If preferRepeat then the old table will always be used if valid. + * If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */ +size_t HUF_compress4X_repeat(void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog, + void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ + HUF_CElt* hufTable, HUF_repeat* repeat, int flags); -/* Error Management */ -HUF_PUBLIC_API unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */ -HUF_PUBLIC_API const char* HUF_getErrorName(size_t code); /**< provides error code string (useful for debugging) */ - - -/* *** Advanced function *** */ - -/** HUF_compress2() : - * Same as HUF_compress(), but offers control over `maxSymbolValue` and `tableLog`. - * `maxSymbolValue` must be <= HUF_SYMBOLVALUE_MAX . - * `tableLog` must be `<= HUF_TABLELOG_MAX` . */ -HUF_PUBLIC_API size_t HUF_compress2 (void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - unsigned maxSymbolValue, unsigned tableLog); - -/** HUF_compress4X_wksp() : - * Same as HUF_compress2(), but uses externally allocated `workSpace`. - * `workspace` must have minimum alignment of 4, and be at least as large as HUF_WORKSPACE_SIZE */ -#define HUF_WORKSPACE_SIZE ((6 << 10) + 256) -#define HUF_WORKSPACE_SIZE_U32 (HUF_WORKSPACE_SIZE / sizeof(U32)) -HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - unsigned maxSymbolValue, unsigned tableLog, - void* workSpace, size_t wkspSize); +/** HUF_buildCTable_wksp() : + * Same as HUF_buildCTable(), but using externally allocated scratch buffer. + * `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE. + */ +#define HUF_CTABLE_WORKSPACE_SIZE_U32 ((4 * (HUF_SYMBOLVALUE_MAX + 1)) + 192) +#define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned)) +size_t HUF_buildCTable_wksp (HUF_CElt* tree, + const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, + void* workSpace, size_t wkspSize); + +/*! HUF_readStats() : + * Read compact Huffman tree, saved by HUF_writeCTable(). + * `huffWeight` is destination buffer. + * @return : size read from `src` , or an error Code . + * Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */ +size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, + U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize); + +/*! HUF_readStats_wksp() : + * Same as HUF_readStats() but takes an external workspace which must be + * 4-byte aligned and its size must be >= HUF_READ_STATS_WORKSPACE_SIZE. + * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. + */ +#define HUF_READ_STATS_WORKSPACE_SIZE_U32 FSE_DECOMPRESS_WKSP_SIZE_U32(6, HUF_TABLELOG_MAX-1) +#define HUF_READ_STATS_WORKSPACE_SIZE (HUF_READ_STATS_WORKSPACE_SIZE_U32 * sizeof(unsigned)) +size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, + U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workspace, size_t wkspSize, + int flags); + +/** HUF_readCTable() : + * Loading a CTable saved with HUF_writeCTable() */ +size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned *hasZeroWeights); + +/** HUF_getNbBitsFromCTable() : + * Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX + * Note 1 : If symbolValue > HUF_readCTableHeader(symbolTable).maxSymbolValue, returns 0 + * Note 2 : is not inlined, as HUF_CElt definition is private + */ +U32 HUF_getNbBitsFromCTable(const HUF_CElt* symbolTable, U32 symbolValue); + +typedef struct { + BYTE tableLog; + BYTE maxSymbolValue; + BYTE unused[sizeof(size_t) - 2]; +} HUF_CTableHeader; + +/** HUF_readCTableHeader() : + * @returns The header from the CTable specifying the tableLog and the maxSymbolValue. + */ +HUF_CTableHeader HUF_readCTableHeader(HUF_CElt const* ctable); + +/* + * HUF_decompress() does the following: + * 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics + * 2. build Huffman table from save, using HUF_readDTableX?() + * 3. decode 1 or 4 segments in parallel using HUF_decompress?X?_usingDTable() + */ + +/** HUF_selectDecoder() : + * Tells which decoder is likely to decode faster, + * based on a set of pre-computed metrics. + * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 . + * Assumption : 0 < dstSize <= 128 KB */ +U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize); + +/** + * The minimum workspace size for the `workSpace` used in + * HUF_readDTableX1_wksp() and HUF_readDTableX2_wksp(). + * + * The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when + * HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15. + * Buffer overflow errors may potentially occur if code modifications result in + * a required workspace size greater than that specified in the following + * macro. + */ +#define HUF_DECOMPRESS_WORKSPACE_SIZE ((2 << 10) + (1 << 9)) +#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32)) + + +/* ====================== */ +/* single stream variants */ +/* ====================== */ + +size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags); +/** HUF_compress1X_repeat() : + * Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. + * If it uses hufTable it does not modify hufTable or repeat. + * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. + * If preferRepeat then the old table will always be used if valid. + * If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */ +size_t HUF_compress1X_repeat(void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog, + void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ + HUF_CElt* hufTable, HUF_repeat* repeat, int flags); + +size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); /**< double-symbols decoder */ +#endif + +/* BMI2 variants. + * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. + */ +size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); +#endif +size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags); +size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int flags); +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int flags); +#endif + +} // namespace duckdb_zstd #endif /* HUF_H_298734234 */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/huf_static.h b/src/duckdb/third_party/zstd/include/zstd/common/huf_static.h deleted file mode 100644 index 7701972e6..000000000 --- a/src/duckdb/third_party/zstd/include/zstd/common/huf_static.h +++ /dev/null @@ -1,238 +0,0 @@ -/* ****************************************************************** - * WARNING !! - * The following section contains advanced and experimental definitions - * which shall never be used in the context of a dynamic library, - * because they are not guaranteed to remain stable in the future. - * Only consider them in association with static linking. - * **************************************************************** */ -#ifndef HUF_H_HUF_STATIC_LINKING_ONLY -#define HUF_H_HUF_STATIC_LINKING_ONLY - -/* *** Dependencies *** */ -#include "zstd/common/mem.h" /* U32 */ - - -/* *** Constants *** */ -#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */ -#define HUF_TABLELOG_DEFAULT 11 /* default tableLog value when none specified */ -#define HUF_SYMBOLVALUE_MAX 255 - -#define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */ -#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX) -# error "HUF_TABLELOG_MAX is too large !" -#endif - - -/* **************************************** -* Static allocation -******************************************/ -/* HUF buffer bounds */ -#define HUF_CTABLEBOUND 129 -#define HUF_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true when incompressible is pre-filtered with fast heuristic */ -#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ - -/* static allocation of HUF's Compression Table */ -#define HUF_CTABLE_SIZE_U32(maxSymbolValue) ((maxSymbolValue)+1) /* Use tables of U32, for proper alignment */ -#define HUF_CTABLE_SIZE(maxSymbolValue) (HUF_CTABLE_SIZE_U32(maxSymbolValue) * sizeof(U32)) -#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \ - U32 name##hb[HUF_CTABLE_SIZE_U32(maxSymbolValue)]; \ - void* name##hv = &(name##hb); \ - HUF_CElt* name = (HUF_CElt*)(name##hv) /* no final ; */ - -/* static allocation of HUF's DTable */ -typedef U32 HUF_DTable; -#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog))) -#define HUF_CREATE_STATIC_DTABLEX1(DTable, maxTableLog) \ - HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) } -#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \ - HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) } - - -/* **************************************** -* Advanced decompression functions -******************************************/ -size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ -#ifndef HUF_FORCE_DECOMPRESS_X1 -size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ -#endif - -size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< decodes RLE and uncompressed */ -size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */ -size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< considers RLE and uncompressed as errors */ -size_t HUF_decompress4X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ -size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */ -#ifndef HUF_FORCE_DECOMPRESS_X1 -size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ -size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */ -#endif - - -/* **************************************** - * HUF detailed API - * ****************************************/ - -/*! HUF_compress() does the following: - * 1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "zstd/common/fse.h") - * 2. (optional) refine tableLog using HUF_optimalTableLog() - * 3. build Huffman table from count using HUF_buildCTable() - * 4. save Huffman table to memory buffer using HUF_writeCTable() - * 5. encode the data stream using HUF_compress4X_usingCTable() - * - * The following API allows targeting specific sub-functions for advanced tasks. - * For example, it's possible to compress several blocks using the same 'CTable', - * or to save and regenerate 'CTable' using external methods. - */ -unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue); -typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */ -size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */ -size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog); -size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); -size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); -int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); - -typedef enum { - HUF_repeat_none, /**< Cannot use the previous table */ - HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */ - HUF_repeat_valid /**< Can use the previous table and it is assumed to be valid */ - } HUF_repeat; -/** HUF_compress4X_repeat() : - * Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. - * If it uses hufTable it does not modify hufTable or repeat. - * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. - * If preferRepeat then the old table will always be used if valid. */ -size_t HUF_compress4X_repeat(void* dst, size_t dstSize, - const void* src, size_t srcSize, - unsigned maxSymbolValue, unsigned tableLog, - void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ - HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2); - -/** HUF_buildCTable_wksp() : - * Same as HUF_buildCTable(), but using externally allocated scratch buffer. - * `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE. - */ -#define HUF_CTABLE_WORKSPACE_SIZE_U32 (2*HUF_SYMBOLVALUE_MAX +1 +1) -#define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned)) -size_t HUF_buildCTable_wksp (HUF_CElt* tree, - const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, - void* workSpace, size_t wkspSize); - -/*! HUF_readStats() : - * Read compact Huffman tree, saved by HUF_writeCTable(). - * `huffWeight` is destination buffer. - * @return : size read from `src` , or an error Code . - * Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */ -size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, - U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, - const void* src, size_t srcSize); - -/** HUF_readCTable() : - * Loading a CTable saved with HUF_writeCTable() */ -size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned *hasZeroWeights); - -/** HUF_getNbBits() : - * Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX - * Note 1 : is not inlined, as HUF_CElt definition is private - * Note 2 : const void* used, so that it can provide a statically allocated table as argument (which uses type U32) */ -U32 HUF_getNbBits(const void* symbolTable, U32 symbolValue); - -/* - * HUF_decompress() does the following: - * 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics - * 2. build Huffman table from save, using HUF_readDTableX?() - * 3. decode 1 or 4 segments in parallel using HUF_decompress?X?_usingDTable() - */ - -/** HUF_selectDecoder() : - * Tells which decoder is likely to decode faster, - * based on a set of pre-computed metrics. - * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 . - * Assumption : 0 < dstSize <= 128 KB */ -U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize); - -/** - * The minimum workspace size for the `workSpace` used in - * HUF_readDTableX1_wksp() and HUF_readDTableX2_wksp(). - * - * The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when - * HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15. - * Buffer overflow errors may potentially occur if code modifications result in - * a required workspace size greater than that specified in the following - * macro. - */ -#define HUF_DECOMPRESS_WORKSPACE_SIZE (2 << 10) -#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32)) - -#ifndef HUF_FORCE_DECOMPRESS_X2 -size_t HUF_readDTableX1 (HUF_DTable* DTable, const void* src, size_t srcSize); -size_t HUF_readDTableX1_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize); -#endif -#ifndef HUF_FORCE_DECOMPRESS_X1 -size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize); -size_t HUF_readDTableX2_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize); -#endif - -size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); -#ifndef HUF_FORCE_DECOMPRESS_X2 -size_t HUF_decompress4X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); -#endif -#ifndef HUF_FORCE_DECOMPRESS_X1 -size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); -#endif - - -/* ====================== */ -/* single stream variants */ -/* ====================== */ - -size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog); -size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */ -size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); -/** HUF_compress1X_repeat() : - * Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. - * If it uses hufTable it does not modify hufTable or repeat. - * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. - * If preferRepeat then the old table will always be used if valid. */ -size_t HUF_compress1X_repeat(void* dst, size_t dstSize, - const void* src, size_t srcSize, - unsigned maxSymbolValue, unsigned tableLog, - void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ - HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2); - -size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */ -#ifndef HUF_FORCE_DECOMPRESS_X1 -size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */ -#endif - -size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); -size_t HUF_decompress1X_DCtx_wksp (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); -#ifndef HUF_FORCE_DECOMPRESS_X2 -size_t HUF_decompress1X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ -size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */ -#endif -#ifndef HUF_FORCE_DECOMPRESS_X1 -size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ -size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */ -#endif - -size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */ -#ifndef HUF_FORCE_DECOMPRESS_X2 -size_t HUF_decompress1X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); -#endif -#ifndef HUF_FORCE_DECOMPRESS_X1 -size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); -#endif - -/* BMI2 variants. - * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. - */ -size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2); -#ifndef HUF_FORCE_DECOMPRESS_X2 -size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2); -#endif -size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2); -size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2); - -} - -#endif /* HUF_STATIC_LINKING_ONLY */ - diff --git a/src/duckdb/third_party/zstd/include/zstd/common/mem.h b/src/duckdb/third_party/zstd/include/zstd/common/mem.h index 7c7b1f32d..4d36251d4 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/mem.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/mem.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,8 +14,10 @@ /*-**************************************** * Dependencies ******************************************/ -#include /* size_t, ptrdiff_t */ -#include /* memcpy */ +#include /* size_t, ptrdiff_t */ +#include "zstd/common/compiler.h" /* __has_builtin */ +#include "zstd/common/debug.h" /* DEBUG_STATIC_ASSERT */ +#include "zstd/common/zstd_deps.h" /* ZSTD_memcpy */ /*-**************************************** @@ -25,37 +27,19 @@ # include /* _byteswap_ulong */ # include /* _byteswap_* */ #endif -#if defined(__GNUC__) -# define MEM_STATIC static __inline __attribute__((unused)) -#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# define MEM_STATIC static inline -#elif defined(_MSC_VER) -# define MEM_STATIC static __inline -#else -# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ -#endif - -#ifndef __has_builtin -# define __has_builtin(x) 0 /* compat. with non-clang compilers */ -#endif - -/* code only tested on 32 and 64 bits systems */ -#define MEM_STATIC_ASSERT(c) { enum { MEM_static_assert = 1/(int)(!!(c)) }; } -MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); } - -/* detects whether we are being compiled under msan */ -#if defined (__has_feature) -# if __has_feature(memory_sanitizer) -# define MEMORY_SANITIZER 1 -# endif -#endif /*-************************************************************** * Basic Types *****************************************************************/ #if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) -# include +# if defined(_AIX) +# include +# else +# include /* intptr_t */ +# endif typedef uint8_t BYTE; + typedef uint8_t U8; + typedef int8_t S8; typedef uint16_t U16; typedef int16_t S16; typedef uint32_t U32; @@ -68,6 +52,8 @@ MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (size # error "this implementation requires char to be exactly 8-bit type" #endif typedef unsigned char BYTE; + typedef unsigned char U8; + typedef signed char S8; #if USHRT_MAX != 65535 # error "this implementation requires short to be exactly 16-bit type" #endif @@ -87,25 +73,63 @@ MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (size namespace duckdb_zstd { /*-************************************************************** -* Memory I/O +* Memory I/O API *****************************************************************/ -/* MEM_FORCE_MEMORY_ACCESS : - * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable. - * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal. - * The below switch allow to select different access method for improved performance. - * Method 0 (default) : use `memcpy()`. Safe and portable. - * Method 1 : `__packed` statement. It depends on compiler extension (i.e., not portable). - * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. +/*=== Static platform detection ===*/ +MEM_STATIC unsigned MEM_32bits(void); +MEM_STATIC unsigned MEM_64bits(void); +MEM_STATIC unsigned MEM_isLittleEndian(void); + +/*=== Native unaligned read/write ===*/ +MEM_STATIC U16 MEM_read16(const void* memPtr); +MEM_STATIC U32 MEM_read32(const void* memPtr); +MEM_STATIC U64 MEM_read64(const void* memPtr); +MEM_STATIC size_t MEM_readST(const void* memPtr); + +MEM_STATIC void MEM_write16(void* memPtr, U16 value); +MEM_STATIC void MEM_write32(void* memPtr, U32 value); +MEM_STATIC void MEM_write64(void* memPtr, U64 value); + +/*=== Little endian unaligned read/write ===*/ +MEM_STATIC U16 MEM_readLE16(const void* memPtr); +MEM_STATIC U32 MEM_readLE24(const void* memPtr); +MEM_STATIC U32 MEM_readLE32(const void* memPtr); +MEM_STATIC U64 MEM_readLE64(const void* memPtr); +MEM_STATIC size_t MEM_readLEST(const void* memPtr); + +MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val); +MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val); +MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32); +MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64); +MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val); + +/*=== Big endian unaligned read/write ===*/ +MEM_STATIC U32 MEM_readBE32(const void* memPtr); +MEM_STATIC U64 MEM_readBE64(const void* memPtr); +MEM_STATIC size_t MEM_readBEST(const void* memPtr); + +MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32); +MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64); +MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val); + +/*=== Byteswap ===*/ +MEM_STATIC U32 MEM_swap32(U32 in); +MEM_STATIC U64 MEM_swap64(U64 in); +MEM_STATIC size_t MEM_swapST(size_t in); + + +/*-************************************************************** +* Memory I/O Implementation +*****************************************************************/ +/* MEM_FORCE_MEMORY_ACCESS : For accessing unaligned memory: + * Method 0 : always use `memcpy()`. Safe and portable. + * Method 1 : Use compiler extension to set unaligned access. * Method 2 : direct access. This method is portable but violate C standard. * It can generate buggy code on targets depending on alignment. - * In some circumstances, it's the only known way to get the most performance (i.e. GCC + ARMv6) - * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. - * Prefer these methods in priority order (0 > 1 > 2) + * Default : method 1 if supported, else method 0 */ #ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ -# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) -# define MEM_FORCE_MEMORY_ACCESS 2 -# elif defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__) +# ifdef __GNUC__ # define MEM_FORCE_MEMORY_ACCESS 1 # endif #endif @@ -115,8 +139,22 @@ MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; } MEM_STATIC unsigned MEM_isLittleEndian(void) { +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + return 1; +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + return 0; +#elif defined(__clang__) && __LITTLE_ENDIAN__ + return 1; +#elif defined(__clang__) && __BIG_ENDIAN__ + return 0; +#elif defined(_MSC_VER) && (_M_AMD64 || _M_IX86) + return 1; +#elif defined(__DMC__) && defined(_M_IX86) + return 1; +#else const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ return one.c[0]; +#endif } #if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2) @@ -134,30 +172,19 @@ MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; } #elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1) -/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ -/* currently only defined for gcc and icc */ -#if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32)) - __pragma( pack(push, 1) ) - typedef struct { U16 v; } unalign16; - typedef struct { U32 v; } unalign32; - typedef struct { U64 v; } unalign64; - typedef struct { size_t v; } unalignArch; - __pragma( pack(pop) ) -#else - typedef struct { U16 v; } __attribute__((packed)) unalign16; - typedef struct { U32 v; } __attribute__((packed)) unalign32; - typedef struct { U64 v; } __attribute__((packed)) unalign64; - typedef struct { size_t v; } __attribute__((packed)) unalignArch; -#endif +typedef __attribute__((aligned(1))) U16 unalign16; +typedef __attribute__((aligned(1))) U32 unalign32; +typedef __attribute__((aligned(1))) U64 unalign64; +typedef __attribute__((aligned(1))) size_t unalignArch; -MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign16*)ptr)->v; } -MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign32*)ptr)->v; } -MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign64*)ptr)->v; } -MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalignArch*)ptr)->v; } +MEM_STATIC U16 MEM_read16(const void* ptr) { return *(const unalign16*)ptr; } +MEM_STATIC U32 MEM_read32(const void* ptr) { return *(const unalign32*)ptr; } +MEM_STATIC U64 MEM_read64(const void* ptr) { return *(const unalign64*)ptr; } +MEM_STATIC size_t MEM_readST(const void* ptr) { return *(const unalignArch*)ptr; } -MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign16*)memPtr)->v = value; } -MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign32*)memPtr)->v = value; } -MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v = value; } +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(unalign16*)memPtr = value; } +MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(unalign32*)memPtr = value; } +MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(unalign64*)memPtr = value; } #else @@ -166,41 +193,49 @@ MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v = MEM_STATIC U16 MEM_read16(const void* memPtr) { - U16 val; memcpy(&val, memPtr, sizeof(val)); return val; + U16 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; } MEM_STATIC U32 MEM_read32(const void* memPtr) { - U32 val; memcpy(&val, memPtr, sizeof(val)); return val; + U32 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; } MEM_STATIC U64 MEM_read64(const void* memPtr) { - U64 val; memcpy(&val, memPtr, sizeof(val)); return val; + U64 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; } MEM_STATIC size_t MEM_readST(const void* memPtr) { - size_t val; memcpy(&val, memPtr, sizeof(val)); return val; + size_t val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; } MEM_STATIC void MEM_write16(void* memPtr, U16 value) { - memcpy(memPtr, &value, sizeof(value)); + ZSTD_memcpy(memPtr, &value, sizeof(value)); } MEM_STATIC void MEM_write32(void* memPtr, U32 value) { - memcpy(memPtr, &value, sizeof(value)); + ZSTD_memcpy(memPtr, &value, sizeof(value)); } MEM_STATIC void MEM_write64(void* memPtr, U64 value) { - memcpy(memPtr, &value, sizeof(value)); + ZSTD_memcpy(memPtr, &value, sizeof(value)); } #endif /* MEM_FORCE_MEMORY_ACCESS */ +MEM_STATIC U32 MEM_swap32_fallback(U32 in) +{ + return ((in << 24) & 0xff000000 ) | + ((in << 8) & 0x00ff0000 ) | + ((in >> 8) & 0x0000ff00 ) | + ((in >> 24) & 0x000000ff ); +} + MEM_STATIC U32 MEM_swap32(U32 in) { #if defined(_MSC_VER) /* Visual Studio */ @@ -209,22 +244,13 @@ MEM_STATIC U32 MEM_swap32(U32 in) || (defined(__clang__) && __has_builtin(__builtin_bswap32)) return __builtin_bswap32(in); #else - return ((in << 24) & 0xff000000 ) | - ((in << 8) & 0x00ff0000 ) | - ((in >> 8) & 0x0000ff00 ) | - ((in >> 24) & 0x000000ff ); + return MEM_swap32_fallback(in); #endif } -MEM_STATIC U64 MEM_swap64(U64 in) +MEM_STATIC U64 MEM_swap64_fallback(U64 in) { -#if defined(_MSC_VER) /* Visual Studio */ - return _byteswap_uint64(in); -#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \ - || (defined(__clang__) && __has_builtin(__builtin_bswap64)) - return __builtin_bswap64(in); -#else - return ((in << 56) & 0xff00000000000000ULL) | + return ((in << 56) & 0xff00000000000000ULL) | ((in << 40) & 0x00ff000000000000ULL) | ((in << 24) & 0x0000ff0000000000ULL) | ((in << 8) & 0x000000ff00000000ULL) | @@ -232,6 +258,17 @@ MEM_STATIC U64 MEM_swap64(U64 in) ((in >> 24) & 0x0000000000ff0000ULL) | ((in >> 40) & 0x000000000000ff00ULL) | ((in >> 56) & 0x00000000000000ffULL); +} + +MEM_STATIC U64 MEM_swap64(U64 in) +{ +#if defined(_MSC_VER) /* Visual Studio */ + return _byteswap_uint64(in); +#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \ + || (defined(__clang__) && __has_builtin(__builtin_bswap64)) + return __builtin_bswap64(in); +#else + return MEM_swap64_fallback(in); #endif } @@ -268,7 +305,7 @@ MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) MEM_STATIC U32 MEM_readLE24(const void* memPtr) { - return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16); + return (U32)MEM_readLE16(memPtr) + ((U32)(((const BYTE*)memPtr)[2]) << 16); } MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val) @@ -375,6 +412,9 @@ MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val) MEM_writeBE64(memPtr, (U64)val); } -} +/* code only tested on 32 and 64 bits systems */ +MEM_STATIC void MEM_check(void) { DEBUG_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); } + +} // namespace duckdb_zstd #endif /* MEM_H_MODULE */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/pool.h b/src/duckdb/third_party/zstd/include/zstd/common/pool.h new file mode 100644 index 000000000..e85948f05 --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd/common/pool.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef POOL_H +#define POOL_H + +#include "zstd/common/zstd_deps.h" +#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_customMem */ +#include "zstd.h" + +namespace duckdb_zstd { + +typedef struct POOL_ctx_s POOL_ctx; + +/*! POOL_create() : + * Create a thread pool with at most `numThreads` threads. + * `numThreads` must be at least 1. + * The maximum number of queued jobs before blocking is `queueSize`. + * @return : POOL_ctx pointer on success, else NULL. +*/ +POOL_ctx* POOL_create(size_t numThreads, size_t queueSize); + +POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, + ZSTD_customMem customMem); + +/*! POOL_free() : + * Free a thread pool returned by POOL_create(). + */ +void POOL_free(POOL_ctx* ctx); + + +/*! POOL_joinJobs() : + * Waits for all queued jobs to finish executing. + */ +void POOL_joinJobs(POOL_ctx* ctx); + +/*! POOL_resize() : + * Expands or shrinks pool's number of threads. + * This is more efficient than releasing + creating a new context, + * since it tries to preserve and reuse existing threads. + * `numThreads` must be at least 1. + * @return : 0 when resize was successful, + * !0 (typically 1) if there is an error. + * note : only numThreads can be resized, queueSize remains unchanged. + */ +int POOL_resize(POOL_ctx* ctx, size_t numThreads); + +/*! POOL_sizeof() : + * @return threadpool memory usage + * note : compatible with NULL (returns 0 in this case) + */ +size_t POOL_sizeof(const POOL_ctx* ctx); + +/*! POOL_function : + * The function type that can be added to a thread pool. + */ +typedef void (*POOL_function)(void*); + +/*! POOL_add() : + * Add the job `function(opaque)` to the thread pool. `ctx` must be valid. + * Possibly blocks until there is room in the queue. + * Note : The function may be executed asynchronously, + * therefore, `opaque` must live until function has been completed. + */ +void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque); + + +/*! POOL_tryAdd() : + * Add the job `function(opaque)` to thread pool _if_ a queue slot is available. + * Returns immediately even if not (does not block). + * @return : 1 if successful, 0 if not. + */ +int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque); + +} // namespace duckdb_zstd + +#endif diff --git a/src/duckdb/third_party/zstd/include/zstd/common/portability_macros.h b/src/duckdb/third_party/zstd/include/zstd/common/portability_macros.h new file mode 100644 index 000000000..e50314a78 --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd/common/portability_macros.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_PORTABILITY_MACROS_H +#define ZSTD_PORTABILITY_MACROS_H + +/** + * This header file contains macro definitions to support portability. + * This header is shared between C and ASM code, so it MUST only + * contain macro definitions. It MUST not contain any C code. + * + * This header ONLY defines macros to detect platforms/feature support. + * + */ + + +/* compat. with non-clang compilers */ +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif + +/* compat. with non-clang compilers */ +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +/* compat. with non-clang compilers */ +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +/* detects whether we are being compiled under msan */ +#ifndef ZSTD_MEMORY_SANITIZER +# if __has_feature(memory_sanitizer) +# define ZSTD_MEMORY_SANITIZER 1 +# else +# define ZSTD_MEMORY_SANITIZER 0 +# endif +#endif + +/* detects whether we are being compiled under asan */ +#ifndef ZSTD_ADDRESS_SANITIZER +# if __has_feature(address_sanitizer) +# define ZSTD_ADDRESS_SANITIZER 1 +# elif defined(__SANITIZE_ADDRESS__) +# define ZSTD_ADDRESS_SANITIZER 1 +# else +# define ZSTD_ADDRESS_SANITIZER 0 +# endif +#endif + +/* detects whether we are being compiled under dfsan */ +#ifndef ZSTD_DATAFLOW_SANITIZER +# if __has_feature(dataflow_sanitizer) +# define ZSTD_DATAFLOW_SANITIZER 1 +# else +# define ZSTD_DATAFLOW_SANITIZER 0 +# endif +#endif + +/* Mark the internal assembly functions as hidden */ +#ifdef __ELF__ +# define ZSTD_HIDE_ASM_FUNCTION(func) .hidden func +#elif defined(__APPLE__) +# define ZSTD_HIDE_ASM_FUNCTION(func) .private_extern func +#else +# define ZSTD_HIDE_ASM_FUNCTION(func) +#endif + +/* Enable runtime BMI2 dispatch based on the CPU. + * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default. + */ +#ifndef DYNAMIC_BMI2 + #if ((defined(__clang__) && __has_attribute(__target__)) \ + || (defined(__GNUC__) \ + && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \ + && (defined(__x86_64__) || defined(_M_X64)) \ + && !defined(__BMI2__) + # define DYNAMIC_BMI2 1 + #else + # define DYNAMIC_BMI2 0 + #endif +#endif + +/** + * Only enable assembly for GNUC compatible compilers, + * because other platforms may not support GAS assembly syntax. + * + * Only enable assembly for Linux / MacOS, other platforms may + * work, but they haven't been tested. This could likely be + * extended to BSD systems. + * + * Disable assembly when MSAN is enabled, because MSAN requires + * 100% of code to be instrumented to work. + */ +#if defined(__GNUC__) +# if defined(__linux__) || defined(__linux) || defined(__APPLE__) +# if ZSTD_MEMORY_SANITIZER +# define ZSTD_ASM_SUPPORTED 0 +# elif ZSTD_DATAFLOW_SANITIZER +# define ZSTD_ASM_SUPPORTED 0 +# else +# define ZSTD_ASM_SUPPORTED 1 +# endif +# else +# define ZSTD_ASM_SUPPORTED 0 +# endif +#else +# define ZSTD_ASM_SUPPORTED 0 +#endif + +/** + * Determines whether we should enable assembly for x86-64 + * with BMI2. + * + * Enable if all of the following conditions hold: + * - ASM hasn't been explicitly disabled by defining ZSTD_DISABLE_ASM + * - Assembly is supported + * - We are compiling for x86-64 and either: + * - DYNAMIC_BMI2 is enabled + * - BMI2 is supported at compile time + */ +#if !defined(ZSTD_DISABLE_ASM) && \ + ZSTD_ASM_SUPPORTED && \ + defined(__x86_64__) && \ + (DYNAMIC_BMI2 || defined(__BMI2__)) +# define ZSTD_ENABLE_ASM_X86_64_BMI2 1 +#else +# define ZSTD_ENABLE_ASM_X86_64_BMI2 0 +#endif + +/* + * For x86 ELF targets, add .note.gnu.property section for Intel CET in + * assembly sources when CET is enabled. + * + * Additionally, any function that may be called indirectly must begin + * with ZSTD_CET_ENDBRANCH. + */ +#if defined(__ELF__) && (defined(__x86_64__) || defined(__i386__)) \ + && defined(__has_include) +# if __has_include() +# include +# define ZSTD_CET_ENDBRANCH _CET_ENDBR +# endif +#endif + +#ifndef ZSTD_CET_ENDBRANCH +# define ZSTD_CET_ENDBRANCH +#endif + +#endif /* ZSTD_PORTABILITY_MACROS_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/threading.h b/src/duckdb/third_party/zstd/include/zstd/common/threading.h new file mode 100644 index 000000000..fc13da1bf --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd/common/threading.h @@ -0,0 +1,152 @@ +/** + * Copyright (c) 2016 Tino Reichardt + * All rights reserved. + * + * You can contact the author at: + * - zstdmt source repository: https://github.com/mcmilk/zstdmt + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef THREADING_H_938743 +#define THREADING_H_938743 + +#include "zstd/common/debug.h" + +#if defined(ZSTD_MULTITHREAD) && defined(_WIN32) + +/** + * Windows minimalist Pthread Wrapper + */ +#ifdef WINVER +# undef WINVER +#endif +#define WINVER 0x0600 + +#ifdef _WIN32_WINNT +# undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0600 + +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ +#include +#undef ERROR +#define ERROR(name) ZSTD_ERROR(name) + +/* mutex */ +#define ZSTD_pthread_mutex_t CRITICAL_SECTION +#define ZSTD_pthread_mutex_init(a, b) ((void)(b), InitializeCriticalSection((a)), 0) +#define ZSTD_pthread_mutex_destroy(a) DeleteCriticalSection((a)) +#define ZSTD_pthread_mutex_lock(a) EnterCriticalSection((a)) +#define ZSTD_pthread_mutex_unlock(a) LeaveCriticalSection((a)) + +/* condition variable */ +#define ZSTD_pthread_cond_t CONDITION_VARIABLE +#define ZSTD_pthread_cond_init(a, b) ((void)(b), InitializeConditionVariable((a)), 0) +#define ZSTD_pthread_cond_destroy(a) ((void)(a)) +#define ZSTD_pthread_cond_wait(a, b) SleepConditionVariableCS((a), (b), INFINITE) +#define ZSTD_pthread_cond_signal(a) WakeConditionVariable((a)) +#define ZSTD_pthread_cond_broadcast(a) WakeAllConditionVariable((a)) + +namespace duckdb_zstd { + +/* ZSTD_pthread_create() and ZSTD_pthread_join() */ +typedef HANDLE ZSTD_pthread_t; + +int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, + void* (*start_routine) (void*), void* arg); + +int ZSTD_pthread_join(ZSTD_pthread_t thread); + +} // namespace duckdb_zstd + +/** + * add here more wrappers as required + */ + + +#elif defined(ZSTD_MULTITHREAD) /* posix assumed ; need a better detection method */ +/* === POSIX Systems === */ +# include + +# if DEBUGLEVEL < 1 + +#define ZSTD_pthread_mutex_t pthread_mutex_t +#define ZSTD_pthread_mutex_init(a, b) pthread_mutex_init((a), (b)) +#define ZSTD_pthread_mutex_destroy(a) pthread_mutex_destroy((a)) +#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock((a)) +#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock((a)) + +#define ZSTD_pthread_cond_t pthread_cond_t +#define ZSTD_pthread_cond_init(a, b) pthread_cond_init((a), (b)) +#define ZSTD_pthread_cond_destroy(a) pthread_cond_destroy((a)) +#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait((a), (b)) +#define ZSTD_pthread_cond_signal(a) pthread_cond_signal((a)) +#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast((a)) + +#define ZSTD_pthread_t pthread_t +#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) +#define ZSTD_pthread_join(a) pthread_join((a),NULL) + +# else /* DEBUGLEVEL >= 1 */ + +/* Debug implementation of threading. + * In this implementation we use pointers for mutexes and condition variables. + * This way, if we forget to init/destroy them the program will crash or ASAN + * will report leaks. + */ + +namespace duckdb_zstd { + +#define ZSTD_pthread_mutex_t pthread_mutex_t* +int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr); +int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex); +#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock(*(a)) +#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock(*(a)) + +#define ZSTD_pthread_cond_t pthread_cond_t* +int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr); +int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond); +#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait(*(a), *(b)) +#define ZSTD_pthread_cond_signal(a) pthread_cond_signal(*(a)) +#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast(*(a)) + +#define ZSTD_pthread_t pthread_t +#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) +#define ZSTD_pthread_join(a) pthread_join((a),NULL) + +} // namespace duckdb_zstd + +# endif + +#else /* ZSTD_MULTITHREAD not defined */ +/* No multithreading support */ + +namespace duckdb_zstd { + +typedef int ZSTD_pthread_mutex_t; +#define ZSTD_pthread_mutex_init(a, b) ((void)(a), (void)(b), 0) +#define ZSTD_pthread_mutex_destroy(a) ((void)(a)) +#define ZSTD_pthread_mutex_lock(a) ((void)(a)) +#define ZSTD_pthread_mutex_unlock(a) ((void)(a)) + +typedef int ZSTD_pthread_cond_t; +#define ZSTD_pthread_cond_init(a, b) ((void)(a), (void)(b), 0) +#define ZSTD_pthread_cond_destroy(a) ((void)(a)) +#define ZSTD_pthread_cond_wait(a, b) ((void)(a), (void)(b)) +#define ZSTD_pthread_cond_signal(a) ((void)(a)) +#define ZSTD_pthread_cond_broadcast(a) ((void)(a)) + +/* do not use ZSTD_pthread_t */ + +} // namespace duckdb_zstd + +#endif /* ZSTD_MULTITHREAD */ +#endif /* THREADING_H_938743 */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/xxhash.h b/src/duckdb/third_party/zstd/include/zstd/common/xxhash.hpp similarity index 99% rename from src/duckdb/third_party/zstd/include/zstd/common/xxhash.h rename to src/duckdb/third_party/zstd/include/zstd/common/xxhash.hpp index a6b7990c8..1ebadc466 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/xxhash.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/xxhash.hpp @@ -232,4 +232,3 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src } #endif /* XXHASH_H_5627135585666179 */ - diff --git a/src/duckdb/third_party/zstd/include/zstd/common/xxhash_static.h b/src/duckdb/third_party/zstd/include/zstd/common/xxhash_static.hpp similarity index 100% rename from src/duckdb/third_party/zstd/include/zstd/common/xxhash_static.h rename to src/duckdb/third_party/zstd/include/zstd/common/xxhash_static.hpp diff --git a/src/duckdb/third_party/zstd/include/zstd/common/zstd_deps.h b/src/duckdb/third_party/zstd/include/zstd/common/zstd_deps.h new file mode 100644 index 000000000..0be68bbb1 --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd/common/zstd_deps.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* This file provides common libc dependencies that zstd requires. + * The purpose is to allow replacing this file with a custom implementation + * to compile zstd without libc support. + */ + +/* Need: + * NULL + * INT_MAX + * UINT_MAX + * ZSTD_memcpy() + * ZSTD_memset() + * ZSTD_memmove() + */ +#ifndef ZSTD_DEPS_COMMON +#define ZSTD_DEPS_COMMON + +#include +#include +#include + +// DuckDB: just enable everything for amalgamation +#ifdef DUCKDB_AMALGAMATION +#define ZSTD_DEPS_NEED_MALLOC +#define ZSTD_DEPS_NEED_MATH64 +#define ZSTD_DEPS_NEED_ASSERT +#define ZSTD_DEPS_NEED_IO +#define ZSTD_DEPS_NEED_STDINT +#define ZSTD_MULTITHREAD +#define FSE_STATIC_LINKING_ONLY +#endif + +#if defined(__GNUC__) && __GNUC__ >= 4 +# define ZSTD_memcpy(d,s,l) __builtin_memcpy((d),(s),(l)) +# define ZSTD_memmove(d,s,l) __builtin_memmove((d),(s),(l)) +# define ZSTD_memset(p,v,l) __builtin_memset((p),(v),(l)) +#else +# define ZSTD_memcpy(d,s,l) memcpy((d),(s),(l)) +# define ZSTD_memmove(d,s,l) memmove((d),(s),(l)) +# define ZSTD_memset(p,v,l) memset((p),(v),(l)) +#endif + +#endif /* ZSTD_DEPS_COMMON */ + +/* Need: + * ZSTD_malloc() + * ZSTD_free() + * ZSTD_calloc() + */ +#ifdef ZSTD_DEPS_NEED_MALLOC +#ifndef ZSTD_DEPS_MALLOC +#define ZSTD_DEPS_MALLOC + +#include + +#define ZSTD_malloc(s) malloc(s) +#define ZSTD_calloc(n,s) calloc((n), (s)) +#define ZSTD_free(p) free((p)) + +#endif /* ZSTD_DEPS_MALLOC */ +#endif /* ZSTD_DEPS_NEED_MALLOC */ + +/* + * Provides 64-bit math support. + * Need: + * U64 ZSTD_div64(U64 dividend, U32 divisor) + */ +#ifdef ZSTD_DEPS_NEED_MATH64 +#ifndef ZSTD_DEPS_MATH64 +#define ZSTD_DEPS_MATH64 + +#define ZSTD_div64(dividend, divisor) ((dividend) / (divisor)) + +#endif /* ZSTD_DEPS_MATH64 */ +#endif /* ZSTD_DEPS_NEED_MATH64 */ + +/* Need: + * assert() + */ +#ifdef ZSTD_DEPS_NEED_ASSERT +#ifndef ZSTD_DEPS_ASSERT +#define ZSTD_DEPS_ASSERT + +#include + +#endif /* ZSTD_DEPS_ASSERT */ +#endif /* ZSTD_DEPS_NEED_ASSERT */ + +/* Need: + * ZSTD_DEBUG_PRINT() + */ +#ifdef ZSTD_DEPS_NEED_IO +#ifndef ZSTD_DEPS_IO +#define ZSTD_DEPS_IO + +#include +#define ZSTD_DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__) + +#endif /* ZSTD_DEPS_IO */ +#endif /* ZSTD_DEPS_NEED_IO */ + +/* Only requested when is known to be present. + * Need: + * intptr_t + */ +#ifdef ZSTD_DEPS_NEED_STDINT +#ifndef ZSTD_DEPS_STDINT +#define ZSTD_DEPS_STDINT + +#include + +#endif /* ZSTD_DEPS_STDINT */ +#endif /* ZSTD_DEPS_NEED_STDINT */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/zstd_internal.h b/src/duckdb/third_party/zstd/include/zstd/common/zstd_internal.h index 93cb45856..3e800e3dc 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/zstd_internal.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/zstd_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -19,29 +19,34 @@ /*-************************************* * Dependencies ***************************************/ -#ifdef __aarch64__ -#include -#endif #include "zstd/common/compiler.h" +#include "zstd/common/cpu.h" #include "zstd/common/mem.h" #include "zstd/common/debug.h" /* assert, DEBUGLOG, RAWLOG, g_debuglevel */ #include "zstd/common/error_private.h" +#define ZSTD_STATIC_LINKING_ONLY #include "zstd.h" -#include "zstd_static.h" +#define FSE_STATIC_LINKING_ONLY #include "zstd/common/fse.h" -#include "zstd/common/fse_static.h" #include "zstd/common/huf.h" -#include "zstd/common/huf_static.h" -#include "zstd/common/xxhash.h" /* XXH_reset, update, digest */ -#include "zstd/common/xxhash_static.h" /* XXH_reset, update, digest */ +#ifndef XXH_STATIC_LINKING_ONLY +# define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */ +#endif +#include "zstd/common/xxhash.hpp" /* XXH_reset, update, digest */ +#include "zstd/common/xxhash_static.hpp" +#ifndef ZSTD_NO_TRACE +# include "zstd/common/zstd_trace.h" +#else +# define ZSTD_TRACE 0 +#endif namespace duckdb_zstd { /* ---- static assert (debug) --- */ #define ZSTD_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) #define ZSTD_isError ERR_isError /* for inlining */ -// #define FSE_isError ERR_isError -// #define HUF_isError ERR_isError +#define FSE_isError ERR_isError +#define HUF_isError ERR_isError /*-************************************* @@ -51,81 +56,7 @@ namespace duckdb_zstd { #undef MAX #define MIN(a,b) ((a)<(b) ? (a) : (b)) #define MAX(a,b) ((a)>(b) ? (a) : (b)) - -/** - * Ignore: this is an internal helper. - * - * This is a helper function to help force C99-correctness during compilation. - * Under strict compilation modes, variadic macro arguments can't be empty. - * However, variadic function arguments can be. Using a function therefore lets - * us statically check that at least one (string) argument was passed, - * independent of the compilation flags. - */ -static INLINE_KEYWORD UNUSED_ATTR -void _force_has_format_string(const char *format, ...) { - (void)format; -} - -/** - * Ignore: this is an internal helper. - * - * We want to force this function invocation to be syntactically correct, but - * we don't want to force runtime evaluation of its arguments. - */ -#define _FORCE_HAS_FORMAT_STRING(...) \ - if (0) { \ - _force_has_format_string(__VA_ARGS__); \ - } - -/** - * Return the specified error if the condition evaluates to true. - * - * In debug modes, prints additional information. - * In order to do that (particularly, printing the conditional that failed), - * this can't just wrap RETURN_ERROR(). - */ -#define RETURN_ERROR_IF(cond, err, ...) \ - if (cond) { \ - RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \ - __FILE__, __LINE__, ZSTD_QUOTE(cond), ZSTD_QUOTE(ERROR(err))); \ - _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ - RAWLOG(3, ": " __VA_ARGS__); \ - RAWLOG(3, "\n"); \ - return ERROR(err); \ - } - -/** - * Unconditionally return the specified error. - * - * In debug modes, prints additional information. - */ -#define RETURN_ERROR(err, ...) \ - do { \ - RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \ - __FILE__, __LINE__, ZSTD_QUOTE(ERROR(err))); \ - _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ - RAWLOG(3, ": " __VA_ARGS__); \ - RAWLOG(3, "\n"); \ - return ERROR(err); \ - } while(0); - -/** - * If the provided expression evaluates to an error code, returns that error code. - * - * In debug modes, prints additional information. - */ -#define FORWARD_IF_ERROR(err, ...) \ - do { \ - size_t const err_code = (err); \ - if (ERR_isError(err_code)) { \ - RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \ - __FILE__, __LINE__, ZSTD_QUOTE(err), ERR_getErrorName(err_code)); \ - _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ - RAWLOG(3, ": " __VA_ARGS__); \ - RAWLOG(3, "\n"); \ - return err_code; \ - } \ - } while(0); +#define BOUNDED(min,val,max) (MAX(min,MIN(val,max))) /*-************************************* @@ -134,7 +65,7 @@ void _force_has_format_string(const char *format, ...) { #define ZSTD_OPT_NUM (1<<12) #define ZSTD_REP_NUM 3 /* number of repcodes */ -#define ZSTD_REP_MOVE (ZSTD_REP_NUM-1) +static UNUSED_ATTR const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; #define KB *(1 <<10) #define MB *(1 <<20) @@ -148,19 +79,21 @@ void _force_has_format_string(const char *format, ...) { #define BIT0 1 #define ZSTD_WINDOWLOG_ABSOLUTEMIN 10 +static UNUSED_ATTR const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 }; +static UNUSED_ATTR const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 }; #define ZSTD_FRAMEIDSIZE 4 /* magic number size */ #define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */ - +static UNUSED_ATTR const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e; #define ZSTD_FRAMECHECKSUMSIZE 4 #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ -#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ +#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */) /* for a non-null block */ +#define MIN_LITERALS_FOR_4_STREAMS 6 -#define HufLog 12 typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e; #define LONGNBSEQ 0x7F00 @@ -168,6 +101,7 @@ typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingTy #define MINMATCH 3 #define Litbits 8 +#define LitHufLog 11 #define MaxLit ((1<= 8 || (ovtype == ZSTD_no_overlap && diff <= -WILDCOPY_VECLEN)); - if (ovtype == ZSTD_overlap_src_before_dst && diff < WILDCOPY_VECLEN) { /* Handle short offset copies. */ do { - COPY8(op, ip) + COPY8(op, ip); } while (op < oend); } else { assert(diff >= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN); @@ -260,20 +236,15 @@ void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e * one COPY16() in the first call. Then, do two calls per loop since * at that point it is more likely to have a high trip count. */ -#ifndef __aarch64__ - do { - COPY16(op, ip); - } - while (op < oend); -#else - COPY16(op, ip); - if (op >= oend) return; + ZSTD_copy16(op, ip); + if (16 >= length) return; + op += 16; + ip += 16; do { COPY16(op, ip); COPY16(op, ip); } while (op < oend); -#endif } } @@ -281,7 +252,7 @@ MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, { size_t const length = MIN(dstCapacity, srcSize); if (length > 0) { - memcpy(dst, src, length); + ZSTD_memcpy(dst, src, length); } return length; } @@ -296,28 +267,46 @@ MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, * In which case, resize it down to free some memory */ #define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 +/* Controls whether the input/output buffer is buffered or stable. */ +typedef enum { + ZSTD_bm_buffered = 0, /* Buffer the input/output */ + ZSTD_bm_stable = 1 /* ZSTD_inBuffer/ZSTD_outBuffer is stable */ +} ZSTD_bufferMode_e; + /*-******************************************* * Private declarations *********************************************/ typedef struct seqDef_s { - U32 offset; + U32 offBase; /* offBase == Offset + ZSTD_REP_NUM, or repcode 1,2,3 */ U16 litLength; - U16 matchLength; + U16 mlBase; /* mlBase == matchLength - MINMATCH */ } seqDef; +/* Controls whether seqStore has a single "long" litLength or matchLength. See seqStore_t. */ +typedef enum { + ZSTD_llt_none = 0, /* no longLengthType */ + ZSTD_llt_literalLength = 1, /* represents a long literal */ + ZSTD_llt_matchLength = 2 /* represents a long match */ +} ZSTD_longLengthType_e; + typedef struct { seqDef* sequencesStart; - seqDef* sequences; - BYTE* litStart; - BYTE* lit; - BYTE* llCode; - BYTE* mlCode; - BYTE* ofCode; + seqDef* sequences; /* ptr to end of sequences */ + BYTE* litStart; + BYTE* lit; /* ptr to end of literals */ + BYTE* llCode; + BYTE* mlCode; + BYTE* ofCode; size_t maxNbSeq; size_t maxNbLit; - U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */ - U32 longLengthPos; + + /* longLengthPos and longLengthType to allow us to represent either a single litLength or matchLength + * in the seqStore that has a value larger than U16 (if it exists). To do so, we increment + * the existing value of the litLength or matchLength by 0x10000. + */ + ZSTD_longLengthType_e longLengthType; + U32 longLengthPos; /* Index of the sequence to apply long length modification to */ } seqStore_t; typedef struct { @@ -327,19 +316,19 @@ typedef struct { /** * Returns the ZSTD_sequenceLength for the given sequences. It handles the decoding of long sequences - * indicated by longLengthPos and longLengthID, and adds MINMATCH back to matchLength. + * indicated by longLengthPos and longLengthType, and adds MINMATCH back to matchLength. */ MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore, seqDef const* seq) { ZSTD_sequenceLength seqLen; seqLen.litLength = seq->litLength; - seqLen.matchLength = seq->matchLength + MINMATCH; + seqLen.matchLength = seq->mlBase + MINMATCH; if (seqStore->longLengthPos == (U32)(seq - seqStore->sequencesStart)) { - if (seqStore->longLengthID == 1) { - seqLen.litLength += 0xFFFF; + if (seqStore->longLengthType == ZSTD_llt_literalLength) { + seqLen.litLength += 0x10000; } - if (seqStore->longLengthID == 2) { - seqLen.matchLength += 0xFFFF; + if (seqStore->longLengthType == ZSTD_llt_matchLength) { + seqLen.matchLength += 0x10000; } } return seqLen; @@ -352,42 +341,13 @@ MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore * `decompressedBound != ZSTD_CONTENTSIZE_ERROR` */ typedef struct { + size_t nbBlocks; size_t compressedSize; unsigned long long decompressedBound; } ZSTD_frameSizeInfo; /* decompress & legacy */ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBuilder */ -void ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */ - -/* custom memory allocation functions */ -void* ZSTD_malloc(size_t size, ZSTD_customMem customMem); -void* ZSTD_calloc(size_t size, ZSTD_customMem customMem); -void ZSTD_free(void* ptr, ZSTD_customMem customMem); - - -MEM_STATIC U32 ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */ -{ - assert(val != 0); - { -# if defined(_MSC_VER) /* Visual */ - unsigned long r=0; - return _BitScanReverse(&r, val) ? (unsigned)r : 0; -# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */ - return __builtin_clz (val) ^ 31; -# elif defined(__ICCARM__) /* IAR Intrinsic */ - return 31 - __CLZ(val); -# else /* Software version */ - static const U32 DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; - U32 v = val; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - return DeBruijnClz[(v * 0x07C4ACDDU) >> 27]; -# endif - } -} +int ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */ /* ZSTD_invalidateRepCodes() : @@ -405,16 +365,25 @@ typedef struct { /*! ZSTD_getcBlockSize() : * Provides the size of compressed block from block header `src` */ -/* Used by: decompress, fullbench (does not get its definition from here) */ +/* Used by: decompress, fullbench */ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr); /*! ZSTD_decodeSeqHeaders() : * decode sequence header from src */ -/* Used by: decompress, fullbench (does not get its definition from here) */ +/* Used by: zstd_decompress_block, fullbench */ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, const void* src, size_t srcSize); +/** + * @returns true iff the CPU supports dynamic BMI2 dispatch. + */ +MEM_STATIC int ZSTD_cpuSupportsBmi2(void) +{ + ZSTD_cpuid_t cpuid = ZSTD_cpuid(); + return ZSTD_cpuid_bmi1(cpuid) && ZSTD_cpuid_bmi2(cpuid); } +} // namespace duckdb_zstd + #endif /* ZSTD_CCOMMON_H_MODULE */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/zstd_trace.h b/src/duckdb/third_party/zstd/include/zstd/common/zstd_trace.h new file mode 100644 index 000000000..045ce9067 --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd/common/zstd_trace.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_TRACE_H +#define ZSTD_TRACE_H + +#include + +namespace duckdb_zstd { + +/* weak symbol support + * For now, enable conservatively: + * - Only GNUC + * - Only ELF + * - Only x86-64, i386 and aarch64 + * Also, explicitly disable on platforms known not to work so they aren't + * forgotten in the future. + */ +#if !defined(ZSTD_HAVE_WEAK_SYMBOLS) && \ + defined(__GNUC__) && defined(__ELF__) && \ + (defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86) || defined(__aarch64__)) && \ + !defined(__APPLE__) && !defined(_WIN32) && !defined(__MINGW32__) && \ + !defined(__CYGWIN__) && !defined(_AIX) +# define ZSTD_HAVE_WEAK_SYMBOLS 1 +#else +# define ZSTD_HAVE_WEAK_SYMBOLS 0 +#endif +#if ZSTD_HAVE_WEAK_SYMBOLS +# define ZSTD_WEAK_ATTR __attribute__((__weak__)) +#else +# define ZSTD_WEAK_ATTR +#endif + +/* Only enable tracing when weak symbols are available. */ +#ifndef ZSTD_TRACE +# define ZSTD_TRACE ZSTD_HAVE_WEAK_SYMBOLS +#endif + +#if ZSTD_TRACE + +struct ZSTD_CCtx_s; +struct ZSTD_DCtx_s; +struct ZSTD_CCtx_params_s; + +typedef struct { + /** + * ZSTD_VERSION_NUMBER + * + * This is guaranteed to be the first member of ZSTD_trace. + * Otherwise, this struct is not stable between versions. If + * the version number does not match your expectation, you + * should not interpret the rest of the struct. + */ + unsigned version; + /** + * Non-zero if streaming (de)compression is used. + */ + unsigned streaming; + /** + * The dictionary ID. + */ + unsigned dictionaryID; + /** + * Is the dictionary cold? + * Only set on decompression. + */ + unsigned dictionaryIsCold; + /** + * The dictionary size or zero if no dictionary. + */ + size_t dictionarySize; + /** + * The uncompressed size of the data. + */ + size_t uncompressedSize; + /** + * The compressed size of the data. + */ + size_t compressedSize; + /** + * The fully resolved CCtx parameters (NULL on decompression). + */ + struct ZSTD_CCtx_params_s const* params; + /** + * The ZSTD_CCtx pointer (NULL on decompression). + */ + struct ZSTD_CCtx_s const* cctx; + /** + * The ZSTD_DCtx pointer (NULL on compression). + */ + struct ZSTD_DCtx_s const* dctx; +} ZSTD_Trace; + +/** + * A tracing context. It must be 0 when tracing is disabled. + * Otherwise, any non-zero value returned by a tracing begin() + * function is presented to any subsequent calls to end(). + * + * Any non-zero value is treated as tracing is enabled and not + * interpreted by the library. + * + * Two possible uses are: + * * A timestamp for when the begin() function was called. + * * A unique key identifying the (de)compression, like the + * address of the [dc]ctx pointer if you need to track + * more information than just a timestamp. + */ +typedef unsigned long long ZSTD_TraceCtx; + +/** + * Trace the beginning of a compression call. + * @param cctx The dctx pointer for the compression. + * It can be used as a key to map begin() to end(). + * @returns Non-zero if tracing is enabled. The return value is + * passed to ZSTD_trace_compress_end(). + */ +ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_compress_begin( + struct ZSTD_CCtx_s const* cctx); + +/** + * Trace the end of a compression call. + * @param ctx The return value of ZSTD_trace_compress_begin(). + * @param trace The zstd tracing info. + */ +ZSTD_WEAK_ATTR void ZSTD_trace_compress_end( + ZSTD_TraceCtx ctx, + ZSTD_Trace const* trace); + +/** + * Trace the beginning of a decompression call. + * @param dctx The dctx pointer for the decompression. + * It can be used as a key to map begin() to end(). + * @returns Non-zero if tracing is enabled. The return value is + * passed to ZSTD_trace_compress_end(). + */ +ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_decompress_begin( + struct ZSTD_DCtx_s const* dctx); + +/** + * Trace the end of a decompression call. + * @param ctx The return value of ZSTD_trace_decompress_begin(). + * @param trace The zstd tracing info. + */ +ZSTD_WEAK_ATTR void ZSTD_trace_decompress_end( + ZSTD_TraceCtx ctx, + ZSTD_Trace const* trace); + +#endif /* ZSTD_TRACE */ + +} // namespace duckdb_zstd + +#endif /* ZSTD_TRACE_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/clevels.h b/src/duckdb/third_party/zstd/include/zstd/compress/clevels.h new file mode 100644 index 000000000..be9424b13 --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd/compress/clevels.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_CLEVELS_H +#define ZSTD_CLEVELS_H + +#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressionParameters */ +#include "zstd.h" + +namespace duckdb_zstd { + +/*-===== Pre-defined compression levels =====-*/ + +#define ZSTD_MAX_CLEVEL 22 + +#ifdef __GNUC__ +__attribute__((__unused__)) +#endif + +static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { +{ /* "default" - for any srcSize > 256 KB */ + /* W, C, H, S, L, TL, strat */ + { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */ + { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */ + { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */ + { 21, 16, 17, 1, 5, 0, ZSTD_dfast }, /* level 3 */ + { 21, 18, 18, 1, 5, 0, ZSTD_dfast }, /* level 4 */ + { 21, 18, 19, 3, 5, 2, ZSTD_greedy }, /* level 5 */ + { 21, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6 */ + { 21, 19, 20, 4, 5, 8, ZSTD_lazy }, /* level 7 */ + { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 8 */ + { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */ + { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 10 */ + { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 11 */ + { 22, 22, 23, 6, 5, 32, ZSTD_lazy2 }, /* level 12 */ + { 22, 22, 22, 4, 5, 32, ZSTD_btlazy2 }, /* level 13 */ + { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */ + { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */ + { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */ + { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */ + { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */ + { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */ + { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */ + { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */ + { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */ +}, +{ /* for srcSize <= 256 KB */ + /* W, C, H, S, L, T, strat */ + { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ + { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */ + { 18, 14, 14, 1, 5, 0, ZSTD_dfast }, /* level 2 */ + { 18, 16, 16, 1, 4, 0, ZSTD_dfast }, /* level 3 */ + { 18, 16, 17, 3, 5, 2, ZSTD_greedy }, /* level 4.*/ + { 18, 17, 18, 5, 5, 2, ZSTD_greedy }, /* level 5.*/ + { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/ + { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */ + { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ + { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ + { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ + { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/ + { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/ + { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */ + { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ + { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/ + { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/ + { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/ + { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/ + { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ + { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/ + { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/ + { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/ +}, +{ /* for srcSize <= 128 KB */ + /* W, C, H, S, L, T, strat */ + { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ + { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */ + { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */ + { 17, 15, 16, 2, 5, 0, ZSTD_dfast }, /* level 3 */ + { 17, 17, 17, 2, 4, 0, ZSTD_dfast }, /* level 4 */ + { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */ + { 17, 16, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ + { 17, 16, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */ + { 17, 16, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ + { 17, 16, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ + { 17, 16, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ + { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */ + { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */ + { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/ + { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ + { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/ + { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/ + { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/ + { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/ + { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/ + { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/ + { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ + { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/ +}, +{ /* for srcSize <= 16 KB */ + /* W, C, H, S, L, T, strat */ + { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ + { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */ + { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */ + { 14, 14, 15, 2, 4, 0, ZSTD_dfast }, /* level 3 */ + { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */ + { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/ + { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */ + { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */ + { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/ + { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/ + { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/ + { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/ + { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/ + { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/ + { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/ + { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/ + { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/ + { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/ + { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/ + { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ + { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/ + { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ + { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/ +}, +}; + +} // namespace duckdb_zstd + +#endif /* ZSTD_CLEVELS_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/hist.h b/src/duckdb/third_party/zstd/include/zstd/compress/hist.h index 41bbbbeab..083af82c1 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/hist.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/hist.h @@ -1,7 +1,7 @@ /* ****************************************************************** * hist : Histogram functions * part of Finite State Entropy project - * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * You can contact the author at : * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -14,10 +14,10 @@ ****************************************************************** */ /* --- dependencies --- */ -#include /* size_t */ - +#include "zstd/common/zstd_deps.h" /* size_t */ namespace duckdb_zstd { + /* --- simple histogram functions --- */ /*! HIST_count(): @@ -75,4 +75,4 @@ size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize); -} +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_internal.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_internal.h index 5e8c6e099..1f55ab1bc 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_internal.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -20,9 +20,12 @@ ***************************************/ #include "zstd/common/zstd_internal.h" #include "zstd/compress/zstd_cwksp.h" -// #ifdef ZSTD_MULTITHREAD -// # include "zstdmt_compress.h" -// #endif +#ifdef ZSTD_MULTITHREAD +# include "zstd/compress/zstdmt_compress.h" +#endif +#include "zstd/common/bits.h" /* ZSTD_highbit32, ZSTD_NbCommonBytes */ + +namespace duckdb_zstd { /*-************************************* * Constants @@ -34,11 +37,10 @@ It's not a big deal though : candidate will just be sorted again. Additionally, candidate position 1 will be lost. But candidate 1 cannot hide a large tree of candidates, so it's a minimal loss. - The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be mishandled after table re-use with a different strategy. + The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be mishandled after table reuse with a different strategy. This constant is required by ZSTD_compressBlock_btlazy2() and ZSTD_reduceTable_internal() */ -namespace duckdb_zstd { /*-************************************* * Context memory management ***************************************/ @@ -60,7 +62,7 @@ typedef struct { } ZSTD_localDict; typedef struct { - U32 CTable[HUF_CTABLE_SIZE_U32(255)]; + HUF_CElt CTable[HUF_CTABLE_SIZE_ST(255)]; HUF_repeat repeatMode; } ZSTD_hufCTables_t; @@ -78,29 +80,101 @@ typedef struct { ZSTD_fseCTables_t fse; } ZSTD_entropyCTables_t; +/*********************************************** +* Entropy buffer statistics structs and funcs * +***********************************************/ +/** ZSTD_hufCTablesMetadata_t : + * Stores Literals Block Type for a super-block in hType, and + * huffman tree description in hufDesBuffer. + * hufDesSize refers to the size of huffman tree description in bytes. + * This metadata is populated in ZSTD_buildBlockEntropyStats_literals() */ +typedef struct { + symbolEncodingType_e hType; + BYTE hufDesBuffer[ZSTD_MAX_HUF_HEADER_SIZE]; + size_t hufDesSize; +} ZSTD_hufCTablesMetadata_t; + +/** ZSTD_fseCTablesMetadata_t : + * Stores symbol compression modes for a super-block in {ll, ol, ml}Type, and + * fse tables in fseTablesBuffer. + * fseTablesSize refers to the size of fse tables in bytes. + * This metadata is populated in ZSTD_buildBlockEntropyStats_sequences() */ typedef struct { - U32 off; - U32 len; + symbolEncodingType_e llType; + symbolEncodingType_e ofType; + symbolEncodingType_e mlType; + BYTE fseTablesBuffer[ZSTD_MAX_FSE_HEADERS_SIZE]; + size_t fseTablesSize; + size_t lastCountSize; /* This is to account for bug in 1.3.4. More detail in ZSTD_entropyCompressSeqStore_internal() */ +} ZSTD_fseCTablesMetadata_t; + +typedef struct { + ZSTD_hufCTablesMetadata_t hufMetadata; + ZSTD_fseCTablesMetadata_t fseMetadata; +} ZSTD_entropyCTablesMetadata_t; + +/** ZSTD_buildBlockEntropyStats() : + * Builds entropy for the block. + * @return : 0 on success or error code */ +size_t ZSTD_buildBlockEntropyStats( + const seqStore_t* seqStorePtr, + const ZSTD_entropyCTables_t* prevEntropy, + ZSTD_entropyCTables_t* nextEntropy, + const ZSTD_CCtx_params* cctxParams, + ZSTD_entropyCTablesMetadata_t* entropyMetadata, + void* workspace, size_t wkspSize); + +/********************************* +* Compression internals structs * +*********************************/ + +typedef struct { + U32 off; /* Offset sumtype code for the match, using ZSTD_storeSeq() format */ + U32 len; /* Raw length of match */ } ZSTD_match_t; typedef struct { - int price; - U32 off; - U32 mlen; - U32 litlen; - U32 rep[ZSTD_REP_NUM]; + U32 offset; /* Offset of sequence */ + U32 litLength; /* Length of literals prior to match */ + U32 matchLength; /* Raw length of match */ +} rawSeq; + +typedef struct { + rawSeq* seq; /* The start of the sequences */ + size_t pos; /* The index in seq where reading stopped. pos <= size. */ + size_t posInSequence; /* The position within the sequence at seq[pos] where reading + stopped. posInSequence <= seq[pos].litLength + seq[pos].matchLength */ + size_t size; /* The number of sequences. <= capacity. */ + size_t capacity; /* The capacity starting from `seq` pointer */ +} rawSeqStore_t; + +typedef struct { + U32 idx; /* Index in array of ZSTD_Sequence */ + U32 posInSequence; /* Position within sequence at idx */ + size_t posInSrc; /* Number of bytes given by sequences provided so far */ +} ZSTD_sequencePosition; + +UNUSED_ATTR static const rawSeqStore_t kNullRawSeqStore = {NULL, 0, 0, 0, 0}; + +typedef struct { + int price; /* price from beginning of segment to this position */ + U32 off; /* offset of previous match */ + U32 mlen; /* length of previous match */ + U32 litlen; /* nb of literals since previous match */ + U32 rep[ZSTD_REP_NUM]; /* offset history after previous match */ } ZSTD_optimal_t; typedef enum { zop_dynamic=0, zop_predef } ZSTD_OptPrice_e; +#define ZSTD_OPT_SIZE (ZSTD_OPT_NUM+3) typedef struct { /* All tables are allocated inside cctx->workspace by ZSTD_resetCCtx_internal() */ unsigned* litFreq; /* table of literals statistics, of size 256 */ unsigned* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */ unsigned* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */ unsigned* offCodeFreq; /* table of offCode statistics, of size (MaxOff+1) */ - ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_NUM+1 */ - ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */ + ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_SIZE */ + ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_SIZE */ U32 litSum; /* nb of literals */ U32 litLengthSum; /* nb of litLength codes */ @@ -112,7 +186,7 @@ typedef struct { U32 offCodeSumBasePrice; /* to compare to log2(offreq) */ ZSTD_OptPrice_e priceType; /* prices can be determined dynamically, or follow a pre-defined cost structure */ const ZSTD_entropyCTables_t* symbolCosts; /* pre-calculated dictionary statistics */ - ZSTD_literalCompressionMode_e literalCompressionMode; + ZSTD_paramSwitch_e literalCompressionMode; } optState_t; typedef struct { @@ -121,14 +195,23 @@ typedef struct { } ZSTD_compressedBlockState_t; typedef struct { - BYTE const* nextSrc; /* next block here to continue on current prefix */ - BYTE const* base; /* All regular indexes relative to this position */ - BYTE const* dictBase; /* extDict indexes relative to this position */ - U32 dictLimit; /* below that point, need extDict */ - U32 lowLimit; /* below that point, no more valid data */ + BYTE const* nextSrc; /* next block here to continue on current prefix */ + BYTE const* base; /* All regular indexes relative to this position */ + BYTE const* dictBase; /* extDict indexes relative to this position */ + U32 dictLimit; /* below that point, need extDict */ + U32 lowLimit; /* below that point, no more valid data */ + U32 nbOverflowCorrections; /* Number of times overflow correction has run since + * ZSTD_window_init(). Useful for debugging coredumps + * and for ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY. + */ } ZSTD_window_t; +#define ZSTD_WINDOW_START_INDEX 2 + typedef struct ZSTD_matchState_t ZSTD_matchState_t; + +#define ZSTD_ROW_HASH_CACHE_SIZE 8 /* Size of prefetching hash cache for row-based matchfinder */ + struct ZSTD_matchState_t { ZSTD_window_t window; /* State for window round buffer management */ U32 loadedDictEnd; /* index of end of dictionary, within context's referential. @@ -140,12 +223,38 @@ struct ZSTD_matchState_t { */ U32 nextToUpdate; /* index from which to continue table update */ U32 hashLog3; /* dispatch table for matches of len==3 : larger == faster, more memory */ + + U32 rowHashLog; /* For row-based matchfinder: Hashlog based on nb of rows in the hashTable.*/ + BYTE* tagTable; /* For row-based matchFinder: A row-based table containing the hashes and head index. */ + U32 hashCache[ZSTD_ROW_HASH_CACHE_SIZE]; /* For row-based matchFinder: a cache of hashes to improve speed */ + U64 hashSalt; /* For row-based matchFinder: salts the hash for reuse of tag table */ + U32 hashSaltEntropy; /* For row-based matchFinder: collects entropy for salt generation */ + U32* hashTable; U32* hashTable3; U32* chainTable; + + U32 forceNonContiguous; /* Non-zero if we should force non-contiguous load for the next window update. */ + + int dedicatedDictSearch; /* Indicates whether this matchState is using the + * dedicated dictionary search structure. + */ optState_t opt; /* optimal parser state */ const ZSTD_matchState_t* dictMatchState; ZSTD_compressionParameters cParams; + const rawSeqStore_t* ldmSeqStore; + + /* Controls prefetching in some dictMatchState matchfinders. + * This behavior is controlled from the cctx ms. + * This parameter has no effect in the cdict ms. */ + int prefetchCDictTables; + + /* When == 0, lazy match finders insert every position. + * When != 0, lazy match finders only insert positions they search. + * This allows them to skip much faster over incompressible data, + * at a small cost to compression ratio. + */ + int lazySkipping; }; typedef struct { @@ -159,17 +268,26 @@ typedef struct { U32 checksum; } ldmEntry_t; +typedef struct { + BYTE const* split; + U32 hash; + U32 checksum; + ldmEntry_t* bucket; +} ldmMatchCandidate_t; + +#define LDM_BATCH_SIZE 64 + typedef struct { ZSTD_window_t window; /* State for the window round buffer management */ ldmEntry_t* hashTable; U32 loadedDictEnd; BYTE* bucketOffsets; /* Next position in bucket to insert entry */ - U64 hashPower; /* Used to compute the rolling hash. - * Depends on ldmParams.minMatchLength */ + size_t splitIndices[LDM_BATCH_SIZE]; + ldmMatchCandidate_t matchCandidates[LDM_BATCH_SIZE]; } ldmState_t; typedef struct { - U32 enableLdm; /* 1 if enable long distance matching */ + ZSTD_paramSwitch_e enableLdm; /* ZSTD_ps_enable to enable LDM. ZSTD_ps_auto by default */ U32 hashLog; /* Log size of hashTable */ U32 bucketSizeLog; /* Log bucket size for collision resolution, at most 8 */ U32 minMatchLength; /* Minimum match length */ @@ -177,19 +295,6 @@ typedef struct { U32 windowLog; /* Window log for the LDM */ } ldmParams_t; -typedef struct { - U32 offset; - U32 litLength; - U32 matchLength; -} rawSeq; - -typedef struct { - rawSeq* seq; /* The start of the sequences */ - size_t pos; /* The position where reading stopped. <= size. */ - size_t size; /* The number of sequences. <= capacity. */ - size_t capacity; /* The capacity starting from `seq` pointer */ -} rawSeqStore_t; - typedef struct { int collectSequences; ZSTD_Sequence* seqStart; @@ -213,7 +318,7 @@ struct ZSTD_CCtx_params_s { * There is no guarantee that hint is close to actual source size */ ZSTD_dictAttachPref_e attachDictPref; - ZSTD_literalCompressionMode_e literalCompressionMode; + ZSTD_paramSwitch_e literalCompressionMode; /* Multithreading: used to pass parameters to mtctx */ int nbWorkers; @@ -224,17 +329,87 @@ struct ZSTD_CCtx_params_s { /* Long distance matching parameters */ ldmParams_t ldmParams; + /* Dedicated dict search algorithm trigger */ + int enableDedicatedDictSearch; + + /* Input/output buffer modes */ + ZSTD_bufferMode_e inBufferMode; + ZSTD_bufferMode_e outBufferMode; + + /* Sequence compression API */ + ZSTD_sequenceFormat_e blockDelimiters; + int validateSequences; + + /* Block splitting */ + ZSTD_paramSwitch_e useBlockSplitter; + + /* Param for deciding whether to use row-based matchfinder */ + ZSTD_paramSwitch_e useRowMatchFinder; + + /* Always load a dictionary in ext-dict mode (not prefix mode)? */ + int deterministicRefPrefix; + /* Internal use, for createCCtxParams() and freeCCtxParams() only */ ZSTD_customMem customMem; + + /* Controls prefetching in some dictMatchState matchfinders */ + ZSTD_paramSwitch_e prefetchCDictTables; + + /* Controls whether zstd will fall back to an internal matchfinder + * if the external matchfinder returns an error code. */ + int enableMatchFinderFallback; + + /* Parameters for the external sequence producer API. + * Users set these parameters through ZSTD_registerSequenceProducer(). + * It is not possible to set these parameters individually through the public API. */ + void* extSeqProdState; + ZSTD_sequenceProducer_F extSeqProdFunc; + + /* Adjust the max block size*/ + size_t maxBlockSize; + + /* Controls repcode search in external sequence parsing */ + ZSTD_paramSwitch_e searchForExternalRepcodes; }; /* typedef'd to ZSTD_CCtx_params within "zstd.h" */ +#define COMPRESS_SEQUENCES_WORKSPACE_SIZE (sizeof(unsigned) * (MaxSeq + 2)) +#define ENTROPY_WORKSPACE_SIZE (HUF_WORKSPACE_SIZE + COMPRESS_SEQUENCES_WORKSPACE_SIZE) + +/** + * Indicates whether this compression proceeds directly from user-provided + * source buffer to user-provided destination buffer (ZSTDb_not_buffered), or + * whether the context needs to buffer the input/output (ZSTDb_buffered). + */ +typedef enum { + ZSTDb_not_buffered, + ZSTDb_buffered +} ZSTD_buffered_policy_e; + +/** + * Struct that contains all elements of block splitter that should be allocated + * in a wksp. + */ +#define ZSTD_MAX_NB_BLOCK_SPLITS 196 +typedef struct { + seqStore_t fullSeqStoreChunk; + seqStore_t firstHalfSeqStore; + seqStore_t secondHalfSeqStore; + seqStore_t currSeqStore; + seqStore_t nextSeqStore; + + U32 partitions[ZSTD_MAX_NB_BLOCK_SPLITS]; + ZSTD_entropyCTablesMetadata_t entropyMetadata; +} ZSTD_blockSplitCtx; + struct ZSTD_CCtx_s { ZSTD_compressionStage_e stage; int cParamsChanged; /* == 1 if cParams(except wlog) or compression level are changed in requestedParams. Triggers transmission of new params to ZSTDMT (if available) then reset to 0. */ int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */ ZSTD_CCtx_params requestedParams; ZSTD_CCtx_params appliedParams; + ZSTD_CCtx_params simpleApiParams; /* Param storage used by the simple API - not sticky. Must only be used in top-level simple API functions for storage. */ U32 dictID; + size_t dictContentSize; ZSTD_cwksp workspace; /* manages buffer for dynamic allocations */ size_t blockSize; @@ -243,6 +418,7 @@ struct ZSTD_CCtx_s { unsigned long long producedCSize; XXH64_state_t xxhState; ZSTD_customMem customMem; + ZSTD_threadPool* pool; size_t staticSize; SeqCollector seqCollector; int isFirstBlock; @@ -254,7 +430,10 @@ struct ZSTD_CCtx_s { size_t maxNbLdmSequences; rawSeqStore_t externSeqStore; /* Mutable reference to external sequences */ ZSTD_blockState_t blockState; - U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */ + U32* entropyWorkspace; /* entropy workspace of ENTROPY_WORKSPACE_SIZE bytes */ + + /* Whether we are streaming or not */ + ZSTD_buffered_policy_e bufferedPolicy; /* streaming */ char* inBuff; @@ -269,6 +448,11 @@ struct ZSTD_CCtx_s { ZSTD_cStreamStage streamStage; U32 frameEnded; + /* Stable in/out buffer verification */ + ZSTD_inBuffer expectedInBuffer; + size_t stableIn_notConsumed; /* nb bytes within stable input buffer that are said to be consumed but are not */ + size_t expectedOutBufferSize; + /* Dictionary */ ZSTD_localDict localDict; const ZSTD_CDict* cdict; @@ -278,17 +462,54 @@ struct ZSTD_CCtx_s { #ifdef ZSTD_MULTITHREAD ZSTDMT_CCtx* mtctx; #endif -}; -typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e; + /* Tracing */ +#if ZSTD_TRACE + ZSTD_TraceCtx traceCtx; +#endif -typedef enum { ZSTD_noDict = 0, ZSTD_extDict = 1, ZSTD_dictMatchState = 2 } ZSTD_dictMode_e; + /* Workspace for block splitter */ + ZSTD_blockSplitCtx blockSplitCtx; + /* Buffer for output from external sequence producer */ + ZSTD_Sequence* extSeqBuf; + size_t extSeqBufCapacity; +}; + +typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e; +typedef enum { ZSTD_tfp_forCCtx, ZSTD_tfp_forCDict } ZSTD_tableFillPurpose_e; + +typedef enum { + ZSTD_noDict = 0, + ZSTD_extDict = 1, + ZSTD_dictMatchState = 2, + ZSTD_dedicatedDictSearch = 3 +} ZSTD_dictMode_e; + +typedef enum { + ZSTD_cpm_noAttachDict = 0, /* Compression with ZSTD_noDict or ZSTD_extDict. + * In this mode we use both the srcSize and the dictSize + * when selecting and adjusting parameters. + */ + ZSTD_cpm_attachDict = 1, /* Compression with ZSTD_dictMatchState or ZSTD_dedicatedDictSearch. + * In this mode we only take the srcSize into account when selecting + * and adjusting parameters. + */ + ZSTD_cpm_createCDict = 2, /* Creating a CDict. + * In this mode we take both the source size and the dictionary size + * into account when selecting and adjusting the parameters. + */ + ZSTD_cpm_unknown = 3 /* ZSTD_getCParams, ZSTD_getParams, ZSTD_adjustParams. + * We don't know what these parameters are for. We default to the legacy + * behavior of taking both the source size and the dict size into account + * when selecting and adjusting parameters. + */ +} ZSTD_cParamMode_e; typedef size_t (*ZSTD_blockCompressor) ( ZSTD_matchState_t* bs, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode); +ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_paramSwitch_e rowMatchfinderMode, ZSTD_dictMode_e dictMode); MEM_STATIC U32 ZSTD_LLcode(U32 litLength) @@ -322,31 +543,6 @@ MEM_STATIC U32 ZSTD_MLcode(U32 mlBase) return (mlBase > 127) ? ZSTD_highbit32(mlBase) + ML_deltaCode : ML_Code[mlBase]; } -typedef struct repcodes_s { - U32 rep[3]; -} repcodes_t; - -MEM_STATIC repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0) -{ - repcodes_t newReps; - if (offset >= ZSTD_REP_NUM) { /* full offset */ - newReps.rep[2] = rep[1]; - newReps.rep[1] = rep[0]; - newReps.rep[0] = offset - ZSTD_REP_MOVE; - } else { /* repcode */ - U32 const repCode = offset + ll0; - if (repCode > 0) { /* note : if repCode==0, no change */ - U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; - newReps.rep[2] = (repCode >= 2) ? rep[1] : rep[2]; - newReps.rep[1] = rep[0]; - newReps.rep[0] = currentOffset; - } else { /* repCode == 0 */ - memcpy(&newReps, rep, sizeof(newReps)); - } - } - return newReps; -} - /* ZSTD_cParam_withinBounds: * @return 1 if value is within cParam bounds, * 0 otherwise */ @@ -362,17 +558,20 @@ MEM_STATIC int ZSTD_cParam_withinBounds(ZSTD_cParameter cParam, int value) /* ZSTD_noCompressBlock() : * Writes uncompressed block to dst buffer from given src. * Returns the size of the block */ -MEM_STATIC size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock) +MEM_STATIC size_t +ZSTD_noCompressBlock(void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock) { U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(srcSize << 3); - RETURN_ERROR_IF(srcSize + ZSTDInternalConstants::ZSTD_blockHeaderSize > dstCapacity, + DEBUGLOG(5, "ZSTD_noCompressBlock (srcSize=%zu, dstCapacity=%zu)", srcSize, dstCapacity); + RETURN_ERROR_IF(srcSize + ZSTD_blockHeaderSize > dstCapacity, dstSize_tooSmall, "dst buf too small for uncompressed block"); MEM_writeLE24(dst, cBlockHeader24); - memcpy((BYTE*)dst + ZSTDInternalConstants::ZSTD_blockHeaderSize, src, srcSize); - return ZSTDInternalConstants::ZSTD_blockHeaderSize + srcSize; + ZSTD_memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize); + return ZSTD_blockHeaderSize + srcSize; } -MEM_STATIC size_t ZSTD_rleCompressBlock (void* dst, size_t dstCapacity, BYTE src, size_t srcSize, U32 lastBlock) +MEM_STATIC size_t +ZSTD_rleCompressBlock(void* dst, size_t dstCapacity, BYTE src, size_t srcSize, U32 lastBlock) { BYTE* const op = (BYTE*)dst; U32 const cBlockHeader = lastBlock + (((U32)bt_rle)<<1) + (U32)(srcSize << 3); @@ -391,21 +590,21 @@ MEM_STATIC size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat) { U32 const minlog = (strat>=ZSTD_btultra) ? (U32)(strat) - 1 : 6; ZSTD_STATIC_ASSERT(ZSTD_btultra == 8); - assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat)); + assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, (int)strat)); return (srcSize >> minlog) + 2; } -MEM_STATIC int ZSTD_disableLiteralsCompression(const ZSTD_CCtx_params* cctxParams) +MEM_STATIC int ZSTD_literalsCompressionIsDisabled(const ZSTD_CCtx_params* cctxParams) { switch (cctxParams->literalCompressionMode) { - case ZSTD_lcm_huffman: + case ZSTD_ps_enable: return 0; - case ZSTD_lcm_uncompressed: + case ZSTD_ps_disable: return 1; default: assert(0 /* impossible: pre-validated */); - /* fall-through */ - case ZSTD_lcm_auto: + ZSTD_FALLTHROUGH; + case ZSTD_ps_auto: return (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0); } } @@ -415,7 +614,9 @@ MEM_STATIC int ZSTD_disableLiteralsCompression(const ZSTD_CCtx_params* cctxParam * Only called when the sequence ends past ilimit_w, so it only needs to be optimized for single * large copies. */ -static void ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const iend, BYTE const* ilimit_w) { +static void +ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const iend, BYTE const* ilimit_w) +{ assert(iend > ilimit_w); if (ip <= ilimit_w) { ZSTD_wildcopy(op, ip, ilimit_w - ip, ZSTD_no_overlap); @@ -425,14 +626,28 @@ static void ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const ie while (ip < iend) *op++ = *ip++; } + +#define REPCODE1_TO_OFFBASE REPCODE_TO_OFFBASE(1) +#define REPCODE2_TO_OFFBASE REPCODE_TO_OFFBASE(2) +#define REPCODE3_TO_OFFBASE REPCODE_TO_OFFBASE(3) +#define REPCODE_TO_OFFBASE(r) (assert((r)>=1), assert((r)<=ZSTD_REP_NUM), (r)) /* accepts IDs 1,2,3 */ +#define OFFSET_TO_OFFBASE(o) (assert((o)>0), o + ZSTD_REP_NUM) +#define OFFBASE_IS_OFFSET(o) ((o) > ZSTD_REP_NUM) +#define OFFBASE_IS_REPCODE(o) ( 1 <= (o) && (o) <= ZSTD_REP_NUM) +#define OFFBASE_TO_OFFSET(o) (assert(OFFBASE_IS_OFFSET(o)), (o) - ZSTD_REP_NUM) +#define OFFBASE_TO_REPCODE(o) (assert(OFFBASE_IS_REPCODE(o)), (o)) /* returns ID 1,2,3 */ + /*! ZSTD_storeSeq() : - * Store a sequence (litlen, litPtr, offCode and mlBase) into seqStore_t. - * `offCode` : distance to match + ZSTD_REP_MOVE (values <= ZSTD_REP_MOVE are repCodes). - * `mlBase` : matchLength - MINMATCH - * Allowed to overread literals up to litLimit. + * Store a sequence (litlen, litPtr, offBase and matchLength) into seqStore_t. + * @offBase : Users should employ macros REPCODE_TO_OFFBASE() and OFFSET_TO_OFFBASE(). + * @matchLength : must be >= MINMATCH + * Allowed to over-read literals up to litLimit. */ -HINT_INLINE UNUSED_ATTR -void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, const BYTE* litLimit, U32 offCode, size_t mlBase) +HINT_INLINE UNUSED_ATTR void +ZSTD_storeSeq(seqStore_t* seqStorePtr, + size_t litLength, const BYTE* literals, const BYTE* litLimit, + U32 offBase, + size_t matchLength) { BYTE const* const litLimit_w = litLimit - WILDCOPY_OVERLENGTH; BYTE const* const litEnd = literals + litLength; @@ -440,8 +655,8 @@ void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* litera static const BYTE* g_start = NULL; if (g_start==NULL) g_start = (const BYTE*)literals; /* note : index only works for compression within a single segment */ { U32 const pos = (U32)((const BYTE*)literals - g_start); - DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offCode%7u", - pos, (U32)litLength, (U32)mlBase+MINMATCH, (U32)offCode); + DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offBase%7u", + pos, (U32)litLength, (U32)matchLength, (U32)offBase); } #endif assert((size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart) < seqStorePtr->maxNbSeq); @@ -451,9 +666,9 @@ void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* litera assert(literals + litLength <= litLimit); if (litEnd <= litLimit_w) { /* Common case we can use wildcopy. - * First copy 16 bytes, because literals are likely short. - */ - assert(WILDCOPY_OVERLENGTH >= 16); + * First copy 16 bytes, because literals are likely short. + */ + ZSTD_STATIC_ASSERT(WILDCOPY_OVERLENGTH >= 16); ZSTD_copy16(seqStorePtr->lit, literals); if (litLength > 16) { ZSTD_wildcopy(seqStorePtr->lit+16, literals+16, (ptrdiff_t)litLength-16, ZSTD_no_overlap); @@ -465,95 +680,70 @@ void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* litera /* literal Length */ if (litLength>0xFFFF) { - assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */ - seqStorePtr->longLengthID = 1; + assert(seqStorePtr->longLengthType == ZSTD_llt_none); /* there can only be a single long length */ + seqStorePtr->longLengthType = ZSTD_llt_literalLength; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); } seqStorePtr->sequences[0].litLength = (U16)litLength; /* match offset */ - seqStorePtr->sequences[0].offset = offCode + 1; + seqStorePtr->sequences[0].offBase = offBase; /* match Length */ - if (mlBase>0xFFFF) { - assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */ - seqStorePtr->longLengthID = 2; - seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); + assert(matchLength >= MINMATCH); + { size_t const mlBase = matchLength - MINMATCH; + if (mlBase>0xFFFF) { + assert(seqStorePtr->longLengthType == ZSTD_llt_none); /* there can only be a single long length */ + seqStorePtr->longLengthType = ZSTD_llt_matchLength; + seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); + } + seqStorePtr->sequences[0].mlBase = (U16)mlBase; } - seqStorePtr->sequences[0].matchLength = (U16)mlBase; seqStorePtr->sequences++; } - -/*-************************************* -* Match length counter -***************************************/ -static unsigned ZSTD_NbCommonBytes (size_t val) +/* ZSTD_updateRep() : + * updates in-place @rep (array of repeat offsets) + * @offBase : sum-type, using numeric representation of ZSTD_storeSeq() + */ +MEM_STATIC void +ZSTD_updateRep(U32 rep[ZSTD_REP_NUM], U32 const offBase, U32 const ll0) { - if (MEM_isLittleEndian()) { - if (MEM_64bits()) { -# if defined(_MSC_VER) && defined(_WIN64) - unsigned long r = 0; - return _BitScanForward64( &r, (U64)val ) ? (unsigned)(r >> 3) : 0; -# elif defined(__GNUC__) && (__GNUC__ >= 4) - return (__builtin_ctzll((U64)val) >> 3); -# else - static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, - 0, 3, 1, 3, 1, 4, 2, 7, - 0, 2, 3, 6, 1, 5, 3, 5, - 1, 3, 4, 4, 2, 5, 6, 7, - 7, 0, 1, 2, 3, 3, 4, 6, - 2, 6, 5, 5, 3, 4, 5, 6, - 7, 1, 2, 4, 6, 4, 4, 5, - 7, 2, 6, 5, 7, 6, 7, 7 }; - return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; -# endif - } else { /* 32 bits */ -# if defined(_MSC_VER) - unsigned long r=0; - return _BitScanForward( &r, (U32)val ) ? (unsigned)(r >> 3) : 0; -# elif defined(__GNUC__) && (__GNUC__ >= 3) - return (__builtin_ctz((U32)val) >> 3); -# else - static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, - 3, 2, 2, 1, 3, 2, 0, 1, - 3, 3, 1, 2, 2, 2, 2, 0, - 3, 1, 2, 0, 1, 0, 1, 1 }; - return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; -# endif + if (OFFBASE_IS_OFFSET(offBase)) { /* full offset */ + rep[2] = rep[1]; + rep[1] = rep[0]; + rep[0] = OFFBASE_TO_OFFSET(offBase); + } else { /* repcode */ + U32 const repCode = OFFBASE_TO_REPCODE(offBase) - 1 + ll0; + if (repCode > 0) { /* note : if repCode==0, no change */ + U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; + rep[2] = (repCode >= 2) ? rep[1] : rep[2]; + rep[1] = rep[0]; + rep[0] = currentOffset; + } else { /* repCode == 0 */ + /* nothing to do */ } - } else { /* Big Endian CPU */ - if (MEM_64bits()) { -# if defined(_MSC_VER) && defined(_WIN64) - unsigned long r = 0; - return _BitScanReverse64( &r, val ) ? (unsigned)(r >> 3) : 0; -# elif defined(__GNUC__) && (__GNUC__ >= 4) - return (__builtin_clzll(val) >> 3); -# else - unsigned r; - const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */ - if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; } - if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } - r += (!val); - return r; -# endif - } else { /* 32 bits */ -# if defined(_MSC_VER) - unsigned long r = 0; - return _BitScanReverse( &r, (unsigned long)val ) ? (unsigned)(r >> 3) : 0; -# elif defined(__GNUC__) && (__GNUC__ >= 3) - return (__builtin_clz((U32)val) >> 3); -# else - unsigned r; - if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } - r += (!val); - return r; -# endif - } } + } +} + +typedef struct repcodes_s { + U32 rep[3]; +} repcodes_t; + +MEM_STATIC repcodes_t +ZSTD_newRep(U32 const rep[ZSTD_REP_NUM], U32 const offBase, U32 const ll0) +{ + repcodes_t newReps; + ZSTD_memcpy(&newReps, rep, sizeof(newReps)); + ZSTD_updateRep(newReps.rep, offBase, ll0); + return newReps; } +/*-************************************* +* Match length counter +***************************************/ MEM_STATIC size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit) { const BYTE* const pStart = pIn; @@ -599,31 +789,43 @@ ZSTD_count_2segments(const BYTE* ip, const BYTE* match, * Hashes ***************************************/ static const U32 prime3bytes = 506832829U; -static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; } -MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */ +static U32 ZSTD_hash3(U32 u, U32 h, U32 s) { assert(h <= 32); return (((u << (32-24)) * prime3bytes) ^ s) >> (32-h) ; } +MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h, 0); } /* only in zstd_opt.h */ +MEM_STATIC size_t ZSTD_hash3PtrS(const void* ptr, U32 h, U32 s) { return ZSTD_hash3(MEM_readLE32(ptr), h, s); } static const U32 prime4bytes = 2654435761U; -static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; } -static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); } +static U32 ZSTD_hash4(U32 u, U32 h, U32 s) { assert(h <= 32); return ((u * prime4bytes) ^ s) >> (32-h) ; } +static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_readLE32(ptr), h, 0); } +static size_t ZSTD_hash4PtrS(const void* ptr, U32 h, U32 s) { return ZSTD_hash4(MEM_readLE32(ptr), h, s); } static const U64 prime5bytes = 889523592379ULL; -static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; } -static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); } +static size_t ZSTD_hash5(U64 u, U32 h, U64 s) { assert(h <= 64); return (size_t)((((u << (64-40)) * prime5bytes) ^ s) >> (64-h)) ; } +static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h, 0); } +static size_t ZSTD_hash5PtrS(const void* p, U32 h, U64 s) { return ZSTD_hash5(MEM_readLE64(p), h, s); } static const U64 prime6bytes = 227718039650203ULL; -static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; } -static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); } +static size_t ZSTD_hash6(U64 u, U32 h, U64 s) { assert(h <= 64); return (size_t)((((u << (64-48)) * prime6bytes) ^ s) >> (64-h)) ; } +static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h, 0); } +static size_t ZSTD_hash6PtrS(const void* p, U32 h, U64 s) { return ZSTD_hash6(MEM_readLE64(p), h, s); } static const U64 prime7bytes = 58295818150454627ULL; -static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; } -static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); } +static size_t ZSTD_hash7(U64 u, U32 h, U64 s) { assert(h <= 64); return (size_t)((((u << (64-56)) * prime7bytes) ^ s) >> (64-h)) ; } +static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h, 0); } +static size_t ZSTD_hash7PtrS(const void* p, U32 h, U64 s) { return ZSTD_hash7(MEM_readLE64(p), h, s); } static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL; -static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; } -static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); } +static size_t ZSTD_hash8(U64 u, U32 h, U64 s) { assert(h <= 64); return (size_t)((((u) * prime8bytes) ^ s) >> (64-h)) ; } +static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h, 0); } +static size_t ZSTD_hash8PtrS(const void* p, U32 h, U64 s) { return ZSTD_hash8(MEM_readLE64(p), h, s); } + -MEM_STATIC size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) +MEM_STATIC FORCE_INLINE_ATTR +size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) { + /* Although some of these hashes do support hBits up to 64, some do not. + * To be on the safe side, always avoid hBits > 32. */ + assert(hBits <= 32); + switch(mls) { default: @@ -635,6 +837,24 @@ MEM_STATIC size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) } } +MEM_STATIC FORCE_INLINE_ATTR +size_t ZSTD_hashPtrSalted(const void* p, U32 hBits, U32 mls, const U64 hashSalt) { + /* Although some of these hashes do support hBits up to 64, some do not. + * To be on the safe side, always avoid hBits > 32. */ + assert(hBits <= 32); + + switch(mls) + { + default: + case 4: return ZSTD_hash4PtrS(p, hBits, (U32)hashSalt); + case 5: return ZSTD_hash5PtrS(p, hBits, hashSalt); + case 6: return ZSTD_hash6PtrS(p, hBits, hashSalt); + case 7: return ZSTD_hash7PtrS(p, hBits, hashSalt); + case 8: return ZSTD_hash8PtrS(p, hBits, hashSalt); + } +} + + /** ZSTD_ipow() : * Return base^exponent. */ @@ -719,6 +939,13 @@ MEM_STATIC void ZSTD_window_clear(ZSTD_window_t* window) window->dictLimit = end; } +MEM_STATIC U32 ZSTD_window_isEmpty(ZSTD_window_t const window) +{ + return window.dictLimit == ZSTD_WINDOW_START_INDEX && + window.lowLimit == ZSTD_WINDOW_START_INDEX && + (window.nextSrc - window.base) == ZSTD_WINDOW_START_INDEX; +} + /** * ZSTD_window_hasExtDict(): * Returns non-zero if the window has a non-empty extDict. @@ -738,20 +965,76 @@ MEM_STATIC ZSTD_dictMode_e ZSTD_matchState_dictMode(const ZSTD_matchState_t *ms) return ZSTD_window_hasExtDict(ms->window) ? ZSTD_extDict : ms->dictMatchState != NULL ? - ZSTD_dictMatchState : + (ms->dictMatchState->dedicatedDictSearch ? ZSTD_dedicatedDictSearch : ZSTD_dictMatchState) : ZSTD_noDict; } +/* Defining this macro to non-zero tells zstd to run the overflow correction + * code much more frequently. This is very inefficient, and should only be + * used for tests and fuzzers. + */ +#ifndef ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY +# ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +# define ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY 1 +# else +# define ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY 0 +# endif +#endif + +/** + * ZSTD_window_canOverflowCorrect(): + * Returns non-zero if the indices are large enough for overflow correction + * to work correctly without impacting compression ratio. + */ +MEM_STATIC U32 ZSTD_window_canOverflowCorrect(ZSTD_window_t const window, + U32 cycleLog, + U32 maxDist, + U32 loadedDictEnd, + void const* src) +{ + U32 const cycleSize = 1u << cycleLog; + U32 const curr = (U32)((BYTE const*)src - window.base); + U32 const minIndexToOverflowCorrect = cycleSize + + MAX(maxDist, cycleSize) + + ZSTD_WINDOW_START_INDEX; + + /* Adjust the min index to backoff the overflow correction frequency, + * so we don't waste too much CPU in overflow correction. If this + * computation overflows we don't really care, we just need to make + * sure it is at least minIndexToOverflowCorrect. + */ + U32 const adjustment = window.nbOverflowCorrections + 1; + U32 const adjustedIndex = MAX(minIndexToOverflowCorrect * adjustment, + minIndexToOverflowCorrect); + U32 const indexLargeEnough = curr > adjustedIndex; + + /* Only overflow correct early if the dictionary is invalidated already, + * so we don't hurt compression ratio. + */ + U32 const dictionaryInvalidated = curr > maxDist + loadedDictEnd; + + return indexLargeEnough && dictionaryInvalidated; +} + /** * ZSTD_window_needOverflowCorrection(): * Returns non-zero if the indices are getting too large and need overflow * protection. */ MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window, + U32 cycleLog, + U32 maxDist, + U32 loadedDictEnd, + void const* src, void const* srcEnd) { - U32 const current = (U32)((BYTE const*)srcEnd - window.base); - return current > ZSTD_CURRENT_MAX; + U32 const curr = (U32)((BYTE const*)srcEnd - window.base); + if (ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY) { + if (ZSTD_window_canOverflowCorrect(window, cycleLog, maxDist, loadedDictEnd, src)) { + return 1; + } + } + return curr > ZSTD_CURRENT_MAX; } /** @@ -762,9 +1045,10 @@ MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window, * * The least significant cycleLog bits of the indices must remain the same, * which may be 0. Every index up to maxDist in the past must be valid. - * NOTE: (maxDist & cycleMask) must be zero. */ -MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog, +MEM_STATIC +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog, U32 maxDist, void const* src) { /* preemptive overflow correction: @@ -786,32 +1070,52 @@ MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog, * 3. (cctx->lowLimit + 1< 3<<29 + 1<base); - U32 const currentCycle0 = current & cycleMask; - /* Exclude zero so that newCurrent - maxDist >= 1. */ - U32 const currentCycle1 = currentCycle0 == 0 ? (1U << cycleLog) : currentCycle0; - U32 const newCurrent = currentCycle1 + maxDist; - U32 const correction = current - newCurrent; - assert((maxDist & cycleMask) == 0); - assert(current > newCurrent); - /* Loose bound, should be around 1<<29 (see above) */ - assert(correction > 1<<28); + U32 const cycleSize = 1u << cycleLog; + U32 const cycleMask = cycleSize - 1; + U32 const curr = (U32)((BYTE const*)src - window->base); + U32 const currentCycle = curr & cycleMask; + /* Ensure newCurrent - maxDist >= ZSTD_WINDOW_START_INDEX. */ + U32 const currentCycleCorrection = currentCycle < ZSTD_WINDOW_START_INDEX + ? MAX(cycleSize, ZSTD_WINDOW_START_INDEX) + : 0; + U32 const newCurrent = currentCycle + + currentCycleCorrection + + MAX(maxDist, cycleSize); + U32 const correction = curr - newCurrent; + /* maxDist must be a power of two so that: + * (newCurrent & cycleMask) == (curr & cycleMask) + * This is required to not corrupt the chains / binary tree. + */ + assert((maxDist & (maxDist - 1)) == 0); + assert((curr & cycleMask) == (newCurrent & cycleMask)); + assert(curr > newCurrent); + if (!ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY) { + /* Loose bound, should be around 1<<29 (see above) */ + assert(correction > 1<<28); + } window->base += correction; window->dictBase += correction; - if (window->lowLimit <= correction) window->lowLimit = 1; - else window->lowLimit -= correction; - if (window->dictLimit <= correction) window->dictLimit = 1; - else window->dictLimit -= correction; + if (window->lowLimit < correction + ZSTD_WINDOW_START_INDEX) { + window->lowLimit = ZSTD_WINDOW_START_INDEX; + } else { + window->lowLimit -= correction; + } + if (window->dictLimit < correction + ZSTD_WINDOW_START_INDEX) { + window->dictLimit = ZSTD_WINDOW_START_INDEX; + } else { + window->dictLimit -= correction; + } /* Ensure we can still reference the full window. */ assert(newCurrent >= maxDist); - assert(newCurrent - maxDist >= 1); + assert(newCurrent - maxDist >= ZSTD_WINDOW_START_INDEX); /* Ensure that lowLimit and dictLimit didn't underflow. */ assert(window->lowLimit <= newCurrent); assert(window->dictLimit <= newCurrent); + ++window->nbOverflowCorrections; + DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x", correction, window->lowLimit); return correction; @@ -900,10 +1204,15 @@ ZSTD_checkDictValidity(const ZSTD_window_t* window, (unsigned)blockEndIdx, (unsigned)maxDist, (unsigned)loadedDictEnd); assert(blockEndIdx >= loadedDictEnd); - if (blockEndIdx > loadedDictEnd + maxDist) { + if (blockEndIdx > loadedDictEnd + maxDist || loadedDictEnd != window->dictLimit) { /* On reaching window size, dictionaries are invalidated. * For simplification, if window size is reached anywhere within next block, * the dictionary is invalidated for the full block. + * + * We also have to invalidate the dictionary if ZSTD_window_update() has detected + * non-contiguous segments, which means that loadedDictEnd != window->dictLimit. + * loadedDictEnd may be 0, if forceWindow is true, but in that case we never use + * dictMatchState, so setting it to NULL is not a problem. */ DEBUGLOG(6, "invalidating dictionary for current block (distance > windowSize)"); *loadedDictEndPtr = 0; @@ -915,12 +1224,14 @@ ZSTD_checkDictValidity(const ZSTD_window_t* window, } MEM_STATIC void ZSTD_window_init(ZSTD_window_t* window) { - memset(window, 0, sizeof(*window)); - window->base = (BYTE const*)""; - window->dictBase = (BYTE const*)""; - window->dictLimit = 1; /* start from 1, so that 1st position is valid */ - window->lowLimit = 1; /* it ensures first and later CCtx usages compress the same */ - window->nextSrc = window->base + 1; /* see issue #1241 */ + ZSTD_memset(window, 0, sizeof(*window)); + window->base = (BYTE const*)" "; + window->dictBase = (BYTE const*)" "; + ZSTD_STATIC_ASSERT(ZSTD_DUBT_UNSORTED_MARK < ZSTD_WINDOW_START_INDEX); /* Start above ZSTD_DUBT_UNSORTED_MARK */ + window->dictLimit = ZSTD_WINDOW_START_INDEX; /* start from >0, so that 1st position is valid */ + window->lowLimit = ZSTD_WINDOW_START_INDEX; /* it ensures first and later CCtx usages compress the same */ + window->nextSrc = window->base + ZSTD_WINDOW_START_INDEX; /* see issue #1241 */ + window->nbOverflowCorrections = 0; } /** @@ -930,8 +1241,11 @@ MEM_STATIC void ZSTD_window_init(ZSTD_window_t* window) { * forget about the extDict. Handles overlap of the prefix and extDict. * Returns non-zero if the segment is contiguous. */ -MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window, - void const* src, size_t srcSize) +MEM_STATIC +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +U32 ZSTD_window_update(ZSTD_window_t* window, + void const* src, size_t srcSize, + int forceNonContiguous) { BYTE const* const ip = (BYTE const*)src; U32 contiguous = 1; @@ -941,7 +1255,7 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window, assert(window->base != NULL); assert(window->dictBase != NULL); /* Check if blocks follow each other */ - if (src != window->nextSrc) { + if (src != window->nextSrc || forceNonContiguous) { /* not contiguous */ size_t const distanceFromBase = (size_t)(window->nextSrc - window->base); DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u", window->dictLimit); @@ -969,25 +1283,32 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window, /** * Returns the lowest allowed match index. It may either be in the ext-dict or the prefix. */ -MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_matchState_t* ms, U32 current, unsigned windowLog) +MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_matchState_t* ms, U32 curr, unsigned windowLog) { - U32 const maxDistance = 1U << windowLog; - U32 const lowestValid = ms->window.lowLimit; - U32 const withinWindow = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid; - U32 const isDictionary = (ms->loadedDictEnd != 0); - U32 const matchLowest = isDictionary ? lowestValid : withinWindow; + U32 const maxDistance = 1U << windowLog; + U32 const lowestValid = ms->window.lowLimit; + U32 const withinWindow = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; + U32 const isDictionary = (ms->loadedDictEnd != 0); + /* When using a dictionary the entire dictionary is valid if a single byte of the dictionary + * is within the window. We invalidate the dictionary (and set loadedDictEnd to 0) when it isn't + * valid for the entire block. So this check is sufficient to find the lowest valid match index. + */ + U32 const matchLowest = isDictionary ? lowestValid : withinWindow; return matchLowest; } /** * Returns the lowest allowed match index in the prefix. */ -MEM_STATIC U32 ZSTD_getLowestPrefixIndex(const ZSTD_matchState_t* ms, U32 current, unsigned windowLog) +MEM_STATIC U32 ZSTD_getLowestPrefixIndex(const ZSTD_matchState_t* ms, U32 curr, unsigned windowLog) { U32 const maxDistance = 1U << windowLog; U32 const lowestValid = ms->window.dictLimit; - U32 const withinWindow = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid; + U32 const withinWindow = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; U32 const isDictionary = (ms->loadedDictEnd != 0); + /* When computing the lowest prefix index we need to take the dictionary into account to handle + * the edge case where the dictionary and the source are contiguous in memory. + */ U32 const matchLowest = isDictionary ? lowestValid : withinWindow; return matchLowest; } @@ -1025,6 +1346,43 @@ MEM_STATIC void ZSTD_debugTable(const U32* table, U32 max) #endif +/* Short Cache */ + +/* Normally, zstd matchfinders follow this flow: + * 1. Compute hash at ip + * 2. Load index from hashTable[hash] + * 3. Check if *ip == *(base + index) + * In dictionary compression, loading *(base + index) is often an L2 or even L3 miss. + * + * Short cache is an optimization which allows us to avoid step 3 most of the time + * when the data doesn't actually match. With short cache, the flow becomes: + * 1. Compute (hash, currentTag) at ip. currentTag is an 8-bit independent hash at ip. + * 2. Load (index, matchTag) from hashTable[hash]. See ZSTD_writeTaggedIndex to understand how this works. + * 3. Only if currentTag == matchTag, check *ip == *(base + index). Otherwise, continue. + * + * Currently, short cache is only implemented in CDict hashtables. Thus, its use is limited to + * dictMatchState matchfinders. + */ +#define ZSTD_SHORT_CACHE_TAG_BITS 8 +#define ZSTD_SHORT_CACHE_TAG_MASK ((1u << ZSTD_SHORT_CACHE_TAG_BITS) - 1) + +/* Helper function for ZSTD_fillHashTable and ZSTD_fillDoubleHashTable. + * Unpacks hashAndTag into (hash, tag), then packs (index, tag) into hashTable[hash]. */ +MEM_STATIC void ZSTD_writeTaggedIndex(U32* const hashTable, size_t hashAndTag, U32 index) { + size_t const hash = hashAndTag >> ZSTD_SHORT_CACHE_TAG_BITS; + U32 const tag = (U32)(hashAndTag & ZSTD_SHORT_CACHE_TAG_MASK); + assert(index >> (32 - ZSTD_SHORT_CACHE_TAG_BITS) == 0); + hashTable[hash] = (index << ZSTD_SHORT_CACHE_TAG_BITS) | tag; +} + +/* Helper function for short cache matchfinders. + * Unpacks tag1 and tag2 from lower bits of packedTag1 and packedTag2, then checks if the tags match. */ +MEM_STATIC int ZSTD_comparePackedTags(size_t packedTag1, size_t packedTag2) { + U32 const tag1 = packedTag1 & ZSTD_SHORT_CACHE_TAG_MASK; + U32 const tag2 = packedTag2 & ZSTD_SHORT_CACHE_TAG_MASK; + return tag1 == tag2; +} + /* =============================================================== * Shared internal declarations * These prototypes may be called from sources not in lib/compress @@ -1036,7 +1394,6 @@ MEM_STATIC void ZSTD_debugTable(const U32* table, U32 max) * assumptions : magic number supposed already checked * and dictSize >= 8 */ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, - short* offcodeNCount, unsigned* offcodeMaxValue, const void* const dict, size_t dictSize); void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs); @@ -1052,7 +1409,7 @@ void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs); * Note: srcSizeHint == 0 means 0! */ ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( - const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize); + const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode); /*! ZSTD_initCStream_internal() : * Private use only. Init streaming operation. @@ -1103,16 +1460,70 @@ size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity); * This cannot be used when long range matching is enabled. * Zstd will use these sequences, and pass the literals to a secondary block * compressor. - * @return : An error code on failure. * NOTE: seqs are not verified! Invalid sequences can cause out-of-bounds memory * access and data corruption. */ -size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq); +void ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq); /** ZSTD_cycleLog() : * condition for correct operation : hashLog > 1 */ U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat); +/** ZSTD_CCtx_trace() : + * Trace the end of a compression call. + */ +void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize); + +/* Returns 0 on success, and a ZSTD_error otherwise. This function scans through an array of + * ZSTD_Sequence, storing the sequences it finds, until it reaches a block delimiter. + * Note that the block delimiter must include the last literals of the block. + */ +size_t +ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx, + ZSTD_sequencePosition* seqPos, + const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, + const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch); + +/* Returns the number of bytes to move the current read position back by. + * Only non-zero if we ended up splitting a sequence. + * Otherwise, it may return a ZSTD error if something went wrong. + * + * This function will attempt to scan through blockSize bytes + * represented by the sequences in @inSeqs, + * storing any (partial) sequences. + * + * Occasionally, we may want to change the actual number of bytes we consumed from inSeqs to + * avoid splitting a match, or to avoid splitting a match such that it would produce a match + * smaller than MINMATCH. In this case, we return the number of bytes that we didn't read from this block. + */ +size_t +ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos, + const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, + const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch); + +/* Returns 1 if an external sequence producer is registered, otherwise returns 0. */ +MEM_STATIC int ZSTD_hasExtSeqProd(const ZSTD_CCtx_params* params) { + return params->extSeqProdFunc != NULL; } +/* =============================================================== + * Deprecated definitions that are still used internally to avoid + * deprecation warnings. These functions are exactly equivalent to + * their public variants, but avoid the deprecation warnings. + * =============================================================== */ + +size_t ZSTD_compressBegin_usingCDict_deprecated(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); + +size_t ZSTD_compressContinue_public(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + +size_t ZSTD_compressEnd_public(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + +size_t ZSTD_compressBlock_deprecated(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); + +} // namespace duckdb_zstd + #endif /* ZSTD_COMPRESS_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_literals.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_literals.h index 7082db522..a8fc05ba7 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_literals.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_literals.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -17,16 +17,26 @@ namespace duckdb_zstd { size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize); +/* ZSTD_compressRleLiteralsBlock() : + * Conditions : + * - All bytes in @src are identical + * - dstCapacity >= 4 */ size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize); -size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, - ZSTD_hufCTables_t* nextHuf, - ZSTD_strategy strategy, int disableLiteralCompression, - void* dst, size_t dstCapacity, +/* ZSTD_compressLiterals(): + * @entropyWorkspace: must be aligned on 4-bytes boundaries + * @entropyWorkspaceSize : must be >= HUF_WORKSPACE_SIZE + * @suspectUncompressible: sampling checks, to potentially skip huffman coding + */ +size_t ZSTD_compressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize, void* entropyWorkspace, size_t entropyWorkspaceSize, - const int bmi2); + const ZSTD_hufCTables_t* prevHuf, + ZSTD_hufCTables_t* nextHuf, + ZSTD_strategy strategy, int disableLiteralCompression, + int suspectUncompressible, + int bmi2); -} +} // namespace duckdb_zstd #endif /* ZSTD_COMPRESS_LITERALS_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_sequences.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_sequences.h index 63e27ea63..885663f2e 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_sequences.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_sequences.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -54,6 +54,6 @@ size_t ZSTD_fseBitCost( size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog, unsigned const* count, unsigned const max); -} +} // namespace duckdb_zstd #endif /* ZSTD_COMPRESS_SEQUENCES_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_superblock.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_superblock.h index df4055036..34b7a3bf2 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_superblock.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_superblock.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -18,6 +18,7 @@ #include "zstd.h" /* ZSTD_CCtx */ namespace duckdb_zstd { + /*-************************************* * Target Compressed Block Size ***************************************/ @@ -29,7 +30,7 @@ size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, void const* src, size_t srcSize, unsigned lastBlock); -} +} // namespace duckdb_zstd #endif /* ZSTD_COMPRESS_ADVANCED_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_cwksp.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_cwksp.h index aea4f469c..70cfcfa53 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_cwksp.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_cwksp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,7 +14,11 @@ /*-************************************* * Dependencies ***************************************/ +#include "zstd/common/allocations.h" /* ZSTD_customMalloc, ZSTD_customFree */ #include "zstd/common/zstd_internal.h" +#include "zstd/common/portability_macros.h" + +namespace duckdb_zstd { /*-************************************* * Constants @@ -31,21 +35,30 @@ #define ZSTD_CWKSP_ASAN_REDZONE_SIZE 128 #endif -#if defined (MEMORY_SANITIZER) -#include -#endif -namespace duckdb_zstd { +/* Set our tables and aligneds to align by 64 bytes */ +#define ZSTD_CWKSP_ALIGNMENT_BYTES 64 /*-************************************* * Structures ***************************************/ typedef enum { ZSTD_cwksp_alloc_objects, - ZSTD_cwksp_alloc_buffers, - ZSTD_cwksp_alloc_aligned + ZSTD_cwksp_alloc_aligned_init_once, + ZSTD_cwksp_alloc_aligned, + ZSTD_cwksp_alloc_buffers } ZSTD_cwksp_alloc_phase_e; +/** + * Used to describe whether the workspace is statically allocated (and will not + * necessarily ever be freed), or if it's dynamically allocated and we can + * expect a well-formed caller to free this. + */ +typedef enum { + ZSTD_cwksp_dynamic_alloc, + ZSTD_cwksp_static_alloc +} ZSTD_cwksp_static_alloc_e; + /** * Zstd fits all its internal datastructures into a single continuous buffer, * so that it only needs to perform a single OS allocation (or so that a buffer @@ -86,15 +99,15 @@ typedef enum { * * Workspace Layout: * - * [ ... workspace ... ] - * [objects][tables ... ->] free space [<- ... aligned][<- ... buffers] + * [ ... workspace ... ] + * [objects][tables ->] free space [<- buffers][<- aligned][<- init once] * * The various objects that live in the workspace are divided into the * following categories, and are allocated separately: * * - Static objects: this is optionally the enclosing ZSTD_CCtx or ZSTD_CDict, * so that literally everything fits in a single buffer. Note: if present, - * this must be the first object in the workspace, since ZSTD_free{CCtx, + * this must be the first object in the workspace, since ZSTD_customFree{CCtx, * CDict}() rely on a pointer comparison to see whether one or two frees are * required. * @@ -109,10 +122,20 @@ typedef enum { * - Tables: these are any of several different datastructures (hash tables, * chain tables, binary trees) that all respect a common format: they are * uint32_t arrays, all of whose values are between 0 and (nextSrc - base). - * Their sizes depend on the cparams. + * Their sizes depend on the cparams. These tables are 64-byte aligned. + * + * - Init once: these buffers require to be initialized at least once before + * use. They should be used when we want to skip memory initialization + * while not triggering memory checkers (like Valgrind) when reading from + * from this memory without writing to it first. + * These buffers should be used carefully as they might contain data + * from previous compressions. + * Buffers are aligned to 64 bytes. * - * - Aligned: these buffers are used for various purposes that require 4 byte - * alignment, but don't require any initialization before they're used. + * - Aligned: these buffers don't require any initialization before they're + * used. The user of the buffer should make sure they write into a buffer + * location before reading from it. + * Buffers are aligned to 64 bytes. * * - Buffers: these buffers are used for various purposes that don't require * any alignment or initialization before they're used. This means they can @@ -124,9 +147,9 @@ typedef enum { * correctly packed into the workspace buffer. That order is: * * 1. Objects - * 2. Buffers - * 3. Aligned - * 4. Tables + * 2. Init once / Tables + * 3. Aligned / Tables + * 4. Buffers / Tables * * Attempts to reserve objects of different types out of order will fail. */ @@ -138,10 +161,12 @@ typedef struct { void* tableEnd; void* tableValidEnd; void* allocStart; + void* initOnceStart; - int allocFailed; + BYTE allocFailed; int workspaceOversizedDuration; ZSTD_cwksp_alloc_phase_e phase; + ZSTD_cwksp_static_alloc_e isStatic; } ZSTD_cwksp; /*-************************************* @@ -149,6 +174,7 @@ typedef struct { ***************************************/ MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws); +MEM_STATIC void* ZSTD_cwksp_initialAllocStart(ZSTD_cwksp* ws); MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) { (void)ws; @@ -158,6 +184,21 @@ MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) { assert(ws->tableEnd <= ws->allocStart); assert(ws->tableValidEnd <= ws->allocStart); assert(ws->allocStart <= ws->workspaceEnd); + assert(ws->initOnceStart <= ZSTD_cwksp_initialAllocStart(ws)); + assert(ws->workspace <= ws->initOnceStart); +#if ZSTD_MEMORY_SANITIZER + { + intptr_t const offset = __msan_test_shadow(ws->initOnceStart, + (U8*)ZSTD_cwksp_initialAllocStart(ws) - (U8*)ws->initOnceStart); + (void)offset; +#if defined(ZSTD_MSAN_PRINT) + if(offset!=-1) { + __msan_print_shadow((U8*)ws->initOnceStart + offset - 8, 32); + } +#endif + assert(offset==-1); + }; +#endif } /** @@ -178,63 +219,68 @@ MEM_STATIC size_t ZSTD_cwksp_align(size_t size, size_t const align) { * Since tables aren't currently redzoned, you don't need to call through this * to figure out how much space you need for the matchState tables. Everything * else is though. + * + * Do not use for sizing aligned buffers. Instead, use ZSTD_cwksp_aligned_alloc_size(). */ MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) { -#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) - return size + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE; -#else + if (size == 0) + return 0; return size; -#endif } -MEM_STATIC void ZSTD_cwksp_internal_advance_phase( - ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) { - assert(phase >= ws->phase); - if (phase > ws->phase) { - if (ws->phase < ZSTD_cwksp_alloc_buffers && - phase >= ZSTD_cwksp_alloc_buffers) { - ws->tableValidEnd = ws->objectEnd; - } - if (ws->phase < ZSTD_cwksp_alloc_aligned && - phase >= ZSTD_cwksp_alloc_aligned) { - /* If unaligned allocations down from a too-large top have left us - * unaligned, we need to realign our alloc ptr. Technically, this - * can consume space that is unaccounted for in the neededSpace - * calculation. However, I believe this can only happen when the - * workspace is too large, and specifically when it is too large - * by a larger margin than the space that will be consumed. */ - /* TODO: cleaner, compiler warning friendly way to do this??? */ - ws->allocStart = (BYTE*)ws->allocStart - ((size_t)ws->allocStart & (sizeof(U32)-1)); - if (ws->allocStart < ws->tableValidEnd) { - ws->tableValidEnd = ws->allocStart; - } - } - ws->phase = phase; - } +/** + * Returns an adjusted alloc size that is the nearest larger multiple of 64 bytes. + * Used to determine the number of bytes required for a given "aligned". + */ +MEM_STATIC size_t ZSTD_cwksp_aligned_alloc_size(size_t size) { + return ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(size, ZSTD_CWKSP_ALIGNMENT_BYTES)); } /** - * Returns whether this object/buffer/etc was allocated in this workspace. + * Returns the amount of additional space the cwksp must allocate + * for internal purposes (currently only alignment). */ -MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr) { - return (ptr != NULL) && (ws->workspace <= ptr) && (ptr <= ws->workspaceEnd); +MEM_STATIC size_t ZSTD_cwksp_slack_space_required(void) { + /* For alignment, the wksp will always allocate an additional 2*ZSTD_CWKSP_ALIGNMENT_BYTES + * bytes to align the beginning of tables section and end of buffers; + */ + size_t const slackSpace = ZSTD_CWKSP_ALIGNMENT_BYTES * 2; + return slackSpace; } + /** - * Internal function. Do not use directly. + * Return the number of additional bytes required to align a pointer to the given number of bytes. + * alignBytes must be a power of two. */ -MEM_STATIC void* ZSTD_cwksp_reserve_internal( - ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase_e phase) { - void* alloc; - void* bottom = ws->tableEnd; - ZSTD_cwksp_internal_advance_phase(ws, phase); - alloc = (BYTE *)ws->allocStart - bytes; +MEM_STATIC size_t ZSTD_cwksp_bytes_to_align_ptr(void* ptr, const size_t alignBytes) { + size_t const alignBytesMask = alignBytes - 1; + size_t const bytes = (alignBytes - ((size_t)ptr & (alignBytesMask))) & alignBytesMask; + assert((alignBytes & alignBytesMask) == 0); + assert(bytes < alignBytes); + return bytes; +} -#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) - /* over-reserve space */ - alloc = (BYTE *)alloc - 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE; -#endif +/** + * Returns the initial value for allocStart which is used to determine the position from + * which we can allocate from the end of the workspace. + */ +MEM_STATIC void* ZSTD_cwksp_initialAllocStart(ZSTD_cwksp* ws) { + return (void*)((size_t)ws->workspaceEnd & ~(ZSTD_CWKSP_ALIGNMENT_BYTES-1)); +} +/** + * Internal function. Do not use directly. + * Reserves the given number of bytes within the aligned/buffer segment of the wksp, + * which counts from the end of the wksp (as opposed to the object/table segment). + * + * Returns a pointer to the beginning of that space. + */ +MEM_STATIC void* +ZSTD_cwksp_reserve_internal_buffer_space(ZSTD_cwksp* ws, size_t const bytes) +{ + void* const alloc = (BYTE*)ws->allocStart - bytes; + void* const bottom = ws->tableEnd; DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining", alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes); ZSTD_cwksp_assert_internal_consistency(ws); @@ -244,51 +290,149 @@ MEM_STATIC void* ZSTD_cwksp_reserve_internal( ws->allocFailed = 1; return NULL; } + /* the area is reserved from the end of wksp. + * If it overlaps with tableValidEnd, it voids guarantees on values' range */ if (alloc < ws->tableValidEnd) { ws->tableValidEnd = alloc; } ws->allocStart = alloc; + return alloc; +} -#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) - /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on - * either size. */ - alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE; - __asan_unpoison_memory_region(alloc, bytes); -#endif +/** + * Moves the cwksp to the next phase, and does any necessary allocations. + * cwksp initialization must necessarily go through each phase in order. + * Returns a 0 on success, or zstd error + */ +MEM_STATIC size_t +ZSTD_cwksp_internal_advance_phase(ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) +{ + assert(phase >= ws->phase); + if (phase > ws->phase) { + /* Going from allocating objects to allocating initOnce / tables */ + if (ws->phase < ZSTD_cwksp_alloc_aligned_init_once && + phase >= ZSTD_cwksp_alloc_aligned_init_once) { + ws->tableValidEnd = ws->objectEnd; + ws->initOnceStart = ZSTD_cwksp_initialAllocStart(ws); + + { /* Align the start of the tables to 64 bytes. Use [0, 63] bytes */ + void *const alloc = ws->objectEnd; + size_t const bytesToAlign = ZSTD_cwksp_bytes_to_align_ptr(alloc, ZSTD_CWKSP_ALIGNMENT_BYTES); + void *const objectEnd = (BYTE *) alloc + bytesToAlign; + DEBUGLOG(5, "reserving table alignment addtl space: %zu", bytesToAlign); + RETURN_ERROR_IF(objectEnd > ws->workspaceEnd, memory_allocation, + "table phase - alignment initial allocation failed!"); + ws->objectEnd = objectEnd; + ws->tableEnd = objectEnd; /* table area starts being empty */ + if (ws->tableValidEnd < ws->tableEnd) { + ws->tableValidEnd = ws->tableEnd; + } + } + } + ws->phase = phase; + ZSTD_cwksp_assert_internal_consistency(ws); + } + return 0; +} +/** + * Returns whether this object/buffer/etc was allocated in this workspace. + */ +MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr) +{ + return (ptr != NULL) && (ws->workspace <= ptr) && (ptr < ws->workspaceEnd); +} + +/** + * Internal function. Do not use directly. + */ +MEM_STATIC void* +ZSTD_cwksp_reserve_internal(ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase_e phase) +{ + void* alloc; + if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase)) || bytes == 0) { + return NULL; + } + + alloc = ZSTD_cwksp_reserve_internal_buffer_space(ws, bytes); return alloc; } /** * Reserves and returns unaligned memory. */ -MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes) { +MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes) +{ return (BYTE*)ZSTD_cwksp_reserve_internal(ws, bytes, ZSTD_cwksp_alloc_buffers); } /** - * Reserves and returns memory sized on and aligned on sizeof(unsigned). + * Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes). + * This memory has been initialized at least once in the past. + * This doesn't mean it has been initialized this time, and it might contain data from previous + * operations. + * The main usage is for algorithms that might need read access into uninitialized memory. + * The algorithm must maintain safety under these conditions and must make sure it doesn't + * leak any of the past data (directly or in side channels). */ -MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes) { - assert((bytes & (sizeof(U32)-1)) == 0); - return ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, sizeof(U32)), ZSTD_cwksp_alloc_aligned); +MEM_STATIC void* ZSTD_cwksp_reserve_aligned_init_once(ZSTD_cwksp* ws, size_t bytes) +{ + size_t const alignedBytes = ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES); + void* ptr = ZSTD_cwksp_reserve_internal(ws, alignedBytes, ZSTD_cwksp_alloc_aligned_init_once); + assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0); + if(ptr && ptr < ws->initOnceStart) { + /* We assume the memory following the current allocation is either: + * 1. Not usable as initOnce memory (end of workspace) + * 2. Another initOnce buffer that has been allocated before (and so was previously memset) + * 3. An ASAN redzone, in which case we don't want to write on it + * For these reasons it should be fine to not explicitly zero every byte up to ws->initOnceStart. + * Note that we assume here that MSAN and ASAN cannot run in the same time. */ + ZSTD_memset(ptr, 0, MIN((size_t)((U8*)ws->initOnceStart - (U8*)ptr), alignedBytes)); + ws->initOnceStart = ptr; + } +#if ZSTD_MEMORY_SANITIZER + assert(__msan_test_shadow(ptr, bytes) == -1); +#endif + return ptr; +} + +/** + * Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes). + */ +MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes) +{ + void* ptr = ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES), + ZSTD_cwksp_alloc_aligned); + assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0); + return ptr; } /** - * Aligned on sizeof(unsigned). These buffers have the special property that - * their values remain constrained, allowing us to re-use them without + * Aligned on 64 bytes. These buffers have the special property that + * their values remain constrained, allowing us to reuse them without * memset()-ing them. */ -MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) { - const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned; - void* alloc = ws->tableEnd; - void* end = (BYTE *)alloc + bytes; - void* top = ws->allocStart; +MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) +{ + const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned_init_once; + void* alloc; + void* end; + void* top; + + /* We can only start allocating tables after we are done reserving space for objects at the + * start of the workspace */ + if(ws->phase < phase) { + if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase))) { + return NULL; + } + } + alloc = ws->tableEnd; + end = (BYTE *)alloc + bytes; + top = ws->allocStart; DEBUGLOG(5, "cwksp: reserving %p table %zd bytes, %zd bytes remaining", alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes); assert((bytes & (sizeof(U32)-1)) == 0); - ZSTD_cwksp_internal_advance_phase(ws, phase); ZSTD_cwksp_assert_internal_consistency(ws); assert(end <= top); if (end > top) { @@ -298,35 +442,30 @@ MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) { } ws->tableEnd = end; -#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) - __asan_unpoison_memory_region(alloc, bytes); -#endif - + assert((bytes & (ZSTD_CWKSP_ALIGNMENT_BYTES-1)) == 0); + assert(((size_t)alloc & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0); return alloc; } /** * Aligned on sizeof(void*). + * Note : should happen only once, at workspace first initialization */ -MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) { - size_t roundedBytes = ZSTD_cwksp_align(bytes, sizeof(void*)); +MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) +{ + size_t const roundedBytes = ZSTD_cwksp_align(bytes, sizeof(void*)); void* alloc = ws->objectEnd; void* end = (BYTE*)alloc + roundedBytes; -#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) - /* over-reserve space */ - end = (BYTE *)end + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE; -#endif - - DEBUGLOG(5, + DEBUGLOG(4, "cwksp: reserving %p object %zd bytes (rounded to %zd), %zd bytes remaining", alloc, bytes, roundedBytes, ZSTD_cwksp_available_space(ws) - roundedBytes); - assert(((size_t)alloc & (sizeof(void*)-1)) == 0); - assert((bytes & (sizeof(void*)-1)) == 0); + assert((size_t)alloc % ZSTD_ALIGNOF(void*) == 0); + assert(bytes % ZSTD_ALIGNOF(void*) == 0); ZSTD_cwksp_assert_internal_consistency(ws); /* we must be in the first phase, no advance is possible */ if (ws->phase != ZSTD_cwksp_alloc_objects || end > ws->workspaceEnd) { - DEBUGLOG(4, "cwksp: object alloc failed!"); + DEBUGLOG(3, "cwksp: object alloc failed!"); ws->allocFailed = 1; return NULL; } @@ -334,30 +473,13 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) { ws->tableEnd = end; ws->tableValidEnd = end; -#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) - /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on - * either size. */ - alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE; - __asan_unpoison_memory_region(alloc, bytes); -#endif - return alloc; } -MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws) { +MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws) +{ DEBUGLOG(4, "cwksp: ZSTD_cwksp_mark_tables_dirty"); -#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) - /* To validate that the table re-use logic is sound, and that we don't - * access table space that we haven't cleaned, we re-"poison" the table - * space every time we mark it dirty. */ - { - size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd; - assert(__msan_test_shadow(ws->objectEnd, size) == -1); - __msan_poison(ws->objectEnd, size); - } -#endif - assert(ws->tableValidEnd >= ws->objectEnd); assert(ws->tableValidEnd <= ws->allocStart); ws->tableValidEnd = ws->objectEnd; @@ -382,7 +504,7 @@ MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) { assert(ws->tableValidEnd >= ws->objectEnd); assert(ws->tableValidEnd <= ws->allocStart); if (ws->tableValidEnd < ws->tableEnd) { - memset(ws->tableValidEnd, 0, (BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd); + ZSTD_memset(ws->tableValidEnd, 0, (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd)); } ZSTD_cwksp_mark_tables_clean(ws); } @@ -394,13 +516,6 @@ MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) { MEM_STATIC void ZSTD_cwksp_clear_tables(ZSTD_cwksp* ws) { DEBUGLOG(4, "cwksp: clearing tables!"); -#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) - { - size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd; - __asan_poison_memory_region(ws->objectEnd, size); - } -#endif - ws->tableEnd = ws->objectEnd; ZSTD_cwksp_assert_internal_consistency(ws); } @@ -412,77 +527,66 @@ MEM_STATIC void ZSTD_cwksp_clear_tables(ZSTD_cwksp* ws) { MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) { DEBUGLOG(4, "cwksp: clearing!"); -#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) - /* To validate that the context re-use logic is sound, and that we don't - * access stuff that this compression hasn't initialized, we re-"poison" - * the workspace (or at least the non-static, non-table parts of it) - * every time we start a new compression. */ - { - size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->tableValidEnd; - __msan_poison(ws->tableValidEnd, size); - } -#endif - -#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) - { - size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->objectEnd; - __asan_poison_memory_region(ws->objectEnd, size); - } -#endif - ws->tableEnd = ws->objectEnd; - ws->allocStart = ws->workspaceEnd; + ws->allocStart = ZSTD_cwksp_initialAllocStart(ws); ws->allocFailed = 0; - if (ws->phase > ZSTD_cwksp_alloc_buffers) { - ws->phase = ZSTD_cwksp_alloc_buffers; + if (ws->phase > ZSTD_cwksp_alloc_aligned_init_once) { + ws->phase = ZSTD_cwksp_alloc_aligned_init_once; } ZSTD_cwksp_assert_internal_consistency(ws); } +MEM_STATIC size_t ZSTD_cwksp_sizeof(const ZSTD_cwksp* ws) { + return (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->workspace); +} + +MEM_STATIC size_t ZSTD_cwksp_used(const ZSTD_cwksp* ws) { + return (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->workspace) + + (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->allocStart); +} + /** * The provided workspace takes ownership of the buffer [start, start+size). * Any existing values in the workspace are ignored (the previously managed * buffer, if present, must be separately freed). */ -MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size) { +MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size, ZSTD_cwksp_static_alloc_e isStatic) { DEBUGLOG(4, "cwksp: init'ing workspace with %zd bytes", size); assert(((size_t)start & (sizeof(void*)-1)) == 0); /* ensure correct alignment */ ws->workspace = start; ws->workspaceEnd = (BYTE*)start + size; ws->objectEnd = ws->workspace; ws->tableValidEnd = ws->objectEnd; + ws->initOnceStart = ZSTD_cwksp_initialAllocStart(ws); ws->phase = ZSTD_cwksp_alloc_objects; + ws->isStatic = isStatic; ZSTD_cwksp_clear(ws); ws->workspaceOversizedDuration = 0; ZSTD_cwksp_assert_internal_consistency(ws); } MEM_STATIC size_t ZSTD_cwksp_create(ZSTD_cwksp* ws, size_t size, ZSTD_customMem customMem) { - void* workspace = ZSTD_malloc(size, customMem); + void* workspace = ZSTD_customMalloc(size, customMem); DEBUGLOG(4, "cwksp: creating new workspace with %zd bytes", size); RETURN_ERROR_IF(workspace == NULL, memory_allocation, "NULL pointer!"); - ZSTD_cwksp_init(ws, workspace, size); + ZSTD_cwksp_init(ws, workspace, size, ZSTD_cwksp_dynamic_alloc); return 0; } MEM_STATIC void ZSTD_cwksp_free(ZSTD_cwksp* ws, ZSTD_customMem customMem) { void *ptr = ws->workspace; DEBUGLOG(4, "cwksp: freeing workspace"); - memset(ws, 0, sizeof(ZSTD_cwksp)); - ZSTD_free(ptr, customMem); + ZSTD_memset(ws, 0, sizeof(ZSTD_cwksp)); + ZSTD_customFree(ptr, customMem); } /** * Moves the management of a workspace from one cwksp to another. The src cwksp - * is left in an invalid state (src must be re-init()'ed before its used again). + * is left in an invalid state (src must be re-init()'ed before it's used again). */ MEM_STATIC void ZSTD_cwksp_move(ZSTD_cwksp* dst, ZSTD_cwksp* src) { *dst = *src; - memset(src, 0, sizeof(ZSTD_cwksp)); -} - -MEM_STATIC size_t ZSTD_cwksp_sizeof(const ZSTD_cwksp* ws) { - return (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->workspace); + ZSTD_memset(src, 0, sizeof(ZSTD_cwksp)); } MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) { @@ -493,6 +597,18 @@ MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) { * Functions Checking Free Space ***************************************/ +/* ZSTD_alignmentSpaceWithinBounds() : + * Returns if the estimated space needed for a wksp is within an acceptable limit of the + * actual amount of space used. + */ +MEM_STATIC int ZSTD_cwksp_estimated_space_within_bounds(const ZSTD_cwksp *const ws, size_t const estimatedSpace) { + /* We have an alignment space between objects and tables between tables and buffers, so we can have up to twice + * the alignment bytes difference between estimation and actual usage */ + return (estimatedSpace - ZSTD_cwksp_slack_space_required()) <= ZSTD_cwksp_used(ws) && + ZSTD_cwksp_used(ws) <= estimatedSpace; +} + + MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws) { return (size_t)((BYTE*)ws->allocStart - (BYTE*)ws->tableEnd); } @@ -520,6 +636,6 @@ MEM_STATIC void ZSTD_cwksp_bump_oversized_duration( } } -} +} // namespace duckdb_zstd #endif /* ZSTD_CWKSP_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_double_fast.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_double_fast.h index 7991711fa..c91680abc 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_double_fast.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_double_fast.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -16,8 +16,12 @@ namespace duckdb_zstd { +#ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR + void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, - void const* end, ZSTD_dictTableLoadMethod_e dtlm); + void const* end, ZSTD_dictTableLoadMethod_e dtlm, + ZSTD_tableFillPurpose_e tfp); + size_t ZSTD_compressBlock_doubleFast( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); @@ -28,6 +32,15 @@ size_t ZSTD_compressBlock_doubleFast_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -} +#define ZSTD_COMPRESSBLOCK_DOUBLEFAST ZSTD_compressBlock_doubleFast +#define ZSTD_COMPRESSBLOCK_DOUBLEFAST_DICTMATCHSTATE ZSTD_compressBlock_doubleFast_dictMatchState +#define ZSTD_COMPRESSBLOCK_DOUBLEFAST_EXTDICT ZSTD_compressBlock_doubleFast_extDict +#else +#define ZSTD_COMPRESSBLOCK_DOUBLEFAST NULL +#define ZSTD_COMPRESSBLOCK_DOUBLEFAST_DICTMATCHSTATE NULL +#define ZSTD_COMPRESSBLOCK_DOUBLEFAST_EXTDICT NULL +#endif /* ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR */ + +} // namespace duckdb_zstd #endif /* ZSTD_DOUBLE_FAST_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_fast.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_fast.h index a75839a06..2f7ee5b64 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_fast.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_fast.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -17,7 +17,8 @@ namespace duckdb_zstd { void ZSTD_fillHashTable(ZSTD_matchState_t* ms, - void const* end, ZSTD_dictTableLoadMethod_e dtlm); + void const* end, ZSTD_dictTableLoadMethod_e dtlm, + ZSTD_tableFillPurpose_e tfp); size_t ZSTD_compressBlock_fast( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); @@ -28,6 +29,6 @@ size_t ZSTD_compressBlock_fast_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -} +} // namespace duckdb_zstd #endif /* ZSTD_FAST_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_lazy.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_lazy.h index 555edbf1b..d43882c46 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_lazy.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_lazy.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,49 +15,183 @@ namespace duckdb_zstd { +/** + * Dedicated Dictionary Search Structure bucket log. In the + * ZSTD_dedicatedDictSearch mode, the hashTable has + * 2 ** ZSTD_LAZY_DDSS_BUCKET_LOG entries in each bucket, rather than just + * one. + */ +#define ZSTD_LAZY_DDSS_BUCKET_LOG 2 + +#define ZSTD_ROW_HASH_TAG_BITS 8 /* nb bits to use for the tag */ + +#if !defined(ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip); +void ZSTD_row_update(ZSTD_matchState_t* const ms, const BYTE* ip); + +void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const BYTE* const ip); void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue); /*! used in ZSTD_reduceIndex(). preemptively increase value of ZSTD_DUBT_UNSORTED_MARK */ +#endif -size_t ZSTD_compressBlock_btlazy2( +#ifndef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR +size_t ZSTD_compressBlock_greedy( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy2( +size_t ZSTD_compressBlock_greedy_row( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy( +size_t ZSTD_compressBlock_greedy_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_greedy( +size_t ZSTD_compressBlock_greedy_dictMatchState_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_greedy_dedicatedDictSearch( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_greedy_extDict( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_greedy_extDict_row( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_btlazy2_dictMatchState( +#define ZSTD_COMPRESSBLOCK_GREEDY ZSTD_compressBlock_greedy +#define ZSTD_COMPRESSBLOCK_GREEDY_ROW ZSTD_compressBlock_greedy_row +#define ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE ZSTD_compressBlock_greedy_dictMatchState +#define ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE_ROW ZSTD_compressBlock_greedy_dictMatchState_row +#define ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH ZSTD_compressBlock_greedy_dedicatedDictSearch +#define ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH_ROW ZSTD_compressBlock_greedy_dedicatedDictSearch_row +#define ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT ZSTD_compressBlock_greedy_extDict +#define ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT_ROW ZSTD_compressBlock_greedy_extDict_row +#else +#define ZSTD_COMPRESSBLOCK_GREEDY NULL +#define ZSTD_COMPRESSBLOCK_GREEDY_ROW NULL +#define ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE NULL +#define ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE_ROW NULL +#define ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH NULL +#define ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH_ROW NULL +#define ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT NULL +#define ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT_ROW NULL +#endif + +#ifndef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR +size_t ZSTD_compressBlock_lazy( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy2_dictMatchState( +size_t ZSTD_compressBlock_lazy_row( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); size_t ZSTD_compressBlock_lazy_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_greedy_dictMatchState( +size_t ZSTD_compressBlock_lazy_dictMatchState_row( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); - -size_t ZSTD_compressBlock_greedy_extDict( +size_t ZSTD_compressBlock_lazy_dedicatedDictSearch( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); size_t ZSTD_compressBlock_lazy_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy_extDict_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); + +#define ZSTD_COMPRESSBLOCK_LAZY ZSTD_compressBlock_lazy +#define ZSTD_COMPRESSBLOCK_LAZY_ROW ZSTD_compressBlock_lazy_row +#define ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE ZSTD_compressBlock_lazy_dictMatchState +#define ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE_ROW ZSTD_compressBlock_lazy_dictMatchState_row +#define ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH ZSTD_compressBlock_lazy_dedicatedDictSearch +#define ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH_ROW ZSTD_compressBlock_lazy_dedicatedDictSearch_row +#define ZSTD_COMPRESSBLOCK_LAZY_EXTDICT ZSTD_compressBlock_lazy_extDict +#define ZSTD_COMPRESSBLOCK_LAZY_EXTDICT_ROW ZSTD_compressBlock_lazy_extDict_row +#else +#define ZSTD_COMPRESSBLOCK_LAZY NULL +#define ZSTD_COMPRESSBLOCK_LAZY_ROW NULL +#define ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE NULL +#define ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE_ROW NULL +#define ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH NULL +#define ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH_ROW NULL +#define ZSTD_COMPRESSBLOCK_LAZY_EXTDICT NULL +#define ZSTD_COMPRESSBLOCK_LAZY_EXTDICT_ROW NULL +#endif + +#ifndef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR +size_t ZSTD_compressBlock_lazy2( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy2_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy2_dictMatchState( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy2_dictMatchState_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); size_t ZSTD_compressBlock_lazy2_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); +size_t ZSTD_compressBlock_lazy2_extDict_row( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); + +#define ZSTD_COMPRESSBLOCK_LAZY2 ZSTD_compressBlock_lazy2 +#define ZSTD_COMPRESSBLOCK_LAZY2_ROW ZSTD_compressBlock_lazy2_row +#define ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE ZSTD_compressBlock_lazy2_dictMatchState +#define ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE_ROW ZSTD_compressBlock_lazy2_dictMatchState_row +#define ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH ZSTD_compressBlock_lazy2_dedicatedDictSearch +#define ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH_ROW ZSTD_compressBlock_lazy2_dedicatedDictSearch_row +#define ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT ZSTD_compressBlock_lazy2_extDict +#define ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT_ROW ZSTD_compressBlock_lazy2_extDict_row +#else +#define ZSTD_COMPRESSBLOCK_LAZY2 NULL +#define ZSTD_COMPRESSBLOCK_LAZY2_ROW NULL +#define ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE NULL +#define ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE_ROW NULL +#define ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH NULL +#define ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH_ROW NULL +#define ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT NULL +#define ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT_ROW NULL +#endif + +#ifndef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR +size_t ZSTD_compressBlock_btlazy2( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); +size_t ZSTD_compressBlock_btlazy2_dictMatchState( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); size_t ZSTD_compressBlock_btlazy2_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -} +#define ZSTD_COMPRESSBLOCK_BTLAZY2 ZSTD_compressBlock_btlazy2 +#define ZSTD_COMPRESSBLOCK_BTLAZY2_DICTMATCHSTATE ZSTD_compressBlock_btlazy2_dictMatchState +#define ZSTD_COMPRESSBLOCK_BTLAZY2_EXTDICT ZSTD_compressBlock_btlazy2_extDict +#else +#define ZSTD_COMPRESSBLOCK_BTLAZY2 NULL +#define ZSTD_COMPRESSBLOCK_BTLAZY2_DICTMATCHSTATE NULL +#define ZSTD_COMPRESSBLOCK_BTLAZY2_EXTDICT NULL +#endif + +} // namespace duckdb_zstd #endif /* ZSTD_LAZY_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_ldm.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_ldm.h index d2640c776..a389c64f2 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_ldm.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_ldm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,17 +11,18 @@ #ifndef ZSTD_LDM_H #define ZSTD_LDM_H + #include "zstd/compress/zstd_compress_internal.h" /* ldmParams_t, U32 */ #include "zstd.h" /* ZSTD_CCtx, size_t */ +namespace duckdb_zstd { + /*-************************************* * Long distance matching ***************************************/ #define ZSTD_LDM_DEFAULT_WINDOW_LOG ZSTD_WINDOWLOG_LIMIT_DEFAULT -namespace duckdb_zstd { - void ZSTD_ldm_fillHashTable( ldmState_t* state, const BYTE* ip, const BYTE* iend, ldmParams_t const* params); @@ -64,6 +65,7 @@ size_t ZSTD_ldm_generateSequences( */ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + ZSTD_paramSwitch_e useRowMatchFinder, void const* src, size_t srcSize); /** @@ -71,11 +73,17 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, * * Skip past `srcSize` bytes worth of sequences in `rawSeqStore`. * Avoids emitting matches less than `minMatch` bytes. - * Must be called for data with is not passed to ZSTD_ldm_blockCompress(). + * Must be called for data that is not passed to ZSTD_ldm_blockCompress(). */ void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch); +/* ZSTD_ldm_skipRawSeqStoreBytes(): + * Moves forward in rawSeqStore by nbBytes, updating fields 'pos' and 'posInSequence'. + * Not to be used in conjunction with ZSTD_ldm_skipSequences(). + * Must be called for data with is not passed to ZSTD_ldm_blockCompress(). + */ +void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes); /** ZSTD_ldm_getTableSize() : * Estimate the space needed for long distance matching tables or 0 if LDM is @@ -101,6 +109,6 @@ size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize); void ZSTD_ldm_adjustParameters(ldmParams_t* params, ZSTD_compressionParameters const* cParams); -} +} // namespace duckdb_zstd -#endif /* ZSTD_FAST_H */ +#endif /* ZSTD_LDM_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_ldm_geartab.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_ldm_geartab.h new file mode 100644 index 000000000..3d4b1daa1 --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_ldm_geartab.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_LDM_GEARTAB_H +#define ZSTD_LDM_GEARTAB_H + +#include "zstd/common/compiler.h" /* UNUSED_ATTR */ +#include "zstd/common/mem.h" /* U64 */ + +namespace duckdb_zstd { + +static UNUSED_ATTR const U64 ZSTD_ldm_gearTab[256] = { + 0xf5b8f72c5f77775c, 0x84935f266b7ac412, 0xb647ada9ca730ccc, + 0xb065bb4b114fb1de, 0x34584e7e8c3a9fd0, 0x4e97e17c6ae26b05, + 0x3a03d743bc99a604, 0xcecd042422c4044f, 0x76de76c58524259e, + 0x9c8528f65badeaca, 0x86563706e2097529, 0x2902475fa375d889, + 0xafb32a9739a5ebe6, 0xce2714da3883e639, 0x21eaf821722e69e, + 0x37b628620b628, 0x49a8d455d88caf5, 0x8556d711e6958140, + 0x4f7ae74fc605c1f, 0x829f0c3468bd3a20, 0x4ffdc885c625179e, + 0x8473de048a3daf1b, 0x51008822b05646b2, 0x69d75d12b2d1cc5f, + 0x8c9d4a19159154bc, 0xc3cc10f4abbd4003, 0xd06ddc1cecb97391, + 0xbe48e6e7ed80302e, 0x3481db31cee03547, 0xacc3f67cdaa1d210, + 0x65cb771d8c7f96cc, 0x8eb27177055723dd, 0xc789950d44cd94be, + 0x934feadc3700b12b, 0x5e485f11edbdf182, 0x1e2e2a46fd64767a, + 0x2969ca71d82efa7c, 0x9d46e9935ebbba2e, 0xe056b67e05e6822b, + 0x94d73f55739d03a0, 0xcd7010bdb69b5a03, 0x455ef9fcd79b82f4, + 0x869cb54a8749c161, 0x38d1a4fa6185d225, 0xb475166f94bbe9bb, + 0xa4143548720959f1, 0x7aed4780ba6b26ba, 0xd0ce264439e02312, + 0x84366d746078d508, 0xa8ce973c72ed17be, 0x21c323a29a430b01, + 0x9962d617e3af80ee, 0xab0ce91d9c8cf75b, 0x530e8ee6d19a4dbc, + 0x2ef68c0cf53f5d72, 0xc03a681640a85506, 0x496e4e9f9c310967, + 0x78580472b59b14a0, 0x273824c23b388577, 0x66bf923ad45cb553, + 0x47ae1a5a2492ba86, 0x35e304569e229659, 0x4765182a46870b6f, + 0x6cbab625e9099412, 0xddac9a2e598522c1, 0x7172086e666624f2, + 0xdf5003ca503b7837, 0x88c0c1db78563d09, 0x58d51865acfc289d, + 0x177671aec65224f1, 0xfb79d8a241e967d7, 0x2be1e101cad9a49a, + 0x6625682f6e29186b, 0x399553457ac06e50, 0x35dffb4c23abb74, + 0x429db2591f54aade, 0xc52802a8037d1009, 0x6acb27381f0b25f3, + 0xf45e2551ee4f823b, 0x8b0ea2d99580c2f7, 0x3bed519cbcb4e1e1, + 0xff452823dbb010a, 0x9d42ed614f3dd267, 0x5b9313c06257c57b, + 0xa114b8008b5e1442, 0xc1fe311c11c13d4b, 0x66e8763ea34c5568, + 0x8b982af1c262f05d, 0xee8876faaa75fbb7, 0x8a62a4d0d172bb2a, + 0xc13d94a3b7449a97, 0x6dbbba9dc15d037c, 0xc786101f1d92e0f1, + 0xd78681a907a0b79b, 0xf61aaf2962c9abb9, 0x2cfd16fcd3cb7ad9, + 0x868c5b6744624d21, 0x25e650899c74ddd7, 0xba042af4a7c37463, + 0x4eb1a539465a3eca, 0xbe09dbf03b05d5ca, 0x774e5a362b5472ba, + 0x47a1221229d183cd, 0x504b0ca18ef5a2df, 0xdffbdfbde2456eb9, + 0x46cd2b2fbee34634, 0xf2aef8fe819d98c3, 0x357f5276d4599d61, + 0x24a5483879c453e3, 0x88026889192b4b9, 0x28da96671782dbec, + 0x4ef37c40588e9aaa, 0x8837b90651bc9fb3, 0xc164f741d3f0e5d6, + 0xbc135a0a704b70ba, 0x69cd868f7622ada, 0xbc37ba89e0b9c0ab, + 0x47c14a01323552f6, 0x4f00794bacee98bb, 0x7107de7d637a69d5, + 0x88af793bb6f2255e, 0xf3c6466b8799b598, 0xc288c616aa7f3b59, + 0x81ca63cf42fca3fd, 0x88d85ace36a2674b, 0xd056bd3792389e7, + 0xe55c396c4e9dd32d, 0xbefb504571e6c0a6, 0x96ab32115e91e8cc, + 0xbf8acb18de8f38d1, 0x66dae58801672606, 0x833b6017872317fb, + 0xb87c16f2d1c92864, 0xdb766a74e58b669c, 0x89659f85c61417be, + 0xc8daad856011ea0c, 0x76a4b565b6fe7eae, 0xa469d085f6237312, + 0xaaf0365683a3e96c, 0x4dbb746f8424f7b8, 0x638755af4e4acc1, + 0x3d7807f5bde64486, 0x17be6d8f5bbb7639, 0x903f0cd44dc35dc, + 0x67b672eafdf1196c, 0xa676ff93ed4c82f1, 0x521d1004c5053d9d, + 0x37ba9ad09ccc9202, 0x84e54d297aacfb51, 0xa0b4b776a143445, + 0x820d471e20b348e, 0x1874383cb83d46dc, 0x97edeec7a1efe11c, + 0xb330e50b1bdc42aa, 0x1dd91955ce70e032, 0xa514cdb88f2939d5, + 0x2791233fd90db9d3, 0x7b670a4cc50f7a9b, 0x77c07d2a05c6dfa5, + 0xe3778b6646d0a6fa, 0xb39c8eda47b56749, 0x933ed448addbef28, + 0xaf846af6ab7d0bf4, 0xe5af208eb666e49, 0x5e6622f73534cd6a, + 0x297daeca42ef5b6e, 0x862daef3d35539a6, 0xe68722498f8e1ea9, + 0x981c53093dc0d572, 0xfa09b0bfbf86fbf5, 0x30b1e96166219f15, + 0x70e7d466bdc4fb83, 0x5a66736e35f2a8e9, 0xcddb59d2b7c1baef, + 0xd6c7d247d26d8996, 0xea4e39eac8de1ba3, 0x539c8bb19fa3aff2, + 0x9f90e4c5fd508d8, 0xa34e5956fbaf3385, 0x2e2f8e151d3ef375, + 0x173691e9b83faec1, 0xb85a8d56bf016379, 0x8382381267408ae3, + 0xb90f901bbdc0096d, 0x7c6ad32933bcec65, 0x76bb5e2f2c8ad595, + 0x390f851a6cf46d28, 0xc3e6064da1c2da72, 0xc52a0c101cfa5389, + 0xd78eaf84a3fbc530, 0x3781b9e2288b997e, 0x73c2f6dea83d05c4, + 0x4228e364c5b5ed7, 0x9d7a3edf0da43911, 0x8edcfeda24686756, + 0x5e7667a7b7a9b3a1, 0x4c4f389fa143791d, 0xb08bc1023da7cddc, + 0x7ab4be3ae529b1cc, 0x754e6132dbe74ff9, 0x71635442a839df45, + 0x2f6fb1643fbe52de, 0x961e0a42cf7a8177, 0xf3b45d83d89ef2ea, + 0xee3de4cf4a6e3e9b, 0xcd6848542c3295e7, 0xe4cee1664c78662f, + 0x9947548b474c68c4, 0x25d73777a5ed8b0b, 0xc915b1d636b7fc, + 0x21c2ba75d9b0d2da, 0x5f6b5dcf608a64a1, 0xdcf333255ff9570c, + 0x633b922418ced4ee, 0xc136dde0b004b34a, 0x58cc83b05d4b2f5a, + 0x5eb424dda28e42d2, 0x62df47369739cd98, 0xb4e0b42485e4ce17, + 0x16e1f0c1f9a8d1e7, 0x8ec3916707560ebf, 0x62ba6e2df2cc9db3, + 0xcbf9f4ff77d83a16, 0x78d9d7d07d2bbcc4, 0xef554ce1e02c41f4, + 0x8d7581127eccf94d, 0xa9b53336cb3c8a05, 0x38c42c0bf45c4f91, + 0x640893cdf4488863, 0x80ec34bc575ea568, 0x39f324f5b48eaa40, + 0xe9d9ed1f8eff527f, 0x9224fc058cc5a214, 0xbaba00b04cfe7741, + 0x309a9f120fcf52af, 0xa558f3ec65626212, 0x424bec8b7adabe2f, + 0x41622513a6aea433, 0xb88da2d5324ca798, 0xd287733b245528a4, + 0x9a44697e6d68aec3, 0x7b1093be2f49bb28, 0x50bbec632e3d8aad, + 0x6cd90723e1ea8283, 0x897b9e7431b02bf3, 0x219efdcb338a7047, + 0x3b0311f0a27c0656, 0xdb17bf91c0db96e7, 0x8cd4fd6b4e85a5b2, + 0xfab071054ba6409d, 0x40d6fe831fa9dfd9, 0xaf358debad7d791e, + 0xeb8d0e25a65e3e58, 0xbbcbd3df14e08580, 0xcf751f27ecdab2b, + 0x2b4da14f2613d8f4 +}; + +} // namespace duckdb_zstd + +#endif /* ZSTD_LDM_GEARTAB_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_opt.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_opt.h index b0d7bc3e2..e2d45826f 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_opt.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_opt.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,30 +15,40 @@ namespace duckdb_zstd { +#if !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR) \ + || !defined(ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR) /* used in ZSTD_loadDictionaryContent() */ void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend); +#endif +#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR size_t ZSTD_compressBlock_btopt( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_btultra( +size_t ZSTD_compressBlock_btopt_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_btultra2( +size_t ZSTD_compressBlock_btopt_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); +#define ZSTD_COMPRESSBLOCK_BTOPT ZSTD_compressBlock_btopt +#define ZSTD_COMPRESSBLOCK_BTOPT_DICTMATCHSTATE ZSTD_compressBlock_btopt_dictMatchState +#define ZSTD_COMPRESSBLOCK_BTOPT_EXTDICT ZSTD_compressBlock_btopt_extDict +#else +#define ZSTD_COMPRESSBLOCK_BTOPT NULL +#define ZSTD_COMPRESSBLOCK_BTOPT_DICTMATCHSTATE NULL +#define ZSTD_COMPRESSBLOCK_BTOPT_EXTDICT NULL +#endif -size_t ZSTD_compressBlock_btopt_dictMatchState( +#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR +size_t ZSTD_compressBlock_btultra( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); size_t ZSTD_compressBlock_btultra_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); - -size_t ZSTD_compressBlock_btopt_extDict( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); size_t ZSTD_compressBlock_btultra_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); @@ -46,7 +56,21 @@ size_t ZSTD_compressBlock_btultra_extDict( /* note : no btultra2 variant for extDict nor dictMatchState, * because btultra2 is not meant to work with dictionaries * and is only specific for the first block (no prefix) */ +size_t ZSTD_compressBlock_btultra2( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); + +#define ZSTD_COMPRESSBLOCK_BTULTRA ZSTD_compressBlock_btultra +#define ZSTD_COMPRESSBLOCK_BTULTRA_DICTMATCHSTATE ZSTD_compressBlock_btultra_dictMatchState +#define ZSTD_COMPRESSBLOCK_BTULTRA_EXTDICT ZSTD_compressBlock_btultra_extDict +#define ZSTD_COMPRESSBLOCK_BTULTRA2 ZSTD_compressBlock_btultra2 +#else +#define ZSTD_COMPRESSBLOCK_BTULTRA NULL +#define ZSTD_COMPRESSBLOCK_BTULTRA_DICTMATCHSTATE NULL +#define ZSTD_COMPRESSBLOCK_BTULTRA_EXTDICT NULL +#define ZSTD_COMPRESSBLOCK_BTULTRA2 NULL +#endif -} +} // namespace duckdb_zstd #endif /* ZSTD_OPT_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstdmt_compress.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstdmt_compress.h new file mode 100644 index 000000000..99f7757dd --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstdmt_compress.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + #ifndef ZSTDMT_COMPRESS_H + #define ZSTDMT_COMPRESS_H + +/* Note : This is an internal API. + * These APIs used to be exposed with ZSTDLIB_API, + * because it used to be the only way to invoke MT compression. + * Now, you must use ZSTD_compress2 and ZSTD_compressStream2() instead. + * + * This API requires ZSTD_MULTITHREAD to be defined during compilation, + * otherwise ZSTDMT_createCCtx*() will fail. + */ + +/* === Dependencies === */ +#include "zstd/common/zstd_deps.h" /* size_t */ +#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_parameters */ +#include "zstd.h" /* ZSTD_inBuffer, ZSTD_outBuffer, ZSTDLIB_API */ + +namespace duckdb_zstd { + +/* === Constants === */ +#ifndef ZSTDMT_NBWORKERS_MAX /* a different value can be selected at compile time */ +# define ZSTDMT_NBWORKERS_MAX ((sizeof(void*)==4) /*32-bit*/ ? 64 : 256) +#endif +#ifndef ZSTDMT_JOBSIZE_MIN /* a different value can be selected at compile time */ +# define ZSTDMT_JOBSIZE_MIN (512 KB) +#endif +#define ZSTDMT_JOBLOG_MAX (MEM_32bits() ? 29 : 30) +#define ZSTDMT_JOBSIZE_MAX (MEM_32bits() ? (512 MB) : (1024 MB)) + + +/* ======================================================== + * === Private interface, for use by ZSTD_compress.c === + * === Not exposed in libzstd. Never invoke directly === + * ======================================================== */ + +/* === Memory management === */ +typedef struct ZSTDMT_CCtx_s ZSTDMT_CCtx; +/* Requires ZSTD_MULTITHREAD to be defined during compilation, otherwise it will return NULL. */ +ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, + ZSTD_customMem cMem, + ZSTD_threadPool *pool); +size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx); + +size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx); + +/* === Streaming functions === */ + +size_t ZSTDMT_nextInputSizeHint(const ZSTDMT_CCtx* mtctx); + +/*! ZSTDMT_initCStream_internal() : + * Private use only. Init streaming operation. + * expects params to be valid. + * must receive dict, or cdict, or none, but not both. + * mtctx can be freshly constructed or reused from a prior compression. + * If mtctx is reused, memory allocations from the prior compression may not be freed, + * even if they are not needed for the current compression. + * @return : 0, or an error code */ +size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* mtctx, + const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, + const ZSTD_CDict* cdict, + ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); + +/*! ZSTDMT_compressStream_generic() : + * Combines ZSTDMT_compressStream() with optional ZSTDMT_flushStream() or ZSTDMT_endStream() + * depending on flush directive. + * @return : minimum amount of data still to be flushed + * 0 if fully flushed + * or an error code + * note : needs to be init using any ZSTD_initCStream*() variant */ +size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, + ZSTD_outBuffer* output, + ZSTD_inBuffer* input, + ZSTD_EndDirective endOp); + + /*! ZSTDMT_toFlushNow() + * Tell how many bytes are ready to be flushed immediately. + * Probe the oldest active job (not yet entirely flushed) and check its output buffer. + * If return 0, it means there is no active job, + * or, it means oldest job is still active, but everything produced has been flushed so far, + * therefore flushing is limited by speed of oldest job. */ +size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx); + +/*! ZSTDMT_updateCParams_whileCompressing() : + * Updates only a selected set of compression parameters, to remain compatible with current frame. + * New parameters will be applied to next compression job. */ +void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_params* cctxParams); + +/*! ZSTDMT_getFrameProgression(): + * tells how much data has been consumed (input) and produced (output) for current frame. + * able to count progression inside worker threads. + */ +ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx); + + +} // namespace duckdb_zstd + +#endif /* ZSTDMT_COMPRESS_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_ddict.h b/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_ddict.h index a95f384fb..7dc647936 100644 --- a/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_ddict.h +++ b/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_ddict.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,10 +15,11 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include /* size_t */ +#include "zstd/common/zstd_deps.h" /* size_t */ #include "zstd.h" /* ZSTD_DDict, and several public functions */ namespace duckdb_zstd { + /*-******************************************************* * Interface *********************************************************/ @@ -39,6 +40,6 @@ size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict); void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); -} +} // namespace duckdb_zstd #endif /* ZSTD_DDICT_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_decompress_block.h b/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_decompress_block.h index 46d4a2103..7131a0d95 100644 --- a/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_decompress_block.h +++ b/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_decompress_block.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,7 +15,7 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include /* size_t */ +#include "zstd/common/zstd_deps.h" /* size_t */ #include "zstd.h" /* DCtx, and some public functions */ #include "zstd/common/zstd_internal.h" /* blockProperties_t, and some public functions */ #include "zstd/decompress/zstd_decompress_internal.h" /* ZSTD_seqSymbol */ @@ -34,6 +34,12 @@ namespace duckdb_zstd { */ + /* Streaming state is used to inform allocation of the literal buffer */ +typedef enum { + not_streaming = 0, + is_streaming = 1 +} streaming_operation; + /* ZSTD_decompressBlock_internal() : * decompress block, starting at `src`, * into destination buffer `dst`. @@ -42,20 +48,28 @@ namespace duckdb_zstd { */ size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, - const void* src, size_t srcSize, const int frame); + const void* src, size_t srcSize, const streaming_operation streaming); /* ZSTD_buildFSETable() : * generate FSE decoding table for one symbol (ll, ml or off) * this function must be called with valid parameters only * (dt is large enough, normalizedCounter distribution total is a power of 2, max is within range, etc.) * in which case it cannot fail. + * The workspace must be 4-byte aligned and at least ZSTD_BUILD_FSE_TABLE_WKSP_SIZE bytes, which is + * defined in zstd_decompress_internal.h. * Internal use only. */ void ZSTD_buildFSETable(ZSTD_seqSymbol* dt, const short* normalizedCounter, unsigned maxSymbolValue, - const U32* baseValue, const U32* nbAdditionalBits, - unsigned tableLog); + const U32* baseValue, const U8* nbAdditionalBits, + unsigned tableLog, void* wksp, size_t wkspSize, + int bmi2); + +/* Internal definition of ZSTD_decompressBlock() to avoid deprecation warnings. */ +size_t ZSTD_decompressBlock_deprecated(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize); -} +} // namespace duckdb_zstd #endif /* ZSTD_DEC_BLOCK_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_decompress_internal.h b/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_decompress_internal.h index 6ff422e2c..0f7e198e1 100644 --- a/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_decompress_internal.h +++ b/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_decompress_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -20,19 +20,40 @@ * Dependencies *********************************************************/ #include "zstd/common/mem.h" /* BYTE, U16, U32 */ -#include "zstd/common/zstd_internal.h" /* ZSTD_seqSymbol */ +#include "zstd/common/zstd_internal.h" /* constants : MaxLL, MaxML, MaxOff, LLFSELog, etc. */ namespace duckdb_zstd { /*-******************************************************* * Constants *********************************************************/ -struct ZSTDConstants { - static const U32 LL_base[MaxLL+1]; - static const U32 OF_base[MaxOff+1]; - static const U32 OF_bits[MaxOff+1]; - static const U32 ML_base[MaxML+1]; -}; +static UNUSED_ATTR const U32 LL_base[MaxLL+1] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 18, 20, 22, 24, 28, 32, 40, + 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, + 0x2000, 0x4000, 0x8000, 0x10000 }; + +static UNUSED_ATTR const U32 OF_base[MaxOff+1] = { + 0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, + 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD, + 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, + 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD }; + +static UNUSED_ATTR const U8 OF_bits[MaxOff+1] = { + 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 }; + +static UNUSED_ATTR const U32 ML_base[MaxML+1] = { + 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, 37, 39, 41, 43, 47, 51, 59, + 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803, + 0x1003, 0x2003, 0x4003, 0x8003, 0x10003 }; /*-******************************************************* @@ -52,12 +73,17 @@ struct ZSTDConstants { #define SEQSYMBOL_TABLE_SIZE(log) (1 + (1 << (log))) +#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE (sizeof(S16) * (MaxSeq + 1) + (1u << MaxFSELog) + sizeof(U64)) +#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32 ((ZSTD_BUILD_FSE_TABLE_WKSP_SIZE + sizeof(U32) - 1) / sizeof(U32)) +#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 + typedef struct { ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)]; /* Note : Space reserved for FSE Tables */ ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)]; /* is also used as temporary workspace while building hufTable during DDict creation */ ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)]; /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */ - HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */ + HUF_DTable hufTable[HUF_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; /* can accommodate HUF_decompress4X */ U32 rep[ZSTD_REP_NUM]; + U32 workspace[ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32]; } ZSTD_entropyDTables_t; typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader, @@ -74,10 +100,28 @@ typedef enum { ZSTD_use_once = 1 /* Use the dictionary once and set to ZSTD_dont_use */ } ZSTD_dictUses_e; +/* Hashset for storing references to multiple ZSTD_DDict within ZSTD_DCtx */ +typedef struct { + const ZSTD_DDict** ddictPtrTable; + size_t ddictPtrTableSize; + size_t ddictPtrCount; +} ZSTD_DDictHashSet; + +#ifndef ZSTD_DECODER_INTERNAL_BUFFER +# define ZSTD_DECODER_INTERNAL_BUFFER (1 << 16) +#endif + +#define ZSTD_LBMIN 64 +#define ZSTD_LBMAX (128 << 10) + +/* extra buffer, compensates when dst is not large enough to store litBuffer */ +#define ZSTD_LITBUFFEREXTRASIZE BOUNDED(ZSTD_LBMIN, ZSTD_DECODER_INTERNAL_BUFFER, ZSTD_LBMAX) + typedef enum { - ZSTD_obm_buffered = 0, /* Buffer the output */ - ZSTD_obm_stable = 1 /* ZSTD_outBuffer is stable */ -} ZSTD_outBufferMode_e; + ZSTD_not_in_dst = 0, /* Stored entirely within litExtraBuffer */ + ZSTD_in_dst = 1, /* Stored entirely within dst (in memory after current output write) */ + ZSTD_split = 2 /* Split between litExtraBuffer and dst */ +} ZSTD_litLocation_e; struct ZSTD_DCtx_s { @@ -93,6 +137,7 @@ struct ZSTD_DCtx_s const void* dictEnd; /* end of previous segment */ size_t expected; ZSTD_frameHeader fParams; + U64 processedCSize; U64 decodedSize; blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */ ZSTD_dStage stage; @@ -101,12 +146,17 @@ struct ZSTD_DCtx_s XXH64_state_t xxhState; size_t headerSize; ZSTD_format_e format; + ZSTD_forceIgnoreChecksum_e forceIgnoreChecksum; /* User specified: if == 1, will ignore checksums in compressed frame. Default == 0 */ + U32 validateChecksum; /* if == 1, will validate checksum. Is == 1 if (fParams.checksumFlag == 1) and (forceIgnoreChecksum == 0). */ const BYTE* litPtr; ZSTD_customMem customMem; size_t litSize; size_t rleSize; size_t staticSize; + int isFrameDecompression; +#if DYNAMIC_BMI2 != 0 int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */ +#endif /* dictionary */ ZSTD_DDict* ddictLocal; @@ -114,6 +164,10 @@ struct ZSTD_DCtx_s U32 dictID; int ddictIsCold; /* if == 1 : dictionary is "new" for working context, and presumed "cold" (not in cpu cache) */ ZSTD_dictUses_e dictUses; + ZSTD_DDictHashSet* ddictSet; /* Hash set for multiple ddicts */ + ZSTD_refMultipleDDicts_e refMultipleDDicts; /* User specified: if == 1, will allow references to multiple DDicts. Default == 0 (disabled) */ + int disableHufAsm; + int maxBlockSizeParam; /* streaming */ ZSTD_dStreamStage streamStage; @@ -126,16 +180,21 @@ struct ZSTD_DCtx_s size_t outStart; size_t outEnd; size_t lhSize; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) void* legacyContext; U32 previousLegacyVersion; U32 legacyVersion; +#endif U32 hostageByte; int noForwardProgress; - ZSTD_outBufferMode_e outBufferMode; + ZSTD_bufferMode_e outBufferMode; ZSTD_outBuffer expectedOutBuffer; /* workspace */ - BYTE litBuffer[ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH]; + BYTE* litBuffer; + const BYTE* litBufferEnd; + ZSTD_litLocation_e litBufferLocation; + BYTE litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE + WILDCOPY_OVERLENGTH]; /* literal buffer can be split between storage within dst and within this scratch buffer */ BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; size_t oversizedDuration; @@ -144,8 +203,21 @@ struct ZSTD_DCtx_s void const* dictContentBeginForFuzzing; void const* dictContentEndForFuzzing; #endif + + /* Tracing */ +#if ZSTD_TRACE + ZSTD_TraceCtx traceCtx; +#endif }; /* typedef'd to ZSTD_DCtx within "zstd.h" */ +MEM_STATIC int ZSTD_DCtx_get_bmi2(const struct ZSTD_DCtx_s *dctx) { +#if DYNAMIC_BMI2 != 0 + return dctx->bmi2; +#else + (void)dctx; + return 0; +#endif +} /*-******************************************************* * Shared internal functions @@ -162,8 +234,8 @@ size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, * If yes, do nothing (continue on current segment). * If not, classify previous segment as "external dictionary", and start a new segment. * This function cannot fail. */ -void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst); +void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize); -} +} // namespace duckdb_zstd #endif /* ZSTD_DECOMPRESS_INTERNAL_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/deprecated/zbuff.h b/src/duckdb/third_party/zstd/include/zstd/deprecated/zbuff.h new file mode 100644 index 000000000..04c75ef1a --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd/deprecated/zbuff.h @@ -0,0 +1,214 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* *************************************************************** +* NOTES/WARNINGS +******************************************************************/ +/* The streaming API defined here is deprecated. + * Consider migrating towards ZSTD_compressStream() API in `zstd.h` + * See 'lib/README.md'. + *****************************************************************/ + +#ifndef ZSTD_BUFFERED_H_23987 +#define ZSTD_BUFFERED_H_23987 + +/* ************************************* +* Dependencies +***************************************/ +// DuckDB: just enable everything +#define ZSTD_STATIC_LINKING_ONLY + +#include /* size_t */ +#include "zstd.h" /* ZSTD_CStream, ZSTD_DStream, ZSTDLIB_API */ + +namespace duckdb_zstd { + +/* *************************************************************** +* Compiler specifics +*****************************************************************/ +/* Deprecation warnings */ +/* Should these warnings be a problem, + * it is generally possible to disable them, + * typically with -Wno-deprecated-declarations for gcc + * or _CRT_SECURE_NO_WARNINGS in Visual. + * Otherwise, it's also possible to define ZBUFF_DISABLE_DEPRECATE_WARNINGS + */ +#ifdef ZBUFF_DISABLE_DEPRECATE_WARNINGS +# define ZBUFF_DEPRECATED(message) ZSTDLIB_API /* disable deprecation warnings */ +#else +# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ +# define ZBUFF_DEPRECATED(message) [[deprecated(message)]] ZSTDLIB_API +# elif (defined(GNUC) && (GNUC > 4 || (GNUC == 4 && GNUC_MINOR >= 5))) || defined(__clang__) +# define ZBUFF_DEPRECATED(message) ZSTDLIB_API __attribute__((deprecated(message))) +# elif defined(__GNUC__) && (__GNUC__ >= 3) +# define ZBUFF_DEPRECATED(message) ZSTDLIB_API __attribute__((deprecated)) +# elif defined(_MSC_VER) +# define ZBUFF_DEPRECATED(message) ZSTDLIB_API __declspec(deprecated(message)) +# else +# pragma message("WARNING: You need to implement ZBUFF_DEPRECATED for this compiler") +# define ZBUFF_DEPRECATED(message) ZSTDLIB_API +# endif +#endif /* ZBUFF_DISABLE_DEPRECATE_WARNINGS */ + + +/* ************************************* +* Streaming functions +***************************************/ +/* This is the easier "buffered" streaming API, +* using an internal buffer to lift all restrictions on user-provided buffers +* which can be any size, any place, for both input and output. +* ZBUFF and ZSTD are 100% interoperable, +* frames created by one can be decoded by the other one */ + +typedef ZSTD_CStream ZBUFF_CCtx; +ZBUFF_DEPRECATED("use ZSTD_createCStream") ZBUFF_CCtx* ZBUFF_createCCtx(void); +ZBUFF_DEPRECATED("use ZSTD_freeCStream") size_t ZBUFF_freeCCtx(ZBUFF_CCtx* cctx); + +ZBUFF_DEPRECATED("use ZSTD_initCStream") size_t ZBUFF_compressInit(ZBUFF_CCtx* cctx, int compressionLevel); +ZBUFF_DEPRECATED("use ZSTD_initCStream_usingDict") size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); + +ZBUFF_DEPRECATED("use ZSTD_compressStream") size_t ZBUFF_compressContinue(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr, const void* src, size_t* srcSizePtr); +ZBUFF_DEPRECATED("use ZSTD_flushStream") size_t ZBUFF_compressFlush(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr); +ZBUFF_DEPRECATED("use ZSTD_endStream") size_t ZBUFF_compressEnd(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr); + +/*-************************************************* +* Streaming compression - howto +* +* A ZBUFF_CCtx object is required to track streaming operation. +* Use ZBUFF_createCCtx() and ZBUFF_freeCCtx() to create/release resources. +* ZBUFF_CCtx objects can be reused multiple times. +* +* Start by initializing ZBUF_CCtx. +* Use ZBUFF_compressInit() to start a new compression operation. +* Use ZBUFF_compressInitDictionary() for a compression which requires a dictionary. +* +* Use ZBUFF_compressContinue() repetitively to consume input stream. +* *srcSizePtr and *dstCapacityPtr can be any size. +* The function will report how many bytes were read or written within *srcSizePtr and *dstCapacityPtr. +* Note that it may not consume the entire input, in which case it's up to the caller to present again remaining data. +* The content of `dst` will be overwritten (up to *dstCapacityPtr) at each call, so save its content if it matters or change @dst . +* @return : a hint to preferred nb of bytes to use as input for next function call (it's just a hint, to improve latency) +* or an error code, which can be tested using ZBUFF_isError(). +* +* At any moment, it's possible to flush whatever data remains within buffer, using ZBUFF_compressFlush(). +* The nb of bytes written into `dst` will be reported into *dstCapacityPtr. +* Note that the function cannot output more than *dstCapacityPtr, +* therefore, some content might still be left into internal buffer if *dstCapacityPtr is too small. +* @return : nb of bytes still present into internal buffer (0 if it's empty) +* or an error code, which can be tested using ZBUFF_isError(). +* +* ZBUFF_compressEnd() instructs to finish a frame. +* It will perform a flush and write frame epilogue. +* The epilogue is required for decoders to consider a frame completed. +* Similar to ZBUFF_compressFlush(), it may not be able to output the entire internal buffer content if *dstCapacityPtr is too small. +* In which case, call again ZBUFF_compressFlush() to complete the flush. +* @return : nb of bytes still present into internal buffer (0 if it's empty) +* or an error code, which can be tested using ZBUFF_isError(). +* +* Hint : _recommended buffer_ sizes (not compulsory) : ZBUFF_recommendedCInSize() / ZBUFF_recommendedCOutSize() +* input : ZBUFF_recommendedCInSize==128 KB block size is the internal unit, use this value to reduce intermediate stages (better latency) +* output : ZBUFF_recommendedCOutSize==ZSTD_compressBound(128 KB) + 3 + 3 : ensures it's always possible to write/flush/end a full block. Skip some buffering. +* By using both, it ensures that input will be entirely consumed, and output will always contain the result, reducing intermediate buffering. +* **************************************************/ + + +typedef ZSTD_DStream ZBUFF_DCtx; +ZBUFF_DEPRECATED("use ZSTD_createDStream") ZBUFF_DCtx* ZBUFF_createDCtx(void); +ZBUFF_DEPRECATED("use ZSTD_freeDStream") size_t ZBUFF_freeDCtx(ZBUFF_DCtx* dctx); + +ZBUFF_DEPRECATED("use ZSTD_initDStream") size_t ZBUFF_decompressInit(ZBUFF_DCtx* dctx); +ZBUFF_DEPRECATED("use ZSTD_initDStream_usingDict") size_t ZBUFF_decompressInitDictionary(ZBUFF_DCtx* dctx, const void* dict, size_t dictSize); + +ZBUFF_DEPRECATED("use ZSTD_decompressStream") size_t ZBUFF_decompressContinue(ZBUFF_DCtx* dctx, + void* dst, size_t* dstCapacityPtr, + const void* src, size_t* srcSizePtr); + +/*-*************************************************************************** +* Streaming decompression howto +* +* A ZBUFF_DCtx object is required to track streaming operations. +* Use ZBUFF_createDCtx() and ZBUFF_freeDCtx() to create/release resources. +* Use ZBUFF_decompressInit() to start a new decompression operation, +* or ZBUFF_decompressInitDictionary() if decompression requires a dictionary. +* Note that ZBUFF_DCtx objects can be re-init multiple times. +* +* Use ZBUFF_decompressContinue() repetitively to consume your input. +* *srcSizePtr and *dstCapacityPtr can be any size. +* The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr. +* Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again. +* The content of `dst` will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters, or change `dst`. +* @return : 0 when a frame is completely decoded and fully flushed, +* 1 when there is still some data left within internal buffer to flush, +* >1 when more data is expected, with value being a suggested next input size (it's just a hint, which helps latency), +* or an error code, which can be tested using ZBUFF_isError(). +* +* Hint : recommended buffer sizes (not compulsory) : ZBUFF_recommendedDInSize() and ZBUFF_recommendedDOutSize() +* output : ZBUFF_recommendedDOutSize== 128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded. +* input : ZBUFF_recommendedDInSize == 128KB + 3; +* just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 . +* *******************************************************************************/ + + +/* ************************************* +* Tool functions +***************************************/ +ZBUFF_DEPRECATED("use ZSTD_isError") unsigned ZBUFF_isError(size_t errorCode); +ZBUFF_DEPRECATED("use ZSTD_getErrorName") const char* ZBUFF_getErrorName(size_t errorCode); + +/** Functions below provide recommended buffer sizes for Compression or Decompression operations. +* These sizes are just hints, they tend to offer better latency */ +ZBUFF_DEPRECATED("use ZSTD_CStreamInSize") size_t ZBUFF_recommendedCInSize(void); +ZBUFF_DEPRECATED("use ZSTD_CStreamOutSize") size_t ZBUFF_recommendedCOutSize(void); +ZBUFF_DEPRECATED("use ZSTD_DStreamInSize") size_t ZBUFF_recommendedDInSize(void); +ZBUFF_DEPRECATED("use ZSTD_DStreamOutSize") size_t ZBUFF_recommendedDOutSize(void); + +} // namespace duckdb_zstd + +#endif /* ZSTD_BUFFERED_H_23987 */ + +#ifdef ZBUFF_STATIC_LINKING_ONLY +# ifndef ZBUFF_STATIC_H_30298098432 +# define ZBUFF_STATIC_H_30298098432 + +/* ==================================================================================== + * The definitions in this section are considered experimental. + * They should never be used in association with a dynamic library, as they may change in the future. + * They are provided for advanced usages. + * Use them only in association with static linking. + * ==================================================================================== */ + + +/*--- Dependency ---*/ +// DuckDB: comment out otherwise amalgamation won't be happy +// # define ZSTD_STATIC_LINKING_ONLY /* ZSTD_parameters, ZSTD_customMem */ +// #include "zstd.h" + +namespace duckdb_zstd { + +/*--- Custom memory allocator ---*/ +/*! ZBUFF_createCCtx_advanced() : + * Create a ZBUFF compression context using external alloc and free functions */ +ZBUFF_DEPRECATED("use ZSTD_createCStream_advanced") ZBUFF_CCtx* ZBUFF_createCCtx_advanced(ZSTD_customMem customMem); + +/*! ZBUFF_createDCtx_advanced() : + * Create a ZBUFF decompression context using external alloc and free functions */ +ZBUFF_DEPRECATED("use ZSTD_createDStream_advanced") ZBUFF_DCtx* ZBUFF_createDCtx_advanced(ZSTD_customMem customMem); + + +/*--- Advanced Streaming Initialization ---*/ +ZBUFF_DEPRECATED("use ZSTD_initDStream_usingDict") size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, + const void* dict, size_t dictSize, + ZSTD_parameters params, unsigned long long pledgedSrcSize); + +} // namespace duckdb_zstd + +# endif /* ZBUFF_STATIC_H_30298098432 */ +#endif /* ZBUFF_STATIC_LINKING_ONLY */ + diff --git a/src/duckdb/third_party/zstd/include/zstd/dict/cover.h b/src/duckdb/third_party/zstd/include/zstd/dict/cover.h new file mode 100644 index 000000000..dd458ce58 --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd/dict/cover.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZDICT_STATIC_LINKING_ONLY +# define ZDICT_STATIC_LINKING_ONLY +#endif + +#include "zstd/common/threading.h" /* ZSTD_pthread_mutex_t */ +#include "zstd/common/mem.h" /* U32, BYTE */ +#include "zdict.h" + +namespace duckdb_zstd { + +/** + * COVER_best_t is used for two purposes: + * 1. Synchronizing threads. + * 2. Saving the best parameters and dictionary. + * + * All of the methods except COVER_best_init() are thread safe if zstd is + * compiled with multithreaded support. + */ +typedef struct COVER_best_s { + ZSTD_pthread_mutex_t mutex; + ZSTD_pthread_cond_t cond; + size_t liveJobs; + void *dict; + size_t dictSize; + ZDICT_cover_params_t parameters; + size_t compressedSize; +} COVER_best_t; + +/** + * A segment is a range in the source as well as the score of the segment. + */ +typedef struct { + U32 begin; + U32 end; + U32 score; +} COVER_segment_t; + +/** + *Number of epochs and size of each epoch. + */ +typedef struct { + U32 num; + U32 size; +} COVER_epoch_info_t; + +/** + * Struct used for the dictionary selection function. + */ +typedef struct COVER_dictSelection { + BYTE* dictContent; + size_t dictSize; + size_t totalCompressedSize; +} COVER_dictSelection_t; + +/** + * Computes the number of epochs and the size of each epoch. + * We will make sure that each epoch gets at least 10 * k bytes. + * + * The COVER algorithms divide the data up into epochs of equal size and + * select one segment from each epoch. + * + * @param maxDictSize The maximum allowed dictionary size. + * @param nbDmers The number of dmers we are training on. + * @param k The parameter k (segment size). + * @param passes The target number of passes over the dmer corpus. + * More passes means a better dictionary. + */ +COVER_epoch_info_t COVER_computeEpochs(U32 maxDictSize, U32 nbDmers, + U32 k, U32 passes); + +/** + * Warns the user when their corpus is too small. + */ +void COVER_warnOnSmallCorpus(size_t maxDictSize, size_t nbDmers, int displayLevel); + +/** + * Checks total compressed size of a dictionary + */ +size_t COVER_checkTotalCompressedSize(const ZDICT_cover_params_t parameters, + const size_t *samplesSizes, const BYTE *samples, + size_t *offsets, + size_t nbTrainSamples, size_t nbSamples, + BYTE *const dict, size_t dictBufferCapacity); + +/** + * Returns the sum of the sample sizes. + */ +size_t COVER_sum(const size_t *samplesSizes, unsigned nbSamples) ; + +/** + * Initialize the `COVER_best_t`. + */ +void COVER_best_init(COVER_best_t *best); + +/** + * Wait until liveJobs == 0. + */ +void COVER_best_wait(COVER_best_t *best); + +/** + * Call COVER_best_wait() and then destroy the COVER_best_t. + */ +void COVER_best_destroy(COVER_best_t *best); + +/** + * Called when a thread is about to be launched. + * Increments liveJobs. + */ +void COVER_best_start(COVER_best_t *best); + +/** + * Called when a thread finishes executing, both on error or success. + * Decrements liveJobs and signals any waiting threads if liveJobs == 0. + * If this dictionary is the best so far save it and its parameters. + */ +void COVER_best_finish(COVER_best_t *best, ZDICT_cover_params_t parameters, + COVER_dictSelection_t selection); +/** + * Error function for COVER_selectDict function. Checks if the return + * value is an error. + */ +unsigned COVER_dictSelectionIsError(COVER_dictSelection_t selection); + + /** + * Error function for COVER_selectDict function. Returns a struct where + * return.totalCompressedSize is a ZSTD error. + */ +COVER_dictSelection_t COVER_dictSelectionError(size_t error); + +/** + * Always call after selectDict is called to free up used memory from + * newly created dictionary. + */ +void COVER_dictSelectionFree(COVER_dictSelection_t selection); + +/** + * Called to finalize the dictionary and select one based on whether or not + * the shrink-dict flag was enabled. If enabled the dictionary used is the + * smallest dictionary within a specified regression of the compressed size + * from the largest dictionary. + */ + COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBufferCapacity, + size_t dictContentSize, const BYTE* samplesBuffer, const size_t* samplesSizes, unsigned nbFinalizeSamples, + size_t nbCheckSamples, size_t nbSamples, ZDICT_cover_params_t params, size_t* offsets, size_t totalCompressedSize); + +} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/include/zstd/dict/divsufsort.h b/src/duckdb/third_party/zstd/include/zstd/dict/divsufsort.h new file mode 100644 index 000000000..4f7cbdee8 --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd/dict/divsufsort.h @@ -0,0 +1,62 @@ +/* + * divsufsort.h for libdivsufsort-lite + * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _DIVSUFSORT_H +#define _DIVSUFSORT_H 1 + +namespace duckdb_zstd { + +/*- Prototypes -*/ + +/** + * Constructs the suffix array of a given string. + * @param T [0..n-1] The input string. + * @param SA [0..n-1] The output array of suffixes. + * @param n The length of the given string. + * @param openMP enables OpenMP optimization. + * @return 0 if no error occurred, -1 or -2 otherwise. + */ +int +divsufsort(const unsigned char *T, int *SA, int n, int openMP); + +/** + * Constructs the burrows-wheeler transformed string of a given string. + * @param T [0..n-1] The input string. + * @param U [0..n-1] The output string. (can be T) + * @param A [0..n-1] The temporary array. (can be NULL) + * @param n The length of the given string. + * @param num_indexes The length of secondary indexes array. (can be NULL) + * @param indexes The secondary indexes array. (can be NULL) + * @param openMP enables OpenMP optimization. + * @return The primary index if no error occurred, -1 or -2 otherwise. + */ +int +divbwt(const unsigned char *T, unsigned char *U, int *A, int n, unsigned char * num_indexes, int * indexes, int openMP); + + +} // namespace duckdb_zstd + +#endif /* _DIVSUFSORT_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/zstd_errors.h b/src/duckdb/third_party/zstd/include/zstd_errors.h similarity index 73% rename from src/duckdb/third_party/zstd/include/zstd/common/zstd_errors.h rename to src/duckdb/third_party/zstd/include/zstd_errors.h index a719982bc..401f67004 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/zstd_errors.h +++ b/src/duckdb/third_party/zstd/include/zstd_errors.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,23 +14,36 @@ /*===== dependency =====*/ #include /* size_t */ +namespace duckdb_zstd { /* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */ -#ifndef ZSTDERRORLIB_VISIBILITY -# if defined(__GNUC__) && (__GNUC__ >= 4) -# define ZSTDERRORLIB_VISIBILITY __attribute__ ((visibility ("default"))) +#ifndef ZSTDERRORLIB_VISIBLE + /* Backwards compatibility with old macro name */ +# ifdef ZSTDERRORLIB_VISIBILITY +# define ZSTDERRORLIB_VISIBLE ZSTDERRORLIB_VISIBILITY +# elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) +# define ZSTDERRORLIB_VISIBLE __attribute__ ((visibility ("default"))) +# else +# define ZSTDERRORLIB_VISIBLE +# endif +#endif + +#ifndef ZSTDERRORLIB_HIDDEN +# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) +# define ZSTDERRORLIB_HIDDEN __attribute__ ((visibility ("hidden"))) # else -# define ZSTDERRORLIB_VISIBILITY +# define ZSTDERRORLIB_HIDDEN # endif #endif + #if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) -# define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBILITY +# define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBLE #elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) -# define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +# define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ #else -# define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBILITY +# define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBLE #endif -namespace duckdb_zstd { + /*-********************************************* * Error codes list *-********************************************* @@ -54,14 +67,17 @@ typedef enum { ZSTD_error_frameParameter_windowTooLarge = 16, ZSTD_error_corruption_detected = 20, ZSTD_error_checksum_wrong = 22, + ZSTD_error_literals_headerWrong = 24, ZSTD_error_dictionary_corrupted = 30, ZSTD_error_dictionary_wrong = 32, ZSTD_error_dictionaryCreation_failed = 34, ZSTD_error_parameter_unsupported = 40, + ZSTD_error_parameter_combination_unsupported = 41, ZSTD_error_parameter_outOfBound = 42, ZSTD_error_tableLog_tooLarge = 44, ZSTD_error_maxSymbolValue_tooLarge = 46, ZSTD_error_maxSymbolValue_tooSmall = 48, + ZSTD_error_stabilityCondition_notRespected = 50, ZSTD_error_stage_wrong = 60, ZSTD_error_init_missing = 62, ZSTD_error_memory_allocation = 64, @@ -69,10 +85,15 @@ typedef enum { ZSTD_error_dstSize_tooSmall = 70, ZSTD_error_srcSize_wrong = 72, ZSTD_error_dstBuffer_null = 74, + ZSTD_error_noForwardProgress_destFull = 80, + ZSTD_error_noForwardProgress_inputEmpty = 82, /* following error codes are __NOT STABLE__, they can be removed or changed in future versions */ ZSTD_error_frameIndex_tooLarge = 100, ZSTD_error_seekableIO = 102, ZSTD_error_dstBuffer_wrong = 104, + ZSTD_error_srcBuffer_wrong = 105, + ZSTD_error_sequenceProducer_failed = 106, + ZSTD_error_externalSequences_invalid = 107, ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */ } ZSTD_ErrorCode; @@ -82,6 +103,7 @@ typedef enum { ZSTDERRORLIB_API ZSTD_ErrorCode ZSTD_getErrorCode(size_t functionResult); ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); /**< Same as ZSTD_getErrorName, but using a `ZSTD_ErrorCode` enum argument */ -} + +} // namespace duckdb_zstd #endif /* ZSTD_ERRORS_H_398273423 */ diff --git a/src/duckdb/third_party/zstd/include/zstd_static.h b/src/duckdb/third_party/zstd/include/zstd_static.h deleted file mode 100644 index 2c31f3d36..000000000 --- a/src/duckdb/third_party/zstd/include/zstd_static.h +++ /dev/null @@ -1,1070 +0,0 @@ - -/* ************************************************************************************** - * ADVANCED AND EXPERIMENTAL FUNCTIONS - **************************************************************************************** - * The definitions in the following section are considered experimental. - * They are provided for advanced scenarios. - * They should never be used with a dynamic library, as prototypes may change in the future. - * Use them only in association with static linking. - * ***************************************************************************************/ - -#ifndef ZSTD_H_ZSTD_STATIC_LINKING_ONLY -#define ZSTD_H_ZSTD_STATIC_LINKING_ONLY - -namespace duckdb_zstd { - -/**************************************************************************************** - * experimental API (static linking only) - **************************************************************************************** - * The following symbols and constants - * are not planned to join "stable API" status in the near future. - * They can still change in future versions. - * Some of them are planned to remain in the static_only section indefinitely. - * Some of them might be removed in the future (especially when redundant with existing stable functions) - * ***************************************************************************************/ - -#define ZSTD_FRAMEHEADERSIZE_PREFIX(format) ((format) == ZSTD_f_zstd1 ? 5 : 1) /* minimum input size required to query frame header size */ -#define ZSTD_FRAMEHEADERSIZE_MIN(format) ((format) == ZSTD_f_zstd1 ? 6 : 2) -#define ZSTD_FRAMEHEADERSIZE_MAX 18 /* can be useful for static allocation */ -#define ZSTD_SKIPPABLEHEADERSIZE 8 - -/* compression parameter bounds */ -#define ZSTD_WINDOWLOG_MAX_32 30 -#define ZSTD_WINDOWLOG_MAX_64 31 -#define ZSTD_WINDOWLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64)) -#define ZSTD_WINDOWLOG_MIN 10 -#define ZSTD_HASHLOG_MAX ((ZSTD_WINDOWLOG_MAX < 30) ? ZSTD_WINDOWLOG_MAX : 30) -#define ZSTD_HASHLOG_MIN 6 -#define ZSTD_CHAINLOG_MAX_32 29 -#define ZSTD_CHAINLOG_MAX_64 30 -#define ZSTD_CHAINLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_CHAINLOG_MAX_32 : ZSTD_CHAINLOG_MAX_64)) -#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN -#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1) -#define ZSTD_SEARCHLOG_MIN 1 -#define ZSTD_MINMATCH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */ -#define ZSTD_MINMATCH_MIN 3 /* only for ZSTD_btopt+, faster strategies are limited to 4 */ -#define ZSTD_TARGETLENGTH_MAX ZSTD_BLOCKSIZE_MAX -#define ZSTD_TARGETLENGTH_MIN 0 /* note : comparing this constant to an unsigned results in a tautological test */ -#define ZSTD_STRATEGY_MIN ZSTD_fast -#define ZSTD_STRATEGY_MAX ZSTD_btultra2 - - -#define ZSTD_OVERLAPLOG_MIN 0 -#define ZSTD_OVERLAPLOG_MAX 9 - -#define ZSTD_WINDOWLOG_LIMIT_DEFAULT 27 /* by default, the streaming decoder will refuse any frame - * requiring larger than (1< 3, then this is seqDef.offset - 3 - * If seqDef.offset < 3, then this is the corresponding repeat offset - * But if seqDef.offset < 3 and litLength == 0, this is the - * repeat offset before the corresponding repeat offset - * And if seqDef.offset == 3 and litLength == 0, this is the - * most recent repeat offset - 1 - */ - unsigned int offset; - unsigned int litLength; /* Literal length */ - unsigned int matchLength; /* Match length */ - /* 0 when seq not rep and seqDef.offset otherwise - * when litLength == 0 this will be <= 4, otherwise <= 3 like normal - */ - unsigned int rep; -} ZSTD_Sequence; - -typedef struct { - unsigned windowLog; /**< largest match distance : larger == more compression, more memory needed during decompression */ - unsigned chainLog; /**< fully searched segment : larger == more compression, slower, more memory (useless for fast) */ - unsigned hashLog; /**< dispatch table : larger == faster, more memory */ - unsigned searchLog; /**< nb of searches : larger == more compression, slower */ - unsigned minMatch; /**< match length searched : larger == faster decompression, sometimes less compression */ - unsigned targetLength; /**< acceptable match size for optimal parser (only) : larger == more compression, slower */ - ZSTD_strategy strategy; /**< see ZSTD_strategy definition above */ -} ZSTD_compressionParameters; - -typedef struct { - int contentSizeFlag; /**< 1: content size will be in frame header (when known) */ - int checksumFlag; /**< 1: generate a 32-bits checksum using XXH64 algorithm at end of frame, for error detection */ - int noDictIDFlag; /**< 1: no dictID will be saved into frame header (dictID is only useful for dictionary compression) */ -} ZSTD_frameParameters; - -typedef struct { - ZSTD_compressionParameters cParams; - ZSTD_frameParameters fParams; -} ZSTD_parameters; - -typedef enum { - ZSTD_dct_auto = 0, /* dictionary is "full" when starting with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */ - ZSTD_dct_rawContent = 1, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */ - ZSTD_dct_fullDict = 2 /* refuses to load a dictionary if it does not respect Zstandard's specification, starting with ZSTD_MAGIC_DICTIONARY */ -} ZSTD_dictContentType_e; - -typedef enum { - ZSTD_dlm_byCopy = 0, /**< Copy dictionary content internally */ - ZSTD_dlm_byRef = 1 /**< Reference dictionary content -- the dictionary buffer must outlive its users. */ -} ZSTD_dictLoadMethod_e; - -typedef enum { - ZSTD_f_zstd1 = 0, /* zstd frame format, specified in zstd_compression_format.md (default) */ - ZSTD_f_zstd1_magicless = 1 /* Variant of zstd frame format, without initial 4-bytes magic number. - * Useful to save 4 bytes per generated frame. - * Decoder cannot recognise automatically this format, requiring this instruction. */ -} ZSTD_format_e; - -typedef enum { - /* Note: this enum and the behavior it controls are effectively internal - * implementation details of the compressor. They are expected to continue - * to evolve and should be considered only in the context of extremely - * advanced performance tuning. - * - * Zstd currently supports the use of a CDict in three ways: - * - * - The contents of the CDict can be copied into the working context. This - * means that the compression can search both the dictionary and input - * while operating on a single set of internal tables. This makes - * the compression faster per-byte of input. However, the initial copy of - * the CDict's tables incurs a fixed cost at the beginning of the - * compression. For small compressions (< 8 KB), that copy can dominate - * the cost of the compression. - * - * - The CDict's tables can be used in-place. In this model, compression is - * slower per input byte, because the compressor has to search two sets of - * tables. However, this model incurs no start-up cost (as long as the - * working context's tables can be reused). For small inputs, this can be - * faster than copying the CDict's tables. - * - * - The CDict's tables are not used at all, and instead we use the working - * context alone to reload the dictionary and use params based on the source - * size. See ZSTD_compress_insertDictionary() and ZSTD_compress_usingDict(). - * This method is effective when the dictionary sizes are very small relative - * to the input size, and the input size is fairly large to begin with. - * - * Zstd has a simple internal heuristic that selects which strategy to use - * at the beginning of a compression. However, if experimentation shows that - * Zstd is making poor choices, it is possible to override that choice with - * this enum. - */ - ZSTD_dictDefaultAttach = 0, /* Use the default heuristic. */ - ZSTD_dictForceAttach = 1, /* Never copy the dictionary. */ - ZSTD_dictForceCopy = 2, /* Always copy the dictionary. */ - ZSTD_dictForceLoad = 3 /* Always reload the dictionary */ -} ZSTD_dictAttachPref_e; - -typedef enum { - ZSTD_lcm_auto = 0, /**< Automatically determine the compression mode based on the compression level. - * Negative compression levels will be uncompressed, and positive compression - * levels will be compressed. */ - ZSTD_lcm_huffman = 1, /**< Always attempt Huffman compression. Uncompressed literals will still be - * emitted if Huffman compression is not profitable. */ - ZSTD_lcm_uncompressed = 2 /**< Always emit uncompressed literals. */ -} ZSTD_literalCompressionMode_e; - - -/*************************************** -* Frame size functions -***************************************/ - -/*! ZSTD_findDecompressedSize() : - * `src` should point to the start of a series of ZSTD encoded and/or skippable frames - * `srcSize` must be the _exact_ size of this series - * (i.e. there should be a frame boundary at `src + srcSize`) - * @return : - decompressed size of all data in all successive frames - * - if the decompressed size cannot be determined: ZSTD_CONTENTSIZE_UNKNOWN - * - if an error occurred: ZSTD_CONTENTSIZE_ERROR - * - * note 1 : decompressed size is an optional field, that may not be present, especially in streaming mode. - * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size. - * In which case, it's necessary to use streaming mode to decompress data. - * note 2 : decompressed size is always present when compression is done with ZSTD_compress() - * note 3 : decompressed size can be very large (64-bits value), - * potentially larger than what local system can handle as a single memory segment. - * In which case, it's necessary to use streaming mode to decompress data. - * note 4 : If source is untrusted, decompressed size could be wrong or intentionally modified. - * Always ensure result fits within application's authorized limits. - * Each application can set its own limits. - * note 5 : ZSTD_findDecompressedSize handles multiple frames, and so it must traverse the input to - * read each contained frame header. This is fast as most of the data is skipped, - * however it does mean that all frame data must be present and valid. */ -ZSTDLIB_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize); - -/*! ZSTD_decompressBound() : - * `src` should point to the start of a series of ZSTD encoded and/or skippable frames - * `srcSize` must be the _exact_ size of this series - * (i.e. there should be a frame boundary at `src + srcSize`) - * @return : - upper-bound for the decompressed size of all data in all successive frames - * - if an error occurred: ZSTD_CONTENTSIZE_ERROR - * - * note 1 : an error can occur if `src` contains an invalid or incorrectly formatted frame. - * note 2 : the upper-bound is exact when the decompressed size field is available in every ZSTD encoded frame of `src`. - * in this case, `ZSTD_findDecompressedSize` and `ZSTD_decompressBound` return the same value. - * note 3 : when the decompressed size field isn't available, the upper-bound for that frame is calculated by: - * upper-bound = # blocks * min(128 KB, Window_Size) - */ -ZSTDLIB_API unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize); - -/*! ZSTD_frameHeaderSize() : - * srcSize must be >= ZSTD_FRAMEHEADERSIZE_PREFIX. - * @return : size of the Frame Header, - * or an error code (if srcSize is too small) */ -ZSTDLIB_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize); - -/*! ZSTD_getSequences() : - * Extract sequences from the sequence store - * zc can be used to insert custom compression params. - * This function invokes ZSTD_compress2 - * @return : number of sequences extracted - */ -ZSTDLIB_API size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, - size_t outSeqsSize, const void* src, size_t srcSize); - - -/*************************************** -* Memory management -***************************************/ - -/*! ZSTD_estimate*() : - * These functions make it possible to estimate memory usage - * of a future {D,C}Ctx, before its creation. - * - * ZSTD_estimateCCtxSize() will provide a memory budget large enough - * for any compression level up to selected one. - * Note : Unlike ZSTD_estimateCStreamSize*(), this estimate - * does not include space for a window buffer. - * Therefore, the estimation is only guaranteed for single-shot compressions, not streaming. - * The estimate will assume the input may be arbitrarily large, - * which is the worst case. - * - * When srcSize can be bound by a known and rather "small" value, - * this fact can be used to provide a tighter estimation - * because the CCtx compression context will need less memory. - * This tighter estimation can be provided by more advanced functions - * ZSTD_estimateCCtxSize_usingCParams(), which can be used in tandem with ZSTD_getCParams(), - * and ZSTD_estimateCCtxSize_usingCCtxParams(), which can be used in tandem with ZSTD_CCtxParams_setParameter(). - * Both can be used to estimate memory using custom compression parameters and arbitrary srcSize limits. - * - * Note 2 : only single-threaded compression is supported. - * ZSTD_estimateCCtxSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. - */ -ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel); -ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams); -ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params); -ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); - -/*! ZSTD_estimateCStreamSize() : - * ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one. - * It will also consider src size to be arbitrarily "large", which is worst case. - * If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation. - * ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. - * ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParams_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_c_nbWorkers is >= 1. - * Note : CStream size estimation is only correct for single-threaded compression. - * ZSTD_DStream memory budget depends on window Size. - * This information can be passed manually, using ZSTD_estimateDStreamSize, - * or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame(); - * Note : if streaming is init with function ZSTD_init?Stream_usingDict(), - * an internal ?Dict will be created, which additional size is not estimated here. - * In this case, get total size by adding ZSTD_estimate?DictSize */ -ZSTDLIB_API size_t ZSTD_estimateCStreamSize(int compressionLevel); -ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams); -ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params); -ZSTDLIB_API size_t ZSTD_estimateDStreamSize(size_t windowSize); -ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); - -/*! ZSTD_estimate?DictSize() : - * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). - * ZSTD_estimateCDictSize_advanced() makes it possible to control compression parameters precisely, like ZSTD_createCDict_advanced(). - * Note : dictionaries created by reference (`ZSTD_dlm_byRef`) are logically smaller. - */ -ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); -ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod); -ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod); - -/*! ZSTD_initStatic*() : - * Initialize an object using a pre-allocated fixed-size buffer. - * workspace: The memory area to emplace the object into. - * Provided pointer *must be 8-bytes aligned*. - * Buffer must outlive object. - * workspaceSize: Use ZSTD_estimate*Size() to determine - * how large workspace must be to support target scenario. - * @return : pointer to object (same address as workspace, just different type), - * or NULL if error (size too small, incorrect alignment, etc.) - * Note : zstd will never resize nor malloc() when using a static buffer. - * If the object requires more memory than available, - * zstd will just error out (typically ZSTD_error_memory_allocation). - * Note 2 : there is no corresponding "free" function. - * Since workspace is allocated externally, it must be freed externally too. - * Note 3 : cParams : use ZSTD_getCParams() to convert a compression level - * into its associated cParams. - * Limitation 1 : currently not compatible with internal dictionary creation, triggered by - * ZSTD_CCtx_loadDictionary(), ZSTD_initCStream_usingDict() or ZSTD_initDStream_usingDict(). - * Limitation 2 : static cctx currently not compatible with multi-threading. - * Limitation 3 : static dctx is incompatible with legacy support. - */ -ZSTDLIB_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize); -ZSTDLIB_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */ - -ZSTDLIB_API ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize); -ZSTDLIB_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */ - -ZSTDLIB_API const ZSTD_CDict* ZSTD_initStaticCDict( - void* workspace, size_t workspaceSize, - const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType, - ZSTD_compressionParameters cParams); - -ZSTDLIB_API const ZSTD_DDict* ZSTD_initStaticDDict( - void* workspace, size_t workspaceSize, - const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType); - - -/*! Custom memory allocation : - * These prototypes make it possible to pass your own allocation/free functions. - * ZSTD_customMem is provided at creation time, using ZSTD_create*_advanced() variants listed below. - * All allocation/free operations will be completed using these custom variants instead of regular ones. - */ -typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size); -typedef void (*ZSTD_freeFunction) (void* opaque, void* address); -typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem; - -ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem); -ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); -ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem); -ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem); - -ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType, - ZSTD_compressionParameters cParams, - ZSTD_customMem customMem); - -ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType, - ZSTD_customMem customMem); - - - -/*************************************** -* Advanced compression functions -***************************************/ - -/*! ZSTD_createCDict_byReference() : - * Create a digested dictionary for compression - * Dictionary content is just referenced, not duplicated. - * As a consequence, `dictBuffer` **must** outlive CDict, - * and its content must remain unmodified throughout the lifetime of CDict. - * note: equivalent to ZSTD_createCDict_advanced(), with dictLoadMethod==ZSTD_dlm_byRef */ -ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel); - -/*! ZSTD_getCParams() : - * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. - * `estimatedSrcSize` value is optional, select 0 if not known */ -ZSTDLIB_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); - -/*! ZSTD_getParams() : - * same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`. - * All fields of `ZSTD_frameParameters` are set to default : contentSize=1, checksum=0, noDictID=0 */ -ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); - -/*! ZSTD_checkCParams() : - * Ensure param values remain within authorized range. - * @return 0 on success, or an error code (can be checked with ZSTD_isError()) */ -ZSTDLIB_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params); - -/*! ZSTD_adjustCParams() : - * optimize params for a given `srcSize` and `dictSize`. - * `srcSize` can be unknown, in which case use ZSTD_CONTENTSIZE_UNKNOWN. - * `dictSize` must be `0` when there is no dictionary. - * cPar can be invalid : all parameters will be clamped within valid range in the @return struct. - * This function never fails (wide contract) */ -ZSTDLIB_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize); - -/*! ZSTD_compress_advanced() : - * Note : this function is now DEPRECATED. - * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_setParameter() and other parameter setters. - * This prototype will be marked as deprecated and generate compilation warning on reaching v1.5.x */ -ZSTDLIB_API size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const void* dict,size_t dictSize, - ZSTD_parameters params); - -/*! ZSTD_compress_usingCDict_advanced() : - * Note : this function is now REDUNDANT. - * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_loadDictionary() and other parameter setters. - * This prototype will be marked as deprecated and generate compilation warning in some future version */ -ZSTDLIB_API size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const ZSTD_CDict* cdict, - ZSTD_frameParameters fParams); - - -/*! ZSTD_CCtx_loadDictionary_byReference() : - * Same as ZSTD_CCtx_loadDictionary(), but dictionary content is referenced, instead of being copied into CCtx. - * It saves some memory, but also requires that `dict` outlives its usage within `cctx` */ -ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); - -/*! ZSTD_CCtx_loadDictionary_advanced() : - * Same as ZSTD_CCtx_loadDictionary(), but gives finer control over - * how to load the dictionary (by copy ? by reference ?) - * and how to interpret it (automatic ? force raw mode ? full mode only ?) */ -ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); - -/*! ZSTD_CCtx_refPrefix_advanced() : - * Same as ZSTD_CCtx_refPrefix(), but gives finer control over - * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ -ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); - -/* === experimental parameters === */ -/* these parameters can be used with ZSTD_setParameter() - * they are not guaranteed to remain supported in the future */ - - /* Enables rsyncable mode, - * which makes compressed files more rsync friendly - * by adding periodic synchronization points to the compressed data. - * The target average block size is ZSTD_c_jobSize / 2. - * It's possible to modify the job size to increase or decrease - * the granularity of the synchronization point. - * Once the jobSize is smaller than the window size, - * it will result in compression ratio degradation. - * NOTE 1: rsyncable mode only works when multithreading is enabled. - * NOTE 2: rsyncable performs poorly in combination with long range mode, - * since it will decrease the effectiveness of synchronization points, - * though mileage may vary. - * NOTE 3: Rsyncable mode limits maximum compression speed to ~400 MB/s. - * If the selected compression level is already running significantly slower, - * the overall speed won't be significantly impacted. - */ - #define ZSTD_c_rsyncable ZSTD_c_experimentalParam1 - -/* Select a compression format. - * The value must be of type ZSTD_format_e. - * See ZSTD_format_e enum definition for details */ -#define ZSTD_c_format ZSTD_c_experimentalParam2 - -/* Force back-reference distances to remain < windowSize, - * even when referencing into Dictionary content (default:0) */ -#define ZSTD_c_forceMaxWindow ZSTD_c_experimentalParam3 - -/* Controls whether the contents of a CDict - * are used in place, or copied into the working context. - * Accepts values from the ZSTD_dictAttachPref_e enum. - * See the comments on that enum for an explanation of the feature. */ -#define ZSTD_c_forceAttachDict ZSTD_c_experimentalParam4 - -/* Controls how the literals are compressed (default is auto). - * The value must be of type ZSTD_literalCompressionMode_e. - * See ZSTD_literalCompressionMode_t enum definition for details. - */ -#define ZSTD_c_literalCompressionMode ZSTD_c_experimentalParam5 - -/* Tries to fit compressed block size to be around targetCBlockSize. - * No target when targetCBlockSize == 0. - * There is no guarantee on compressed block size (default:0) */ -#define ZSTD_c_targetCBlockSize ZSTD_c_experimentalParam6 - -/* User's best guess of source size. - * Hint is not valid when srcSizeHint == 0. - * There is no guarantee that hint is close to actual source size, - * but compression ratio may regress significantly if guess considerably underestimates */ -#define ZSTD_c_srcSizeHint ZSTD_c_experimentalParam7 - -/*! ZSTD_CCtx_getParameter() : - * Get the requested compression parameter value, selected by enum ZSTD_cParameter, - * and store it into int* value. - * @return : 0, or an error code (which can be tested with ZSTD_isError()). - */ -ZSTDLIB_API size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value); - - -/*! ZSTD_CCtx_params : - * Quick howto : - * - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure - * - ZSTD_CCtxParams_setParameter() : Push parameters one by one into - * an existing ZSTD_CCtx_params structure. - * This is similar to - * ZSTD_CCtx_setParameter(). - * - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to - * an existing CCtx. - * These parameters will be applied to - * all subsequent frames. - * - ZSTD_compressStream2() : Do compression using the CCtx. - * - ZSTD_freeCCtxParams() : Free the memory. - * - * This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams() - * for static allocation of CCtx for single-threaded compression. - */ -ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); -ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); - -/*! ZSTD_CCtxParams_reset() : - * Reset params to default values. - */ -ZSTDLIB_API size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params); - -/*! ZSTD_CCtxParams_init() : - * Initializes the compression parameters of cctxParams according to - * compression level. All other parameters are reset to their default values. - */ -ZSTDLIB_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel); - -/*! ZSTD_CCtxParams_init_advanced() : - * Initializes the compression and frame parameters of cctxParams according to - * params. All other parameters are reset to their default values. - */ -ZSTDLIB_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); - -/*! ZSTD_CCtxParams_setParameter() : - * Similar to ZSTD_CCtx_setParameter. - * Set one compression parameter, selected by enum ZSTD_cParameter. - * Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_setParametersUsingCCtxParams(). - * @result : 0, or an error code (which can be tested with ZSTD_isError()). - */ -ZSTDLIB_API size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int value); - -/*! ZSTD_CCtxParams_getParameter() : - * Similar to ZSTD_CCtx_getParameter. - * Get the requested value of one compression parameter, selected by enum ZSTD_cParameter. - * @result : 0, or an error code (which can be tested with ZSTD_isError()). - */ -ZSTDLIB_API size_t ZSTD_CCtxParams_getParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value); - -/*! ZSTD_CCtx_setParametersUsingCCtxParams() : - * Apply a set of ZSTD_CCtx_params to the compression context. - * This can be done even after compression is started, - * if nbWorkers==0, this will have no impact until a new compression is started. - * if nbWorkers>=1, new parameters will be picked up at next job, - * with a few restrictions (windowLog, pledgedSrcSize, nbWorkers, jobSize, and overlapLog are not updated). - */ -ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams( - ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params); - -/*! ZSTD_compressStream2_simpleArgs() : - * Same as ZSTD_compressStream2(), - * but using only integral types as arguments. - * This variant might be helpful for binders from dynamic languages - * which have troubles handling structures containing memory pointers. - */ -ZSTDLIB_API size_t ZSTD_compressStream2_simpleArgs ( - ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, size_t* dstPos, - const void* src, size_t srcSize, size_t* srcPos, - ZSTD_EndDirective endOp); - - -/*************************************** -* Advanced decompression functions -***************************************/ - -/*! ZSTD_isFrame() : - * Tells if the content of `buffer` starts with a valid Frame Identifier. - * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. - * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled. - * Note 3 : Skippable Frame Identifiers are considered valid. */ -ZSTDLIB_API unsigned ZSTD_isFrame(const void* buffer, size_t size); - -/*! ZSTD_createDDict_byReference() : - * Create a digested dictionary, ready to start decompression operation without startup delay. - * Dictionary content is referenced, and therefore stays in dictBuffer. - * It is important that dictBuffer outlives DDict, - * it must remain read accessible throughout the lifetime of DDict */ -ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize); - -/*! ZSTD_DCtx_loadDictionary_byReference() : - * Same as ZSTD_DCtx_loadDictionary(), - * but references `dict` content instead of copying it into `dctx`. - * This saves memory if `dict` remains around., - * However, it's imperative that `dict` remains accessible (and unmodified) while being used, so it must outlive decompression. */ -ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); - -/*! ZSTD_DCtx_loadDictionary_advanced() : - * Same as ZSTD_DCtx_loadDictionary(), - * but gives direct control over - * how to load the dictionary (by copy ? by reference ?) - * and how to interpret it (automatic ? force raw mode ? full mode only ?). */ -ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); - -/*! ZSTD_DCtx_refPrefix_advanced() : - * Same as ZSTD_DCtx_refPrefix(), but gives finer control over - * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ -ZSTDLIB_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); - -/*! ZSTD_DCtx_setMaxWindowSize() : - * Refuses allocating internal buffers for frames requiring a window size larger than provided limit. - * This protects a decoder context from reserving too much memory for itself (potential attack scenario). - * This parameter is only useful in streaming mode, since no internal buffer is allocated in single-pass mode. - * By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) - * @return : 0, or an error code (which can be tested using ZSTD_isError()). - */ -ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize); - -/* ZSTD_d_format - * experimental parameter, - * allowing selection between ZSTD_format_e input compression formats - */ -#define ZSTD_d_format ZSTD_d_experimentalParam1 -/* ZSTD_d_stableOutBuffer - * Experimental parameter. - * Default is 0 == disabled. Set to 1 to enable. - * - * Tells the decompressor that the ZSTD_outBuffer will ALWAYS be the same - * between calls, except for the modifications that zstd makes to pos (the - * caller must not modify pos). This is checked by the decompressor, and - * decompression will fail if it ever changes. Therefore the ZSTD_outBuffer - * MUST be large enough to fit the entire decompressed frame. This will be - * checked when the frame content size is known. The data in the ZSTD_outBuffer - * in the range [dst, dst + pos) MUST not be modified during decompression - * or you will get data corruption. - * - * When this flags is enabled zstd won't allocate an output buffer, because - * it can write directly to the ZSTD_outBuffer, but it will still allocate - * an input buffer large enough to fit any compressed block. This will also - * avoid the memcpy() from the internal output buffer to the ZSTD_outBuffer. - * If you need to avoid the input buffer allocation use the buffer-less - * streaming API. - * - * NOTE: So long as the ZSTD_outBuffer always points to valid memory, using - * this flag is ALWAYS memory safe, and will never access out-of-bounds - * memory. However, decompression WILL fail if you violate the preconditions. - * - * WARNING: The data in the ZSTD_outBuffer in the range [dst, dst + pos) MUST - * not be modified during decompression or you will get data corruption. This - * is because zstd needs to reference data in the ZSTD_outBuffer to regenerate - * matches. Normally zstd maintains its own buffer for this purpose, but passing - * this flag tells zstd to use the user provided buffer. - */ -#define ZSTD_d_stableOutBuffer ZSTD_d_experimentalParam2 - -/*! ZSTD_DCtx_setFormat() : - * Instruct the decoder context about what kind of data to decode next. - * This instruction is mandatory to decode data without a fully-formed header, - * such ZSTD_f_zstd1_magicless for example. - * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ -ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); - -/*! ZSTD_decompressStream_simpleArgs() : - * Same as ZSTD_decompressStream(), - * but using only integral types as arguments. - * This can be helpful for binders from dynamic languages - * which have troubles handling structures containing memory pointers. - */ -ZSTDLIB_API size_t ZSTD_decompressStream_simpleArgs ( - ZSTD_DCtx* dctx, - void* dst, size_t dstCapacity, size_t* dstPos, - const void* src, size_t srcSize, size_t* srcPos); - - -/******************************************************************** -* Advanced streaming functions -* Warning : most of these functions are now redundant with the Advanced API. -* Once Advanced API reaches "stable" status, -* redundant functions will be deprecated, and then at some point removed. -********************************************************************/ - -/*===== Advanced Streaming compression functions =====*/ -/**! ZSTD_initCStream_srcSize() : - * This function is deprecated, and equivalent to: - * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); - * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any) - * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); - * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); - * - * pledgedSrcSize must be correct. If it is not known at init time, use - * ZSTD_CONTENTSIZE_UNKNOWN. Note that, for compatibility with older programs, - * "0" also disables frame content size field. It may be enabled in the future. - * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x - */ -ZSTDLIB_API size_t -ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, - int compressionLevel, - unsigned long long pledgedSrcSize); - -/**! ZSTD_initCStream_usingDict() : - * This function is deprecated, and is equivalent to: - * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); - * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); - * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); - * - * Creates of an internal CDict (incompatible with static CCtx), except if - * dict == NULL or dictSize < 8, in which case no dict is used. - * Note: dict is loaded with ZSTD_dct_auto (treated as a full zstd dictionary if - * it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy. - * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x - */ -ZSTDLIB_API size_t -ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, - const void* dict, size_t dictSize, - int compressionLevel); - -/**! ZSTD_initCStream_advanced() : - * This function is deprecated, and is approximately equivalent to: - * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); - * // Pseudocode: Set each zstd parameter and leave the rest as-is. - * for ((param, value) : params) { - * ZSTD_CCtx_setParameter(zcs, param, value); - * } - * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); - * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); - * - * dict is loaded with ZSTD_dct_auto and ZSTD_dlm_byCopy. - * pledgedSrcSize must be correct. - * If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. - * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x - */ -ZSTDLIB_API size_t -ZSTD_initCStream_advanced(ZSTD_CStream* zcs, - const void* dict, size_t dictSize, - ZSTD_parameters params, - unsigned long long pledgedSrcSize); - -/**! ZSTD_initCStream_usingCDict() : - * This function is deprecated, and equivalent to: - * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); - * ZSTD_CCtx_refCDict(zcs, cdict); - * - * note : cdict will just be referenced, and must outlive compression session - * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x - */ -ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); - -/**! ZSTD_initCStream_usingCDict_advanced() : - * This function is DEPRECATED, and is approximately equivalent to: - * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); - * // Pseudocode: Set each zstd frame parameter and leave the rest as-is. - * for ((fParam, value) : fParams) { - * ZSTD_CCtx_setParameter(zcs, fParam, value); - * } - * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); - * ZSTD_CCtx_refCDict(zcs, cdict); - * - * same as ZSTD_initCStream_usingCDict(), with control over frame parameters. - * pledgedSrcSize must be correct. If srcSize is not known at init time, use - * value ZSTD_CONTENTSIZE_UNKNOWN. - * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x - */ -ZSTDLIB_API size_t -ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, - const ZSTD_CDict* cdict, - ZSTD_frameParameters fParams, - unsigned long long pledgedSrcSize); - -/*! ZSTD_resetCStream() : - * This function is deprecated, and is equivalent to: - * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); - * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); - * - * start a new frame, using same parameters from previous frame. - * This is typically useful to skip dictionary loading stage, since it will re-use it in-place. - * Note that zcs must be init at least once before using ZSTD_resetCStream(). - * If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN. - * If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end. - * For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs, - * but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead. - * @return : 0, or an error code (which can be tested using ZSTD_isError()) - * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x - */ -ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize); - - -typedef struct { - unsigned long long ingested; /* nb input bytes read and buffered */ - unsigned long long consumed; /* nb input bytes actually compressed */ - unsigned long long produced; /* nb of compressed bytes generated and buffered */ - unsigned long long flushed; /* nb of compressed bytes flushed : not provided; can be tracked from caller side */ - unsigned currentJobID; /* MT only : latest started job nb */ - unsigned nbActiveWorkers; /* MT only : nb of workers actively compressing at probe time */ -} ZSTD_frameProgression; - -/* ZSTD_getFrameProgression() : - * tells how much data has been ingested (read from input) - * consumed (input actually compressed) and produced (output) for current frame. - * Note : (ingested - consumed) is amount of input data buffered internally, not yet compressed. - * Aggregates progression inside active worker threads. - */ -ZSTDLIB_API ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx); - -/*! ZSTD_toFlushNow() : - * Tell how many bytes are ready to be flushed immediately. - * Useful for multithreading scenarios (nbWorkers >= 1). - * Probe the oldest active job, defined as oldest job not yet entirely flushed, - * and check its output buffer. - * @return : amount of data stored in oldest job and ready to be flushed immediately. - * if @return == 0, it means either : - * + there is no active job (could be checked with ZSTD_frameProgression()), or - * + oldest job is still actively compressing data, - * but everything it has produced has also been flushed so far, - * therefore flush speed is limited by production speed of oldest job - * irrespective of the speed of concurrent (and newer) jobs. - */ -ZSTDLIB_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx); - - -/*===== Advanced Streaming decompression functions =====*/ -/** - * This function is deprecated, and is equivalent to: - * - * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); - * ZSTD_DCtx_loadDictionary(zds, dict, dictSize); - * - * note: no dictionary will be used if dict == NULL or dictSize < 8 - * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x - */ -ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); - -/** - * This function is deprecated, and is equivalent to: - * - * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); - * ZSTD_DCtx_refDDict(zds, ddict); - * - * note : ddict is referenced, it must outlive decompression session - * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x - */ -ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); - -/** - * This function is deprecated, and is equivalent to: - * - * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); - * - * re-use decompression parameters from previous init; saves dictionary loading - * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x - */ -ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); - - -/********************************************************************* -* Buffer-less and synchronous inner streaming functions -* -* This is an advanced API, giving full control over buffer management, for users which need direct control over memory. -* But it's also a complex one, with several restrictions, documented below. -* Prefer normal streaming API for an easier experience. -********************************************************************* */ - -/** - Buffer-less streaming compression (synchronous mode) - - A ZSTD_CCtx object is required to track streaming operations. - Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource. - ZSTD_CCtx object can be re-used multiple times within successive compression operations. - - Start by initializing a context. - Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression, - or ZSTD_compressBegin_advanced(), for finer parameter control. - It's also possible to duplicate a reference context which has already been initialized, using ZSTD_copyCCtx() - - Then, consume your input using ZSTD_compressContinue(). - There are some important considerations to keep in mind when using this advanced function : - - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffers only. - - Interface is synchronous : input is consumed entirely and produces 1+ compressed blocks. - - Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario. - Worst case evaluation is provided by ZSTD_compressBound(). - ZSTD_compressContinue() doesn't guarantee recover after a failed compression. - - ZSTD_compressContinue() presumes prior input ***is still accessible and unmodified*** (up to maximum distance size, see WindowLog). - It remembers all previous contiguous blocks, plus one separated memory segment (which can itself consists of multiple contiguous blocks) - - ZSTD_compressContinue() detects that prior input has been overwritten when `src` buffer overlaps. - In which case, it will "discard" the relevant memory section from its history. - - Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum. - It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame. - Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders. - - `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress again. -*/ - -/*===== Buffer-less streaming compression functions =====*/ -ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); -ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); -ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */ -ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */ -ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */ -ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */ - -ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); - - -/*- - Buffer-less streaming decompression (synchronous mode) - - A ZSTD_DCtx object is required to track streaming operations. - Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it. - A ZSTD_DCtx object can be re-used multiple times. - - First typical operation is to retrieve frame parameters, using ZSTD_getFrameHeader(). - Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough. - Data fragment must be large enough to ensure successful decoding. - `ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough. - @result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled. - >0 : `srcSize` is too small, please provide at least @result bytes on next attempt. - errorCode, which can be tested using ZSTD_isError(). - - It fills a ZSTD_frameHeader structure with important information to correctly decode the frame, - such as the dictionary ID, content size, or maximum back-reference distance (`windowSize`). - Note that these values could be wrong, either because of data corruption, or because a 3rd party deliberately spoofs false information. - As a consequence, check that values remain within valid application range. - For example, do not allocate memory blindly, check that `windowSize` is within expectation. - Each application can set its own limits, depending on local restrictions. - For extended interoperability, it is recommended to support `windowSize` of at least 8 MB. - - ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize` bytes. - ZSTD_decompressContinue() is very sensitive to contiguity, - if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place, - or that previous contiguous segment is large enough to properly handle maximum back-reference distance. - There are multiple ways to guarantee this condition. - - The most memory efficient way is to use a round buffer of sufficient size. - Sufficient size is determined by invoking ZSTD_decodingBufferSize_min(), - which can @return an error code if required value is too large for current system (in 32-bits mode). - In a round buffer methodology, ZSTD_decompressContinue() decompresses each block next to previous one, - up to the moment there is not enough room left in the buffer to guarantee decoding another full block, - which maximum size is provided in `ZSTD_frameHeader` structure, field `blockSizeMax`. - At which point, decoding can resume from the beginning of the buffer. - Note that already decoded data stored in the buffer should be flushed before being overwritten. - - There are alternatives possible, for example using two or more buffers of size `windowSize` each, though they consume more memory. - - Finally, if you control the compression process, you can also ignore all buffer size rules, - as long as the encoder and decoder progress in "lock-step", - aka use exactly the same buffer sizes, break contiguity at the same place, etc. - - Once buffers are setup, start decompression, with ZSTD_decompressBegin(). - If decompression requires a dictionary, use ZSTD_decompressBegin_usingDict() or ZSTD_decompressBegin_usingDDict(). - - Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively. - ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize' to ZSTD_decompressContinue(). - ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will fail. - - @result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity). - It can be zero : it just means ZSTD_decompressContinue() has decoded some metadata item. - It can also be an error code, which can be tested with ZSTD_isError(). - - A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero. - Context can then be reset to start a new decompression. - - Note : it's possible to know if next input to present is a header or a block, using ZSTD_nextInputType(). - This information is not required to properly decode a frame. - - == Special case : skippable frames == - - Skippable frames allow integration of user-defined data into a flow of concatenated frames. - Skippable frames will be ignored (skipped) by decompressor. - The format of skippable frames is as follows : - a) Skippable frame ID - 4 Bytes, Little endian format, any value from 0x184D2A50 to 0x184D2A5F - b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits - c) Frame Content - any content (User Data) of length equal to Frame Size - For skippable frames ZSTD_getFrameHeader() returns zfhPtr->frameType==ZSTD_skippableFrame. - For skippable frames ZSTD_decompressContinue() always returns 0 : it only skips the content. -*/ - -/*===== Buffer-less streaming decompression functions =====*/ -typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e; -typedef struct { - unsigned long long frameContentSize; /* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */ - unsigned long long windowSize; /* can be very large, up to <= frameContentSize */ - unsigned blockSizeMax; - ZSTD_frameType_e frameType; /* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */ - unsigned headerSize; - unsigned dictID; - unsigned checksumFlag; -} ZSTD_frameHeader; - -/*! ZSTD_getFrameHeader() : - * decode Frame Header, or requires larger `srcSize`. - * @return : 0, `zfhPtr` is correctly filled, - * >0, `srcSize` is too small, value is wanted `srcSize` amount, - * or an error code, which can be tested using ZSTD_isError() */ -ZSTDLIB_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */ -/*! ZSTD_getFrameHeader_advanced() : - * same as ZSTD_getFrameHeader(), - * with added capability to select a format (like ZSTD_f_zstd1_magicless) */ -ZSTDLIB_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format); -ZSTDLIB_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */ - -ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); -ZSTDLIB_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); -ZSTDLIB_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); - -ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); -ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); - -/* misc */ -ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); -typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e; -ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); - - - - -/* ============================ */ -/** Block level API */ -/* ============================ */ - -/*! - Block functions produce and decode raw zstd blocks, without frame metadata. - Frame metadata cost is typically ~12 bytes, which can be non-negligible for very small blocks (< 100 bytes). - But users will have to take in charge needed metadata to regenerate data, such as compressed and content sizes. - - A few rules to respect : - - Compressing and decompressing require a context structure - + Use ZSTD_createCCtx() and ZSTD_createDCtx() - - It is necessary to init context before starting - + compression : any ZSTD_compressBegin*() variant, including with dictionary - + decompression : any ZSTD_decompressBegin*() variant, including with dictionary - + copyCCtx() and copyDCtx() can be used too - - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB - + If input is larger than a block size, it's necessary to split input data into multiple blocks - + For inputs larger than a single block, consider using regular ZSTD_compress() instead. - Frame metadata is not that costly, and quickly becomes negligible as source size grows larger than a block. - - When a block is considered not compressible enough, ZSTD_compressBlock() result will be 0 (zero) ! - ===> In which case, nothing is produced into `dst` ! - + User __must__ test for such outcome and deal directly with uncompressed data - + A block cannot be declared incompressible if ZSTD_compressBlock() return value was != 0. - Doing so would mess up with statistics history, leading to potential data corruption. - + ZSTD_decompressBlock() _doesn't accept uncompressed data as input_ !! - + In case of multiple successive blocks, should some of them be uncompressed, - decoder must be informed of their existence in order to follow proper history. - Use ZSTD_insertBlock() for such a case. -*/ - -/*===== Raw zstd block functions =====*/ -ZSTDLIB_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx); -ZSTDLIB_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -ZSTDLIB_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -ZSTDLIB_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */ - -} - -#endif /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */ diff --git a/src/duckdb/ub_src_common.cpp b/src/duckdb/ub_src_common.cpp index 07cab6cd8..626816b8e 100644 --- a/src/duckdb/ub_src_common.cpp +++ b/src/duckdb/ub_src_common.cpp @@ -46,6 +46,8 @@ #include "src/common/error_data.cpp" +#include "src/common/opener_file_system.cpp" + #include "src/common/printer.cpp" #include "src/common/radix_partitioning.cpp" diff --git a/src/duckdb/ub_src_core_functions.cpp b/src/duckdb/ub_src_core_functions.cpp deleted file mode 100644 index 961929d47..000000000 --- a/src/duckdb/ub_src_core_functions.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "src/core_functions/core_functions.cpp" - -#include "src/core_functions/function_list.cpp" - -#include "src/core_functions/lambda_functions.cpp" - diff --git a/src/duckdb/ub_src_core_functions_aggregate_algebraic.cpp b/src/duckdb/ub_src_core_functions_aggregate_algebraic.cpp deleted file mode 100644 index 5aee83e92..000000000 --- a/src/duckdb/ub_src_core_functions_aggregate_algebraic.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "src/core_functions/aggregate/algebraic/avg.cpp" - -#include "src/core_functions/aggregate/algebraic/covar.cpp" - -#include "src/core_functions/aggregate/algebraic/stddev.cpp" - -#include "src/core_functions/aggregate/algebraic/corr.cpp" - diff --git a/src/duckdb/ub_src_core_functions_aggregate_distributive.cpp b/src/duckdb/ub_src_core_functions_aggregate_distributive.cpp deleted file mode 100644 index 7deed6d3b..000000000 --- a/src/duckdb/ub_src_core_functions_aggregate_distributive.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "src/core_functions/aggregate/distributive/approx_count.cpp" - -#include "src/core_functions/aggregate/distributive/arg_min_max.cpp" - -#include "src/core_functions/aggregate/distributive/bitagg.cpp" - -#include "src/core_functions/aggregate/distributive/bitstring_agg.cpp" - -#include "src/core_functions/aggregate/distributive/bool.cpp" - -#include "src/core_functions/aggregate/distributive/entropy.cpp" - -#include "src/core_functions/aggregate/distributive/kurtosis.cpp" - -#include "src/core_functions/aggregate/distributive/minmax.cpp" - -#include "src/core_functions/aggregate/distributive/product.cpp" - -#include "src/core_functions/aggregate/distributive/skew.cpp" - -#include "src/core_functions/aggregate/distributive/string_agg.cpp" - -#include "src/core_functions/aggregate/distributive/sum.cpp" - diff --git a/src/duckdb/ub_src_core_functions_aggregate_holistic.cpp b/src/duckdb/ub_src_core_functions_aggregate_holistic.cpp deleted file mode 100644 index 67d8f8f08..000000000 --- a/src/duckdb/ub_src_core_functions_aggregate_holistic.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "src/core_functions/aggregate/holistic/approx_top_k.cpp" - -#include "src/core_functions/aggregate/holistic/quantile.cpp" - -#include "src/core_functions/aggregate/holistic/mad.cpp" - -#include "src/core_functions/aggregate/holistic/mode.cpp" - -#include "src/core_functions/aggregate/holistic/approximate_quantile.cpp" - -#include "src/core_functions/aggregate/holistic/reservoir_quantile.cpp" - diff --git a/src/duckdb/ub_src_core_functions_aggregate_nested.cpp b/src/duckdb/ub_src_core_functions_aggregate_nested.cpp deleted file mode 100644 index ecd5e3be9..000000000 --- a/src/duckdb/ub_src_core_functions_aggregate_nested.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "src/core_functions/aggregate/nested/binned_histogram.cpp" - -#include "src/core_functions/aggregate/nested/list.cpp" - -#include "src/core_functions/aggregate/nested/histogram.cpp" - diff --git a/src/duckdb/ub_src_core_functions_aggregate_regression.cpp b/src/duckdb/ub_src_core_functions_aggregate_regression.cpp deleted file mode 100644 index 19053bcc0..000000000 --- a/src/duckdb/ub_src_core_functions_aggregate_regression.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "src/core_functions/aggregate/regression/regr_avg.cpp" - -#include "src/core_functions/aggregate/regression/regr_count.cpp" - -#include "src/core_functions/aggregate/regression/regr_slope.cpp" - -#include "src/core_functions/aggregate/regression/regr_r2.cpp" - -#include "src/core_functions/aggregate/regression/regr_sxx_syy.cpp" - -#include "src/core_functions/aggregate/regression/regr_sxy.cpp" - -#include "src/core_functions/aggregate/regression/regr_intercept.cpp" - diff --git a/src/duckdb/ub_src_core_functions_scalar_array.cpp b/src/duckdb/ub_src_core_functions_scalar_array.cpp deleted file mode 100644 index 49ed0ec37..000000000 --- a/src/duckdb/ub_src_core_functions_scalar_array.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "src/core_functions/scalar/array/array_value.cpp" - -#include "src/core_functions/scalar/array/array_functions.cpp" - diff --git a/src/duckdb/ub_src_core_functions_scalar_bit.cpp b/src/duckdb/ub_src_core_functions_scalar_bit.cpp deleted file mode 100644 index c0db08283..000000000 --- a/src/duckdb/ub_src_core_functions_scalar_bit.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "src/core_functions/scalar/bit/bitstring.cpp" - diff --git a/src/duckdb/ub_src_core_functions_scalar_blob.cpp b/src/duckdb/ub_src_core_functions_scalar_blob.cpp deleted file mode 100644 index d1ae2334d..000000000 --- a/src/duckdb/ub_src_core_functions_scalar_blob.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "src/core_functions/scalar/blob/base64.cpp" - -#include "src/core_functions/scalar/blob/create_sort_key.cpp" - -#include "src/core_functions/scalar/blob/encode.cpp" - diff --git a/src/duckdb/ub_src_core_functions_scalar_date.cpp b/src/duckdb/ub_src_core_functions_scalar_date.cpp deleted file mode 100644 index 49bb85bd7..000000000 --- a/src/duckdb/ub_src_core_functions_scalar_date.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "src/core_functions/scalar/date/age.cpp" - -#include "src/core_functions/scalar/date/current.cpp" - -#include "src/core_functions/scalar/date/epoch.cpp" - -#include "src/core_functions/scalar/date/date_diff.cpp" - -#include "src/core_functions/scalar/date/date_part.cpp" - -#include "src/core_functions/scalar/date/date_sub.cpp" - -#include "src/core_functions/scalar/date/date_trunc.cpp" - -#include "src/core_functions/scalar/date/make_date.cpp" - -#include "src/core_functions/scalar/date/strftime.cpp" - -#include "src/core_functions/scalar/date/time_bucket.cpp" - -#include "src/core_functions/scalar/date/to_interval.cpp" - diff --git a/src/duckdb/ub_src_core_functions_scalar_debug.cpp b/src/duckdb/ub_src_core_functions_scalar_debug.cpp deleted file mode 100644 index 7675ec524..000000000 --- a/src/duckdb/ub_src_core_functions_scalar_debug.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "src/core_functions/scalar/debug/vector_type.cpp" - diff --git a/src/duckdb/ub_src_core_functions_scalar_enum.cpp b/src/duckdb/ub_src_core_functions_scalar_enum.cpp deleted file mode 100644 index e84741f5b..000000000 --- a/src/duckdb/ub_src_core_functions_scalar_enum.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "src/core_functions/scalar/enum/enum_functions.cpp" - diff --git a/src/duckdb/ub_src_core_functions_scalar_generic.cpp b/src/duckdb/ub_src_core_functions_scalar_generic.cpp deleted file mode 100644 index 7c80d7dbf..000000000 --- a/src/duckdb/ub_src_core_functions_scalar_generic.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "src/core_functions/scalar/generic/alias.cpp" - -#include "src/core_functions/scalar/generic/can_implicitly_cast.cpp" - -#include "src/core_functions/scalar/generic/current_setting.cpp" - -#include "src/core_functions/scalar/generic/error.cpp" - -#include "src/core_functions/scalar/generic/hash.cpp" - -#include "src/core_functions/scalar/generic/least.cpp" - -#include "src/core_functions/scalar/generic/stats.cpp" - -#include "src/core_functions/scalar/generic/typeof.cpp" - -#include "src/core_functions/scalar/generic/system_functions.cpp" - diff --git a/src/duckdb/ub_src_core_functions_scalar_list.cpp b/src/duckdb/ub_src_core_functions_scalar_list.cpp deleted file mode 100644 index 53a325891..000000000 --- a/src/duckdb/ub_src_core_functions_scalar_list.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "src/core_functions/scalar/list/array_slice.cpp" - -#include "src/core_functions/scalar/list/flatten.cpp" - -#include "src/core_functions/scalar/list/list_aggregates.cpp" - -#include "src/core_functions/scalar/list/list_filter.cpp" - -#include "src/core_functions/scalar/list/list_has_any_or_all.cpp" - -#include "src/core_functions/scalar/list/list_sort.cpp" - -#include "src/core_functions/scalar/list/list_distance.cpp" - -#include "src/core_functions/scalar/list/list_reduce.cpp" - -#include "src/core_functions/scalar/list/list_transform.cpp" - -#include "src/core_functions/scalar/list/list_value.cpp" - -#include "src/core_functions/scalar/list/range.cpp" - diff --git a/src/duckdb/ub_src_core_functions_scalar_map.cpp b/src/duckdb/ub_src_core_functions_scalar_map.cpp deleted file mode 100644 index e86907159..000000000 --- a/src/duckdb/ub_src_core_functions_scalar_map.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "src/core_functions/scalar/map/map.cpp" - -#include "src/core_functions/scalar/map/map_extract.cpp" - -#include "src/core_functions/scalar/map/map_from_entries.cpp" - -#include "src/core_functions/scalar/map/map_entries.cpp" - -#include "src/core_functions/scalar/map/map_concat.cpp" - -#include "src/core_functions/scalar/map/map_contains.cpp" - -#include "src/core_functions/scalar/map/map_keys_values.cpp" - -#include "src/core_functions/scalar/map/cardinality.cpp" - diff --git a/src/duckdb/ub_src_core_functions_scalar_math.cpp b/src/duckdb/ub_src_core_functions_scalar_math.cpp deleted file mode 100644 index d8fcaa8e0..000000000 --- a/src/duckdb/ub_src_core_functions_scalar_math.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "src/core_functions/scalar/math/numeric.cpp" - diff --git a/src/duckdb/ub_src_core_functions_scalar_operators.cpp b/src/duckdb/ub_src_core_functions_scalar_operators.cpp deleted file mode 100644 index edb917bc3..000000000 --- a/src/duckdb/ub_src_core_functions_scalar_operators.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "src/core_functions/scalar/operators/bitwise.cpp" - diff --git a/src/duckdb/ub_src_core_functions_scalar_random.cpp b/src/duckdb/ub_src_core_functions_scalar_random.cpp deleted file mode 100644 index 44b6ee631..000000000 --- a/src/duckdb/ub_src_core_functions_scalar_random.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "src/core_functions/scalar/random/random.cpp" - -#include "src/core_functions/scalar/random/setseed.cpp" - diff --git a/src/duckdb/ub_src_core_functions_scalar_string.cpp b/src/duckdb/ub_src_core_functions_scalar_string.cpp deleted file mode 100644 index 507f1e60d..000000000 --- a/src/duckdb/ub_src_core_functions_scalar_string.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "src/core_functions/scalar/string/ascii.cpp" - -#include "src/core_functions/scalar/string/bar.cpp" - -#include "src/core_functions/scalar/string/chr.cpp" - -#include "src/core_functions/scalar/string/damerau_levenshtein.cpp" - -#include "src/core_functions/scalar/string/format_bytes.cpp" - -#include "src/core_functions/scalar/string/hamming.cpp" - -#include "src/core_functions/scalar/string/hex.cpp" - -#include "src/core_functions/scalar/string/instr.cpp" - -#include "src/core_functions/scalar/string/jaccard.cpp" - -#include "src/core_functions/scalar/string/jaro_winkler.cpp" - -#include "src/core_functions/scalar/string/left_right.cpp" - -#include "src/core_functions/scalar/string/levenshtein.cpp" - -#include "src/core_functions/scalar/string/md5.cpp" - -#include "src/core_functions/scalar/string/pad.cpp" - -#include "src/core_functions/scalar/string/parse_path.cpp" - -#include "src/core_functions/scalar/string/printf.cpp" - -#include "src/core_functions/scalar/string/regexp_escape.cpp" - -#include "src/core_functions/scalar/string/repeat.cpp" - -#include "src/core_functions/scalar/string/replace.cpp" - -#include "src/core_functions/scalar/string/reverse.cpp" - -#include "src/core_functions/scalar/string/sha1.cpp" - -#include "src/core_functions/scalar/string/sha256.cpp" - -#include "src/core_functions/scalar/string/starts_with.cpp" - -#include "src/core_functions/scalar/string/string_split.cpp" - -#include "src/core_functions/scalar/string/to_base.cpp" - -#include "src/core_functions/scalar/string/translate.cpp" - -#include "src/core_functions/scalar/string/trim.cpp" - -#include "src/core_functions/scalar/string/unicode.cpp" - -#include "src/core_functions/scalar/string/url_encode.cpp" - diff --git a/src/duckdb/ub_src_core_functions_scalar_struct.cpp b/src/duckdb/ub_src_core_functions_scalar_struct.cpp deleted file mode 100644 index a58c0d382..000000000 --- a/src/duckdb/ub_src_core_functions_scalar_struct.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "src/core_functions/scalar/struct/struct_pack.cpp" - -#include "src/core_functions/scalar/struct/struct_insert.cpp" - diff --git a/src/duckdb/ub_src_core_functions_scalar_union.cpp b/src/duckdb/ub_src_core_functions_scalar_union.cpp deleted file mode 100644 index 41adab652..000000000 --- a/src/duckdb/ub_src_core_functions_scalar_union.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "src/core_functions/scalar/union/union_extract.cpp" - -#include "src/core_functions/scalar/union/union_tag.cpp" - -#include "src/core_functions/scalar/union/union_value.cpp" - diff --git a/src/duckdb/ub_src_execution_operator_aggregate.cpp b/src/duckdb/ub_src_execution_operator_aggregate.cpp index d7ee3d50a..f8555ee93 100644 --- a/src/duckdb/ub_src_execution_operator_aggregate.cpp +++ b/src/duckdb/ub_src_execution_operator_aggregate.cpp @@ -6,6 +6,8 @@ #include "src/execution/operator/aggregate/grouped_aggregate_data.cpp" +#include "src/execution/operator/aggregate/physical_partitioned_aggregate.cpp" + #include "src/execution/operator/aggregate/physical_perfecthash_aggregate.cpp" #include "src/execution/operator/aggregate/physical_ungrouped_aggregate.cpp" diff --git a/src/duckdb/ub_src_execution_operator_csv_scanner_util.cpp b/src/duckdb/ub_src_execution_operator_csv_scanner_util.cpp index 7deec5a78..5fd16fb67 100644 --- a/src/duckdb/ub_src_execution_operator_csv_scanner_util.cpp +++ b/src/duckdb/ub_src_execution_operator_csv_scanner_util.cpp @@ -2,3 +2,5 @@ #include "src/execution/operator/csv_scanner/util/csv_reader_options.cpp" +#include "src/execution/operator/csv_scanner/util/csv_validator.cpp" + diff --git a/src/duckdb/ub_src_function.cpp b/src/duckdb/ub_src_function.cpp index 586fb8faa..f092a819c 100644 --- a/src/duckdb/ub_src_function.cpp +++ b/src/duckdb/ub_src_function.cpp @@ -12,12 +12,16 @@ #include "src/function/function_binder.cpp" +#include "src/function/function_list.cpp" + #include "src/function/function_set.cpp" #include "src/function/pragma_function.cpp" #include "src/function/macro_function.cpp" +#include "src/function/register_function_list.cpp" + #include "src/function/scalar_macro_function.cpp" #include "src/function/table_macro_function.cpp" diff --git a/src/duckdb/ub_src_function_aggregate.cpp b/src/duckdb/ub_src_function_aggregate.cpp index 389a81ce9..6bfe0ba85 100644 --- a/src/duckdb/ub_src_function_aggregate.cpp +++ b/src/duckdb/ub_src_function_aggregate.cpp @@ -1,4 +1,2 @@ -#include "src/function/aggregate/distributive_functions.cpp" - #include "src/function/aggregate/sorted_aggregate_function.cpp" diff --git a/src/duckdb/ub_src_function_aggregate_distributive.cpp b/src/duckdb/ub_src_function_aggregate_distributive.cpp index 005304196..92bcd6c50 100644 --- a/src/duckdb/ub_src_function_aggregate_distributive.cpp +++ b/src/duckdb/ub_src_function_aggregate_distributive.cpp @@ -1,4 +1,6 @@ #include "src/function/aggregate/distributive/count.cpp" -#include "src/function/aggregate/distributive/first.cpp" +#include "src/function/aggregate/distributive/first_last_any.cpp" + +#include "src/function/aggregate/distributive/minmax.cpp" diff --git a/src/duckdb/ub_src_function_scalar.cpp b/src/duckdb/ub_src_function_scalar.cpp index cb65cab27..a0da28dc6 100644 --- a/src/duckdb/ub_src_function_scalar.cpp +++ b/src/duckdb/ub_src_function_scalar.cpp @@ -1,16 +1,10 @@ -#include "src/function/scalar/compressed_materialization_functions.cpp" +#include "src/function/scalar/compressed_materialization_utils.cpp" -#include "src/function/scalar/generic_functions.cpp" - -#include "src/function/scalar/string_functions.cpp" +#include "src/function/scalar/create_sort_key.cpp" #include "src/function/scalar/strftime_format.cpp" #include "src/function/scalar/nested_functions.cpp" -#include "src/function/scalar/operators.cpp" - #include "src/function/scalar/pragma_functions.cpp" -#include "src/function/scalar/sequence_functions.cpp" - diff --git a/src/duckdb/ub_src_function_scalar_date.cpp b/src/duckdb/ub_src_function_scalar_date.cpp new file mode 100644 index 000000000..81e2c26c1 --- /dev/null +++ b/src/duckdb/ub_src_function_scalar_date.cpp @@ -0,0 +1,2 @@ +#include "src/function/scalar/date/strftime.cpp" + diff --git a/src/duckdb/ub_src_function_scalar_generic.cpp b/src/duckdb/ub_src_function_scalar_generic.cpp index 842724aff..926f394d3 100644 --- a/src/duckdb/ub_src_function_scalar_generic.cpp +++ b/src/duckdb/ub_src_function_scalar_generic.cpp @@ -1,6 +1,6 @@ -#include "src/function/scalar/generic/binning.cpp" - #include "src/function/scalar/generic/constant_or_null.cpp" +#include "src/function/scalar/generic/error.cpp" + #include "src/function/scalar/generic/getvariable.cpp" diff --git a/src/duckdb/ub_src_function_scalar_map.cpp b/src/duckdb/ub_src_function_scalar_map.cpp new file mode 100644 index 000000000..0978d7e0e --- /dev/null +++ b/src/duckdb/ub_src_function_scalar_map.cpp @@ -0,0 +1,2 @@ +#include "src/function/scalar/map/map_contains.cpp" + diff --git a/src/duckdb/ub_src_function_scalar_operator.cpp b/src/duckdb/ub_src_function_scalar_operator.cpp new file mode 100644 index 000000000..f31f65916 --- /dev/null +++ b/src/duckdb/ub_src_function_scalar_operator.cpp @@ -0,0 +1,8 @@ +#include "src/function/scalar/operator/add.cpp" + +#include "src/function/scalar/operator/arithmetic.cpp" + +#include "src/function/scalar/operator/multiply.cpp" + +#include "src/function/scalar/operator/subtract.cpp" + diff --git a/src/duckdb/ub_src_function_scalar_operators.cpp b/src/duckdb/ub_src_function_scalar_operators.cpp deleted file mode 100644 index 8bd5e0bf9..000000000 --- a/src/duckdb/ub_src_function_scalar_operators.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "src/function/scalar/operators/add.cpp" - -#include "src/function/scalar/operators/arithmetic.cpp" - -#include "src/function/scalar/operators/multiply.cpp" - -#include "src/function/scalar/operators/subtract.cpp" - diff --git a/src/duckdb/ub_src_function_scalar_string.cpp b/src/duckdb/ub_src_function_scalar_string.cpp index 9e62653c9..c39a28ea1 100644 --- a/src/duckdb/ub_src_function_scalar_string.cpp +++ b/src/duckdb/ub_src_function_scalar_string.cpp @@ -8,6 +8,8 @@ #include "src/function/scalar/string/like.cpp" +#include "src/function/scalar/string/md5.cpp" + #include "src/function/scalar/string/nfc_normalize.cpp" #include "src/function/scalar/string/regexp.cpp" @@ -16,8 +18,16 @@ #include "src/function/scalar/string/prefix.cpp" +#include "src/function/scalar/string/regexp_escape.cpp" + +#include "src/function/scalar/string/sha1.cpp" + +#include "src/function/scalar/string/sha256.cpp" + #include "src/function/scalar/string/strip_accents.cpp" +#include "src/function/scalar/string/string_split.cpp" + #include "src/function/scalar/string/suffix.cpp" #include "src/function/scalar/string/contains.cpp" diff --git a/src/duckdb/ub_src_function_scalar_struct.cpp b/src/duckdb/ub_src_function_scalar_struct.cpp index 2d3888e7e..19d8d89ee 100644 --- a/src/duckdb/ub_src_function_scalar_struct.cpp +++ b/src/duckdb/ub_src_function_scalar_struct.cpp @@ -1,2 +1,4 @@ #include "src/function/scalar/struct/struct_extract.cpp" +#include "src/function/scalar/struct/struct_pack.cpp" + diff --git a/src/duckdb/ub_src_main_settings.cpp b/src/duckdb/ub_src_main_settings.cpp index 77cb91e4c..6dbcd419e 100644 --- a/src/duckdb/ub_src_main_settings.cpp +++ b/src/duckdb/ub_src_main_settings.cpp @@ -1,2 +1,4 @@ -#include "src/main/settings/settings.cpp" +#include "src/main/settings/custom_settings.cpp" + +#include "src/main/settings/autogenerated_settings.cpp" diff --git a/src/duckdb/ub_src_optimizer.cpp b/src/duckdb/ub_src_optimizer.cpp index 5ef91f3d9..5ba3728a3 100644 --- a/src/duckdb/ub_src_optimizer.cpp +++ b/src/duckdb/ub_src_optimizer.cpp @@ -4,6 +4,8 @@ #include "src/optimizer/column_lifetime_analyzer.cpp" +#include "src/optimizer/empty_result_pullup.cpp" + #include "src/optimizer/common_aggregate_optimizer.cpp" #include "src/optimizer/compressed_materialization.cpp" @@ -44,3 +46,5 @@ #include "src/optimizer/unnest_rewriter.cpp" +#include "src/optimizer/sampling_pushdown.cpp" + diff --git a/src/duckdb/ub_src_optimizer_pushdown.cpp b/src/duckdb/ub_src_optimizer_pushdown.cpp index a96fc9d8a..26f3d9c43 100644 --- a/src/duckdb/ub_src_optimizer_pushdown.cpp +++ b/src/duckdb/ub_src_optimizer_pushdown.cpp @@ -26,3 +26,5 @@ #include "src/optimizer/pushdown/pushdown_window.cpp" +#include "src/optimizer/pushdown/pushdown_unnest.cpp" + diff --git a/src/duckdb/ub_src_parser.cpp b/src/duckdb/ub_src_parser.cpp index efcbb8251..39c2c8368 100644 --- a/src/duckdb/ub_src_parser.cpp +++ b/src/duckdb/ub_src_parser.cpp @@ -16,6 +16,8 @@ #include "src/parser/parser.cpp" +#include "src/parser/qualified_name.cpp" + #include "src/parser/query_error_context.cpp" #include "src/parser/query_node.cpp" diff --git a/src/duckdb/ub_src_parser_parsed_data.cpp b/src/duckdb/ub_src_parser_parsed_data.cpp index bf80fff4b..b5bc65914 100644 --- a/src/duckdb/ub_src_parser_parsed_data.cpp +++ b/src/duckdb/ub_src_parser_parsed_data.cpp @@ -14,6 +14,8 @@ #include "src/parser/parsed_data/create_info.cpp" +#include "src/parser/parsed_data/create_function_info.cpp" + #include "src/parser/parsed_data/create_index_info.cpp" #include "src/parser/parsed_data/create_aggregate_function_info.cpp" diff --git a/src/duckdb/ub_src_planner.cpp b/src/duckdb/ub_src_planner.cpp index a02a37422..450ea623c 100644 --- a/src/duckdb/ub_src_planner.cpp +++ b/src/duckdb/ub_src_planner.cpp @@ -1,3 +1,5 @@ +#include "src/planner/binding_alias.cpp" + #include "src/planner/bound_result_modifier.cpp" #include "src/planner/bound_parameter_map.cpp" diff --git a/src/duckdb/ub_src_planner_filter.cpp b/src/duckdb/ub_src_planner_filter.cpp index 057a07714..700825c31 100644 --- a/src/duckdb/ub_src_planner_filter.cpp +++ b/src/duckdb/ub_src_planner_filter.cpp @@ -6,3 +6,5 @@ #include "src/planner/filter/struct_filter.cpp" +#include "src/planner/filter/optional_filter.cpp" + diff --git a/src/duckdb/ub_src_transaction.cpp b/src/duckdb/ub_src_transaction.cpp index f1f433751..c2b15db55 100644 --- a/src/duckdb/ub_src_transaction.cpp +++ b/src/duckdb/ub_src_transaction.cpp @@ -4,6 +4,8 @@ #include "src/transaction/meta_transaction.cpp" +#include "src/transaction/undo_buffer_allocator.cpp" + #include "src/transaction/undo_buffer.cpp" #include "src/transaction/transaction_context.cpp" diff --git a/src/include/sources.mk b/src/include/sources.mk index 47a534969..8df79ee16 100644 --- a/src/include/sources.mk +++ b/src/include/sources.mk @@ -1 +1 @@ -SOURCES=duckdb/ub_src_catalog.o duckdb/ub_src_catalog_catalog_entry.o duckdb/ub_src_catalog_catalog_entry_dependency.o duckdb/ub_src_catalog_default.o duckdb/ub_src_common_adbc.o duckdb/ub_src_common_adbc_nanoarrow.o duckdb/ub_src_common.o duckdb/ub_src_common_arrow_appender.o duckdb/ub_src_common_arrow.o duckdb/ub_src_common_crypto.o duckdb/ub_src_common_enums.o duckdb/ub_src_common_exception.o duckdb/ub_src_common_operator.o duckdb/ub_src_common_progress_bar.o duckdb/ub_src_common_row_operations.o duckdb/ub_src_common_serializer.o duckdb/ub_src_common_sort.o duckdb/ub_src_common_tree_renderer.o duckdb/ub_src_common_types.o duckdb/ub_src_common_types_column.o duckdb/ub_src_common_types_row.o duckdb/ub_src_common_value_operations.o duckdb/src/common/vector_operations/boolean_operators.o duckdb/src/common/vector_operations/comparison_operators.o duckdb/src/common/vector_operations/generators.o duckdb/src/common/vector_operations/is_distinct_from.o duckdb/src/common/vector_operations/null_operations.o duckdb/src/common/vector_operations/numeric_inplace_operators.o duckdb/src/common/vector_operations/vector_cast.o duckdb/src/common/vector_operations/vector_copy.o duckdb/src/common/vector_operations/vector_hash.o duckdb/src/common/vector_operations/vector_storage.o duckdb/ub_src_core_functions_aggregate_algebraic.o duckdb/ub_src_core_functions_aggregate_distributive.o duckdb/ub_src_core_functions_aggregate_holistic.o duckdb/ub_src_core_functions_aggregate_nested.o duckdb/ub_src_core_functions_aggregate_regression.o duckdb/ub_src_core_functions.o duckdb/ub_src_core_functions_scalar_array.o duckdb/ub_src_core_functions_scalar_bit.o duckdb/ub_src_core_functions_scalar_blob.o duckdb/ub_src_core_functions_scalar_date.o duckdb/ub_src_core_functions_scalar_debug.o duckdb/ub_src_core_functions_scalar_enum.o duckdb/ub_src_core_functions_scalar_generic.o duckdb/ub_src_core_functions_scalar_list.o duckdb/ub_src_core_functions_scalar_map.o duckdb/ub_src_core_functions_scalar_math.o duckdb/ub_src_core_functions_scalar_operators.o duckdb/ub_src_core_functions_scalar_random.o duckdb/ub_src_core_functions_scalar_string.o duckdb/ub_src_core_functions_scalar_struct.o duckdb/ub_src_core_functions_scalar_union.o duckdb/ub_src_execution.o duckdb/ub_src_execution_expression_executor.o duckdb/ub_src_execution_index_art.o duckdb/ub_src_execution_index.o duckdb/ub_src_execution_nested_loop_join.o duckdb/ub_src_execution_operator_aggregate.o duckdb/ub_src_execution_operator_csv_scanner_buffer_manager.o duckdb/ub_src_execution_operator_csv_scanner_scanner.o duckdb/ub_src_execution_operator_csv_scanner_sniffer.o duckdb/ub_src_execution_operator_csv_scanner_state_machine.o duckdb/ub_src_execution_operator_csv_scanner_table_function.o duckdb/ub_src_execution_operator_csv_scanner_util.o duckdb/ub_src_execution_operator_filter.o duckdb/ub_src_execution_operator_helper.o duckdb/ub_src_execution_operator_join.o duckdb/ub_src_execution_operator_order.o duckdb/ub_src_execution_operator_persistent.o duckdb/ub_src_execution_operator_projection.o duckdb/ub_src_execution_operator_scan.o duckdb/ub_src_execution_operator_schema.o duckdb/ub_src_execution_operator_set.o duckdb/ub_src_execution_physical_plan.o duckdb/ub_src_function_aggregate_distributive.o duckdb/ub_src_function_aggregate.o duckdb/ub_src_function.o duckdb/ub_src_function_cast.o duckdb/ub_src_function_cast_union.o duckdb/ub_src_function_pragma.o duckdb/ub_src_function_scalar_compressed_materialization.o duckdb/ub_src_function_scalar.o duckdb/ub_src_function_scalar_generic.o duckdb/ub_src_function_scalar_list.o duckdb/ub_src_function_scalar_operators.o duckdb/ub_src_function_scalar_sequence.o duckdb/ub_src_function_scalar_string.o duckdb/ub_src_function_scalar_string_regexp.o duckdb/ub_src_function_scalar_struct.o duckdb/ub_src_function_scalar_system.o duckdb/ub_src_function_table_arrow.o duckdb/ub_src_function_table.o duckdb/ub_src_function_table_system.o duckdb/ub_src_function_table_version.o duckdb/ub_src_main.o duckdb/ub_src_main_buffered_data.o duckdb/ub_src_main_capi.o duckdb/ub_src_main_capi_cast.o duckdb/ub_src_main_chunk_scan_state.o duckdb/ub_src_main_extension.o duckdb/ub_src_main_relation.o duckdb/ub_src_main_secret.o duckdb/ub_src_main_settings.o duckdb/ub_src_optimizer.o duckdb/ub_src_optimizer_compressed_materialization.o duckdb/ub_src_optimizer_join_order.o duckdb/ub_src_optimizer_matcher.o duckdb/ub_src_optimizer_pullup.o duckdb/ub_src_optimizer_pushdown.o duckdb/ub_src_optimizer_rule.o duckdb/ub_src_optimizer_statistics_expression.o duckdb/ub_src_optimizer_statistics_operator.o duckdb/ub_src_parallel.o duckdb/ub_src_parser.o duckdb/ub_src_parser_constraints.o duckdb/ub_src_parser_expression.o duckdb/ub_src_parser_parsed_data.o duckdb/ub_src_parser_query_node.o duckdb/ub_src_parser_statement.o duckdb/ub_src_parser_tableref.o duckdb/ub_src_parser_transform_constraint.o duckdb/ub_src_parser_transform_expression.o duckdb/ub_src_parser_transform_helpers.o duckdb/ub_src_parser_transform_statement.o duckdb/ub_src_parser_transform_tableref.o duckdb/ub_src_planner.o duckdb/ub_src_planner_binder_expression.o duckdb/ub_src_planner_binder_query_node.o duckdb/ub_src_planner_binder_statement.o duckdb/ub_src_planner_binder_tableref.o duckdb/ub_src_planner_expression.o duckdb/ub_src_planner_expression_binder.o duckdb/ub_src_planner_filter.o duckdb/ub_src_planner_operator.o duckdb/ub_src_planner_subquery.o duckdb/ub_src_storage.o duckdb/ub_src_storage_buffer.o duckdb/ub_src_storage_checkpoint.o duckdb/ub_src_storage_compression_alp.o duckdb/ub_src_storage_compression.o duckdb/ub_src_storage_compression_chimp.o duckdb/ub_src_storage_metadata.o duckdb/ub_src_storage_serialization.o duckdb/ub_src_storage_statistics.o duckdb/ub_src_storage_table.o duckdb/ub_src_transaction.o duckdb/src/verification/copied_statement_verifier.o duckdb/src/verification/deserialized_statement_verifier.o duckdb/src/verification/external_statement_verifier.o duckdb/src/verification/fetch_row_verifier.o duckdb/src/verification/no_operator_caching_verifier.o duckdb/src/verification/parsed_statement_verifier.o duckdb/src/verification/prepared_statement_verifier.o duckdb/src/verification/statement_verifier.o duckdb/src/verification/unoptimized_statement_verifier.o duckdb/third_party/fmt/format.o duckdb/third_party/fsst/libfsst.o duckdb/third_party/miniz/miniz.o duckdb/third_party/re2/re2/bitmap256.o duckdb/third_party/re2/re2/bitstate.o duckdb/third_party/re2/re2/compile.o duckdb/third_party/re2/re2/dfa.o duckdb/third_party/re2/re2/filtered_re2.o duckdb/third_party/re2/re2/mimics_pcre.o duckdb/third_party/re2/re2/nfa.o duckdb/third_party/re2/re2/onepass.o duckdb/third_party/re2/re2/parse.o duckdb/third_party/re2/re2/perl_groups.o duckdb/third_party/re2/re2/prefilter.o duckdb/third_party/re2/re2/prefilter_tree.o duckdb/third_party/re2/re2/prog.o duckdb/third_party/re2/re2/re2.o duckdb/third_party/re2/re2/regexp.o duckdb/third_party/re2/re2/set.o duckdb/third_party/re2/re2/simplify.o duckdb/third_party/re2/re2/stringpiece.o duckdb/third_party/re2/re2/tostring.o duckdb/third_party/re2/re2/unicode_casefold.o duckdb/third_party/re2/re2/unicode_groups.o duckdb/third_party/re2/util/rune.o duckdb/third_party/re2/util/strutil.o duckdb/third_party/hyperloglog/hyperloglog.o duckdb/third_party/hyperloglog/sds.o duckdb/third_party/skiplist/SkipList.o duckdb/third_party/fastpforlib/bitpacking.o duckdb/third_party/utf8proc/utf8proc.o duckdb/third_party/utf8proc/utf8proc_wrapper.o duckdb/third_party/libpg_query/pg_functions.o duckdb/third_party/libpg_query/postgres_parser.o duckdb/third_party/libpg_query/src_backend_nodes_list.o duckdb/third_party/libpg_query/src_backend_nodes_makefuncs.o duckdb/third_party/libpg_query/src_backend_nodes_value.o duckdb/third_party/libpg_query/src_backend_parser_gram.o duckdb/third_party/libpg_query/src_backend_parser_parser.o duckdb/third_party/libpg_query/src_backend_parser_scan.o duckdb/third_party/libpg_query/src_backend_parser_scansup.o duckdb/third_party/libpg_query/src_common_keywords.o duckdb/third_party/mbedtls/library/aes.o duckdb/third_party/mbedtls/library/aria.o duckdb/third_party/mbedtls/library/asn1parse.o duckdb/third_party/mbedtls/library/base64.o duckdb/third_party/mbedtls/library/bignum.o duckdb/third_party/mbedtls/library/camellia.o duckdb/third_party/mbedtls/library/cipher.o duckdb/third_party/mbedtls/library/cipher_wrap.o duckdb/third_party/mbedtls/library/constant_time.o duckdb/third_party/mbedtls/library/entropy.o duckdb/third_party/mbedtls/library/entropy_poll.o duckdb/third_party/mbedtls/library/gcm.o duckdb/third_party/mbedtls/library/md.o duckdb/third_party/mbedtls/library/oid.o duckdb/third_party/mbedtls/library/pem.o duckdb/third_party/mbedtls/library/pk.o duckdb/third_party/mbedtls/library/pk_wrap.o duckdb/third_party/mbedtls/library/pkparse.o duckdb/third_party/mbedtls/library/platform_util.o duckdb/third_party/mbedtls/library/rsa.o duckdb/third_party/mbedtls/library/rsa_alt_helpers.o duckdb/third_party/mbedtls/library/sha1.o duckdb/third_party/mbedtls/library/sha256.o duckdb/third_party/mbedtls/library/sha512.o duckdb/third_party/mbedtls/mbedtls_wrapper.o duckdb/third_party/yyjson/yyjson.o duckdb/extension/parquet/column_reader.o duckdb/extension/parquet/column_writer.o duckdb/extension/parquet/parquet_crypto.o duckdb/extension/parquet/parquet_extension.o duckdb/extension/parquet/parquet_metadata.o duckdb/extension/parquet/parquet_reader.o duckdb/extension/parquet/parquet_statistics.o duckdb/extension/parquet/parquet_timestamp.o duckdb/extension/parquet/parquet_writer.o duckdb/extension/parquet/serialize_parquet.o duckdb/extension/parquet/zstd_file_system.o duckdb/extension/parquet/geo_parquet.o duckdb/third_party/parquet/parquet_constants.o duckdb/third_party/parquet/parquet_types.o duckdb/third_party/thrift/thrift/protocol/TProtocol.o duckdb/third_party/thrift/thrift/transport/TTransportException.o duckdb/third_party/thrift/thrift/transport/TBufferTransports.o duckdb/third_party/snappy/snappy.o duckdb/third_party/snappy/snappy-sinksource.o duckdb/third_party/zstd/decompress/zstd_ddict.o duckdb/third_party/zstd/decompress/huf_decompress.o duckdb/third_party/zstd/decompress/zstd_decompress.o duckdb/third_party/zstd/decompress/zstd_decompress_block.o duckdb/third_party/zstd/common/entropy_common.o duckdb/third_party/zstd/common/fse_decompress.o duckdb/third_party/zstd/common/zstd_common.o duckdb/third_party/zstd/common/error_private.o duckdb/third_party/zstd/common/xxhash.o duckdb/third_party/zstd/compress/fse_compress.o duckdb/third_party/zstd/compress/hist.o duckdb/third_party/zstd/compress/huf_compress.o duckdb/third_party/zstd/compress/zstd_compress.o duckdb/third_party/zstd/compress/zstd_compress_literals.o duckdb/third_party/zstd/compress/zstd_compress_sequences.o duckdb/third_party/zstd/compress/zstd_compress_superblock.o duckdb/third_party/zstd/compress/zstd_double_fast.o duckdb/third_party/zstd/compress/zstd_fast.o duckdb/third_party/zstd/compress/zstd_lazy.o duckdb/third_party/zstd/compress/zstd_ldm.o duckdb/third_party/zstd/compress/zstd_opt.o duckdb/third_party/lz4/lz4.o duckdb/third_party/brotli/common/constants.o duckdb/third_party/brotli/common/context.o duckdb/third_party/brotli/common/dictionary.o duckdb/third_party/brotli/common/platform.o duckdb/third_party/brotli/common/shared_dictionary.o duckdb/third_party/brotli/common/transform.o duckdb/third_party/brotli/dec/bit_reader.o duckdb/third_party/brotli/dec/decode.o duckdb/third_party/brotli/dec/huffman.o duckdb/third_party/brotli/dec/state.o duckdb/third_party/brotli/enc/backward_references.o duckdb/third_party/brotli/enc/backward_references_hq.o duckdb/third_party/brotli/enc/bit_cost.o duckdb/third_party/brotli/enc/block_splitter.o duckdb/third_party/brotli/enc/brotli_bit_stream.o duckdb/third_party/brotli/enc/cluster.o duckdb/third_party/brotli/enc/command.o duckdb/third_party/brotli/enc/compound_dictionary.o duckdb/third_party/brotli/enc/compress_fragment.o duckdb/third_party/brotli/enc/compress_fragment_two_pass.o duckdb/third_party/brotli/enc/dictionary_hash.o duckdb/third_party/brotli/enc/encode.o duckdb/third_party/brotli/enc/encoder_dict.o duckdb/third_party/brotli/enc/entropy_encode.o duckdb/third_party/brotli/enc/fast_log.o duckdb/third_party/brotli/enc/histogram.o duckdb/third_party/brotli/enc/literal_cost.o duckdb/third_party/brotli/enc/memory.o duckdb/third_party/brotli/enc/metablock.o duckdb/third_party/brotli/enc/static_dict.o duckdb/third_party/brotli/enc/utf8_util.o +SOURCES=duckdb/ub_src_catalog.o duckdb/ub_src_catalog_catalog_entry.o duckdb/ub_src_catalog_catalog_entry_dependency.o duckdb/ub_src_catalog_default.o duckdb/ub_src_common_adbc.o duckdb/ub_src_common_adbc_nanoarrow.o duckdb/ub_src_common.o duckdb/ub_src_common_arrow_appender.o duckdb/ub_src_common_arrow.o duckdb/ub_src_common_crypto.o duckdb/ub_src_common_enums.o duckdb/ub_src_common_exception.o duckdb/ub_src_common_operator.o duckdb/ub_src_common_progress_bar.o duckdb/ub_src_common_row_operations.o duckdb/ub_src_common_serializer.o duckdb/ub_src_common_sort.o duckdb/ub_src_common_tree_renderer.o duckdb/ub_src_common_types.o duckdb/ub_src_common_types_column.o duckdb/ub_src_common_types_row.o duckdb/ub_src_common_value_operations.o duckdb/src/common/vector_operations/boolean_operators.o duckdb/src/common/vector_operations/comparison_operators.o duckdb/src/common/vector_operations/generators.o duckdb/src/common/vector_operations/is_distinct_from.o duckdb/src/common/vector_operations/null_operations.o duckdb/src/common/vector_operations/numeric_inplace_operators.o duckdb/src/common/vector_operations/vector_cast.o duckdb/src/common/vector_operations/vector_copy.o duckdb/src/common/vector_operations/vector_hash.o duckdb/src/common/vector_operations/vector_storage.o duckdb/ub_src_execution.o duckdb/ub_src_execution_expression_executor.o duckdb/ub_src_execution_index_art.o duckdb/ub_src_execution_index.o duckdb/ub_src_execution_nested_loop_join.o duckdb/ub_src_execution_operator_aggregate.o duckdb/ub_src_execution_operator_csv_scanner_buffer_manager.o duckdb/ub_src_execution_operator_csv_scanner_scanner.o duckdb/ub_src_execution_operator_csv_scanner_sniffer.o duckdb/ub_src_execution_operator_csv_scanner_state_machine.o duckdb/ub_src_execution_operator_csv_scanner_table_function.o duckdb/ub_src_execution_operator_csv_scanner_util.o duckdb/ub_src_execution_operator_filter.o duckdb/ub_src_execution_operator_helper.o duckdb/ub_src_execution_operator_join.o duckdb/ub_src_execution_operator_order.o duckdb/ub_src_execution_operator_persistent.o duckdb/ub_src_execution_operator_projection.o duckdb/ub_src_execution_operator_scan.o duckdb/ub_src_execution_operator_schema.o duckdb/ub_src_execution_operator_set.o duckdb/ub_src_execution_physical_plan.o duckdb/ub_src_function_aggregate_distributive.o duckdb/ub_src_function_aggregate.o duckdb/ub_src_function.o duckdb/ub_src_function_cast.o duckdb/ub_src_function_cast_union.o duckdb/ub_src_function_pragma.o duckdb/ub_src_function_scalar_compressed_materialization.o duckdb/ub_src_function_scalar.o duckdb/ub_src_function_scalar_date.o duckdb/ub_src_function_scalar_generic.o duckdb/ub_src_function_scalar_list.o duckdb/ub_src_function_scalar_map.o duckdb/ub_src_function_scalar_operator.o duckdb/ub_src_function_scalar_sequence.o duckdb/ub_src_function_scalar_string.o duckdb/ub_src_function_scalar_string_regexp.o duckdb/ub_src_function_scalar_struct.o duckdb/ub_src_function_scalar_system.o duckdb/ub_src_function_table_arrow.o duckdb/ub_src_function_table.o duckdb/ub_src_function_table_system.o duckdb/ub_src_function_table_version.o duckdb/ub_src_main.o duckdb/ub_src_main_buffered_data.o duckdb/ub_src_main_capi.o duckdb/ub_src_main_capi_cast.o duckdb/ub_src_main_chunk_scan_state.o duckdb/ub_src_main_extension.o duckdb/ub_src_main_relation.o duckdb/ub_src_main_secret.o duckdb/ub_src_main_settings.o duckdb/ub_src_optimizer.o duckdb/ub_src_optimizer_compressed_materialization.o duckdb/ub_src_optimizer_join_order.o duckdb/ub_src_optimizer_matcher.o duckdb/ub_src_optimizer_pullup.o duckdb/ub_src_optimizer_pushdown.o duckdb/ub_src_optimizer_rule.o duckdb/ub_src_optimizer_statistics_expression.o duckdb/ub_src_optimizer_statistics_operator.o duckdb/ub_src_parallel.o duckdb/ub_src_parser.o duckdb/ub_src_parser_constraints.o duckdb/ub_src_parser_expression.o duckdb/ub_src_parser_parsed_data.o duckdb/ub_src_parser_query_node.o duckdb/ub_src_parser_statement.o duckdb/ub_src_parser_tableref.o duckdb/ub_src_parser_transform_constraint.o duckdb/ub_src_parser_transform_expression.o duckdb/ub_src_parser_transform_helpers.o duckdb/ub_src_parser_transform_statement.o duckdb/ub_src_parser_transform_tableref.o duckdb/ub_src_planner.o duckdb/ub_src_planner_binder_expression.o duckdb/ub_src_planner_binder_query_node.o duckdb/ub_src_planner_binder_statement.o duckdb/ub_src_planner_binder_tableref.o duckdb/ub_src_planner_expression.o duckdb/ub_src_planner_expression_binder.o duckdb/ub_src_planner_filter.o duckdb/ub_src_planner_operator.o duckdb/ub_src_planner_subquery.o duckdb/ub_src_storage.o duckdb/ub_src_storage_buffer.o duckdb/ub_src_storage_checkpoint.o duckdb/ub_src_storage_compression_alp.o duckdb/ub_src_storage_compression.o duckdb/ub_src_storage_compression_chimp.o duckdb/ub_src_storage_metadata.o duckdb/ub_src_storage_serialization.o duckdb/ub_src_storage_statistics.o duckdb/ub_src_storage_table.o duckdb/ub_src_transaction.o duckdb/src/verification/copied_statement_verifier.o duckdb/src/verification/deserialized_statement_verifier.o duckdb/src/verification/external_statement_verifier.o duckdb/src/verification/fetch_row_verifier.o duckdb/src/verification/no_operator_caching_verifier.o duckdb/src/verification/parsed_statement_verifier.o duckdb/src/verification/prepared_statement_verifier.o duckdb/src/verification/statement_verifier.o duckdb/src/verification/unoptimized_statement_verifier.o duckdb/third_party/fmt/format.o duckdb/third_party/fsst/libfsst.o duckdb/third_party/miniz/miniz.o duckdb/third_party/re2/re2/bitmap256.o duckdb/third_party/re2/re2/bitstate.o duckdb/third_party/re2/re2/compile.o duckdb/third_party/re2/re2/dfa.o duckdb/third_party/re2/re2/filtered_re2.o duckdb/third_party/re2/re2/mimics_pcre.o duckdb/third_party/re2/re2/nfa.o duckdb/third_party/re2/re2/onepass.o duckdb/third_party/re2/re2/parse.o duckdb/third_party/re2/re2/perl_groups.o duckdb/third_party/re2/re2/prefilter.o duckdb/third_party/re2/re2/prefilter_tree.o duckdb/third_party/re2/re2/prog.o duckdb/third_party/re2/re2/re2.o duckdb/third_party/re2/re2/regexp.o duckdb/third_party/re2/re2/set.o duckdb/third_party/re2/re2/simplify.o duckdb/third_party/re2/re2/stringpiece.o duckdb/third_party/re2/re2/tostring.o duckdb/third_party/re2/re2/unicode_casefold.o duckdb/third_party/re2/re2/unicode_groups.o duckdb/third_party/re2/util/rune.o duckdb/third_party/re2/util/strutil.o duckdb/third_party/hyperloglog/hyperloglog.o duckdb/third_party/hyperloglog/sds.o duckdb/third_party/skiplist/SkipList.o duckdb/third_party/fastpforlib/bitpacking.o duckdb/third_party/utf8proc/utf8proc.o duckdb/third_party/utf8proc/utf8proc_wrapper.o duckdb/third_party/libpg_query/pg_functions.o duckdb/third_party/libpg_query/postgres_parser.o duckdb/third_party/libpg_query/src_backend_nodes_list.o duckdb/third_party/libpg_query/src_backend_nodes_makefuncs.o duckdb/third_party/libpg_query/src_backend_nodes_value.o duckdb/third_party/libpg_query/src_backend_parser_gram.o duckdb/third_party/libpg_query/src_backend_parser_parser.o duckdb/third_party/libpg_query/src_backend_parser_scan.o duckdb/third_party/libpg_query/src_backend_parser_scansup.o duckdb/third_party/libpg_query/src_common_keywords.o duckdb/third_party/mbedtls/library/aes.o duckdb/third_party/mbedtls/library/aria.o duckdb/third_party/mbedtls/library/asn1parse.o duckdb/third_party/mbedtls/library/base64.o duckdb/third_party/mbedtls/library/bignum.o duckdb/third_party/mbedtls/library/camellia.o duckdb/third_party/mbedtls/library/cipher.o duckdb/third_party/mbedtls/library/cipher_wrap.o duckdb/third_party/mbedtls/library/constant_time.o duckdb/third_party/mbedtls/library/entropy.o duckdb/third_party/mbedtls/library/entropy_poll.o duckdb/third_party/mbedtls/library/gcm.o duckdb/third_party/mbedtls/library/md.o duckdb/third_party/mbedtls/library/oid.o duckdb/third_party/mbedtls/library/pem.o duckdb/third_party/mbedtls/library/pk.o duckdb/third_party/mbedtls/library/pk_wrap.o duckdb/third_party/mbedtls/library/pkparse.o duckdb/third_party/mbedtls/library/platform_util.o duckdb/third_party/mbedtls/library/rsa.o duckdb/third_party/mbedtls/library/rsa_alt_helpers.o duckdb/third_party/mbedtls/library/sha1.o duckdb/third_party/mbedtls/library/sha256.o duckdb/third_party/mbedtls/library/sha512.o duckdb/third_party/mbedtls/mbedtls_wrapper.o duckdb/third_party/yyjson/yyjson.o duckdb/third_party/zstd/common/debug.o duckdb/third_party/zstd/common/entropy_common.o duckdb/third_party/zstd/common/error_private.o duckdb/third_party/zstd/common/fse_decompress.o duckdb/third_party/zstd/common/pool.o duckdb/third_party/zstd/common/threading.o duckdb/third_party/zstd/common/xxhash.o duckdb/third_party/zstd/common/zstd_common.o duckdb/third_party/zstd/compress/fse_compress.o duckdb/third_party/zstd/compress/hist.o duckdb/third_party/zstd/compress/huf_compress.o duckdb/third_party/zstd/compress/zstd_compress.o duckdb/third_party/zstd/compress/zstd_compress_literals.o duckdb/third_party/zstd/compress/zstd_compress_sequences.o duckdb/third_party/zstd/compress/zstd_compress_superblock.o duckdb/third_party/zstd/compress/zstd_double_fast.o duckdb/third_party/zstd/compress/zstd_fast.o duckdb/third_party/zstd/compress/zstd_lazy.o duckdb/third_party/zstd/compress/zstd_ldm.o duckdb/third_party/zstd/compress/zstd_opt.o duckdb/third_party/zstd/compress/zstdmt_compress.o duckdb/third_party/zstd/decompress/huf_decompress.o duckdb/third_party/zstd/decompress/zstd_ddict.o duckdb/third_party/zstd/decompress/zstd_decompress.o duckdb/third_party/zstd/decompress/zstd_decompress_block.o duckdb/third_party/zstd/deprecated/zbuff_common.o duckdb/third_party/zstd/deprecated/zbuff_compress.o duckdb/third_party/zstd/deprecated/zbuff_decompress.o duckdb/third_party/zstd/dict/cover.o duckdb/third_party/zstd/dict/divsufsort.o duckdb/third_party/zstd/dict/fastcover.o duckdb/third_party/zstd/dict/zdict.o duckdb/extension/parquet/column_reader.o duckdb/extension/parquet/column_writer.o duckdb/extension/parquet/parquet_crypto.o duckdb/extension/parquet/parquet_extension.o duckdb/extension/parquet/parquet_metadata.o duckdb/extension/parquet/parquet_reader.o duckdb/extension/parquet/parquet_statistics.o duckdb/extension/parquet/parquet_timestamp.o duckdb/extension/parquet/parquet_writer.o duckdb/extension/parquet/serialize_parquet.o duckdb/extension/parquet/zstd_file_system.o duckdb/extension/parquet/geo_parquet.o duckdb/third_party/parquet/parquet_types.o duckdb/third_party/thrift/thrift/protocol/TProtocol.o duckdb/third_party/thrift/thrift/transport/TTransportException.o duckdb/third_party/thrift/thrift/transport/TBufferTransports.o duckdb/third_party/snappy/snappy.o duckdb/third_party/snappy/snappy-sinksource.o duckdb/third_party/lz4/lz4.o duckdb/third_party/brotli/common/constants.o duckdb/third_party/brotli/common/context.o duckdb/third_party/brotli/common/dictionary.o duckdb/third_party/brotli/common/platform.o duckdb/third_party/brotli/common/shared_dictionary.o duckdb/third_party/brotli/common/transform.o duckdb/third_party/brotli/dec/bit_reader.o duckdb/third_party/brotli/dec/decode.o duckdb/third_party/brotli/dec/huffman.o duckdb/third_party/brotli/dec/state.o duckdb/third_party/brotli/enc/backward_references.o duckdb/third_party/brotli/enc/backward_references_hq.o duckdb/third_party/brotli/enc/bit_cost.o duckdb/third_party/brotli/enc/block_splitter.o duckdb/third_party/brotli/enc/brotli_bit_stream.o duckdb/third_party/brotli/enc/cluster.o duckdb/third_party/brotli/enc/command.o duckdb/third_party/brotli/enc/compound_dictionary.o duckdb/third_party/brotli/enc/compress_fragment.o duckdb/third_party/brotli/enc/compress_fragment_two_pass.o duckdb/third_party/brotli/enc/dictionary_hash.o duckdb/third_party/brotli/enc/encode.o duckdb/third_party/brotli/enc/encoder_dict.o duckdb/third_party/brotli/enc/entropy_encode.o duckdb/third_party/brotli/enc/fast_log.o duckdb/third_party/brotli/enc/histogram.o duckdb/third_party/brotli/enc/literal_cost.o duckdb/third_party/brotli/enc/memory.o duckdb/third_party/brotli/enc/metablock.o duckdb/third_party/brotli/enc/static_dict.o duckdb/third_party/brotli/enc/utf8_util.o