/src/duckdb/extension/parquet/parquet_metadata.cpp
Line | Count | Source |
1 | | #include <stdint.h> |
2 | | #include <functional> |
3 | | #include <memory> |
4 | | #include <string> |
5 | | #include <utility> |
6 | | #include <vector> |
7 | | #include <sstream> |
8 | | |
9 | | #include "duckdb/common/vector/list_vector.hpp" |
10 | | #include "duckdb/common/vector/struct_vector.hpp" |
11 | | #include "parquet_metadata.hpp" |
12 | | #include "parquet_statistics.hpp" |
13 | | #include "duckdb/common/multi_file/multi_file_reader.hpp" |
14 | | #include "duckdb/common/multi_file/multi_file_list.hpp" |
15 | | #include "parquet_reader.hpp" |
16 | | #include "duckdb/common/numeric_utils.hpp" |
17 | | #include "duckdb/common/allocator.hpp" |
18 | | #include "duckdb/common/assert.hpp" |
19 | | #include "duckdb/common/enums/expression_type.hpp" |
20 | | #include "duckdb/common/enums/file_glob_options.hpp" |
21 | | #include "duckdb/common/enums/vector_type.hpp" |
22 | | #include "duckdb/common/exception.hpp" |
23 | | #include "duckdb/common/helper.hpp" |
24 | | #include "duckdb/common/multi_file/multi_file_data.hpp" |
25 | | #include "duckdb/common/mutex.hpp" |
26 | | #include "duckdb/common/open_file_info.hpp" |
27 | | #include "duckdb/common/optional_idx.hpp" |
28 | | #include "duckdb/common/optional_ptr.hpp" |
29 | | #include "duckdb/common/pair.hpp" |
30 | | #include "duckdb/common/shared_ptr_ipp.hpp" |
31 | | #include "duckdb/common/string.hpp" |
32 | | #include "duckdb/common/string_util.hpp" |
33 | | #include "duckdb/common/typedefs.hpp" |
34 | | #include "duckdb/common/types.hpp" |
35 | | #include "duckdb/common/types/data_chunk.hpp" |
36 | | #include "duckdb/common/types/validity_mask.hpp" |
37 | | #include "duckdb/common/types/value.hpp" |
38 | | #include "duckdb/common/types/vector.hpp" |
39 | | #include "duckdb/common/unique_ptr.hpp" |
40 | | #include "duckdb/common/vector.hpp" |
41 | | #include "duckdb/common/vector/flat_vector.hpp" |
42 | | #include "duckdb/common/vector_size.hpp" |
43 | | #include "duckdb/execution/partition_info.hpp" |
44 | | #include "duckdb/function/function.hpp" |
45 | | #include "duckdb/function/table_function.hpp" |
46 | | #include "duckdb/original/std/memory.hpp" |
47 | | #include "duckdb/parallel/task_scheduler.hpp" |
48 | | #include "duckdb/storage/external_file_cache/caching_file_system.hpp" |
49 | | #include "duckdb/storage/statistics/geometry_stats.hpp" |
50 | | #include "parquet_column_schema.hpp" |
51 | | #include "parquet_file_metadata_cache.hpp" |
52 | | #include "parquet_types.h" |
53 | | #include "thrift/protocol/TCompactProtocol.h" |
54 | | #include "thrift_tools.hpp" |
55 | | #include "duckdb/planner/filter/expression_filter.hpp" |
56 | | #include "duckdb/planner/expression/bound_comparison_expression.hpp" |
57 | | #include "duckdb/planner/expression/bound_constant_expression.hpp" |
58 | | #include "duckdb/planner/expression/bound_reference_expression.hpp" |
59 | | |
60 | | namespace duckdb { |
61 | | class ClientContext; |
62 | | class ExecutionContext; |
63 | | enum class GeometryType : uint8_t; |
64 | | enum class VertexType : uint8_t; |
65 | | |
66 | | struct ParquetMetadataFilePaths { |
67 | | MultiFileListScanData scan_data; |
68 | | shared_ptr<MultiFileList> file_list; |
69 | | mutex file_lock; |
70 | | |
71 | 974 | bool NextFile(OpenFileInfo &result) { |
72 | 974 | D_ASSERT(file_list); |
73 | 974 | unique_lock<mutex> lock(file_lock); |
74 | 974 | return file_list->Scan(scan_data, result); |
75 | 974 | } |
76 | | |
77 | 974 | FileExpandResult GetExpandResult() { |
78 | 974 | D_ASSERT(file_list); |
79 | 974 | unique_lock<mutex> lock(file_lock); |
80 | 974 | return file_list->GetExpandResult(); |
81 | 974 | } |
82 | | }; |
83 | | |
84 | | struct ParquetMetaDataBindData : public TableFunctionData { |
85 | | unique_ptr<ParquetMetadataFilePaths> file_paths; |
86 | | }; |
87 | | |
88 | | struct ParquetBloomProbeBindData : public ParquetMetaDataBindData { |
89 | | string probe_column_name; |
90 | | Value probe_constant; |
91 | | }; |
92 | | |
93 | | enum class ParquetMetadataOperatorType : uint8_t { |
94 | | META_DATA, |
95 | | SCHEMA, |
96 | | KEY_VALUE_META_DATA, |
97 | | FILE_META_DATA, |
98 | | BLOOM_PROBE, |
99 | | FULL_METADATA |
100 | | }; |
101 | | |
102 | | class ParquetMetadataFileProcessor { |
103 | | public: |
104 | 974 | ParquetMetadataFileProcessor() = default; |
105 | 974 | virtual ~ParquetMetadataFileProcessor() = default; |
106 | 0 | void Initialize(ClientContext &context, ParquetReader &reader) { |
107 | 0 | InitializeInternal(context, reader); |
108 | 0 | } |
109 | 0 | virtual void InitializeInternal(ClientContext &context, ParquetReader &reader) {}; |
110 | | virtual idx_t TotalRowCount(ParquetReader &reader) = 0; |
111 | | virtual void ReadRow(vector<reference<Vector>> &output, idx_t row_idx, ParquetReader &reader) = 0; |
112 | 0 | virtual bool ForceFlush() { |
113 | 0 | return false; |
114 | 0 | } |
115 | | }; |
116 | | |
117 | | class ParquetMetaDataOperator { |
118 | | public: |
119 | | template <ParquetMetadataOperatorType OP_TYPE> |
120 | | static unique_ptr<FunctionData> Bind(ClientContext &context, TableFunctionBindInput &input, |
121 | | vector<LogicalType> &return_types, vector<string> &names); |
122 | | static unique_ptr<GlobalTableFunctionState> InitGlobal(ClientContext &context, TableFunctionInitInput &input); |
123 | | template <ParquetMetadataOperatorType OP_TYPE> |
124 | | static unique_ptr<LocalTableFunctionState> InitLocal(ExecutionContext &context, TableFunctionInitInput &input, |
125 | | GlobalTableFunctionState *global_state); |
126 | | static void Function(ClientContext &context, TableFunctionInput &data_p, DataChunk &output); |
127 | | static double Progress(ClientContext &context, const FunctionData *bind_data_p, |
128 | | const GlobalTableFunctionState *global_state); |
129 | | |
130 | | template <ParquetMetadataOperatorType OP_TYPE> |
131 | | static void BindSchema(vector<LogicalType> &return_types, vector<string> &names); |
132 | | |
133 | | static OperatorPartitionData GetPartitionData(ClientContext &context, TableFunctionGetPartitionInput &input); |
134 | | }; |
135 | | |
136 | | struct ParquetMetadataGlobalState : public GlobalTableFunctionState { |
137 | | ParquetMetadataGlobalState(unique_ptr<ParquetMetadataFilePaths> file_paths_p, ClientContext &context) |
138 | 974 | : file_paths(std::move(file_paths_p)) { |
139 | 974 | auto expand_result = file_paths->GetExpandResult(); |
140 | 974 | if (expand_result == FileExpandResult::MULTIPLE_FILES) { |
141 | 0 | max_threads = TaskScheduler::GetScheduler(context).NumberOfThreads(); |
142 | 974 | } else { |
143 | 974 | max_threads = 1; |
144 | 974 | } |
145 | 974 | } |
146 | | |
147 | 974 | idx_t MaxThreads() const override { |
148 | 974 | return max_threads; |
149 | 974 | } |
150 | | |
151 | 0 | bool NextFile(ClientContext &context, OpenFileInfo &result) { |
152 | 0 | return file_paths->NextFile(result); |
153 | 0 | } |
154 | | |
155 | 0 | double GetProgress() const { |
156 | | // Not the most accurate, instantly assumes all files are done and equal |
157 | 0 | unique_lock<mutex> lock(file_paths->file_lock); |
158 | 0 | return static_cast<double>(file_paths->scan_data.current_file_idx) / |
159 | 0 | static_cast<double>(file_paths->file_list->GetTotalFileCount()); |
160 | 0 | } |
161 | | |
162 | | unique_ptr<ParquetMetadataFilePaths> file_paths; |
163 | | idx_t max_threads; |
164 | | mutex lock; |
165 | | idx_t current_file = 0; |
166 | | }; |
167 | | |
168 | | struct ParquetMetadataLocalState : public LocalTableFunctionState { |
169 | | unique_ptr<ParquetReader> reader; |
170 | | unique_ptr<ParquetMetadataFileProcessor> processor; |
171 | | bool file_exhausted = true; |
172 | | idx_t row_idx = 0; |
173 | | idx_t total_rows = 0; |
174 | | optional_idx file_idx; |
175 | | |
176 | 974 | void Initialize(ClientContext &context, OpenFileInfo &file_info, idx_t next_file_idx) { |
177 | 974 | ParquetOptions parquet_options(context); |
178 | 974 | reader = make_uniq<ParquetReader>(context, file_info, parquet_options); |
179 | 974 | processor->Initialize(context, *reader); |
180 | 974 | total_rows = processor->TotalRowCount(*reader); |
181 | 974 | row_idx = 0; |
182 | 974 | file_idx = next_file_idx; |
183 | 974 | file_exhausted = false; |
184 | 974 | } |
185 | | }; |
186 | | |
187 | | template <class T> |
188 | 0 | static string ConvertParquetElementToString(T &&entry) { |
189 | 0 | duckdb::stringstream ss; |
190 | 0 | ss << entry; |
191 | 0 | return ss.str(); |
192 | 0 | } Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::ConvertParquetElementToString<duckdb_parquet::Type::type const&>(duckdb_parquet::Type::type const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::ConvertParquetElementToString<duckdb_parquet::CompressionCodec::type const&>(duckdb_parquet::CompressionCodec::type const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::ConvertParquetElementToString<duckdb_parquet::Encoding::type const&>(duckdb_parquet::Encoding::type const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::ConvertParquetElementToString<duckdb_parquet::FieldRepetitionType::type const&>(duckdb_parquet::FieldRepetitionType::type const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::ConvertParquetElementToString<duckdb_parquet::ConvertedType::type const&>(duckdb_parquet::ConvertedType::type const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::ConvertParquetElementToString<duckdb_parquet::EncryptionAlgorithm const&>(duckdb_parquet::EncryptionAlgorithm const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::ConvertParquetElementToString<duckdb_parquet::ColumnOrder const&>(duckdb_parquet::ColumnOrder const&) |
193 | | |
194 | | template <class T> |
195 | 0 | static string PrintParquetElementToString(T &&entry) { |
196 | 0 | duckdb::stringstream ss; |
197 | 0 | entry.printTo(ss); |
198 | 0 | return ss.str(); |
199 | 0 | } Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::PrintParquetElementToString<duckdb_parquet::StringType const&>(duckdb_parquet::StringType const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::PrintParquetElementToString<duckdb_parquet::MapType const&>(duckdb_parquet::MapType const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::PrintParquetElementToString<duckdb_parquet::ListType const&>(duckdb_parquet::ListType const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::PrintParquetElementToString<duckdb_parquet::EnumType const&>(duckdb_parquet::EnumType const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::PrintParquetElementToString<duckdb_parquet::DecimalType const&>(duckdb_parquet::DecimalType const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::PrintParquetElementToString<duckdb_parquet::DateType const&>(duckdb_parquet::DateType const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::PrintParquetElementToString<duckdb_parquet::TimeType const&>(duckdb_parquet::TimeType const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::PrintParquetElementToString<duckdb_parquet::TimestampType const&>(duckdb_parquet::TimestampType const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::PrintParquetElementToString<duckdb_parquet::IntType const&>(duckdb_parquet::IntType const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::PrintParquetElementToString<duckdb_parquet::NullType const&>(duckdb_parquet::NullType const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::PrintParquetElementToString<duckdb_parquet::JsonType const&>(duckdb_parquet::JsonType const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::PrintParquetElementToString<duckdb_parquet::BsonType const&>(duckdb_parquet::BsonType const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::PrintParquetElementToString<duckdb_parquet::UUIDType const&>(duckdb_parquet::UUIDType const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::PrintParquetElementToString<duckdb_parquet::Float16Type const&>(duckdb_parquet::Float16Type const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::PrintParquetElementToString<duckdb_parquet::GeometryType const&>(duckdb_parquet::GeometryType const&) Unexecuted instantiation: parquet_metadata.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > duckdb::PrintParquetElementToString<duckdb_parquet::GeographyType const&>(duckdb_parquet::GeographyType const&) |
200 | | |
201 | | template <class T> |
202 | 0 | static Value ParquetElementString(T &&value, bool is_set) { |
203 | 0 | if (!is_set) { |
204 | 0 | return Value(); |
205 | 0 | } |
206 | 0 | return Value(ConvertParquetElementToString(value)); |
207 | 0 | } Unexecuted instantiation: parquet_metadata.cpp:duckdb::Value duckdb::ParquetElementString<duckdb_parquet::Type::type const&>(duckdb_parquet::Type::type const&, bool) Unexecuted instantiation: parquet_metadata.cpp:duckdb::Value duckdb::ParquetElementString<duckdb_parquet::FieldRepetitionType::type const&>(duckdb_parquet::FieldRepetitionType::type const&, bool) Unexecuted instantiation: parquet_metadata.cpp:duckdb::Value duckdb::ParquetElementString<duckdb_parquet::ConvertedType::type const&>(duckdb_parquet::ConvertedType::type const&, bool) Unexecuted instantiation: parquet_metadata.cpp:duckdb::Value duckdb::ParquetElementString<duckdb_parquet::EncryptionAlgorithm const&>(duckdb_parquet::EncryptionAlgorithm const&, bool) |
208 | | |
209 | 0 | static Value ParquetElementStringVal(const string &value, bool is_set) { |
210 | 0 | if (!is_set) { |
211 | 0 | return Value(); |
212 | 0 | } |
213 | 0 | return Value(value); |
214 | 0 | } |
215 | | |
216 | | template <class T> |
217 | 0 | static Value ParquetElementInteger(T &&value, bool is_iset) { |
218 | 0 | if (!is_iset) { |
219 | 0 | return Value(); |
220 | 0 | } |
221 | 0 | return Value::INTEGER(value); |
222 | 0 | } |
223 | | |
224 | | template <class T> |
225 | 0 | static Value ParquetElementBigint(T &&value, bool is_iset) { |
226 | 0 | if (!is_iset) { |
227 | 0 | return Value(); |
228 | 0 | } |
229 | 0 | return Value::BIGINT(value); |
230 | 0 | } Unexecuted instantiation: parquet_metadata.cpp:duckdb::Value duckdb::ParquetElementBigint<long const&>(long const&, bool) Unexecuted instantiation: parquet_metadata.cpp:duckdb::Value duckdb::ParquetElementBigint<int const&>(int const&, bool) |
231 | | |
232 | 0 | static Value ParquetElementBoolean(bool value, bool is_iset) { |
233 | 0 | if (!is_iset) { |
234 | 0 | return Value(); |
235 | 0 | } |
236 | 0 | return Value::BOOLEAN(value); |
237 | 0 | } |
238 | | |
239 | | //===--------------------------------------------------------------------===// |
240 | | // Row Group Meta Data |
241 | | //===--------------------------------------------------------------------===// |
242 | | |
243 | | class ParquetRowGroupMetadataProcessor : public ParquetMetadataFileProcessor { |
244 | | public: |
245 | | void InitializeInternal(ClientContext &context, ParquetReader &reader) override; |
246 | | idx_t TotalRowCount(ParquetReader &reader) override; |
247 | | void ReadRow(vector<reference<Vector>> &output, idx_t row_idx, ParquetReader &reader) override; |
248 | | |
249 | | private: |
250 | | vector<ParquetColumnSchema> column_schemas; |
251 | | }; |
252 | | |
253 | | template <> |
254 | | void ParquetMetaDataOperator::BindSchema<ParquetMetadataOperatorType::META_DATA>(vector<LogicalType> &return_types, |
255 | 0 | vector<string> &names) { |
256 | 0 | names.emplace_back("file_name"); |
257 | 0 | return_types.emplace_back(LogicalType::VARCHAR); |
258 | |
|
259 | 0 | names.emplace_back("row_group_id"); |
260 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
261 | |
|
262 | 0 | names.emplace_back("row_group_num_rows"); |
263 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
264 | |
|
265 | 0 | names.emplace_back("row_group_num_columns"); |
266 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
267 | |
|
268 | 0 | names.emplace_back("row_group_bytes"); |
269 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
270 | |
|
271 | 0 | names.emplace_back("column_id"); |
272 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
273 | |
|
274 | 0 | names.emplace_back("file_offset"); |
275 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
276 | |
|
277 | 0 | names.emplace_back("num_values"); |
278 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
279 | |
|
280 | 0 | names.emplace_back("path_in_schema"); |
281 | 0 | return_types.emplace_back(LogicalType::VARCHAR); |
282 | |
|
283 | 0 | names.emplace_back("type"); |
284 | 0 | return_types.emplace_back(LogicalType::VARCHAR); |
285 | |
|
286 | 0 | names.emplace_back("stats_min"); |
287 | 0 | return_types.emplace_back(LogicalType::VARCHAR); |
288 | |
|
289 | 0 | names.emplace_back("stats_max"); |
290 | 0 | return_types.emplace_back(LogicalType::VARCHAR); |
291 | |
|
292 | 0 | names.emplace_back("stats_null_count"); |
293 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
294 | |
|
295 | 0 | names.emplace_back("stats_distinct_count"); |
296 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
297 | |
|
298 | 0 | names.emplace_back("stats_min_value"); |
299 | 0 | return_types.emplace_back(LogicalType::VARCHAR); |
300 | |
|
301 | 0 | names.emplace_back("stats_max_value"); |
302 | 0 | return_types.emplace_back(LogicalType::VARCHAR); |
303 | |
|
304 | 0 | names.emplace_back("compression"); |
305 | 0 | return_types.emplace_back(LogicalType::VARCHAR); |
306 | |
|
307 | 0 | names.emplace_back("encodings"); |
308 | 0 | return_types.emplace_back(LogicalType::VARCHAR); |
309 | |
|
310 | 0 | names.emplace_back("index_page_offset"); |
311 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
312 | |
|
313 | 0 | names.emplace_back("dictionary_page_offset"); |
314 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
315 | |
|
316 | 0 | names.emplace_back("data_page_offset"); |
317 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
318 | |
|
319 | 0 | names.emplace_back("total_compressed_size"); |
320 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
321 | |
|
322 | 0 | names.emplace_back("total_uncompressed_size"); |
323 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
324 | |
|
325 | 0 | names.emplace_back("key_value_metadata"); |
326 | 0 | return_types.emplace_back(LogicalType::MAP(LogicalType::BLOB, LogicalType::BLOB)); |
327 | |
|
328 | 0 | names.emplace_back("bloom_filter_offset"); |
329 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
330 | |
|
331 | 0 | names.emplace_back("bloom_filter_length"); |
332 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
333 | |
|
334 | 0 | names.emplace_back("min_is_exact"); |
335 | 0 | return_types.emplace_back(LogicalType::BOOLEAN); |
336 | |
|
337 | 0 | names.emplace_back("max_is_exact"); |
338 | 0 | return_types.emplace_back(LogicalType::BOOLEAN); |
339 | |
|
340 | 0 | names.emplace_back("row_group_compressed_bytes"); |
341 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
342 | |
|
343 | 0 | names.emplace_back("geo_bbox"); |
344 | 0 | return_types.emplace_back(LogicalType::STRUCT({ |
345 | 0 | {"xmin", LogicalType::DOUBLE}, |
346 | 0 | {"xmax", LogicalType::DOUBLE}, |
347 | 0 | {"ymin", LogicalType::DOUBLE}, |
348 | 0 | {"ymax", LogicalType::DOUBLE}, |
349 | 0 | {"zmin", LogicalType::DOUBLE}, |
350 | 0 | {"zmax", LogicalType::DOUBLE}, |
351 | 0 | {"mmin", LogicalType::DOUBLE}, |
352 | 0 | {"mmax", LogicalType::DOUBLE}, |
353 | 0 | })); |
354 | |
|
355 | 0 | names.emplace_back("geo_types"); |
356 | 0 | return_types.emplace_back(LogicalType::LIST(LogicalType::VARCHAR)); |
357 | 0 | } |
358 | | |
359 | | static Value ConvertParquetStats(const LogicalType &type, const ParquetColumnSchema &schema_ele, bool stats_is_set, |
360 | 0 | const std::string &stats) { |
361 | 0 | if (!stats_is_set) { |
362 | 0 | return Value(LogicalType::VARCHAR); |
363 | 0 | } |
364 | 0 | return ParquetStatisticsUtils::ConvertValue(type, schema_ele, stats).DefaultCastAs(LogicalType::VARCHAR); |
365 | 0 | } |
366 | | |
367 | 0 | static Value ConvertParquetGeoStatsBBOX(const duckdb_parquet::GeospatialStatistics &stats) { |
368 | 0 | if (!stats.__isset.bbox) { |
369 | 0 | return Value(LogicalType::STRUCT({ |
370 | 0 | {"xmin", LogicalType::DOUBLE}, |
371 | 0 | {"xmax", LogicalType::DOUBLE}, |
372 | 0 | {"ymin", LogicalType::DOUBLE}, |
373 | 0 | {"ymax", LogicalType::DOUBLE}, |
374 | 0 | {"zmin", LogicalType::DOUBLE}, |
375 | 0 | {"zmax", LogicalType::DOUBLE}, |
376 | 0 | {"mmin", LogicalType::DOUBLE}, |
377 | 0 | {"mmax", LogicalType::DOUBLE}, |
378 | 0 | })); |
379 | 0 | } |
380 | | |
381 | 0 | return Value::STRUCT({ |
382 | 0 | {"xmin", Value::DOUBLE(stats.bbox.xmin)}, |
383 | 0 | {"xmax", Value::DOUBLE(stats.bbox.xmax)}, |
384 | 0 | {"ymin", Value::DOUBLE(stats.bbox.ymin)}, |
385 | 0 | {"ymax", Value::DOUBLE(stats.bbox.ymax)}, |
386 | 0 | {"zmin", stats.bbox.__isset.zmin ? Value::DOUBLE(stats.bbox.zmin) : Value(LogicalTypeId::DOUBLE)}, |
387 | 0 | {"zmax", stats.bbox.__isset.zmax ? Value::DOUBLE(stats.bbox.zmax) : Value(LogicalTypeId::DOUBLE)}, |
388 | 0 | {"mmin", stats.bbox.__isset.mmin ? Value::DOUBLE(stats.bbox.mmin) : Value(LogicalTypeId::DOUBLE)}, |
389 | 0 | {"mmax", stats.bbox.__isset.mmax ? Value::DOUBLE(stats.bbox.mmax) : Value(LogicalTypeId::DOUBLE)}, |
390 | 0 | }); |
391 | 0 | } |
392 | | |
393 | 0 | static Value ConvertParquetGeoStatsTypes(const duckdb_parquet::GeospatialStatistics &stats) { |
394 | 0 | if (!stats.__isset.geospatial_types) { |
395 | 0 | return Value(LogicalType::LIST(LogicalType::VARCHAR)); |
396 | 0 | } |
397 | 0 | vector<Value> types; |
398 | 0 | types.reserve(stats.geospatial_types.size()); |
399 | |
|
400 | 0 | GeometryTypeSet type_set = GeometryTypeSet::Empty(); |
401 | 0 | for (auto &type : stats.geospatial_types) { |
402 | 0 | const auto geom_type = (type % 1000); |
403 | 0 | const auto vert_type = (type / 1000); |
404 | 0 | if (geom_type < 1 || geom_type > 7) { |
405 | 0 | throw InvalidInputException("Unsupported geometry type in Parquet geo metadata"); |
406 | 0 | } |
407 | 0 | if (vert_type < 0 || vert_type > 3) { |
408 | 0 | throw InvalidInputException("Unsupported geometry vertex type in Parquet geo metadata"); |
409 | 0 | } |
410 | 0 | type_set.Add(static_cast<GeometryType>(geom_type), static_cast<VertexType>(vert_type)); |
411 | 0 | } |
412 | | |
413 | 0 | for (auto &type_name : type_set.ToString(true)) { |
414 | 0 | types.push_back(Value(type_name)); |
415 | 0 | } |
416 | 0 | return Value::LIST(LogicalType::VARCHAR, types); |
417 | 0 | } |
418 | | |
419 | 0 | void ParquetRowGroupMetadataProcessor::InitializeInternal(ClientContext &context, ParquetReader &reader) { |
420 | 0 | auto meta_data = reader.GetFileMetadata(); |
421 | 0 | column_schemas.clear(); |
422 | 0 | for (idx_t schema_idx = 0; schema_idx < meta_data->schema.size(); schema_idx++) { |
423 | 0 | auto &schema_element = meta_data->schema[schema_idx]; |
424 | 0 | if (schema_element.num_children > 0) { |
425 | 0 | continue; |
426 | 0 | } |
427 | 0 | ParquetColumnSchema column_schema; |
428 | 0 | column_schema.type = reader.DeriveLogicalType(schema_element, column_schema); |
429 | 0 | column_schemas.push_back(std::move(column_schema)); |
430 | 0 | } |
431 | 0 | } |
432 | | |
433 | 0 | idx_t ParquetRowGroupMetadataProcessor::TotalRowCount(ParquetReader &reader) { |
434 | 0 | auto meta_data = reader.GetFileMetadata(); |
435 | 0 | return meta_data->row_groups.size() * column_schemas.size(); |
436 | 0 | } |
437 | | |
438 | | void ParquetRowGroupMetadataProcessor::ReadRow(vector<reference<Vector>> &output, idx_t row_idx, |
439 | 0 | ParquetReader &reader) { |
440 | 0 | auto meta_data = reader.GetFileMetadata(); |
441 | 0 | idx_t col_idx = row_idx % column_schemas.size(); |
442 | 0 | idx_t row_group_idx = row_idx / column_schemas.size(); |
443 | |
|
444 | 0 | auto &row_group = meta_data->row_groups[row_group_idx]; |
445 | |
|
446 | 0 | auto &column = row_group.columns[col_idx]; |
447 | 0 | auto &column_schema = column_schemas[col_idx]; |
448 | 0 | auto &col_meta = column.meta_data; |
449 | 0 | auto &stats = col_meta.statistics; |
450 | 0 | auto &column_type = column_schema.type; |
451 | | |
452 | | // file_name |
453 | 0 | output[0].get().Append(reader.file.path); |
454 | | // row_group_id |
455 | 0 | output[1].get().Append(Value::BIGINT(UnsafeNumericCast<int64_t>(row_group_idx))); |
456 | | // row_group_num_rows |
457 | 0 | output[2].get().Append(Value::BIGINT(row_group.num_rows)); |
458 | | // row_group_num_columns |
459 | 0 | output[3].get().Append(Value::BIGINT(UnsafeNumericCast<int64_t>(row_group.columns.size()))); |
460 | | // row_group_bytes |
461 | 0 | output[4].get().Append(Value::BIGINT(row_group.total_byte_size)); |
462 | | // column_id |
463 | 0 | output[5].get().Append(Value::BIGINT(UnsafeNumericCast<int64_t>(col_idx))); |
464 | | // file_offset |
465 | 0 | output[6].get().Append(ParquetElementBigint(column.file_offset, row_group.__isset.file_offset)); |
466 | | // num_values |
467 | 0 | output[7].get().Append(Value::BIGINT(col_meta.num_values)); |
468 | | // path_in_schema |
469 | 0 | output[8].get().Append(StringUtil::Join(col_meta.path_in_schema, ", ")); |
470 | | // type |
471 | 0 | output[9].get().Append(ConvertParquetElementToString(col_meta.type)); |
472 | | // stats_min |
473 | 0 | output[10].get().Append(ConvertParquetStats(column_type, column_schema, stats.__isset.min, stats.min)); |
474 | | // stats_max |
475 | 0 | output[11].get().Append(ConvertParquetStats(column_type, column_schema, stats.__isset.max, stats.max)); |
476 | | // stats_null_count |
477 | 0 | output[12].get().Append(ParquetElementBigint(stats.null_count, stats.__isset.null_count)); |
478 | | // stats_distinct_count |
479 | 0 | output[13].get().Append(ParquetElementBigint(stats.distinct_count, stats.__isset.distinct_count)); |
480 | | // stats_min_value |
481 | 0 | output[14].get().Append(ConvertParquetStats(column_type, column_schema, stats.__isset.min_value, stats.min_value)); |
482 | | // stats_max_value |
483 | 0 | output[15].get().Append(ConvertParquetStats(column_type, column_schema, stats.__isset.max_value, stats.max_value)); |
484 | | // compression |
485 | 0 | output[16].get().Append(ConvertParquetElementToString(col_meta.codec)); |
486 | | // encodings |
487 | 0 | vector<string> encoding_string; |
488 | 0 | encoding_string.reserve(col_meta.encodings.size()); |
489 | 0 | for (auto &encoding : col_meta.encodings) { |
490 | 0 | encoding_string.push_back(ConvertParquetElementToString(encoding)); |
491 | 0 | } |
492 | 0 | output[17].get().Append(Value(StringUtil::Join(encoding_string, ", "))); |
493 | | // index_page_offset |
494 | 0 | output[18].get().Append(ParquetElementBigint(col_meta.index_page_offset, col_meta.__isset.index_page_offset)); |
495 | | // dictionary_page_offset |
496 | 0 | output[19].get().Append( |
497 | 0 | ParquetElementBigint(col_meta.dictionary_page_offset, col_meta.__isset.dictionary_page_offset)); |
498 | | // data_page_offset |
499 | 0 | output[20].get().Append(Value::BIGINT(col_meta.data_page_offset)); |
500 | | // total_compressed_size |
501 | 0 | output[21].get().Append(Value::BIGINT(col_meta.total_compressed_size)); |
502 | | // total_uncompressed_size |
503 | 0 | output[22].get().Append(Value::BIGINT(col_meta.total_uncompressed_size)); |
504 | | // key_value_metadata |
505 | 0 | vector<Value> map_keys, map_values; |
506 | 0 | for (auto &entry : col_meta.key_value_metadata) { |
507 | 0 | map_keys.push_back(Value::BLOB_RAW(entry.key)); |
508 | 0 | map_values.push_back(Value::BLOB_RAW(entry.value)); |
509 | 0 | } |
510 | 0 | output[23].get().Append( |
511 | 0 | Value::MAP(LogicalType::BLOB, LogicalType::BLOB, std::move(map_keys), std::move(map_values))); |
512 | | // bloom_filter_offset |
513 | 0 | output[24].get().Append(ParquetElementBigint(col_meta.bloom_filter_offset, col_meta.__isset.bloom_filter_offset)); |
514 | | // bloom_filter_length |
515 | 0 | output[25].get().Append(ParquetElementBigint(col_meta.bloom_filter_length, col_meta.__isset.bloom_filter_length)); |
516 | | // min_is_exact |
517 | 0 | output[26].get().Append(ParquetElementBoolean(stats.is_min_value_exact, stats.__isset.is_min_value_exact)); |
518 | | // max_is_exact |
519 | 0 | output[27].get().Append(ParquetElementBoolean(stats.is_max_value_exact, stats.__isset.is_max_value_exact)); |
520 | | // row_group_compressed_bytes |
521 | 0 | output[28].get().Append( |
522 | 0 | ParquetElementBigint(row_group.total_compressed_size, row_group.__isset.total_compressed_size)); |
523 | | // geo_stats_bbox, LogicalType::STRUCT(...) |
524 | 0 | output[29].get().Append(ConvertParquetGeoStatsBBOX(col_meta.geospatial_statistics)); |
525 | | |
526 | | // geo_stats_types, LogicalType::LIST(LogicalType::VARCHAR) |
527 | 0 | output[30].get().Append(ConvertParquetGeoStatsTypes(col_meta.geospatial_statistics)); |
528 | 0 | } |
529 | | |
530 | | //===--------------------------------------------------------------------===// |
531 | | // Schema Data |
532 | | //===--------------------------------------------------------------------===// |
533 | | |
534 | | class ParquetSchemaProcessor : public ParquetMetadataFileProcessor { |
535 | | public: |
536 | | idx_t TotalRowCount(ParquetReader &reader) override; |
537 | | void ReadRow(vector<reference<Vector>> &output, idx_t row_idx, ParquetReader &reader) override; |
538 | | }; |
539 | | |
540 | | template <> |
541 | | void ParquetMetaDataOperator::BindSchema<ParquetMetadataOperatorType::SCHEMA>(vector<LogicalType> &return_types, |
542 | 974 | vector<string> &names) { |
543 | 974 | names.emplace_back("file_name"); |
544 | 974 | return_types.emplace_back(LogicalType::VARCHAR); |
545 | | |
546 | 974 | names.emplace_back("name"); |
547 | 974 | return_types.emplace_back(LogicalType::VARCHAR); |
548 | | |
549 | 974 | names.emplace_back("type"); |
550 | 974 | return_types.emplace_back(LogicalType::VARCHAR); |
551 | | |
552 | 974 | names.emplace_back("type_length"); |
553 | 974 | return_types.emplace_back(LogicalType::VARCHAR); |
554 | | |
555 | 974 | names.emplace_back("repetition_type"); |
556 | 974 | return_types.emplace_back(LogicalType::VARCHAR); |
557 | | |
558 | 974 | names.emplace_back("num_children"); |
559 | 974 | return_types.emplace_back(LogicalType::BIGINT); |
560 | | |
561 | 974 | names.emplace_back("converted_type"); |
562 | 974 | return_types.emplace_back(LogicalType::VARCHAR); |
563 | | |
564 | 974 | names.emplace_back("scale"); |
565 | 974 | return_types.emplace_back(LogicalType::BIGINT); |
566 | | |
567 | 974 | names.emplace_back("precision"); |
568 | 974 | return_types.emplace_back(LogicalType::BIGINT); |
569 | | |
570 | 974 | names.emplace_back("field_id"); |
571 | 974 | return_types.emplace_back(LogicalType::BIGINT); |
572 | | |
573 | 974 | names.emplace_back("logical_type"); |
574 | 974 | return_types.emplace_back(LogicalType::VARCHAR); |
575 | | |
576 | 974 | names.emplace_back("duckdb_type"); |
577 | 974 | return_types.emplace_back(LogicalType::VARCHAR); |
578 | | |
579 | 974 | names.emplace_back("column_id"); |
580 | 974 | return_types.emplace_back(LogicalType::BIGINT); |
581 | 974 | } |
582 | | |
583 | 0 | static Value ParquetLogicalTypeToString(const duckdb_parquet::LogicalType &type, bool is_set) { |
584 | 0 | if (!is_set) { |
585 | 0 | return Value(); |
586 | 0 | } |
587 | 0 | if (type.__isset.STRING) { |
588 | 0 | return Value(PrintParquetElementToString(type.STRING)); |
589 | 0 | } |
590 | 0 | if (type.__isset.MAP) { |
591 | 0 | return Value(PrintParquetElementToString(type.MAP)); |
592 | 0 | } |
593 | 0 | if (type.__isset.LIST) { |
594 | 0 | return Value(PrintParquetElementToString(type.LIST)); |
595 | 0 | } |
596 | 0 | if (type.__isset.ENUM) { |
597 | 0 | return Value(PrintParquetElementToString(type.ENUM)); |
598 | 0 | } |
599 | 0 | if (type.__isset.DECIMAL) { |
600 | 0 | return Value(PrintParquetElementToString(type.DECIMAL)); |
601 | 0 | } |
602 | 0 | if (type.__isset.DATE) { |
603 | 0 | return Value(PrintParquetElementToString(type.DATE)); |
604 | 0 | } |
605 | 0 | if (type.__isset.TIME) { |
606 | 0 | return Value(PrintParquetElementToString(type.TIME)); |
607 | 0 | } |
608 | 0 | if (type.__isset.TIMESTAMP) { |
609 | 0 | return Value(PrintParquetElementToString(type.TIMESTAMP)); |
610 | 0 | } |
611 | 0 | if (type.__isset.INTEGER) { |
612 | 0 | return Value(PrintParquetElementToString(type.INTEGER)); |
613 | 0 | } |
614 | 0 | if (type.__isset.UNKNOWN) { |
615 | 0 | return Value(PrintParquetElementToString(type.UNKNOWN)); |
616 | 0 | } |
617 | 0 | if (type.__isset.JSON) { |
618 | 0 | return Value(PrintParquetElementToString(type.JSON)); |
619 | 0 | } |
620 | 0 | if (type.__isset.BSON) { |
621 | 0 | return Value(PrintParquetElementToString(type.BSON)); |
622 | 0 | } |
623 | 0 | if (type.__isset.UUID) { |
624 | 0 | return Value(PrintParquetElementToString(type.UUID)); |
625 | 0 | } |
626 | 0 | if (type.__isset.FLOAT16) { |
627 | 0 | return Value(PrintParquetElementToString(type.FLOAT16)); |
628 | 0 | } |
629 | 0 | if (type.__isset.GEOMETRY) { |
630 | 0 | return Value(PrintParquetElementToString(type.GEOMETRY)); |
631 | 0 | } |
632 | 0 | if (type.__isset.GEOGRAPHY) { |
633 | 0 | return Value(PrintParquetElementToString(type.GEOGRAPHY)); |
634 | 0 | } |
635 | 0 | return Value(); |
636 | 0 | } |
637 | | |
638 | 0 | idx_t ParquetSchemaProcessor::TotalRowCount(ParquetReader &reader) { |
639 | 0 | return reader.GetFileMetadata()->schema.size(); |
640 | 0 | } |
641 | | |
642 | 0 | void ParquetSchemaProcessor::ReadRow(vector<reference<Vector>> &output, idx_t row_idx, ParquetReader &reader) { |
643 | 0 | auto meta_data = reader.GetFileMetadata(); |
644 | 0 | const auto &column = meta_data->schema[row_idx]; |
645 | | |
646 | | // file_name |
647 | 0 | output[0].get().Append(reader.file.path); |
648 | | // name |
649 | 0 | output[1].get().Append(column.name); |
650 | | // type |
651 | 0 | output[2].get().Append(ParquetElementString(column.type, column.__isset.type)); |
652 | | // type_length |
653 | 0 | output[3].get().Append(ParquetElementInteger(column.type_length, column.__isset.type_length)); |
654 | | // repetition_type |
655 | 0 | output[4].get().Append(ParquetElementString(column.repetition_type, column.__isset.repetition_type)); |
656 | | // num_children |
657 | 0 | output[5].get().Append(ParquetElementBigint(column.num_children, column.__isset.num_children)); |
658 | | // converted_type |
659 | 0 | output[6].get().Append(ParquetElementString(column.converted_type, column.__isset.converted_type)); |
660 | | // scale |
661 | 0 | output[7].get().Append(ParquetElementBigint(column.scale, column.__isset.scale)); |
662 | | // precision |
663 | 0 | output[8].get().Append(ParquetElementBigint(column.precision, column.__isset.precision)); |
664 | | // field_id |
665 | 0 | output[9].get().Append(ParquetElementBigint(column.field_id, column.__isset.field_id)); |
666 | | // logical_type |
667 | 0 | output[10].get().Append(ParquetLogicalTypeToString(column.logicalType, column.__isset.logicalType)); |
668 | | // duckdb_type |
669 | 0 | ParquetColumnSchema column_schema; |
670 | 0 | Value duckdb_type; |
671 | 0 | if (column.__isset.type) { |
672 | 0 | duckdb_type = reader.DeriveLogicalType(column, column_schema).ToString(); |
673 | 0 | } |
674 | 0 | output[11].get().Append(duckdb_type); |
675 | | // column_id |
676 | 0 | output[12].get().Append(Value::BIGINT(UnsafeNumericCast<int64_t>(row_idx))); |
677 | 0 | } |
678 | | |
679 | | //===--------------------------------------------------------------------===// |
680 | | // KV Meta Data |
681 | | //===--------------------------------------------------------------------===// |
682 | | |
683 | | class ParquetKeyValueMetadataProcessor : public ParquetMetadataFileProcessor { |
684 | | public: |
685 | | idx_t TotalRowCount(ParquetReader &reader) override; |
686 | | void ReadRow(vector<reference<Vector>> &output, idx_t row_idx, ParquetReader &reader) override; |
687 | | }; |
688 | | |
689 | | template <> |
690 | | void ParquetMetaDataOperator::BindSchema<ParquetMetadataOperatorType::KEY_VALUE_META_DATA>( |
691 | 0 | vector<LogicalType> &return_types, vector<string> &names) { |
692 | 0 | names.emplace_back("file_name"); |
693 | 0 | return_types.emplace_back(LogicalType::VARCHAR); |
694 | |
|
695 | 0 | names.emplace_back("key"); |
696 | 0 | return_types.emplace_back(LogicalType::BLOB); |
697 | |
|
698 | 0 | names.emplace_back("value"); |
699 | 0 | return_types.emplace_back(LogicalType::BLOB); |
700 | 0 | } |
701 | | |
702 | 0 | idx_t ParquetKeyValueMetadataProcessor::TotalRowCount(ParquetReader &reader) { |
703 | 0 | return reader.GetFileMetadata()->key_value_metadata.size(); |
704 | 0 | } |
705 | | |
706 | | void ParquetKeyValueMetadataProcessor::ReadRow(vector<reference<Vector>> &output, idx_t row_idx, |
707 | 0 | ParquetReader &reader) { |
708 | 0 | auto meta_data = reader.GetFileMetadata(); |
709 | 0 | auto &entry = meta_data->key_value_metadata[row_idx]; |
710 | |
|
711 | 0 | output[0].get().Append(Value(reader.file.path)); |
712 | 0 | output[1].get().Append(Value::BLOB_RAW(entry.key)); |
713 | 0 | output[2].get().Append(Value::BLOB_RAW(entry.value)); |
714 | 0 | } |
715 | | |
716 | | //===--------------------------------------------------------------------===// |
717 | | // File Meta Data |
718 | | //===--------------------------------------------------------------------===// |
719 | | |
720 | | class ParquetFileMetadataProcessor : public ParquetMetadataFileProcessor { |
721 | | public: |
722 | | idx_t TotalRowCount(ParquetReader &reader) override; |
723 | | void ReadRow(vector<reference<Vector>> &output, idx_t row_idx, ParquetReader &reader) override; |
724 | | }; |
725 | | |
726 | | template <> |
727 | | void ParquetMetaDataOperator::BindSchema<ParquetMetadataOperatorType::FILE_META_DATA>(vector<LogicalType> &return_types, |
728 | 0 | vector<string> &names) { |
729 | 0 | names.emplace_back("file_name"); |
730 | 0 | return_types.emplace_back(LogicalType::VARCHAR); |
731 | |
|
732 | 0 | names.emplace_back("created_by"); |
733 | 0 | return_types.emplace_back(LogicalType::VARCHAR); |
734 | |
|
735 | 0 | names.emplace_back("num_rows"); |
736 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
737 | |
|
738 | 0 | names.emplace_back("num_row_groups"); |
739 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
740 | |
|
741 | 0 | names.emplace_back("format_version"); |
742 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
743 | |
|
744 | 0 | names.emplace_back("encryption_algorithm"); |
745 | 0 | return_types.emplace_back(LogicalType::VARCHAR); |
746 | |
|
747 | 0 | names.emplace_back("footer_signing_key_metadata"); |
748 | 0 | return_types.emplace_back(LogicalType::VARCHAR); |
749 | |
|
750 | 0 | names.emplace_back("file_size_bytes"); |
751 | 0 | return_types.emplace_back(LogicalType::UBIGINT); |
752 | |
|
753 | 0 | names.emplace_back("footer_size"); |
754 | 0 | return_types.emplace_back(LogicalType::UBIGINT); |
755 | |
|
756 | 0 | names.emplace_back("column_orders"); |
757 | 0 | return_types.emplace_back(LogicalType::LIST(LogicalType::VARCHAR)); |
758 | 0 | } |
759 | | |
760 | 0 | idx_t ParquetFileMetadataProcessor::TotalRowCount(ParquetReader &reader) { |
761 | 0 | return 1; |
762 | 0 | } |
763 | | |
764 | 0 | void ParquetFileMetadataProcessor::ReadRow(vector<reference<Vector>> &output, idx_t row_idx, ParquetReader &reader) { |
765 | 0 | auto meta_data = reader.GetFileMetadata(); |
766 | | |
767 | | // file_name |
768 | 0 | output[0].get().Append(Value(reader.file.path)); |
769 | | // created_by |
770 | 0 | output[1].get().Append(ParquetElementStringVal(meta_data->created_by, meta_data->__isset.created_by)); |
771 | | // num_rows |
772 | 0 | output[2].get().Append(Value::BIGINT(meta_data->num_rows)); |
773 | | // num_row_groups |
774 | 0 | output[3].get().Append(Value::BIGINT(UnsafeNumericCast<int64_t>(meta_data->row_groups.size()))); |
775 | | // format_version |
776 | 0 | output[4].get().Append(Value::BIGINT(meta_data->version)); |
777 | | // encryption_algorithm |
778 | 0 | output[5].get().Append( |
779 | 0 | ParquetElementString(meta_data->encryption_algorithm, meta_data->__isset.encryption_algorithm)); |
780 | | // footer_signing_key_metadata |
781 | 0 | output[6].get().Append(ParquetElementStringVal(meta_data->footer_signing_key_metadata, |
782 | 0 | meta_data->__isset.footer_signing_key_metadata)); |
783 | | // file_size_bytes |
784 | 0 | output[7].get().Append(Value::UBIGINT(reader.GetHandle().GetFileSize())); |
785 | | // footer_size |
786 | 0 | output[8].get().Append(Value::UBIGINT(reader.metadata->footer_size)); |
787 | | // column_orders |
788 | 0 | Value column_orders_value; |
789 | 0 | if (meta_data->__isset.column_orders) { |
790 | 0 | vector<Value> column_orders; |
791 | 0 | column_orders.reserve(meta_data->column_orders.size()); |
792 | 0 | for (auto &column_order : meta_data->column_orders) { |
793 | 0 | column_orders.push_back(Value(ConvertParquetElementToString(column_order))); |
794 | 0 | } |
795 | 0 | column_orders_value = Value::LIST(LogicalType::VARCHAR, column_orders); |
796 | 0 | } |
797 | 0 | output[9].get().Append(column_orders_value); |
798 | 0 | } |
799 | | |
800 | | //===--------------------------------------------------------------------===// |
801 | | // Bloom Probe |
802 | | //===--------------------------------------------------------------------===// |
803 | | |
804 | | class ParquetBloomProbeProcessor : public ParquetMetadataFileProcessor { |
805 | | public: |
806 | | ParquetBloomProbeProcessor(const string &probe_column, const Value &probe_value); |
807 | | |
808 | | void InitializeInternal(ClientContext &context, ParquetReader &reader) override; |
809 | | idx_t TotalRowCount(ParquetReader &reader) override; |
810 | | void ReadRow(vector<reference<Vector>> &output, idx_t row_idx, ParquetReader &reader) override; |
811 | | |
812 | | private: |
813 | | string probe_column_name; |
814 | | Value probe_constant; |
815 | | optional_idx probe_column_idx; |
816 | | |
817 | | unique_ptr<duckdb_apache::thrift::protocol::TCompactProtocolT<ThriftFileTransport>> protocol; |
818 | | optional_ptr<Allocator> allocator; |
819 | | unique_ptr<ExpressionFilter> filter; |
820 | | }; |
821 | | |
822 | | template <> |
823 | | void ParquetMetaDataOperator::BindSchema<ParquetMetadataOperatorType::BLOOM_PROBE>(vector<LogicalType> &return_types, |
824 | 0 | vector<string> &names) { |
825 | 0 | names.emplace_back("file_name"); |
826 | 0 | return_types.emplace_back(LogicalType::VARCHAR); |
827 | |
|
828 | 0 | names.emplace_back("row_group_id"); |
829 | 0 | return_types.emplace_back(LogicalType::BIGINT); |
830 | |
|
831 | 0 | names.emplace_back("bloom_filter_excludes"); |
832 | 0 | return_types.emplace_back(LogicalType::BOOLEAN); |
833 | 0 | } |
834 | | |
835 | | ParquetBloomProbeProcessor::ParquetBloomProbeProcessor(const string &probe_column, const Value &probe_value) |
836 | 0 | : probe_column_name(probe_column), probe_constant(probe_value) { |
837 | 0 | } |
838 | | |
839 | 0 | void ParquetBloomProbeProcessor::InitializeInternal(ClientContext &context, ParquetReader &reader) { |
840 | 0 | probe_column_idx = optional_idx::Invalid(); |
841 | |
|
842 | 0 | for (idx_t column_idx = 0; column_idx < reader.columns.size(); column_idx++) { |
843 | 0 | if (reader.columns[column_idx].name == probe_column_name) { |
844 | 0 | probe_column_idx = column_idx; |
845 | 0 | break; |
846 | 0 | } |
847 | 0 | } |
848 | |
|
849 | 0 | if (!probe_column_idx.IsValid()) { |
850 | 0 | throw InvalidInputException("Column %s not found in %s", probe_column_name, reader.file.path); |
851 | 0 | } |
852 | | |
853 | 0 | auto transport = duckdb_base_std::make_shared<ThriftFileTransport>(context, reader.GetHandle(), false); |
854 | 0 | protocol = make_uniq<duckdb_apache::thrift::protocol::TCompactProtocolT<ThriftFileTransport>>(std::move(transport)); |
855 | 0 | allocator = &BufferAllocator::Get(context); |
856 | 0 | auto column_type = reader.GetColumns()[probe_column_idx.GetIndex()].type; |
857 | 0 | auto comparison = BoundComparisonExpression::Create( |
858 | 0 | ExpressionType::COMPARE_EQUAL, |
859 | 0 | make_uniq<BoundReferenceExpression>(Identifier(probe_column_name), column_type, 0), |
860 | 0 | make_uniq<BoundConstantExpression>(probe_constant.CastAs(context, column_type))); |
861 | 0 | filter = make_uniq<ExpressionFilter>(std::move(comparison)); |
862 | 0 | } |
863 | | |
864 | 0 | idx_t ParquetBloomProbeProcessor::TotalRowCount(ParquetReader &reader) { |
865 | 0 | return reader.GetFileMetadata()->row_groups.size(); |
866 | 0 | } |
867 | | |
868 | 0 | void ParquetBloomProbeProcessor::ReadRow(vector<reference<Vector>> &output, idx_t row_idx, ParquetReader &reader) { |
869 | 0 | auto meta_data = reader.GetFileMetadata(); |
870 | 0 | auto &row_group = meta_data->row_groups[row_idx]; |
871 | 0 | auto &column = row_group.columns[probe_column_idx.GetIndex()]; |
872 | |
|
873 | 0 | D_ASSERT(!probe_constant.IsNull()); |
874 | |
|
875 | 0 | auto bloom_excludes = ParquetStatisticsUtils::BloomFilterExcludes(*filter, column.meta_data, *protocol, *allocator); |
876 | |
|
877 | 0 | output[0].get().Append(Value(reader.file.path)); |
878 | 0 | output[1].get().Append(Value::BIGINT(NumericCast<int64_t>(row_idx))); |
879 | 0 | output[2].get().Append(Value::BOOLEAN(bloom_excludes)); |
880 | 0 | } |
881 | | |
882 | | //===--------------------------------------------------------------------===// |
883 | | // Full Metadata |
884 | | //===--------------------------------------------------------------------===// |
885 | | |
886 | | class FullMetadataProcessor : public ParquetMetadataFileProcessor { |
887 | | public: |
888 | 0 | FullMetadataProcessor() = default; |
889 | | |
890 | | void InitializeInternal(ClientContext &context, ParquetReader &reader) override; |
891 | | idx_t TotalRowCount(ParquetReader &reader) override; |
892 | | void ReadRow(vector<reference<Vector>> &output, idx_t row_idx, ParquetReader &reader) override; |
893 | 0 | bool ForceFlush() override { |
894 | 0 | return true; |
895 | 0 | } |
896 | | |
897 | | private: |
898 | | void PopulateMetadata(ParquetMetadataFileProcessor &processor, Vector &output, ParquetReader &reader); |
899 | | |
900 | | ParquetFileMetadataProcessor file_processor; |
901 | | ParquetRowGroupMetadataProcessor row_group_processor; |
902 | | ParquetSchemaProcessor schema_processor; |
903 | | ParquetKeyValueMetadataProcessor kv_processor; |
904 | | }; |
905 | | |
906 | | void FullMetadataProcessor::PopulateMetadata(ParquetMetadataFileProcessor &processor, Vector &output, |
907 | 0 | ParquetReader &reader) { |
908 | 0 | auto count = processor.TotalRowCount(reader); |
909 | 0 | auto *result_data = FlatVector::GetDataMutable<list_entry_t>(output); |
910 | 0 | auto &result_struct = ListVector::GetChildMutable(output); |
911 | 0 | auto &result_struct_entries = StructVector::GetEntries(result_struct); |
912 | |
|
913 | 0 | ListVector::Reserve(output, count); |
914 | |
|
915 | 0 | auto output_idx = output.size(); |
916 | |
|
917 | 0 | result_data[output_idx].offset = 0; |
918 | 0 | result_data[output_idx].length = count; |
919 | |
|
920 | 0 | FlatVector::ValidityMutable(output).SetValid(output_idx); |
921 | 0 | FlatVector::SetSize(output, output_idx + 1); |
922 | |
|
923 | 0 | vector<reference<Vector>> vectors; |
924 | 0 | for (auto &entry : result_struct_entries) { |
925 | 0 | vectors.push_back(std::ref(entry)); |
926 | 0 | entry.SetVectorType(VectorType::FLAT_VECTOR); |
927 | 0 | auto &validity = FlatVector::ValidityMutable(entry); |
928 | 0 | validity.Initialize(count); |
929 | 0 | } |
930 | 0 | for (idx_t i = 0; i < count; i++) { |
931 | 0 | processor.ReadRow(vectors, i, reader); |
932 | 0 | } |
933 | 0 | ListVector::SetListSize(output, count); |
934 | 0 | } |
935 | | |
936 | | template <> |
937 | | void ParquetMetaDataOperator::BindSchema<ParquetMetadataOperatorType::FULL_METADATA>(vector<LogicalType> &return_types, |
938 | 0 | vector<string> &names) { |
939 | 0 | names.emplace_back("parquet_file_metadata"); |
940 | 0 | vector<LogicalType> file_meta_types; |
941 | 0 | vector<string> file_meta_names; |
942 | 0 | ParquetMetaDataOperator::BindSchema<ParquetMetadataOperatorType::FILE_META_DATA>(file_meta_types, file_meta_names); |
943 | 0 | child_list_t<LogicalType> file_meta_children; |
944 | 0 | for (idx_t i = 0; i < file_meta_types.size(); i++) { |
945 | 0 | file_meta_children.emplace_back(make_pair(file_meta_names[i], file_meta_types[i])); |
946 | 0 | } |
947 | 0 | return_types.emplace_back(LogicalType::LIST(LogicalType::STRUCT(std::move(file_meta_children)))); |
948 | |
|
949 | 0 | names.emplace_back("parquet_metadata"); |
950 | 0 | vector<LogicalType> row_group_types; |
951 | 0 | vector<string> row_group_names; |
952 | 0 | ParquetMetaDataOperator::BindSchema<ParquetMetadataOperatorType::META_DATA>(row_group_types, row_group_names); |
953 | 0 | child_list_t<LogicalType> row_group_children; |
954 | 0 | for (idx_t i = 0; i < row_group_types.size(); i++) { |
955 | 0 | row_group_children.emplace_back(make_pair(row_group_names[i], row_group_types[i])); |
956 | 0 | } |
957 | 0 | return_types.emplace_back(LogicalType::LIST(LogicalType::STRUCT(std::move(row_group_children)))); |
958 | |
|
959 | 0 | names.emplace_back("parquet_schema"); |
960 | 0 | vector<LogicalType> schema_types; |
961 | 0 | vector<string> schema_names; |
962 | 0 | ParquetMetaDataOperator::BindSchema<ParquetMetadataOperatorType::SCHEMA>(schema_types, schema_names); |
963 | 0 | child_list_t<LogicalType> schema_children; |
964 | 0 | for (idx_t i = 0; i < schema_types.size(); i++) { |
965 | 0 | schema_children.emplace_back(make_pair(schema_names[i], schema_types[i])); |
966 | 0 | } |
967 | 0 | return_types.emplace_back(LogicalType::LIST(LogicalType::STRUCT(std::move(schema_children)))); |
968 | |
|
969 | 0 | names.emplace_back("parquet_kv_metadata"); |
970 | 0 | vector<LogicalType> kv_types; |
971 | 0 | vector<string> kv_names; |
972 | 0 | ParquetMetaDataOperator::BindSchema<ParquetMetadataOperatorType::KEY_VALUE_META_DATA>(kv_types, kv_names); |
973 | 0 | child_list_t<LogicalType> kv_children; |
974 | 0 | for (idx_t i = 0; i < kv_types.size(); i++) { |
975 | 0 | kv_children.emplace_back(make_pair(kv_names[i], kv_types[i])); |
976 | 0 | } |
977 | 0 | return_types.emplace_back(LogicalType::LIST(LogicalType::STRUCT(std::move(kv_children)))); |
978 | 0 | } |
979 | | |
980 | 0 | void FullMetadataProcessor::InitializeInternal(ClientContext &context, ParquetReader &reader) { |
981 | 0 | file_processor.Initialize(context, reader); |
982 | 0 | row_group_processor.Initialize(context, reader); |
983 | 0 | schema_processor.Initialize(context, reader); |
984 | 0 | kv_processor.Initialize(context, reader); |
985 | 0 | } |
986 | | |
987 | 0 | idx_t FullMetadataProcessor::TotalRowCount(ParquetReader &reader) { |
988 | 0 | return 1; |
989 | 0 | } |
990 | | |
991 | 0 | void FullMetadataProcessor::ReadRow(vector<reference<Vector>> &output, idx_t row_idx, ParquetReader &reader) { |
992 | 0 | PopulateMetadata(file_processor, output[0].get(), reader); |
993 | 0 | PopulateMetadata(row_group_processor, output[1].get(), reader); |
994 | 0 | PopulateMetadata(schema_processor, output[2].get(), reader); |
995 | 0 | PopulateMetadata(kv_processor, output[3].get(), reader); |
996 | 0 | } |
997 | | |
998 | | //===--------------------------------------------------------------------===// |
999 | | // Template Function Implementation |
1000 | | //===--------------------------------------------------------------------===// |
1001 | | |
1002 | | template <ParquetMetadataOperatorType OP_TYPE> |
1003 | | unique_ptr<FunctionData> ParquetMetaDataOperator::Bind(ClientContext &context, TableFunctionBindInput &input, |
1004 | 974 | vector<LogicalType> &return_types, vector<string> &names) { |
1005 | | // Extract file paths from input using MultiFileReader (handles both single files and arrays) |
1006 | 974 | auto multi_file_reader = MultiFileReader::CreateDefault("ParquetMetadata"); |
1007 | 974 | auto glob_input = FileGlobInput(FileGlobOptions::FALLBACK_GLOB, "parquet"); |
1008 | | |
1009 | 974 | auto result = make_uniq<ParquetMetaDataBindData>(); |
1010 | | // Bind schema based on operation type |
1011 | 974 | if (OP_TYPE == ParquetMetadataOperatorType::BLOOM_PROBE) { |
1012 | 0 | auto probe_bind_data = make_uniq<ParquetBloomProbeBindData>(); |
1013 | 0 | D_ASSERT(input.inputs.size() == 3); |
1014 | 0 | if (input.inputs[1].IsNull() || input.inputs[2].IsNull()) { |
1015 | 0 | throw InvalidInputException("Can't have NULL parameters for parquet_bloom_probe"); |
1016 | 0 | } |
1017 | 0 | probe_bind_data->probe_column_name = input.inputs[1].CastAs(context, LogicalType::VARCHAR).GetValue<string>(); |
1018 | 0 | probe_bind_data->probe_constant = input.inputs[2]; |
1019 | 0 | result = std::move(probe_bind_data); |
1020 | 0 | } |
1021 | | |
1022 | 974 | result->file_paths = make_uniq<ParquetMetadataFilePaths>(); |
1023 | 974 | result->file_paths->file_list = multi_file_reader->CreateFileList(context, input.inputs[0], glob_input); |
1024 | 974 | D_ASSERT(!result->file_paths->file_list->IsEmpty()); |
1025 | 974 | result->file_paths->file_list->InitializeScan(result->file_paths->scan_data); |
1026 | | |
1027 | 974 | BindSchema<OP_TYPE>(return_types, names); |
1028 | | |
1029 | 974 | return std::move(result); |
1030 | 974 | } Unexecuted instantiation: duckdb::unique_ptr<duckdb::FunctionData, std::__1::default_delete<duckdb::FunctionData>, true> duckdb::ParquetMetaDataOperator::Bind<(duckdb::ParquetMetadataOperatorType)0>(duckdb::ClientContext&, duckdb::TableFunctionBindInput&, duckdb::vector<duckdb::LogicalType, true, std::__1::allocator<duckdb::LogicalType> >&, duckdb::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, true, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&) duckdb::unique_ptr<duckdb::FunctionData, std::__1::default_delete<duckdb::FunctionData>, true> duckdb::ParquetMetaDataOperator::Bind<(duckdb::ParquetMetadataOperatorType)1>(duckdb::ClientContext&, duckdb::TableFunctionBindInput&, duckdb::vector<duckdb::LogicalType, true, std::__1::allocator<duckdb::LogicalType> >&, duckdb::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, true, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&) Line | Count | Source | 1004 | 974 | vector<LogicalType> &return_types, vector<string> &names) { | 1005 | | // Extract file paths from input using MultiFileReader (handles both single files and arrays) | 1006 | 974 | auto multi_file_reader = MultiFileReader::CreateDefault("ParquetMetadata"); | 1007 | 974 | auto glob_input = FileGlobInput(FileGlobOptions::FALLBACK_GLOB, "parquet"); | 1008 | | | 1009 | 974 | auto result = make_uniq<ParquetMetaDataBindData>(); | 1010 | | // Bind schema based on operation type | 1011 | 974 | if (OP_TYPE == ParquetMetadataOperatorType::BLOOM_PROBE) { | 1012 | 0 | auto probe_bind_data = make_uniq<ParquetBloomProbeBindData>(); | 1013 | 0 | D_ASSERT(input.inputs.size() == 3); | 1014 | 0 | if (input.inputs[1].IsNull() || input.inputs[2].IsNull()) { | 1015 | 0 | throw InvalidInputException("Can't have NULL parameters for parquet_bloom_probe"); | 1016 | 0 | } | 1017 | 0 | probe_bind_data->probe_column_name = input.inputs[1].CastAs(context, LogicalType::VARCHAR).GetValue<string>(); | 1018 | 0 | probe_bind_data->probe_constant = input.inputs[2]; | 1019 | 0 | result = std::move(probe_bind_data); | 1020 | 0 | } | 1021 | | | 1022 | 974 | result->file_paths = make_uniq<ParquetMetadataFilePaths>(); | 1023 | 974 | result->file_paths->file_list = multi_file_reader->CreateFileList(context, input.inputs[0], glob_input); | 1024 | 974 | D_ASSERT(!result->file_paths->file_list->IsEmpty()); | 1025 | 974 | result->file_paths->file_list->InitializeScan(result->file_paths->scan_data); | 1026 | | | 1027 | 974 | BindSchema<OP_TYPE>(return_types, names); | 1028 | | | 1029 | 974 | return std::move(result); | 1030 | 974 | } |
Unexecuted instantiation: duckdb::unique_ptr<duckdb::FunctionData, std::__1::default_delete<duckdb::FunctionData>, true> duckdb::ParquetMetaDataOperator::Bind<(duckdb::ParquetMetadataOperatorType)2>(duckdb::ClientContext&, duckdb::TableFunctionBindInput&, duckdb::vector<duckdb::LogicalType, true, std::__1::allocator<duckdb::LogicalType> >&, duckdb::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, true, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&) Unexecuted instantiation: duckdb::unique_ptr<duckdb::FunctionData, std::__1::default_delete<duckdb::FunctionData>, true> duckdb::ParquetMetaDataOperator::Bind<(duckdb::ParquetMetadataOperatorType)3>(duckdb::ClientContext&, duckdb::TableFunctionBindInput&, duckdb::vector<duckdb::LogicalType, true, std::__1::allocator<duckdb::LogicalType> >&, duckdb::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, true, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&) Unexecuted instantiation: duckdb::unique_ptr<duckdb::FunctionData, std::__1::default_delete<duckdb::FunctionData>, true> duckdb::ParquetMetaDataOperator::Bind<(duckdb::ParquetMetadataOperatorType)4>(duckdb::ClientContext&, duckdb::TableFunctionBindInput&, duckdb::vector<duckdb::LogicalType, true, std::__1::allocator<duckdb::LogicalType> >&, duckdb::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, true, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&) Unexecuted instantiation: duckdb::unique_ptr<duckdb::FunctionData, std::__1::default_delete<duckdb::FunctionData>, true> duckdb::ParquetMetaDataOperator::Bind<(duckdb::ParquetMetadataOperatorType)5>(duckdb::ClientContext&, duckdb::TableFunctionBindInput&, duckdb::vector<duckdb::LogicalType, true, std::__1::allocator<duckdb::LogicalType> >&, duckdb::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, true, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&) |
1031 | | |
1032 | | unique_ptr<GlobalTableFunctionState> ParquetMetaDataOperator::InitGlobal(ClientContext &context, |
1033 | 974 | TableFunctionInitInput &input) { |
1034 | 974 | auto &bind_data = input.bind_data->CastNoConst<ParquetMetaDataBindData>(); |
1035 | 974 | return make_uniq<ParquetMetadataGlobalState>(std::move(bind_data.file_paths), context); |
1036 | 974 | } |
1037 | | |
1038 | | template <ParquetMetadataOperatorType OP_TYPE> |
1039 | | unique_ptr<LocalTableFunctionState> ParquetMetaDataOperator::InitLocal(ExecutionContext &context, |
1040 | | TableFunctionInitInput &input, |
1041 | 974 | GlobalTableFunctionState *global_state) { |
1042 | 974 | auto &bind_data = input.bind_data->Cast<ParquetMetaDataBindData>(); |
1043 | 974 | auto res = make_uniq<ParquetMetadataLocalState>(); |
1044 | 974 | switch (OP_TYPE) { |
1045 | 0 | case ParquetMetadataOperatorType::META_DATA: |
1046 | 0 | res->processor = make_uniq<ParquetRowGroupMetadataProcessor>(); |
1047 | 0 | break; |
1048 | 974 | case ParquetMetadataOperatorType::SCHEMA: |
1049 | 974 | res->processor = make_uniq<ParquetSchemaProcessor>(); |
1050 | 974 | break; |
1051 | 0 | case ParquetMetadataOperatorType::KEY_VALUE_META_DATA: |
1052 | 0 | res->processor = make_uniq<ParquetKeyValueMetadataProcessor>(); |
1053 | 0 | break; |
1054 | 0 | case ParquetMetadataOperatorType::FILE_META_DATA: |
1055 | 0 | res->processor = make_uniq<ParquetFileMetadataProcessor>(); |
1056 | 0 | break; |
1057 | 0 | case ParquetMetadataOperatorType::BLOOM_PROBE: { |
1058 | 0 | const auto &probe_bind_data = static_cast<const ParquetBloomProbeBindData &>(bind_data); |
1059 | 0 | res->processor = |
1060 | 0 | make_uniq<ParquetBloomProbeProcessor>(probe_bind_data.probe_column_name, probe_bind_data.probe_constant); |
1061 | 0 | break; |
1062 | 0 | } |
1063 | 0 | case ParquetMetadataOperatorType::FULL_METADATA: { |
1064 | 0 | res->processor = make_uniq<FullMetadataProcessor>(); |
1065 | 0 | break; |
1066 | 0 | } |
1067 | 0 | default: |
1068 | 0 | throw InternalException("Unsupported ParquetMetadataOperatorType"); |
1069 | 974 | } |
1070 | 974 | return unique_ptr_cast<LocalTableFunctionState, ParquetMetadataLocalState>(std::move(res)); |
1071 | 974 | } Unexecuted instantiation: duckdb::unique_ptr<duckdb::LocalTableFunctionState, std::__1::default_delete<duckdb::LocalTableFunctionState>, true> duckdb::ParquetMetaDataOperator::InitLocal<(duckdb::ParquetMetadataOperatorType)0>(duckdb::ExecutionContext&, duckdb::TableFunctionInitInput&, duckdb::GlobalTableFunctionState*) duckdb::unique_ptr<duckdb::LocalTableFunctionState, std::__1::default_delete<duckdb::LocalTableFunctionState>, true> duckdb::ParquetMetaDataOperator::InitLocal<(duckdb::ParquetMetadataOperatorType)1>(duckdb::ExecutionContext&, duckdb::TableFunctionInitInput&, duckdb::GlobalTableFunctionState*) Line | Count | Source | 1041 | 974 | GlobalTableFunctionState *global_state) { | 1042 | 974 | auto &bind_data = input.bind_data->Cast<ParquetMetaDataBindData>(); | 1043 | 974 | auto res = make_uniq<ParquetMetadataLocalState>(); | 1044 | 974 | switch (OP_TYPE) { | 1045 | 0 | case ParquetMetadataOperatorType::META_DATA: | 1046 | 0 | res->processor = make_uniq<ParquetRowGroupMetadataProcessor>(); | 1047 | 0 | break; | 1048 | 974 | case ParquetMetadataOperatorType::SCHEMA: | 1049 | 974 | res->processor = make_uniq<ParquetSchemaProcessor>(); | 1050 | 974 | break; | 1051 | 0 | case ParquetMetadataOperatorType::KEY_VALUE_META_DATA: | 1052 | 0 | res->processor = make_uniq<ParquetKeyValueMetadataProcessor>(); | 1053 | 0 | break; | 1054 | 0 | case ParquetMetadataOperatorType::FILE_META_DATA: | 1055 | 0 | res->processor = make_uniq<ParquetFileMetadataProcessor>(); | 1056 | 0 | break; | 1057 | 0 | case ParquetMetadataOperatorType::BLOOM_PROBE: { | 1058 | 0 | const auto &probe_bind_data = static_cast<const ParquetBloomProbeBindData &>(bind_data); | 1059 | 0 | res->processor = | 1060 | 0 | make_uniq<ParquetBloomProbeProcessor>(probe_bind_data.probe_column_name, probe_bind_data.probe_constant); | 1061 | 0 | break; | 1062 | 0 | } | 1063 | 0 | case ParquetMetadataOperatorType::FULL_METADATA: { | 1064 | 0 | res->processor = make_uniq<FullMetadataProcessor>(); | 1065 | 0 | break; | 1066 | 0 | } | 1067 | 0 | default: | 1068 | 0 | throw InternalException("Unsupported ParquetMetadataOperatorType"); | 1069 | 974 | } | 1070 | 974 | return unique_ptr_cast<LocalTableFunctionState, ParquetMetadataLocalState>(std::move(res)); | 1071 | 974 | } |
Unexecuted instantiation: duckdb::unique_ptr<duckdb::LocalTableFunctionState, std::__1::default_delete<duckdb::LocalTableFunctionState>, true> duckdb::ParquetMetaDataOperator::InitLocal<(duckdb::ParquetMetadataOperatorType)2>(duckdb::ExecutionContext&, duckdb::TableFunctionInitInput&, duckdb::GlobalTableFunctionState*) Unexecuted instantiation: duckdb::unique_ptr<duckdb::LocalTableFunctionState, std::__1::default_delete<duckdb::LocalTableFunctionState>, true> duckdb::ParquetMetaDataOperator::InitLocal<(duckdb::ParquetMetadataOperatorType)3>(duckdb::ExecutionContext&, duckdb::TableFunctionInitInput&, duckdb::GlobalTableFunctionState*) Unexecuted instantiation: duckdb::unique_ptr<duckdb::LocalTableFunctionState, std::__1::default_delete<duckdb::LocalTableFunctionState>, true> duckdb::ParquetMetaDataOperator::InitLocal<(duckdb::ParquetMetadataOperatorType)4>(duckdb::ExecutionContext&, duckdb::TableFunctionInitInput&, duckdb::GlobalTableFunctionState*) Unexecuted instantiation: duckdb::unique_ptr<duckdb::LocalTableFunctionState, std::__1::default_delete<duckdb::LocalTableFunctionState>, true> duckdb::ParquetMetaDataOperator::InitLocal<(duckdb::ParquetMetadataOperatorType)5>(duckdb::ExecutionContext&, duckdb::TableFunctionInitInput&, duckdb::GlobalTableFunctionState*) |
1072 | | |
1073 | 974 | void ParquetMetaDataOperator::Function(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) { |
1074 | 974 | auto &global_state = data_p.global_state->Cast<ParquetMetadataGlobalState>(); |
1075 | 974 | auto &local_state = data_p.local_state->Cast<ParquetMetadataLocalState>(); |
1076 | | |
1077 | 974 | idx_t output_count = 0; |
1078 | | |
1079 | 974 | vector<reference<Vector>> output_vectors; |
1080 | 13.6k | for (idx_t i = 0; i < output.ColumnCount(); i++) { |
1081 | 12.6k | output_vectors.push_back(std::ref(output.data[i])); |
1082 | 12.6k | } |
1083 | | |
1084 | 1.94k | while (output_count < STANDARD_VECTOR_SIZE) { |
1085 | | // Check if we need a new file |
1086 | 974 | if (local_state.file_exhausted) { |
1087 | 974 | if (output_count > 0) { |
1088 | | // we already have rows - emit them first |
1089 | 0 | break; |
1090 | 0 | } |
1091 | 974 | idx_t next_file_idx; |
1092 | 974 | OpenFileInfo next_file; |
1093 | 974 | { |
1094 | 974 | lock_guard<mutex> guard(global_state.lock); |
1095 | 974 | if (!global_state.file_paths->NextFile(next_file)) { |
1096 | 0 | break; // No more files to process |
1097 | 0 | } |
1098 | 974 | next_file_idx = global_state.current_file++; |
1099 | 974 | } |
1100 | | |
1101 | 0 | local_state.Initialize(context, next_file, next_file_idx); |
1102 | 974 | } |
1103 | | |
1104 | 974 | idx_t left_in_vector = STANDARD_VECTOR_SIZE - output_count; |
1105 | 974 | idx_t left_in_file = local_state.total_rows - local_state.row_idx; |
1106 | 974 | idx_t rows_to_output = 0; |
1107 | 974 | if (left_in_file <= left_in_vector) { |
1108 | 0 | local_state.file_exhausted = true; |
1109 | 0 | rows_to_output = left_in_file; |
1110 | 974 | } else { |
1111 | 974 | rows_to_output = left_in_vector; |
1112 | 974 | } |
1113 | | |
1114 | 974 | for (idx_t i = 0; i < rows_to_output; ++i) { |
1115 | 0 | local_state.processor->ReadRow(output_vectors, local_state.row_idx + i, *local_state.reader); |
1116 | 0 | } |
1117 | 974 | output_count += rows_to_output; |
1118 | 974 | local_state.row_idx += rows_to_output; |
1119 | | |
1120 | 974 | if (local_state.processor->ForceFlush()) { |
1121 | 0 | break; |
1122 | 0 | } |
1123 | 974 | } |
1124 | 974 | } |
1125 | | |
1126 | | OperatorPartitionData ParquetMetaDataOperator::GetPartitionData(ClientContext &context, |
1127 | 0 | TableFunctionGetPartitionInput &input) { |
1128 | 0 | auto &local_state = input.local_state->Cast<ParquetMetadataLocalState>(); |
1129 | 0 | return OperatorPartitionData(local_state.file_idx.GetIndex()); |
1130 | 0 | } |
1131 | | |
1132 | | double ParquetMetaDataOperator::Progress(ClientContext &context, const FunctionData *bind_data_p, |
1133 | 0 | const GlobalTableFunctionState *global_state) { |
1134 | 0 | auto &global_data = global_state->Cast<ParquetMetadataGlobalState>(); |
1135 | 0 | return global_data.GetProgress() * 100.0; |
1136 | 0 | } |
1137 | | |
1138 | | ParquetMetaDataFunction::ParquetMetaDataFunction() |
1139 | 7.23k | : TableFunction("parquet_metadata", {LogicalType::VARCHAR}, ParquetMetaDataOperator::Function, |
1140 | 7.23k | ParquetMetaDataOperator::Bind<ParquetMetadataOperatorType::META_DATA>, |
1141 | 7.23k | ParquetMetaDataOperator::InitGlobal, |
1142 | 7.23k | ParquetMetaDataOperator::InitLocal<ParquetMetadataOperatorType::META_DATA>) { |
1143 | 7.23k | table_scan_progress = ParquetMetaDataOperator::Progress; |
1144 | 7.23k | get_partition_data = ParquetMetaDataOperator::GetPartitionData; |
1145 | 7.23k | } |
1146 | | |
1147 | | ParquetSchemaFunction::ParquetSchemaFunction() |
1148 | 7.23k | : TableFunction("parquet_schema", {LogicalType::VARCHAR}, ParquetMetaDataOperator::Function, |
1149 | 7.23k | ParquetMetaDataOperator::Bind<ParquetMetadataOperatorType::SCHEMA>, |
1150 | 7.23k | ParquetMetaDataOperator::InitGlobal, |
1151 | 7.23k | ParquetMetaDataOperator::InitLocal<ParquetMetadataOperatorType::SCHEMA>) { |
1152 | 7.23k | table_scan_progress = ParquetMetaDataOperator::Progress; |
1153 | 7.23k | get_partition_data = ParquetMetaDataOperator::GetPartitionData; |
1154 | 7.23k | } |
1155 | | |
1156 | | ParquetKeyValueMetadataFunction::ParquetKeyValueMetadataFunction() |
1157 | 7.23k | : TableFunction("parquet_kv_metadata", {LogicalType::VARCHAR}, ParquetMetaDataOperator::Function, |
1158 | 7.23k | ParquetMetaDataOperator::Bind<ParquetMetadataOperatorType::KEY_VALUE_META_DATA>, |
1159 | 7.23k | ParquetMetaDataOperator::InitGlobal, |
1160 | 7.23k | ParquetMetaDataOperator::InitLocal<ParquetMetadataOperatorType::KEY_VALUE_META_DATA>) { |
1161 | 7.23k | table_scan_progress = ParquetMetaDataOperator::Progress; |
1162 | 7.23k | get_partition_data = ParquetMetaDataOperator::GetPartitionData; |
1163 | 7.23k | } |
1164 | | |
1165 | | ParquetFileMetadataFunction::ParquetFileMetadataFunction() |
1166 | 7.23k | : TableFunction("parquet_file_metadata", {LogicalType::VARCHAR}, ParquetMetaDataOperator::Function, |
1167 | 7.23k | ParquetMetaDataOperator::Bind<ParquetMetadataOperatorType::FILE_META_DATA>, |
1168 | 7.23k | ParquetMetaDataOperator::InitGlobal, |
1169 | 7.23k | ParquetMetaDataOperator::InitLocal<ParquetMetadataOperatorType::FILE_META_DATA>) { |
1170 | 7.23k | table_scan_progress = ParquetMetaDataOperator::Progress; |
1171 | 7.23k | get_partition_data = ParquetMetaDataOperator::GetPartitionData; |
1172 | 7.23k | } |
1173 | | |
1174 | | ParquetBloomProbeFunction::ParquetBloomProbeFunction() |
1175 | 7.23k | : TableFunction("parquet_bloom_probe", {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::ANY}, |
1176 | 7.23k | ParquetMetaDataOperator::Function, |
1177 | 7.23k | ParquetMetaDataOperator::Bind<ParquetMetadataOperatorType::BLOOM_PROBE>, |
1178 | 7.23k | ParquetMetaDataOperator::InitGlobal, |
1179 | 7.23k | ParquetMetaDataOperator::InitLocal<ParquetMetadataOperatorType::BLOOM_PROBE>) { |
1180 | 7.23k | table_scan_progress = ParquetMetaDataOperator::Progress; |
1181 | 7.23k | get_partition_data = ParquetMetaDataOperator::GetPartitionData; |
1182 | 7.23k | } |
1183 | | |
1184 | | ParquetFullMetadataFunction::ParquetFullMetadataFunction() |
1185 | 7.23k | : TableFunction("parquet_full_metadata", {LogicalType::VARCHAR}, ParquetMetaDataOperator::Function, |
1186 | 7.23k | ParquetMetaDataOperator::Bind<ParquetMetadataOperatorType::FULL_METADATA>, |
1187 | 7.23k | ParquetMetaDataOperator::InitGlobal, |
1188 | 7.23k | ParquetMetaDataOperator::InitLocal<ParquetMetadataOperatorType::FULL_METADATA>) { |
1189 | 7.23k | table_scan_progress = ParquetMetaDataOperator::Progress; |
1190 | 7.23k | get_partition_data = ParquetMetaDataOperator::GetPartitionData; |
1191 | 7.23k | } |
1192 | | } // namespace duckdb |