Coverage Report

Created: 2026-07-07 07:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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