Coverage Report

Created: 2026-07-07 07:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/duckdb/extension/parquet/reader/string_column_reader.cpp
Line
Count
Source
1
#include "reader/string_column_reader.hpp"
2
3
#include <stddef.h>
4
#include <utility>
5
6
#include "utf8proc_wrapper.hpp"
7
#include "parquet_reader.hpp"
8
#include "duckdb/common/types/blob.hpp"
9
#include "duckdb/common/helper.hpp"
10
#include "duckdb/common/string_util.hpp"
11
#include "duckdb/common/types/vector_buffer.hpp"
12
#include "duckdb/common/unique_ptr.hpp"
13
#include "duckdb/common/vector/string_vector.hpp"
14
#include "parquet_column_schema.hpp"
15
#include "parquet_types.h"
16
17
namespace duckdb {
18
class Vector;
19
struct SelectionVector;
20
21
//===--------------------------------------------------------------------===//
22
// String Column Reader
23
//===--------------------------------------------------------------------===//
24
StringColumnReader::StringColumnReader(const ParquetReader &reader, const ParquetColumnSchema &schema)
25
0
    : ColumnReader(reader, schema), string_column_type(GetStringColumnType(Type())) {
26
0
  fixed_width_string_length = 0;
27
0
  if (schema.parquet_type == Type::FIXED_LEN_BYTE_ARRAY) {
28
0
    fixed_width_string_length = schema.type_length;
29
0
  }
30
0
}
31
32
0
bool StringColumnReader::IsValid(const char *str_data, uint32_t str_len, const bool is_varchar) {
33
0
  if (!is_varchar) {
34
0
    return true;
35
0
  }
36
  // verify if a string is actually UTF8, and if there are no null bytes in the middle of the string
37
  // technically Parquet should guarantee this, but reality is often disappointing
38
0
  UnicodeInvalidReason reason;
39
0
  size_t pos;
40
0
  auto utf_type = Utf8Proc::Analyze(str_data, str_len, &reason, &pos);
41
0
  return utf_type != UnicodeType::INVALID;
42
0
}
43
44
0
bool StringColumnReader::IsValid(const string &str, bool is_varchar) {
45
0
  return IsValid(str.c_str(), str.size(), is_varchar);
46
0
}
47
0
void StringColumnReader::VerifyString(const char *str_data, uint32_t str_len, const bool is_varchar) const {
48
0
  if (!IsValid(str_data, str_len, is_varchar)) {
49
0
    throw InvalidInputException(
50
0
        "Invalid string encoding found in Parquet file \"%s\": value \"%s\" is not valid UTF8!",
51
0
        reader.GetFileName(), Blob::ToString(string_t(str_data, str_len)));
52
0
  }
53
0
}
54
55
0
void StringColumnReader::VerifyString(const char *str_data, uint32_t str_len) const {
56
0
  switch (string_column_type) {
57
0
  case StringColumnType::VARCHAR:
58
0
    VerifyString(str_data, str_len, true);
59
0
    break;
60
0
  case StringColumnType::JSON: {
61
0
    const auto error = StringUtil::ValidateJSON(str_data, str_len);
62
0
    if (!error.empty()) {
63
0
      throw InvalidInputException("Invalid JSON found in Parquet file: %s", error);
64
0
    }
65
0
    break;
66
0
  }
67
0
  default:
68
0
    break;
69
0
  }
70
0
}
71
72
class ParquetStringVectorBuffer : public AuxiliaryDataHolder {
73
public:
74
0
  explicit ParquetStringVectorBuffer(shared_ptr<ResizeableBuffer> buffer_p) : buffer(std::move(buffer_p)) {
75
0
  }
76
77
private:
78
  shared_ptr<ResizeableBuffer> buffer;
79
};
80
81
0
void StringColumnReader::ReferenceBlock(Vector &result, shared_ptr<ResizeableBuffer> &block) {
82
0
  StringVector::AddAuxiliaryData(result, make_uniq<ParquetStringVectorBuffer>(block));
83
0
}
84
85
void StringColumnReader::Plain(shared_ptr<ResizeableBuffer> &plain_data, uint8_t *defines, idx_t num_values,
86
0
                               idx_t result_offset, Vector &result) {
87
0
  ReferenceBlock(result, plain_data);
88
0
  PlainTemplated<string_t, StringParquetValueConversion>(*plain_data, defines, num_values, result_offset, result);
89
0
}
90
91
0
void StringColumnReader::PlainSkip(ByteBuffer &plain_data, uint8_t *defines, idx_t num_values) {
92
0
  PlainSkipTemplated<StringParquetValueConversion>(plain_data, defines, num_values);
93
0
}
94
95
void StringColumnReader::PlainSelect(shared_ptr<ResizeableBuffer> &plain_data, uint8_t *defines, idx_t num_values,
96
0
                                     Vector &result, const SelectionVector &sel, idx_t count) {
97
0
  ReferenceBlock(result, plain_data);
98
0
  PlainSelectTemplated<string_t, StringParquetValueConversion>(*plain_data, defines, num_values, result, sel, count);
99
0
}
100
101
} // namespace duckdb