quack-ruby 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/LICENSE-DuckDB +7 -0
- data/LICENSE-QuackProtocol +21 -0
- data/LICENSE-Rust-dependencies.json +2057 -0
- data/README.md +229 -0
- data/ext/quack/Cargo.lock +1803 -0
- data/ext/quack/Cargo.toml +17 -0
- data/ext/quack/extconf.rb +4 -0
- data/ext/quack/src/lib.rs +647 -0
- data/ext/quack/vendor/quack_protocol/Cargo.lock +1907 -0
- data/ext/quack/vendor/quack_protocol/Cargo.toml +41 -0
- data/ext/quack/vendor/quack_protocol/LICENSE +21 -0
- data/ext/quack/vendor/quack_protocol/PATCHES.md +16 -0
- data/ext/quack/vendor/quack_protocol/README.md +272 -0
- data/ext/quack/vendor/quack_protocol/src/arrow/columns.rs +399 -0
- data/ext/quack/vendor/quack_protocol/src/arrow/mod.rs +134 -0
- data/ext/quack/vendor/quack_protocol/src/arrow/schema.rs +103 -0
- data/ext/quack/vendor/quack_protocol/src/arrow/tests.rs +851 -0
- data/ext/quack/vendor/quack_protocol/src/arrow/values.rs +150 -0
- data/ext/quack/vendor/quack_protocol/src/binary.rs +504 -0
- data/ext/quack/vendor/quack_protocol/src/builders.rs +217 -0
- data/ext/quack/vendor/quack_protocol/src/client.rs +1486 -0
- data/ext/quack/vendor/quack_protocol/src/constants.rs +11 -0
- data/ext/quack/vendor/quack_protocol/src/errors.rs +103 -0
- data/ext/quack/vendor/quack_protocol/src/inspection.rs +250 -0
- data/ext/quack/vendor/quack_protocol/src/json.rs +225 -0
- data/ext/quack/vendor/quack_protocol/src/lib.rs +54 -0
- data/ext/quack/vendor/quack_protocol/src/logical_types.rs +977 -0
- data/ext/quack/vendor/quack_protocol/src/messages.rs +843 -0
- data/ext/quack/vendor/quack_protocol/src/pool.rs +741 -0
- data/ext/quack/vendor/quack_protocol/src/protocol_tests.rs +759 -0
- data/ext/quack/vendor/quack_protocol/src/proxy_error.rs +77 -0
- data/ext/quack/vendor/quack_protocol/src/sql.rs +359 -0
- data/ext/quack/vendor/quack_protocol/src/tls.rs +354 -0
- data/ext/quack/vendor/quack_protocol/src/values.rs +77 -0
- data/ext/quack/vendor/quack_protocol/src/vector.rs +1364 -0
- data/ext/quack/vendor/quack_protocol/testdata/tls/key.der +0 -0
- data/ext/quack/vendor/quack_protocol/testdata/tls/spki.der +0 -0
- data/ext/quack/vendor/quack_protocol/testdata/tls/v1-cert.der +0 -0
- data/ext/quack/vendor/quack_protocol/testdata/tls/v3-cert.der +0 -0
- data/lib/quack/codec.rb +263 -0
- data/lib/quack/connection.rb +131 -0
- data/lib/quack/logical_types.rb +72 -0
- data/lib/quack/result.rb +64 -0
- data/lib/quack/sql.rb +183 -0
- data/lib/quack/types.rb +40 -0
- data/lib/quack/variant.rb +298 -0
- data/lib/quack.rb +34 -0
- metadata +136 -0
|
@@ -0,0 +1,1364 @@
|
|
|
1
|
+
use indexmap::IndexMap;
|
|
2
|
+
|
|
3
|
+
use crate::binary::{
|
|
4
|
+
BinaryReader, BinaryWriter, HugeIntParts, combine_signed_huge_int, combine_unsigned_huge_int,
|
|
5
|
+
split_signed_huge_int,
|
|
6
|
+
};
|
|
7
|
+
use crate::constants::OPTIONAL_INDEX_INVALID;
|
|
8
|
+
use crate::errors::{QuackError, Result};
|
|
9
|
+
use crate::logical_types::{
|
|
10
|
+
ExtraTypeInfo, LogicalType, LogicalTypeId, PhysicalType, decode_logical_type,
|
|
11
|
+
encode_logical_type, get_array_size, get_child_type, get_enum_values, get_physical_type,
|
|
12
|
+
get_struct_children, is_constant_size_physical_type, physical_type_size, struct_child_key,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
16
|
+
#[repr(u64)]
|
|
17
|
+
pub(crate) enum VectorType {
|
|
18
|
+
Flat = 0,
|
|
19
|
+
Fsst = 1,
|
|
20
|
+
Constant = 2,
|
|
21
|
+
Dictionary = 3,
|
|
22
|
+
Sequence = 4,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
impl TryFrom<u64> for VectorType {
|
|
26
|
+
type Error = QuackError;
|
|
27
|
+
|
|
28
|
+
fn try_from(value: u64) -> Result<Self> {
|
|
29
|
+
Ok(match value {
|
|
30
|
+
0 => Self::Flat,
|
|
31
|
+
1 => Self::Fsst,
|
|
32
|
+
2 => Self::Constant,
|
|
33
|
+
3 => Self::Dictionary,
|
|
34
|
+
4 => Self::Sequence,
|
|
35
|
+
_ => return Err(QuackError::protocol(format!("unknown vector type {value}"))),
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
41
|
+
pub enum TimeUnit {
|
|
42
|
+
Micros,
|
|
43
|
+
Nanos,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
47
|
+
pub enum TimestampUnit {
|
|
48
|
+
Seconds,
|
|
49
|
+
Millis,
|
|
50
|
+
Micros,
|
|
51
|
+
Nanos,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
55
|
+
pub struct DecimalValue {
|
|
56
|
+
pub value: i128,
|
|
57
|
+
pub width: u64,
|
|
58
|
+
pub scale: u64,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
62
|
+
pub struct DateValue {
|
|
63
|
+
pub days: i32,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
67
|
+
pub struct TimeValue {
|
|
68
|
+
pub unit: TimeUnit,
|
|
69
|
+
pub value: i64,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
73
|
+
pub struct TimeTzValue {
|
|
74
|
+
pub bits: i64,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
78
|
+
pub struct TimestampValue {
|
|
79
|
+
pub unit: TimestampUnit,
|
|
80
|
+
pub value: i64,
|
|
81
|
+
pub timezone_utc: bool,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
85
|
+
pub struct IntervalValue {
|
|
86
|
+
pub months: i32,
|
|
87
|
+
pub days: i32,
|
|
88
|
+
pub micros: i64,
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
#[derive(Clone, Debug, PartialEq)]
|
|
92
|
+
pub enum Value {
|
|
93
|
+
Null,
|
|
94
|
+
Bool(bool),
|
|
95
|
+
Int(i64),
|
|
96
|
+
UInt(u64),
|
|
97
|
+
HugeInt(i128),
|
|
98
|
+
UHugeInt(u128),
|
|
99
|
+
Float(f32),
|
|
100
|
+
Double(f64),
|
|
101
|
+
String(String),
|
|
102
|
+
Bytes(Vec<u8>),
|
|
103
|
+
Decimal(DecimalValue),
|
|
104
|
+
Date(DateValue),
|
|
105
|
+
Time(TimeValue),
|
|
106
|
+
TimeTz(TimeTzValue),
|
|
107
|
+
Timestamp(TimestampValue),
|
|
108
|
+
Interval(IntervalValue),
|
|
109
|
+
List(Vec<Value>),
|
|
110
|
+
Struct(IndexMap<String, Value>),
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
impl Value {
|
|
114
|
+
pub fn is_null(&self) -> bool {
|
|
115
|
+
matches!(self, Self::Null)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
impl From<bool> for Value {
|
|
120
|
+
fn from(value: bool) -> Self {
|
|
121
|
+
Self::Bool(value)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
impl From<i32> for Value {
|
|
126
|
+
fn from(value: i32) -> Self {
|
|
127
|
+
Self::Int(value as i64)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
impl From<i64> for Value {
|
|
132
|
+
fn from(value: i64) -> Self {
|
|
133
|
+
Self::Int(value)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
impl From<u32> for Value {
|
|
138
|
+
fn from(value: u32) -> Self {
|
|
139
|
+
Self::UInt(value as u64)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
impl From<u64> for Value {
|
|
144
|
+
fn from(value: u64) -> Self {
|
|
145
|
+
Self::UInt(value)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
impl From<f32> for Value {
|
|
150
|
+
fn from(value: f32) -> Self {
|
|
151
|
+
Self::Float(value)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
impl From<f64> for Value {
|
|
156
|
+
fn from(value: f64) -> Self {
|
|
157
|
+
Self::Double(value)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
impl From<&str> for Value {
|
|
162
|
+
fn from(value: &str) -> Self {
|
|
163
|
+
Self::String(value.to_string())
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
impl From<String> for Value {
|
|
168
|
+
fn from(value: String) -> Self {
|
|
169
|
+
Self::String(value)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
impl From<Vec<u8>> for Value {
|
|
174
|
+
fn from(value: Vec<u8>) -> Self {
|
|
175
|
+
Self::Bytes(value)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
#[derive(Clone, Debug, PartialEq)]
|
|
180
|
+
pub(crate) struct DecodedVector {
|
|
181
|
+
pub(crate) logical_type: LogicalType,
|
|
182
|
+
pub(crate) vector_type: VectorType,
|
|
183
|
+
pub(crate) values: Vec<Value>,
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
#[derive(Clone, Debug, PartialEq)]
|
|
187
|
+
pub struct DataChunk {
|
|
188
|
+
pub row_count: usize,
|
|
189
|
+
pub types: Vec<LogicalType>,
|
|
190
|
+
pub(crate) columns: Vec<DecodedVector>,
|
|
191
|
+
pub column_names: Option<Vec<String>>,
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
impl DataChunk {
|
|
195
|
+
pub fn column_values(&self, column: usize) -> Option<&[Value]> {
|
|
196
|
+
self.columns
|
|
197
|
+
.get(column)
|
|
198
|
+
.map(|vector| vector.values.as_slice())
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
pub type Row = IndexMap<String, Value>;
|
|
203
|
+
|
|
204
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
205
|
+
struct ListEntry {
|
|
206
|
+
offset: usize,
|
|
207
|
+
length: usize,
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
pub(crate) fn decode_data_chunk_wrapper(reader: &mut BinaryReader<'_>) -> Result<DataChunk> {
|
|
211
|
+
reader.read_object(|object| object.read_required_field(300, decode_data_chunk))
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
pub(crate) fn encode_data_chunk_wrapper(
|
|
215
|
+
writer: &mut BinaryWriter,
|
|
216
|
+
chunk: &DataChunk,
|
|
217
|
+
) -> Result<()> {
|
|
218
|
+
writer.write_object(|object| {
|
|
219
|
+
object.write_field(300, |object| encode_data_chunk(object, chunk))?;
|
|
220
|
+
Ok(())
|
|
221
|
+
})
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
pub(crate) fn decode_data_chunk(reader: &mut BinaryReader<'_>) -> Result<DataChunk> {
|
|
225
|
+
reader.read_object(|object| {
|
|
226
|
+
let row_count = object.read_required_field(100, |object| object.read_uleb_usize())?;
|
|
227
|
+
let types = object.read_required_field(101, |object| {
|
|
228
|
+
object.read_list(|object, _| decode_logical_type(object))
|
|
229
|
+
})?;
|
|
230
|
+
let columns = object.read_required_field(102, |object| {
|
|
231
|
+
object.read_list(|object, index| {
|
|
232
|
+
let logical_type = types.get(index).ok_or_else(|| {
|
|
233
|
+
QuackError::protocol(format!(
|
|
234
|
+
"column vector {index} has no matching logical type"
|
|
235
|
+
))
|
|
236
|
+
})?;
|
|
237
|
+
decode_vector(object, logical_type, row_count)
|
|
238
|
+
})
|
|
239
|
+
})?;
|
|
240
|
+
if columns.len() != types.len() {
|
|
241
|
+
return Err(QuackError::protocol(format!(
|
|
242
|
+
"DataChunk declared {} types but serialized {} columns",
|
|
243
|
+
types.len(),
|
|
244
|
+
columns.len()
|
|
245
|
+
)));
|
|
246
|
+
}
|
|
247
|
+
Ok(DataChunk {
|
|
248
|
+
row_count,
|
|
249
|
+
types,
|
|
250
|
+
columns,
|
|
251
|
+
column_names: None,
|
|
252
|
+
})
|
|
253
|
+
})
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
pub(crate) fn encode_data_chunk(writer: &mut BinaryWriter, chunk: &DataChunk) -> Result<()> {
|
|
257
|
+
if chunk.types.len() != chunk.columns.len() {
|
|
258
|
+
return Err(QuackError::protocol(
|
|
259
|
+
"DataChunk type count must match column count",
|
|
260
|
+
));
|
|
261
|
+
}
|
|
262
|
+
writer.write_object(|object| {
|
|
263
|
+
object.write_field(100, |object| object.write_uleb(chunk.row_count as u64))?;
|
|
264
|
+
object.write_field(101, |object| {
|
|
265
|
+
object.write_list(&chunk.types, |object, logical_type, _| {
|
|
266
|
+
encode_logical_type(object, logical_type)
|
|
267
|
+
})
|
|
268
|
+
})?;
|
|
269
|
+
object.write_field(102, |object| {
|
|
270
|
+
object.write_list(&chunk.columns, |object, column, index| {
|
|
271
|
+
let logical_type = chunk.types.get(index).ok_or_else(|| {
|
|
272
|
+
QuackError::protocol(format!("column {index} has no logical type"))
|
|
273
|
+
})?;
|
|
274
|
+
if column.values.len() != chunk.row_count {
|
|
275
|
+
return Err(QuackError::protocol(format!(
|
|
276
|
+
"column {index} has {} values, expected {}",
|
|
277
|
+
column.values.len(),
|
|
278
|
+
chunk.row_count
|
|
279
|
+
)));
|
|
280
|
+
}
|
|
281
|
+
encode_vector(object, logical_type, &column.values, chunk.row_count)
|
|
282
|
+
})
|
|
283
|
+
})?;
|
|
284
|
+
Ok(())
|
|
285
|
+
})
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
pub(crate) fn decode_vector(
|
|
289
|
+
reader: &mut BinaryReader<'_>,
|
|
290
|
+
logical_type: &LogicalType,
|
|
291
|
+
count: usize,
|
|
292
|
+
) -> Result<DecodedVector> {
|
|
293
|
+
reader.read_object(|object| decode_vector_body(object, logical_type, count))
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
pub(crate) fn encode_vector(
|
|
297
|
+
writer: &mut BinaryWriter,
|
|
298
|
+
logical_type: &LogicalType,
|
|
299
|
+
values: &[Value],
|
|
300
|
+
count: usize,
|
|
301
|
+
) -> Result<()> {
|
|
302
|
+
writer.write_object(|object| encode_flat_vector_body(object, logical_type, values, count))
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
pub fn rows_from_chunk(chunk: &DataChunk) -> Result<Vec<Row>> {
|
|
306
|
+
let names = chunk.column_names.clone().unwrap_or_else(|| {
|
|
307
|
+
(0..chunk.columns.len())
|
|
308
|
+
.map(|i| format!("column{i}"))
|
|
309
|
+
.collect()
|
|
310
|
+
});
|
|
311
|
+
rows_from_chunk_with_names(chunk, &names)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
pub(crate) fn rows_from_chunk_with_names(chunk: &DataChunk, names: &[String]) -> Result<Vec<Row>> {
|
|
315
|
+
let mut rows = Vec::with_capacity(chunk.row_count);
|
|
316
|
+
for row_index in 0..chunk.row_count {
|
|
317
|
+
let mut row = Row::new();
|
|
318
|
+
for (column_index, column) in chunk.columns.iter().enumerate() {
|
|
319
|
+
let name = names
|
|
320
|
+
.get(column_index)
|
|
321
|
+
.cloned()
|
|
322
|
+
.unwrap_or_else(|| format!("column{column_index}"));
|
|
323
|
+
let value = column.values.get(row_index).cloned().unwrap_or(Value::Null);
|
|
324
|
+
row.insert(name, value);
|
|
325
|
+
}
|
|
326
|
+
rows.push(row);
|
|
327
|
+
}
|
|
328
|
+
Ok(rows)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
pub fn decimal_to_string(decimal: &DecimalValue) -> String {
|
|
332
|
+
let negative = decimal.value < 0;
|
|
333
|
+
let abs = if negative {
|
|
334
|
+
-decimal.value
|
|
335
|
+
} else {
|
|
336
|
+
decimal.value
|
|
337
|
+
};
|
|
338
|
+
if decimal.scale == 0 {
|
|
339
|
+
return format!("{}{}", if negative { "-" } else { "" }, abs);
|
|
340
|
+
}
|
|
341
|
+
let factor = 10i128.pow(decimal.scale as u32);
|
|
342
|
+
let integer = abs / factor;
|
|
343
|
+
let fraction = abs % factor;
|
|
344
|
+
format!(
|
|
345
|
+
"{}{}.{:0width$}",
|
|
346
|
+
if negative { "-" } else { "" },
|
|
347
|
+
integer,
|
|
348
|
+
fraction,
|
|
349
|
+
width = decimal.scale as usize
|
|
350
|
+
)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
fn decode_vector_body(
|
|
354
|
+
reader: &mut BinaryReader<'_>,
|
|
355
|
+
logical_type: &LogicalType,
|
|
356
|
+
count: usize,
|
|
357
|
+
) -> Result<DecodedVector> {
|
|
358
|
+
let vector_type = VectorType::try_from(reader.read_optional_field(
|
|
359
|
+
90,
|
|
360
|
+
|reader| reader.read_uleb_u64(),
|
|
361
|
+
VectorType::Flat as u64,
|
|
362
|
+
)?)?;
|
|
363
|
+
match vector_type {
|
|
364
|
+
VectorType::Flat => decode_flat_vector_body(reader, logical_type, count, vector_type),
|
|
365
|
+
VectorType::Fsst => Err(QuackError::unsupported(
|
|
366
|
+
"FSST-compressed vectors are not supported",
|
|
367
|
+
)),
|
|
368
|
+
VectorType::Constant => {
|
|
369
|
+
let decoded = decode_vector_body(reader, logical_type, usize::from(count > 0))?;
|
|
370
|
+
let value = decoded.values.first().cloned().unwrap_or(Value::Null);
|
|
371
|
+
Ok(DecodedVector {
|
|
372
|
+
logical_type: logical_type.clone(),
|
|
373
|
+
vector_type,
|
|
374
|
+
values: vec![value; count],
|
|
375
|
+
})
|
|
376
|
+
}
|
|
377
|
+
VectorType::Dictionary => {
|
|
378
|
+
let selection =
|
|
379
|
+
reader.read_required_field(91, |reader| read_selection_vector(reader, count))?;
|
|
380
|
+
let dictionary_count =
|
|
381
|
+
reader.read_required_field(92, |reader| reader.read_uleb_usize())?;
|
|
382
|
+
let dictionary = decode_vector_body(reader, logical_type, dictionary_count)?;
|
|
383
|
+
let mut values = Vec::with_capacity(count);
|
|
384
|
+
for index in selection {
|
|
385
|
+
values.push(dictionary.values.get(index).cloned().ok_or_else(|| {
|
|
386
|
+
QuackError::protocol(format!("dictionary selection {index} is out of range"))
|
|
387
|
+
})?);
|
|
388
|
+
}
|
|
389
|
+
Ok(DecodedVector {
|
|
390
|
+
logical_type: logical_type.clone(),
|
|
391
|
+
vector_type,
|
|
392
|
+
values,
|
|
393
|
+
})
|
|
394
|
+
}
|
|
395
|
+
VectorType::Sequence => {
|
|
396
|
+
let start = reader.read_required_field(91, |reader| reader.read_sleb_i128())?;
|
|
397
|
+
let increment = reader.read_required_field(92, |reader| reader.read_sleb_i128())?;
|
|
398
|
+
let values = (0..count)
|
|
399
|
+
.map(|index| decode_sequence_value(logical_type, start + increment * index as i128))
|
|
400
|
+
.collect::<Result<Vec<_>>>()?;
|
|
401
|
+
Ok(DecodedVector {
|
|
402
|
+
logical_type: logical_type.clone(),
|
|
403
|
+
vector_type,
|
|
404
|
+
values,
|
|
405
|
+
})
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
fn decode_flat_vector_body(
|
|
411
|
+
reader: &mut BinaryReader<'_>,
|
|
412
|
+
logical_type: &LogicalType,
|
|
413
|
+
count: usize,
|
|
414
|
+
vector_type: VectorType,
|
|
415
|
+
) -> Result<DecodedVector> {
|
|
416
|
+
if logical_type.id == LogicalTypeId::Geometry && reader.peek_field_id()? == 99 {
|
|
417
|
+
reader.read_required_field(99, |reader| reader.read_uleb_u64())?;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
let has_validity_mask = reader.read_required_field(100, |reader| reader.read_bool())?;
|
|
421
|
+
let validity = if has_validity_mask {
|
|
422
|
+
Some(reader.read_required_field(101, |reader| read_validity_mask(reader, count))?)
|
|
423
|
+
} else {
|
|
424
|
+
None
|
|
425
|
+
};
|
|
426
|
+
let physical_type = get_physical_type(logical_type)?;
|
|
427
|
+
if is_constant_size_physical_type(physical_type) {
|
|
428
|
+
let byte_length = physical_type_size(physical_type)? * count;
|
|
429
|
+
let bytes = reader.read_required_field(102, |reader| reader.read_blob())?;
|
|
430
|
+
if bytes.len() != byte_length {
|
|
431
|
+
return Err(QuackError::protocol(format!(
|
|
432
|
+
"fixed-size vector data has {} bytes, expected {byte_length}",
|
|
433
|
+
bytes.len()
|
|
434
|
+
)));
|
|
435
|
+
}
|
|
436
|
+
let values = decode_fixed_values(
|
|
437
|
+
logical_type,
|
|
438
|
+
physical_type,
|
|
439
|
+
&bytes,
|
|
440
|
+
count,
|
|
441
|
+
validity.as_deref(),
|
|
442
|
+
)?;
|
|
443
|
+
return Ok(DecodedVector {
|
|
444
|
+
logical_type: logical_type.clone(),
|
|
445
|
+
vector_type,
|
|
446
|
+
values,
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
match physical_type {
|
|
451
|
+
PhysicalType::Varchar => {
|
|
452
|
+
let raw_values = read_string_vector_data(reader, count, validity.as_deref())?;
|
|
453
|
+
let values = raw_values
|
|
454
|
+
.into_iter()
|
|
455
|
+
.enumerate()
|
|
456
|
+
.map(|(index, raw)| {
|
|
457
|
+
if is_valid(validity.as_deref(), index) {
|
|
458
|
+
decode_string_like_value(logical_type, raw)
|
|
459
|
+
} else {
|
|
460
|
+
Ok(Value::Null)
|
|
461
|
+
}
|
|
462
|
+
})
|
|
463
|
+
.collect::<Result<Vec<_>>>()?;
|
|
464
|
+
Ok(DecodedVector {
|
|
465
|
+
logical_type: logical_type.clone(),
|
|
466
|
+
vector_type,
|
|
467
|
+
values,
|
|
468
|
+
})
|
|
469
|
+
}
|
|
470
|
+
PhysicalType::Struct => {
|
|
471
|
+
let children = get_struct_children(logical_type)?;
|
|
472
|
+
let child_vectors = reader.read_required_field(103, |reader| {
|
|
473
|
+
reader.read_list(|reader, index| {
|
|
474
|
+
let child = children.get(index).ok_or_else(|| {
|
|
475
|
+
QuackError::protocol(format!(
|
|
476
|
+
"STRUCT child vector {index} has no matching type metadata"
|
|
477
|
+
))
|
|
478
|
+
})?;
|
|
479
|
+
decode_vector(reader, &child.logical_type, count)
|
|
480
|
+
})
|
|
481
|
+
})?;
|
|
482
|
+
let mut values = Vec::with_capacity(count);
|
|
483
|
+
for row_index in 0..count {
|
|
484
|
+
if !is_valid(validity.as_deref(), row_index) {
|
|
485
|
+
values.push(Value::Null);
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
let mut row = IndexMap::new();
|
|
489
|
+
for (child_index, child) in children.iter().enumerate() {
|
|
490
|
+
let child_vector = child_vectors.get(child_index).ok_or_else(|| {
|
|
491
|
+
QuackError::protocol(format!("STRUCT child {child_index} is incomplete"))
|
|
492
|
+
})?;
|
|
493
|
+
row.insert(
|
|
494
|
+
struct_child_key(logical_type, child_index, child),
|
|
495
|
+
child_vector
|
|
496
|
+
.values
|
|
497
|
+
.get(row_index)
|
|
498
|
+
.cloned()
|
|
499
|
+
.unwrap_or(Value::Null),
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
values.push(Value::Struct(row));
|
|
503
|
+
}
|
|
504
|
+
Ok(DecodedVector {
|
|
505
|
+
logical_type: logical_type.clone(),
|
|
506
|
+
vector_type,
|
|
507
|
+
values,
|
|
508
|
+
})
|
|
509
|
+
}
|
|
510
|
+
PhysicalType::List => {
|
|
511
|
+
let list_size = reader.read_required_field(104, |reader| reader.read_uleb_usize())?;
|
|
512
|
+
let entries =
|
|
513
|
+
reader.read_required_field(105, |reader| read_list_entries(reader, count))?;
|
|
514
|
+
let child_type = get_child_type(logical_type)?;
|
|
515
|
+
let child_vector = reader
|
|
516
|
+
.read_required_field(106, |reader| decode_vector(reader, child_type, list_size))?;
|
|
517
|
+
let values = entries
|
|
518
|
+
.iter()
|
|
519
|
+
.enumerate()
|
|
520
|
+
.map(|(row_index, entry)| {
|
|
521
|
+
if !is_valid(validity.as_deref(), row_index) {
|
|
522
|
+
return Value::Null;
|
|
523
|
+
}
|
|
524
|
+
Value::List(
|
|
525
|
+
child_vector.values[entry.offset..entry.offset + entry.length].to_vec(),
|
|
526
|
+
)
|
|
527
|
+
})
|
|
528
|
+
.collect();
|
|
529
|
+
Ok(DecodedVector {
|
|
530
|
+
logical_type: logical_type.clone(),
|
|
531
|
+
vector_type,
|
|
532
|
+
values,
|
|
533
|
+
})
|
|
534
|
+
}
|
|
535
|
+
PhysicalType::Array => {
|
|
536
|
+
let array_size = reader.read_required_field(103, |reader| reader.read_uleb_usize())?;
|
|
537
|
+
let expected = get_array_size(logical_type)? as usize;
|
|
538
|
+
if array_size != expected {
|
|
539
|
+
return Err(QuackError::protocol(format!(
|
|
540
|
+
"ARRAY vector serialized size {array_size}, expected {expected}"
|
|
541
|
+
)));
|
|
542
|
+
}
|
|
543
|
+
let child_type = get_child_type(logical_type)?;
|
|
544
|
+
let child_vector = reader.read_required_field(104, |reader| {
|
|
545
|
+
decode_vector(reader, child_type, array_size * count)
|
|
546
|
+
})?;
|
|
547
|
+
let values = (0..count)
|
|
548
|
+
.map(|row_index| {
|
|
549
|
+
if !is_valid(validity.as_deref(), row_index) {
|
|
550
|
+
return Value::Null;
|
|
551
|
+
}
|
|
552
|
+
let offset = row_index * array_size;
|
|
553
|
+
Value::List(child_vector.values[offset..offset + array_size].to_vec())
|
|
554
|
+
})
|
|
555
|
+
.collect();
|
|
556
|
+
Ok(DecodedVector {
|
|
557
|
+
logical_type: logical_type.clone(),
|
|
558
|
+
vector_type,
|
|
559
|
+
values,
|
|
560
|
+
})
|
|
561
|
+
}
|
|
562
|
+
other => Err(QuackError::unsupported(format!(
|
|
563
|
+
"variable-width physical type {other:?} is not supported"
|
|
564
|
+
))),
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
fn encode_flat_vector_body(
|
|
569
|
+
writer: &mut BinaryWriter,
|
|
570
|
+
logical_type: &LogicalType,
|
|
571
|
+
values: &[Value],
|
|
572
|
+
count: usize,
|
|
573
|
+
) -> Result<()> {
|
|
574
|
+
if values.len() != count {
|
|
575
|
+
return Err(QuackError::protocol(format!(
|
|
576
|
+
"vector value count {} does not match row count {count}",
|
|
577
|
+
values.len()
|
|
578
|
+
)));
|
|
579
|
+
}
|
|
580
|
+
if logical_type.id == LogicalTypeId::Geometry {
|
|
581
|
+
writer.write_field(99, |writer| writer.write_uleb(1u64))?;
|
|
582
|
+
}
|
|
583
|
+
let validity: Vec<bool> = values.iter().map(|value| !value.is_null()).collect();
|
|
584
|
+
let has_validity_mask = validity.iter().any(|valid| !valid);
|
|
585
|
+
writer.write_field(100, |writer| writer.write_bool(has_validity_mask))?;
|
|
586
|
+
if has_validity_mask {
|
|
587
|
+
writer.write_field(101, |writer| {
|
|
588
|
+
writer.write_blob(&write_validity_mask(&validity))
|
|
589
|
+
})?;
|
|
590
|
+
}
|
|
591
|
+
let physical_type = get_physical_type(logical_type)?;
|
|
592
|
+
if is_constant_size_physical_type(physical_type) {
|
|
593
|
+
let mut data = BinaryWriter::with_capacity(physical_type_size(physical_type)? * count);
|
|
594
|
+
for value in values {
|
|
595
|
+
encode_fixed_value(&mut data, logical_type, physical_type, value)?;
|
|
596
|
+
}
|
|
597
|
+
writer.write_field(102, |writer| writer.write_blob(data.as_slice()))?;
|
|
598
|
+
return Ok(());
|
|
599
|
+
}
|
|
600
|
+
match physical_type {
|
|
601
|
+
PhysicalType::Varchar => writer.write_field(102, |writer| {
|
|
602
|
+
writer.write_list(values, |writer, value, _| {
|
|
603
|
+
writer.write_string_bytes(&encode_string_like_value(logical_type, value))
|
|
604
|
+
})
|
|
605
|
+
}),
|
|
606
|
+
PhysicalType::Struct => encode_struct_vector_body(writer, logical_type, values, count),
|
|
607
|
+
PhysicalType::List => encode_list_vector_body(writer, logical_type, values),
|
|
608
|
+
PhysicalType::Array => encode_array_vector_body(writer, logical_type, values),
|
|
609
|
+
other => Err(QuackError::unsupported(format!(
|
|
610
|
+
"cannot encode physical type {other:?}"
|
|
611
|
+
))),
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/// Reads the payload of a string-like vector.
|
|
616
|
+
///
|
|
617
|
+
/// DuckDB has two layouts. From storage version 2.0, which the Quack server
|
|
618
|
+
/// uses on DuckDB 2.0, a vector carries the byte length of its string data
|
|
619
|
+
/// (field 107), a little-endian `u32` length for every row (108), and the bytes
|
|
620
|
+
/// of the valid rows back to back (109). Older servers send a list of strings
|
|
621
|
+
/// (102). Invalid rows are empty either way; the caller masks them.
|
|
622
|
+
fn read_string_vector_data(
|
|
623
|
+
reader: &mut BinaryReader<'_>,
|
|
624
|
+
count: usize,
|
|
625
|
+
validity: Option<&[bool]>,
|
|
626
|
+
) -> Result<Vec<Vec<u8>>> {
|
|
627
|
+
let byte_data_length = reader
|
|
628
|
+
.read_optional_field(107, |reader| reader.read_uleb_u64().map(Some), None)?
|
|
629
|
+
.filter(|length| *length != OPTIONAL_INDEX_INVALID);
|
|
630
|
+
let Some(byte_data_length) = byte_data_length else {
|
|
631
|
+
return reader.read_required_field(102, |reader| {
|
|
632
|
+
reader.read_list(|reader, _| reader.read_string_bytes())
|
|
633
|
+
});
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
let length_data = reader.read_required_field(108, |reader| reader.read_blob())?;
|
|
637
|
+
let byte_data = reader.read_required_field(109, |reader| reader.read_blob())?;
|
|
638
|
+
if length_data.len() != count * size_of::<u32>() {
|
|
639
|
+
return Err(QuackError::protocol(format!(
|
|
640
|
+
"string vector has {} bytes of lengths, expected {} for {count} rows",
|
|
641
|
+
length_data.len(),
|
|
642
|
+
count * size_of::<u32>()
|
|
643
|
+
)));
|
|
644
|
+
}
|
|
645
|
+
if byte_data.len() as u64 != byte_data_length {
|
|
646
|
+
return Err(QuackError::protocol(format!(
|
|
647
|
+
"string vector has {} bytes of data, header declares {byte_data_length}",
|
|
648
|
+
byte_data.len()
|
|
649
|
+
)));
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
let mut offset = 0;
|
|
653
|
+
let mut values = Vec::with_capacity(count);
|
|
654
|
+
for (index, length) in length_data.chunks_exact(size_of::<u32>()).enumerate() {
|
|
655
|
+
if !is_valid(validity, index) {
|
|
656
|
+
values.push(Vec::new());
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
let length = u32::from_le_bytes([length[0], length[1], length[2], length[3]]) as usize;
|
|
660
|
+
let value = byte_data.get(offset..offset + length).ok_or_else(|| {
|
|
661
|
+
QuackError::protocol(format!(
|
|
662
|
+
"string {index} of {length} bytes overruns the vector's {} bytes of data",
|
|
663
|
+
byte_data.len()
|
|
664
|
+
))
|
|
665
|
+
})?;
|
|
666
|
+
values.push(value.to_vec());
|
|
667
|
+
offset += length;
|
|
668
|
+
}
|
|
669
|
+
if offset != byte_data.len() {
|
|
670
|
+
return Err(QuackError::protocol(format!(
|
|
671
|
+
"string vector uses {offset} of its {} bytes of data",
|
|
672
|
+
byte_data.len()
|
|
673
|
+
)));
|
|
674
|
+
}
|
|
675
|
+
Ok(values)
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
fn decode_fixed_values(
|
|
679
|
+
logical_type: &LogicalType,
|
|
680
|
+
physical_type: PhysicalType,
|
|
681
|
+
bytes: &[u8],
|
|
682
|
+
count: usize,
|
|
683
|
+
validity: Option<&[bool]>,
|
|
684
|
+
) -> Result<Vec<Value>> {
|
|
685
|
+
let mut reader = BinaryReader::new(bytes);
|
|
686
|
+
let mut values = Vec::with_capacity(count);
|
|
687
|
+
for index in 0..count {
|
|
688
|
+
let value = decode_fixed_value(&mut reader, logical_type, physical_type)?;
|
|
689
|
+
values.push(if is_valid(validity, index) {
|
|
690
|
+
value
|
|
691
|
+
} else {
|
|
692
|
+
Value::Null
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
reader.assert_eof()?;
|
|
696
|
+
Ok(values)
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
fn decode_fixed_value(
|
|
700
|
+
reader: &mut BinaryReader<'_>,
|
|
701
|
+
logical_type: &LogicalType,
|
|
702
|
+
physical_type: PhysicalType,
|
|
703
|
+
) -> Result<Value> {
|
|
704
|
+
Ok(match physical_type {
|
|
705
|
+
PhysicalType::Bool => Value::Bool(reader.read_fixed_u8()? != 0),
|
|
706
|
+
PhysicalType::Int8 => Value::Int(reader.read_fixed_i8()? as i64),
|
|
707
|
+
PhysicalType::UInt8 => decode_enum_or_number(logical_type, reader.read_fixed_u8()? as u64)?,
|
|
708
|
+
PhysicalType::Int16 => {
|
|
709
|
+
let value = reader.read_fixed_i16()? as i128;
|
|
710
|
+
if logical_type.id == LogicalTypeId::Decimal {
|
|
711
|
+
Value::Decimal(decimal_from_unscaled(logical_type, value)?)
|
|
712
|
+
} else {
|
|
713
|
+
Value::Int(value as i64)
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
PhysicalType::UInt16 => {
|
|
717
|
+
decode_enum_or_number(logical_type, reader.read_fixed_u16()? as u64)?
|
|
718
|
+
}
|
|
719
|
+
PhysicalType::Int32 => {
|
|
720
|
+
let value = reader.read_fixed_i32()?;
|
|
721
|
+
if logical_type.id == LogicalTypeId::Date {
|
|
722
|
+
Value::Date(DateValue { days: value })
|
|
723
|
+
} else if logical_type.id == LogicalTypeId::Decimal {
|
|
724
|
+
Value::Decimal(decimal_from_unscaled(logical_type, value as i128)?)
|
|
725
|
+
} else {
|
|
726
|
+
Value::Int(value as i64)
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
PhysicalType::UInt32 => {
|
|
730
|
+
decode_enum_or_number(logical_type, reader.read_fixed_u32()? as u64)?
|
|
731
|
+
}
|
|
732
|
+
PhysicalType::Int64 => decode_int64_logical_value(logical_type, reader.read_fixed_i64()?)?,
|
|
733
|
+
PhysicalType::UInt64 => Value::UInt(reader.read_fixed_u64()?),
|
|
734
|
+
PhysicalType::Float => Value::Float(reader.read_fixed_f32()?),
|
|
735
|
+
PhysicalType::Double => Value::Double(reader.read_fixed_f64()?),
|
|
736
|
+
PhysicalType::Int128 => {
|
|
737
|
+
let lower = reader.read_fixed_u64()?;
|
|
738
|
+
let upper = reader.read_fixed_i64()?;
|
|
739
|
+
if logical_type.id == LogicalTypeId::Uuid {
|
|
740
|
+
Value::String(HugeIntParts { upper, lower }.to_string())
|
|
741
|
+
} else {
|
|
742
|
+
let value = combine_signed_huge_int(HugeIntParts { upper, lower });
|
|
743
|
+
if logical_type.id == LogicalTypeId::Decimal {
|
|
744
|
+
Value::Decimal(decimal_from_unscaled(logical_type, value)?)
|
|
745
|
+
} else {
|
|
746
|
+
Value::HugeInt(value)
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
PhysicalType::UInt128 => {
|
|
751
|
+
let lower = reader.read_fixed_u64()?;
|
|
752
|
+
let upper = reader.read_fixed_u64()? as i64;
|
|
753
|
+
Value::UHugeInt(combine_unsigned_huge_int(HugeIntParts { upper, lower }))
|
|
754
|
+
}
|
|
755
|
+
PhysicalType::Interval => Value::Interval(IntervalValue {
|
|
756
|
+
months: reader.read_fixed_i32()?,
|
|
757
|
+
days: reader.read_fixed_i32()?,
|
|
758
|
+
micros: reader.read_fixed_i64()?,
|
|
759
|
+
}),
|
|
760
|
+
other => {
|
|
761
|
+
return Err(QuackError::unsupported(format!(
|
|
762
|
+
"cannot decode fixed physical type {other:?}"
|
|
763
|
+
)));
|
|
764
|
+
}
|
|
765
|
+
})
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
fn encode_fixed_value(
|
|
769
|
+
writer: &mut BinaryWriter,
|
|
770
|
+
logical_type: &LogicalType,
|
|
771
|
+
physical_type: PhysicalType,
|
|
772
|
+
value: &Value,
|
|
773
|
+
) -> Result<()> {
|
|
774
|
+
if value.is_null() {
|
|
775
|
+
return writer.write_bytes(&vec![0; physical_type_size(physical_type)?]);
|
|
776
|
+
}
|
|
777
|
+
match physical_type {
|
|
778
|
+
PhysicalType::Bool => writer.write_fixed_u8(if matches!(value, Value::Bool(true)) {
|
|
779
|
+
1
|
|
780
|
+
} else {
|
|
781
|
+
0
|
|
782
|
+
}),
|
|
783
|
+
PhysicalType::Int8 => writer.write_fixed_i8(value_to_i128(value)? as i8),
|
|
784
|
+
PhysicalType::UInt8 => {
|
|
785
|
+
writer.write_fixed_u8(encode_enum_or_number(logical_type, value)? as u8)
|
|
786
|
+
}
|
|
787
|
+
PhysicalType::Int16 => {
|
|
788
|
+
writer.write_fixed_i16(encode_decimal_or_integer(logical_type, value)? as i16)
|
|
789
|
+
}
|
|
790
|
+
PhysicalType::UInt16 => {
|
|
791
|
+
writer.write_fixed_u16(encode_enum_or_number(logical_type, value)? as u16)
|
|
792
|
+
}
|
|
793
|
+
PhysicalType::Int32 => {
|
|
794
|
+
writer.write_fixed_i32(encode_date_decimal_or_integer(logical_type, value)? as i32)
|
|
795
|
+
}
|
|
796
|
+
PhysicalType::UInt32 => {
|
|
797
|
+
writer.write_fixed_u32(encode_enum_or_number(logical_type, value)? as u32)
|
|
798
|
+
}
|
|
799
|
+
PhysicalType::Int64 => {
|
|
800
|
+
writer.write_fixed_i64(encode_int64_logical_value(logical_type, value)?)
|
|
801
|
+
}
|
|
802
|
+
PhysicalType::UInt64 => writer.write_fixed_u64(value_to_u128(value)? as u64),
|
|
803
|
+
PhysicalType::Float => writer.write_fixed_f32(value_to_f64(value)? as f32),
|
|
804
|
+
PhysicalType::Double => writer.write_fixed_f64(value_to_f64(value)?),
|
|
805
|
+
PhysicalType::Int128 => {
|
|
806
|
+
let parts = if logical_type.id == LogicalTypeId::Uuid {
|
|
807
|
+
match value {
|
|
808
|
+
Value::String(uuid) => uuid_to_huge_int_parts(uuid)?,
|
|
809
|
+
_ => return Err(QuackError::protocol("UUID values must be strings")),
|
|
810
|
+
}
|
|
811
|
+
} else {
|
|
812
|
+
split_signed_huge_int(encode_int128_logical_value(logical_type, value)?)
|
|
813
|
+
};
|
|
814
|
+
writer.write_fixed_u64(parts.lower)?;
|
|
815
|
+
writer.write_fixed_i64(parts.upper)
|
|
816
|
+
}
|
|
817
|
+
PhysicalType::UInt128 => {
|
|
818
|
+
let value = value_to_u128(value)?;
|
|
819
|
+
writer.write_fixed_u64(value as u64)?;
|
|
820
|
+
writer.write_fixed_u64((value >> 64) as u64)
|
|
821
|
+
}
|
|
822
|
+
PhysicalType::Interval => {
|
|
823
|
+
let interval = match value {
|
|
824
|
+
Value::Interval(interval) => *interval,
|
|
825
|
+
_ => {
|
|
826
|
+
return Err(QuackError::protocol(
|
|
827
|
+
"INTERVAL values must be tagged intervals",
|
|
828
|
+
));
|
|
829
|
+
}
|
|
830
|
+
};
|
|
831
|
+
writer.write_fixed_i32(interval.months)?;
|
|
832
|
+
writer.write_fixed_i32(interval.days)?;
|
|
833
|
+
writer.write_fixed_i64(interval.micros)
|
|
834
|
+
}
|
|
835
|
+
other => Err(QuackError::unsupported(format!(
|
|
836
|
+
"cannot encode fixed physical type {other:?}"
|
|
837
|
+
))),
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
fn decode_string_like_value(logical_type: &LogicalType, raw: Vec<u8>) -> Result<Value> {
|
|
842
|
+
match logical_type.id {
|
|
843
|
+
LogicalTypeId::Blob
|
|
844
|
+
| LogicalTypeId::Geometry
|
|
845
|
+
| LogicalTypeId::Bit
|
|
846
|
+
| LogicalTypeId::BigNum => Ok(Value::Bytes(raw)),
|
|
847
|
+
_ => Ok(Value::String(String::from_utf8(raw)?)),
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
fn encode_string_like_value(logical_type: &LogicalType, value: &Value) -> Vec<u8> {
|
|
852
|
+
if value.is_null() {
|
|
853
|
+
return Vec::new();
|
|
854
|
+
}
|
|
855
|
+
match (logical_type.id, value) {
|
|
856
|
+
(
|
|
857
|
+
LogicalTypeId::Blob | LogicalTypeId::Geometry | LogicalTypeId::Bit,
|
|
858
|
+
Value::Bytes(bytes),
|
|
859
|
+
) => bytes.clone(),
|
|
860
|
+
(_, Value::String(value)) => value.as_bytes().to_vec(),
|
|
861
|
+
(_, Value::Bytes(bytes)) => bytes.clone(),
|
|
862
|
+
_ => value_to_string_lossy(value).into_bytes(),
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
fn encode_struct_vector_body(
|
|
867
|
+
writer: &mut BinaryWriter,
|
|
868
|
+
logical_type: &LogicalType,
|
|
869
|
+
values: &[Value],
|
|
870
|
+
count: usize,
|
|
871
|
+
) -> Result<()> {
|
|
872
|
+
let children = get_struct_children(logical_type)?;
|
|
873
|
+
writer.write_field(103, |writer| {
|
|
874
|
+
writer.write_list(children, |writer, child, index| {
|
|
875
|
+
let key = struct_child_key(logical_type, index, child);
|
|
876
|
+
let child_values = values
|
|
877
|
+
.iter()
|
|
878
|
+
.map(|value| match value {
|
|
879
|
+
Value::Struct(row) => row.get(&key).cloned().unwrap_or(Value::Null),
|
|
880
|
+
_ => Value::Null,
|
|
881
|
+
})
|
|
882
|
+
.collect::<Vec<_>>();
|
|
883
|
+
encode_vector(writer, &child.logical_type, &child_values, count)
|
|
884
|
+
})
|
|
885
|
+
})
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
fn encode_list_vector_body(
|
|
889
|
+
writer: &mut BinaryWriter,
|
|
890
|
+
logical_type: &LogicalType,
|
|
891
|
+
values: &[Value],
|
|
892
|
+
) -> Result<()> {
|
|
893
|
+
let child_type = get_child_type(logical_type)?;
|
|
894
|
+
let mut entries = Vec::with_capacity(values.len());
|
|
895
|
+
let mut child_values = Vec::new();
|
|
896
|
+
for value in values {
|
|
897
|
+
match value {
|
|
898
|
+
Value::Null => entries.push(ListEntry {
|
|
899
|
+
offset: 0,
|
|
900
|
+
length: 0,
|
|
901
|
+
}),
|
|
902
|
+
Value::List(items) => {
|
|
903
|
+
let offset = child_values.len();
|
|
904
|
+
child_values.extend(items.iter().cloned());
|
|
905
|
+
entries.push(ListEntry {
|
|
906
|
+
offset,
|
|
907
|
+
length: items.len(),
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
_ => return Err(QuackError::protocol("LIST/MAP values must be lists")),
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
writer.write_field(104, |writer| writer.write_uleb(child_values.len() as u64))?;
|
|
914
|
+
writer.write_field(105, |writer| write_list_entries(writer, &entries))?;
|
|
915
|
+
writer.write_field(106, |writer| {
|
|
916
|
+
encode_vector(writer, child_type, &child_values, child_values.len())
|
|
917
|
+
})
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
fn encode_array_vector_body(
|
|
921
|
+
writer: &mut BinaryWriter,
|
|
922
|
+
logical_type: &LogicalType,
|
|
923
|
+
values: &[Value],
|
|
924
|
+
) -> Result<()> {
|
|
925
|
+
let child_type = get_child_type(logical_type)?;
|
|
926
|
+
let array_size = get_array_size(logical_type)? as usize;
|
|
927
|
+
let mut child_values = Vec::with_capacity(values.len() * array_size);
|
|
928
|
+
for value in values {
|
|
929
|
+
match value {
|
|
930
|
+
Value::Null => child_values.extend(std::iter::repeat_n(Value::Null, array_size)),
|
|
931
|
+
Value::List(items) if items.len() == array_size => {
|
|
932
|
+
child_values.extend(items.iter().cloned());
|
|
933
|
+
}
|
|
934
|
+
Value::List(_) => {
|
|
935
|
+
return Err(QuackError::protocol(format!(
|
|
936
|
+
"ARRAY values must be lists of length {array_size}"
|
|
937
|
+
)));
|
|
938
|
+
}
|
|
939
|
+
_ => return Err(QuackError::protocol("ARRAY values must be lists")),
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
writer.write_field(103, |writer| writer.write_uleb(array_size as u64))?;
|
|
943
|
+
writer.write_field(104, |writer| {
|
|
944
|
+
encode_vector(writer, child_type, &child_values, child_values.len())
|
|
945
|
+
})
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
fn read_selection_vector(reader: &mut BinaryReader<'_>, count: usize) -> Result<Vec<usize>> {
|
|
949
|
+
let expected_bytes = count * 4;
|
|
950
|
+
let bytes = reader.read_blob()?;
|
|
951
|
+
if bytes.len() != expected_bytes {
|
|
952
|
+
return Err(QuackError::protocol(format!(
|
|
953
|
+
"selection vector has {} bytes, expected {expected_bytes}",
|
|
954
|
+
bytes.len()
|
|
955
|
+
)));
|
|
956
|
+
}
|
|
957
|
+
Ok(bytes
|
|
958
|
+
.chunks_exact(4)
|
|
959
|
+
.map(|chunk| u32::from_le_bytes(chunk.try_into().expect("chunk size")) as usize)
|
|
960
|
+
.collect())
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
fn read_validity_mask(reader: &mut BinaryReader<'_>, count: usize) -> Result<Vec<bool>> {
|
|
964
|
+
let expected_bytes = validity_mask_size(count);
|
|
965
|
+
let bytes = reader.read_blob()?;
|
|
966
|
+
if bytes.len() != expected_bytes {
|
|
967
|
+
return Err(QuackError::protocol(format!(
|
|
968
|
+
"validity mask has {} bytes, expected {expected_bytes}",
|
|
969
|
+
bytes.len()
|
|
970
|
+
)));
|
|
971
|
+
}
|
|
972
|
+
Ok((0..count)
|
|
973
|
+
.map(|index| {
|
|
974
|
+
let byte = bytes.get(index / 8).copied().unwrap_or(0);
|
|
975
|
+
(byte & (1 << (index % 8))) != 0
|
|
976
|
+
})
|
|
977
|
+
.collect())
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
fn write_validity_mask(validity: &[bool]) -> Vec<u8> {
|
|
981
|
+
let mut bytes = vec![0u8; validity_mask_size(validity.len())];
|
|
982
|
+
for (index, valid) in validity.iter().enumerate() {
|
|
983
|
+
if *valid {
|
|
984
|
+
bytes[index / 8] |= 1 << (index % 8);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
bytes
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
fn validity_mask_size(count: usize) -> usize {
|
|
991
|
+
count.div_ceil(64) * 8
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
fn is_valid(validity: Option<&[bool]>, index: usize) -> bool {
|
|
995
|
+
validity.map(|values| values[index]).unwrap_or(true)
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
fn read_list_entries(reader: &mut BinaryReader<'_>, count: usize) -> Result<Vec<ListEntry>> {
|
|
999
|
+
let entries = reader.read_list(|reader, _| {
|
|
1000
|
+
reader.read_object(|object| {
|
|
1001
|
+
Ok(ListEntry {
|
|
1002
|
+
offset: object.read_required_field(100, |object| object.read_uleb_usize())?,
|
|
1003
|
+
length: object.read_required_field(101, |object| object.read_uleb_usize())?,
|
|
1004
|
+
})
|
|
1005
|
+
})
|
|
1006
|
+
})?;
|
|
1007
|
+
if entries.len() != count {
|
|
1008
|
+
return Err(QuackError::protocol(format!(
|
|
1009
|
+
"LIST vector serialized {} entries for {count} rows",
|
|
1010
|
+
entries.len()
|
|
1011
|
+
)));
|
|
1012
|
+
}
|
|
1013
|
+
Ok(entries)
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
fn write_list_entries(writer: &mut BinaryWriter, entries: &[ListEntry]) -> Result<()> {
|
|
1017
|
+
writer.write_list(entries, |writer, entry, _| {
|
|
1018
|
+
writer.write_object(|object| {
|
|
1019
|
+
object.write_field(100, |object| object.write_uleb(entry.offset as u64))?;
|
|
1020
|
+
object.write_field(101, |object| object.write_uleb(entry.length as u64))?;
|
|
1021
|
+
Ok(())
|
|
1022
|
+
})
|
|
1023
|
+
})
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
fn decode_enum_or_number(logical_type: &LogicalType, index: u64) -> Result<Value> {
|
|
1027
|
+
if logical_type.id != LogicalTypeId::Enum {
|
|
1028
|
+
return Ok(Value::UInt(index));
|
|
1029
|
+
}
|
|
1030
|
+
let value = get_enum_values(logical_type)?
|
|
1031
|
+
.get(index as usize)
|
|
1032
|
+
.ok_or_else(|| QuackError::protocol(format!("ENUM index {index} is out of range")))?;
|
|
1033
|
+
Ok(Value::String(value.clone()))
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
fn encode_enum_or_number(logical_type: &LogicalType, value: &Value) -> Result<u64> {
|
|
1037
|
+
if logical_type.id != LogicalTypeId::Enum {
|
|
1038
|
+
return value_to_u128(value).map(|value| value as u64);
|
|
1039
|
+
}
|
|
1040
|
+
match value {
|
|
1041
|
+
Value::UInt(value) => Ok(*value),
|
|
1042
|
+
Value::Int(value) if *value >= 0 => Ok(*value as u64),
|
|
1043
|
+
Value::String(value) => get_enum_values(logical_type)?
|
|
1044
|
+
.iter()
|
|
1045
|
+
.position(|candidate| candidate == value)
|
|
1046
|
+
.map(|index| index as u64)
|
|
1047
|
+
.ok_or_else(|| QuackError::protocol(format!("unknown ENUM value {value}"))),
|
|
1048
|
+
_ => Err(QuackError::protocol(
|
|
1049
|
+
"ENUM values must be strings or integers",
|
|
1050
|
+
)),
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
fn decode_int64_logical_value(logical_type: &LogicalType, value: i64) -> Result<Value> {
|
|
1055
|
+
Ok(match logical_type.id {
|
|
1056
|
+
LogicalTypeId::Time => Value::Time(TimeValue {
|
|
1057
|
+
unit: TimeUnit::Micros,
|
|
1058
|
+
value,
|
|
1059
|
+
}),
|
|
1060
|
+
LogicalTypeId::TimeNs => Value::Time(TimeValue {
|
|
1061
|
+
unit: TimeUnit::Nanos,
|
|
1062
|
+
value,
|
|
1063
|
+
}),
|
|
1064
|
+
LogicalTypeId::TimeTz => Value::TimeTz(TimeTzValue { bits: value }),
|
|
1065
|
+
LogicalTypeId::TimestampSec => Value::Timestamp(TimestampValue {
|
|
1066
|
+
unit: TimestampUnit::Seconds,
|
|
1067
|
+
value,
|
|
1068
|
+
timezone_utc: false,
|
|
1069
|
+
}),
|
|
1070
|
+
LogicalTypeId::TimestampMs => Value::Timestamp(TimestampValue {
|
|
1071
|
+
unit: TimestampUnit::Millis,
|
|
1072
|
+
value,
|
|
1073
|
+
timezone_utc: false,
|
|
1074
|
+
}),
|
|
1075
|
+
LogicalTypeId::Timestamp => Value::Timestamp(TimestampValue {
|
|
1076
|
+
unit: TimestampUnit::Micros,
|
|
1077
|
+
value,
|
|
1078
|
+
timezone_utc: false,
|
|
1079
|
+
}),
|
|
1080
|
+
LogicalTypeId::TimestampNs => Value::Timestamp(TimestampValue {
|
|
1081
|
+
unit: TimestampUnit::Nanos,
|
|
1082
|
+
value,
|
|
1083
|
+
timezone_utc: false,
|
|
1084
|
+
}),
|
|
1085
|
+
LogicalTypeId::TimestampTz => Value::Timestamp(TimestampValue {
|
|
1086
|
+
unit: TimestampUnit::Micros,
|
|
1087
|
+
value,
|
|
1088
|
+
timezone_utc: true,
|
|
1089
|
+
}),
|
|
1090
|
+
LogicalTypeId::TimestampTzNs => Value::Timestamp(TimestampValue {
|
|
1091
|
+
unit: TimestampUnit::Nanos,
|
|
1092
|
+
value,
|
|
1093
|
+
timezone_utc: true,
|
|
1094
|
+
}),
|
|
1095
|
+
LogicalTypeId::Decimal => {
|
|
1096
|
+
Value::Decimal(decimal_from_unscaled(logical_type, value as i128)?)
|
|
1097
|
+
}
|
|
1098
|
+
_ => Value::Int(value),
|
|
1099
|
+
})
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
fn encode_int64_logical_value(logical_type: &LogicalType, value: &Value) -> Result<i64> {
|
|
1103
|
+
if logical_type.id == LogicalTypeId::Decimal {
|
|
1104
|
+
return Ok(decimal_to_unscaled(logical_type, value)? as i64);
|
|
1105
|
+
}
|
|
1106
|
+
match value {
|
|
1107
|
+
Value::Time(value) => Ok(value.value),
|
|
1108
|
+
Value::TimeTz(value) => Ok(value.bits),
|
|
1109
|
+
Value::Timestamp(value) => Ok(value.value),
|
|
1110
|
+
_ => Ok(value_to_i128(value)? as i64),
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
fn encode_int128_logical_value(logical_type: &LogicalType, value: &Value) -> Result<i128> {
|
|
1115
|
+
if logical_type.id == LogicalTypeId::Decimal {
|
|
1116
|
+
decimal_to_unscaled(logical_type, value)
|
|
1117
|
+
} else {
|
|
1118
|
+
value_to_i128(value)
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
fn encode_decimal_or_integer(logical_type: &LogicalType, value: &Value) -> Result<i128> {
|
|
1123
|
+
if logical_type.id == LogicalTypeId::Decimal {
|
|
1124
|
+
decimal_to_unscaled(logical_type, value)
|
|
1125
|
+
} else {
|
|
1126
|
+
value_to_i128(value)
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
fn encode_date_decimal_or_integer(logical_type: &LogicalType, value: &Value) -> Result<i128> {
|
|
1131
|
+
if logical_type.id == LogicalTypeId::Date {
|
|
1132
|
+
return match value {
|
|
1133
|
+
Value::Date(value) => Ok(value.days as i128),
|
|
1134
|
+
_ => value_to_i128(value),
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
encode_decimal_or_integer(logical_type, value)
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
fn decimal_from_unscaled(logical_type: &LogicalType, value: i128) -> Result<DecimalValue> {
|
|
1141
|
+
match logical_type.type_info.as_ref() {
|
|
1142
|
+
Some(ExtraTypeInfo::Decimal { width, scale, .. }) => Ok(DecimalValue {
|
|
1143
|
+
value,
|
|
1144
|
+
width: *width,
|
|
1145
|
+
scale: *scale,
|
|
1146
|
+
}),
|
|
1147
|
+
_ => Err(QuackError::protocol(
|
|
1148
|
+
"DECIMAL value is missing DecimalTypeInfo",
|
|
1149
|
+
)),
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
pub(crate) fn decimal_to_unscaled(logical_type: &LogicalType, value: &Value) -> Result<i128> {
|
|
1154
|
+
match value {
|
|
1155
|
+
Value::Decimal(value) => Ok(value.value),
|
|
1156
|
+
Value::String(value) => parse_decimal_string(logical_type, value),
|
|
1157
|
+
_ => value_to_i128(value),
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
fn parse_decimal_string(logical_type: &LogicalType, value: &str) -> Result<i128> {
|
|
1162
|
+
let scale = match logical_type.type_info.as_ref() {
|
|
1163
|
+
Some(ExtraTypeInfo::Decimal { scale, .. }) => *scale as usize,
|
|
1164
|
+
_ => {
|
|
1165
|
+
return Err(QuackError::protocol(
|
|
1166
|
+
"DECIMAL value is missing DecimalTypeInfo",
|
|
1167
|
+
));
|
|
1168
|
+
}
|
|
1169
|
+
};
|
|
1170
|
+
let trimmed = value.trim();
|
|
1171
|
+
let negative = trimmed.starts_with('-');
|
|
1172
|
+
let unsigned = trimmed.strip_prefix(['-', '+']).unwrap_or(trimmed);
|
|
1173
|
+
let (integer, fraction) = unsigned.split_once('.').unwrap_or((unsigned, ""));
|
|
1174
|
+
let mut padded_fraction = fraction.to_string();
|
|
1175
|
+
while padded_fraction.len() < scale {
|
|
1176
|
+
padded_fraction.push('0');
|
|
1177
|
+
}
|
|
1178
|
+
padded_fraction.truncate(scale);
|
|
1179
|
+
let text = format!(
|
|
1180
|
+
"{}{}",
|
|
1181
|
+
if integer.is_empty() { "0" } else { integer },
|
|
1182
|
+
padded_fraction
|
|
1183
|
+
);
|
|
1184
|
+
let unscaled = text
|
|
1185
|
+
.parse::<i128>()
|
|
1186
|
+
.map_err(|_| QuackError::protocol(format!("invalid decimal value {value}")))?;
|
|
1187
|
+
Ok(if negative { -unscaled } else { unscaled })
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
fn value_to_i128(value: &Value) -> Result<i128> {
|
|
1191
|
+
match value {
|
|
1192
|
+
Value::Bool(value) => Ok(i128::from(*value)),
|
|
1193
|
+
Value::Int(value) => Ok(*value as i128),
|
|
1194
|
+
Value::UInt(value) => Ok(*value as i128),
|
|
1195
|
+
Value::HugeInt(value) => Ok(*value),
|
|
1196
|
+
Value::UHugeInt(value) => i128::try_from(*value)
|
|
1197
|
+
.map_err(|_| QuackError::protocol("unsigned integer does not fit i128")),
|
|
1198
|
+
Value::String(value) => value
|
|
1199
|
+
.parse::<i128>()
|
|
1200
|
+
.map_err(|_| QuackError::protocol(format!("cannot convert {value} to integer"))),
|
|
1201
|
+
_ => Err(QuackError::protocol(format!(
|
|
1202
|
+
"cannot convert {value:?} to integer"
|
|
1203
|
+
))),
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
fn value_to_u128(value: &Value) -> Result<u128> {
|
|
1208
|
+
match value {
|
|
1209
|
+
Value::Bool(value) => Ok(u128::from(*value)),
|
|
1210
|
+
Value::Int(value) if *value >= 0 => Ok(*value as u128),
|
|
1211
|
+
Value::UInt(value) => Ok(*value as u128),
|
|
1212
|
+
Value::HugeInt(value) if *value >= 0 => Ok(*value as u128),
|
|
1213
|
+
Value::UHugeInt(value) => Ok(*value),
|
|
1214
|
+
Value::String(value) => value.parse::<u128>().map_err(|_| {
|
|
1215
|
+
QuackError::protocol(format!("cannot convert {value} to unsigned integer"))
|
|
1216
|
+
}),
|
|
1217
|
+
_ => Err(QuackError::protocol(format!(
|
|
1218
|
+
"cannot convert {value:?} to unsigned integer"
|
|
1219
|
+
))),
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
fn value_to_f64(value: &Value) -> Result<f64> {
|
|
1224
|
+
match value {
|
|
1225
|
+
Value::Float(value) => Ok(*value as f64),
|
|
1226
|
+
Value::Double(value) => Ok(*value),
|
|
1227
|
+
Value::Int(value) => Ok(*value as f64),
|
|
1228
|
+
Value::UInt(value) => Ok(*value as f64),
|
|
1229
|
+
Value::String(value) => value
|
|
1230
|
+
.parse::<f64>()
|
|
1231
|
+
.map_err(|_| QuackError::protocol(format!("cannot convert {value} to float"))),
|
|
1232
|
+
_ => Err(QuackError::protocol(format!(
|
|
1233
|
+
"cannot convert {value:?} to float"
|
|
1234
|
+
))),
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
fn decode_sequence_value(logical_type: &LogicalType, value: i128) -> Result<Value> {
|
|
1239
|
+
match logical_type.id {
|
|
1240
|
+
LogicalTypeId::Integer => Ok(Value::Int(value as i64)),
|
|
1241
|
+
LogicalTypeId::Date => Ok(Value::Date(DateValue { days: value as i32 })),
|
|
1242
|
+
LogicalTypeId::BigInt => Ok(Value::Int(value as i64)),
|
|
1243
|
+
_ => decode_int64_logical_value(logical_type, value as i64),
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
fn uuid_to_huge_int_parts(uuid: &str) -> Result<HugeIntParts> {
|
|
1248
|
+
let hex = uuid.replace('-', "").to_ascii_lowercase();
|
|
1249
|
+
if hex.len() != 32 || !hex.bytes().all(|byte| byte.is_ascii_hexdigit()) {
|
|
1250
|
+
return Err(QuackError::protocol(format!("invalid UUID string {uuid}")));
|
|
1251
|
+
}
|
|
1252
|
+
let display_upper = u64::from_str_radix(&hex[0..16], 16)
|
|
1253
|
+
.map_err(|_| QuackError::protocol(format!("invalid UUID string {uuid}")))?;
|
|
1254
|
+
let lower = u64::from_str_radix(&hex[16..32], 16)
|
|
1255
|
+
.map_err(|_| QuackError::protocol(format!("invalid UUID string {uuid}")))?;
|
|
1256
|
+
let upper = (display_upper ^ (1u64 << 63)) as i64;
|
|
1257
|
+
Ok(HugeIntParts { upper, lower })
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
fn value_to_string_lossy(value: &Value) -> String {
|
|
1261
|
+
match value {
|
|
1262
|
+
Value::Null => String::new(),
|
|
1263
|
+
Value::Bool(value) => value.to_string(),
|
|
1264
|
+
Value::Int(value) => value.to_string(),
|
|
1265
|
+
Value::UInt(value) => value.to_string(),
|
|
1266
|
+
Value::HugeInt(value) => value.to_string(),
|
|
1267
|
+
Value::UHugeInt(value) => value.to_string(),
|
|
1268
|
+
Value::Float(value) => value.to_string(),
|
|
1269
|
+
Value::Double(value) => value.to_string(),
|
|
1270
|
+
Value::String(value) => value.clone(),
|
|
1271
|
+
Value::Bytes(value) => String::from_utf8_lossy(value).into_owned(),
|
|
1272
|
+
Value::Decimal(value) => decimal_to_string(value),
|
|
1273
|
+
Value::Date(value) => value.days.to_string(),
|
|
1274
|
+
Value::Time(value) => value.value.to_string(),
|
|
1275
|
+
Value::TimeTz(value) => value.bits.to_string(),
|
|
1276
|
+
Value::Timestamp(value) => value.value.to_string(),
|
|
1277
|
+
Value::Interval(value) => format!("{} {} {}", value.months, value.days, value.micros),
|
|
1278
|
+
Value::List(_) | Value::Struct(_) => String::new(),
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
#[cfg(test)]
|
|
1283
|
+
mod tests {
|
|
1284
|
+
use super::*;
|
|
1285
|
+
use crate::logical_types::LogicalTypes;
|
|
1286
|
+
|
|
1287
|
+
/// A flat string vector in DuckDB's storage version 2.0 layout.
|
|
1288
|
+
fn v2_string_vector(values: &[Option<&[u8]>], byte_data_length: Option<u64>) -> Vec<u8> {
|
|
1289
|
+
let validity: Vec<bool> = values.iter().map(Option::is_some).collect();
|
|
1290
|
+
let lengths: Vec<u8> = values
|
|
1291
|
+
.iter()
|
|
1292
|
+
.flat_map(|value| (value.map_or(0, <[u8]>::len) as u32).to_le_bytes())
|
|
1293
|
+
.collect();
|
|
1294
|
+
let bytes: Vec<u8> = values.iter().flatten().flat_map(|v| v.to_vec()).collect();
|
|
1295
|
+
let mut writer = BinaryWriter::new();
|
|
1296
|
+
writer
|
|
1297
|
+
.write_object(|object| {
|
|
1298
|
+
let has_validity_mask = validity.iter().any(|valid| !valid);
|
|
1299
|
+
object.write_field(100, |object| object.write_bool(has_validity_mask))?;
|
|
1300
|
+
if has_validity_mask {
|
|
1301
|
+
object.write_field(101, |object| {
|
|
1302
|
+
object.write_blob(&write_validity_mask(&validity))
|
|
1303
|
+
})?;
|
|
1304
|
+
}
|
|
1305
|
+
object.write_field(107, |object| {
|
|
1306
|
+
object.write_uleb(byte_data_length.unwrap_or(bytes.len() as u64))
|
|
1307
|
+
})?;
|
|
1308
|
+
object.write_field(108, |object| object.write_blob(&lengths))?;
|
|
1309
|
+
object.write_field(109, |object| object.write_blob(&bytes))
|
|
1310
|
+
})
|
|
1311
|
+
.unwrap();
|
|
1312
|
+
writer.into_bytes()
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
fn decode(bytes: &[u8], logical_type: &LogicalType, count: usize) -> Result<Vec<Value>> {
|
|
1316
|
+
let mut reader = BinaryReader::new(bytes);
|
|
1317
|
+
let vector = decode_vector(&mut reader, logical_type, count)?;
|
|
1318
|
+
reader.assert_eof()?;
|
|
1319
|
+
Ok(vector.values)
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
#[test]
|
|
1323
|
+
fn decodes_v2_string_vector_with_nulls_and_empty_strings() {
|
|
1324
|
+
let bytes = v2_string_vector(&[Some(b"ab"), None, Some(b""), Some(b"cde")], None);
|
|
1325
|
+
assert_eq!(
|
|
1326
|
+
decode(&bytes, &LogicalTypes::varchar(), 4).unwrap(),
|
|
1327
|
+
vec![
|
|
1328
|
+
Value::String("ab".into()),
|
|
1329
|
+
Value::Null,
|
|
1330
|
+
Value::String(String::new()),
|
|
1331
|
+
Value::String("cde".into()),
|
|
1332
|
+
]
|
|
1333
|
+
);
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
#[test]
|
|
1337
|
+
fn decodes_v2_blob_vector_as_bytes() {
|
|
1338
|
+
let bytes = v2_string_vector(&[Some(&[0, 159, 146, 150])], None);
|
|
1339
|
+
assert_eq!(
|
|
1340
|
+
decode(&bytes, &LogicalTypes::blob(), 1).unwrap(),
|
|
1341
|
+
vec![Value::Bytes(vec![0, 159, 146, 150])]
|
|
1342
|
+
);
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
#[test]
|
|
1346
|
+
fn still_decodes_list_string_vector() {
|
|
1347
|
+
let values = vec![Value::String("x".into()), Value::Null];
|
|
1348
|
+
let mut writer = BinaryWriter::new();
|
|
1349
|
+
encode_vector(&mut writer, &LogicalTypes::varchar(), &values, 2).unwrap();
|
|
1350
|
+
assert_eq!(
|
|
1351
|
+
decode(&writer.into_bytes(), &LogicalTypes::varchar(), 2).unwrap(),
|
|
1352
|
+
values
|
|
1353
|
+
);
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
#[test]
|
|
1357
|
+
fn rejects_v2_string_vector_whose_lengths_disagree_with_its_data() {
|
|
1358
|
+
let bytes = v2_string_vector(&[Some(b"ab")], Some(3));
|
|
1359
|
+
assert!(decode(&bytes, &LogicalTypes::varchar(), 1).is_err());
|
|
1360
|
+
// Two rows declared, one row of lengths sent.
|
|
1361
|
+
let bytes = v2_string_vector(&[Some(b"ab")], None);
|
|
1362
|
+
assert!(decode(&bytes, &LogicalTypes::varchar(), 2).is_err());
|
|
1363
|
+
}
|
|
1364
|
+
}
|