/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 |