1use std::io::{Cursor, Read};
16
17use anyhow::Context;
18use byteorder::{BigEndian, ReadBytesExt};
19use risingwave_pb::data::PbArrayType;
20
21use super::*;
22
23impl ArrayImpl {
24 pub fn from_protobuf(array: &PbArray, cardinality: usize) -> ArrayResult<Self> {
25 let array = match array.array_type() {
26 PbArrayType::Unspecified => unreachable!(),
27 PbArrayType::Int16 => read_primitive_array::<i16>(array, cardinality)?,
28 PbArrayType::Int32 => read_primitive_array::<i32>(array, cardinality)?,
29 PbArrayType::Int64 => read_primitive_array::<i64>(array, cardinality)?,
30 PbArrayType::Serial => read_primitive_array::<Serial>(array, cardinality)?,
31 PbArrayType::Float32 => read_primitive_array::<F32>(array, cardinality)?,
32 PbArrayType::Float64 => read_primitive_array::<F64>(array, cardinality)?,
33 PbArrayType::Bool => read_bool_array(array, cardinality)?,
34 PbArrayType::Utf8 => read_var_sized_array::<Utf8ValueReader>(array, cardinality)?,
35 PbArrayType::Decimal => read_primitive_array::<Decimal>(array, cardinality)?,
36 PbArrayType::Date => read_primitive_array::<Date>(array, cardinality)?,
37 PbArrayType::Time => read_primitive_array::<Time>(array, cardinality)?,
38 PbArrayType::Timestamp => read_primitive_array::<Timestamp>(array, cardinality)?,
39 PbArrayType::Timestamptz => read_primitive_array::<Timestamptz>(array, cardinality)?,
40 PbArrayType::Interval => read_primitive_array::<Interval>(array, cardinality)?,
41 PbArrayType::Jsonb => JsonbArray::from_protobuf(array)?,
42 PbArrayType::Variant => read_var_sized_array::<VariantValueReader>(array, cardinality)?,
43 PbArrayType::Struct => StructArray::from_protobuf(array)?,
44 PbArrayType::List => ListArray::from_protobuf(array)?,
45 PbArrayType::Bytea => read_var_sized_array::<BytesValueReader>(array, cardinality)?,
46 PbArrayType::Int256 => Int256Array::from_protobuf(array, cardinality)?,
47 PbArrayType::Map => MapArray::from_protobuf(array)?,
48 PbArrayType::Vector => VectorArray::from_protobuf(array)?,
49 };
50 Ok(array)
51 }
52}
53
54fn read_primitive_array<T: PrimitiveArrayItemType>(
58 array: &PbArray,
59 cardinality: usize,
60) -> ArrayResult<ArrayImpl> {
61 ensure!(
62 array.get_values().len() == 1,
63 "Must have only 1 buffer in a numeric array"
64 );
65
66 let buf = array.get_values()[0].get_body().as_slice();
67
68 let mut builder = PrimitiveArrayBuilder::<T>::new(cardinality);
69 let bitmap: Bitmap = array.get_null_bitmap()?.into();
70 let mut cursor = Cursor::new(buf);
71 for not_null in bitmap.iter() {
72 if not_null {
73 let v = T::from_protobuf(&mut cursor)?;
74 builder.append(Some(v));
75 } else {
76 builder.append(None);
77 }
78 }
79 let arr = builder.finish();
80 ensure_eq!(arr.len(), cardinality);
81
82 Ok(arr.into())
83}
84
85fn read_bool_array(array: &PbArray, cardinality: usize) -> ArrayResult<ArrayImpl> {
86 ensure!(
87 array.get_values().len() == 1,
88 "Must have only 1 buffer in a bool array"
89 );
90
91 let data = (&array.get_values()[0]).into();
92 let bitmap: Bitmap = array.get_null_bitmap()?.into();
93
94 let arr = BoolArray::new(data, bitmap);
95 ensure_eq!(arr.len(), cardinality);
96
97 Ok(arr.into())
98}
99
100fn read_offset(offset_cursor: &mut Cursor<&[u8]>) -> ArrayResult<i64> {
101 let offset = offset_cursor
102 .read_i64::<BigEndian>()
103 .context("failed to read i64 from offset buffer")?;
104 ensure!(
107 offset >= 0,
108 "invalid offset buffer: offsets must not be negative"
109 );
110
111 Ok(offset)
112}
113
114trait VarSizedValueReader {
115 type AB: ArrayBuilder;
116 fn new_builder(capacity: usize) -> Self::AB;
117 fn read(buf: &[u8], builder: &mut Self::AB) -> ArrayResult<()>;
118}
119
120struct Utf8ValueReader;
121
122impl VarSizedValueReader for Utf8ValueReader {
123 type AB = Utf8ArrayBuilder;
124
125 fn new_builder(capacity: usize) -> Self::AB {
126 Utf8ArrayBuilder::new(capacity)
127 }
128
129 fn read(buf: &[u8], builder: &mut Utf8ArrayBuilder) -> ArrayResult<()> {
130 let s = std::str::from_utf8(buf).context("failed to read utf8 string from bytes")?;
131 builder.append(Some(s));
132 Ok(())
133 }
134}
135
136struct BytesValueReader;
137
138impl VarSizedValueReader for BytesValueReader {
139 type AB = BytesArrayBuilder;
140
141 fn new_builder(capacity: usize) -> Self::AB {
142 BytesArrayBuilder::new(capacity)
143 }
144
145 fn read(buf: &[u8], builder: &mut BytesArrayBuilder) -> ArrayResult<()> {
146 builder.append(Some(buf));
147 Ok(())
148 }
149}
150
151struct VariantValueReader;
152
153impl VarSizedValueReader for VariantValueReader {
154 type AB = VariantArrayBuilder;
155
156 fn new_builder(capacity: usize) -> Self::AB {
157 VariantArrayBuilder::new(capacity)
158 }
159
160 fn read(buf: &[u8], builder: &mut VariantArrayBuilder) -> ArrayResult<()> {
161 let variant =
162 VariantRef::from_serialized(buf).context("failed to read variant from bytes")?;
163 builder.append(Some(variant));
164 Ok(())
165 }
166}
167
168fn read_var_sized_array<R: VarSizedValueReader>(
169 array: &PbArray,
170 cardinality: usize,
171) -> ArrayResult<ArrayImpl> {
172 ensure!(
173 array.get_values().len() == 2,
174 "Must have exactly 2 buffers in a variable-sized array"
175 );
176 let offset_buff = array.get_values()[0].get_body().as_slice();
177 let data_buf = array.get_values()[1].get_body().as_slice();
178
179 let mut builder = R::new_builder(cardinality);
180 let bitmap: Bitmap = array.get_null_bitmap()?.into();
181 let mut offset_cursor = Cursor::new(offset_buff);
182 let mut data_cursor = Cursor::new(data_buf);
183 let mut prev_offset: i64 = -1;
184
185 let mut buf = Vec::new();
186 for not_null in bitmap.iter() {
187 if not_null {
188 if prev_offset < 0 {
189 prev_offset = read_offset(&mut offset_cursor)?;
190 }
191 let offset = read_offset(&mut offset_cursor)?;
192 let length = offset
194 .checked_sub(prev_offset)
195 .and_then(|length| usize::try_from(length).ok())
196 .context("invalid offset buffer: offsets must be non-decreasing")?;
197 prev_offset = offset;
198 buf.resize(length, Default::default());
199 data_cursor
200 .read_exact(buf.as_mut_slice())
201 .with_context(|| {
202 format!(
203 "failed to read value from data buffer [length={}, offset={}]",
204 length, offset
205 )
206 })?;
207 R::read(buf.as_slice(), &mut builder)?;
208 } else {
209 builder.append(None);
210 }
211 }
212 let arr = builder.finish();
213 ensure_eq!(arr.len(), cardinality);
214
215 Ok(arr.into())
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221
222 #[test]
225 fn test_column_protobuf_conversion() {
226 let cardinality = 2048;
227 let mut builder = I32ArrayBuilder::new(cardinality);
228 for i in 0..cardinality {
229 if i % 2 == 0 {
230 builder.append(Some(i as i32));
231 } else {
232 builder.append(None);
233 }
234 }
235 let col: ArrayImpl = builder.finish().into();
236 let new_col = ArrayImpl::from_protobuf(&col.to_protobuf(), cardinality).unwrap();
237 assert_eq!(new_col.len(), cardinality);
238 let arr: &I32Array = new_col.as_int32();
239 arr.iter().enumerate().for_each(|(i, x)| {
240 if i % 2 == 0 {
241 assert_eq!(i as i32, x.unwrap());
242 } else {
243 assert!(x.is_none());
244 }
245 });
246 }
247
248 #[test]
249 fn test_bool_column_protobuf_conversion() {
250 let cardinality = 2048;
251 let mut builder = BoolArrayBuilder::new(cardinality);
252 for i in 0..cardinality {
253 match i % 3 {
254 0 => builder.append(Some(false)),
255 1 => builder.append(Some(true)),
256 _ => builder.append(None),
257 }
258 }
259 let col: ArrayImpl = builder.finish().into();
260 let new_col = ArrayImpl::from_protobuf(&col.to_protobuf(), cardinality).unwrap();
261 assert_eq!(new_col.len(), cardinality);
262 let arr: &BoolArray = new_col.as_bool();
263 arr.iter().enumerate().for_each(|(i, x)| match i % 3 {
264 0 => assert_eq!(Some(false), x),
265 1 => assert_eq!(Some(true), x),
266 _ => assert_eq!(None, x),
267 });
268 }
269
270 #[test]
271 fn test_utf8_column_conversion() {
272 let cardinality = 2048;
273 let mut builder = Utf8ArrayBuilder::new(cardinality);
274 for i in 0..cardinality {
275 if i % 2 == 0 {
276 builder.append(Some("abc"));
277 } else {
278 builder.append(None);
279 }
280 }
281 let col: ArrayImpl = builder.finish().into();
282 let new_col = ArrayImpl::from_protobuf(&col.to_protobuf(), cardinality).unwrap();
283 let arr: &Utf8Array = new_col.as_utf8();
284 arr.iter().enumerate().for_each(|(i, x)| {
285 if i % 2 == 0 {
286 assert_eq!("abc", x.unwrap());
287 } else {
288 assert!(x.is_none());
289 }
290 });
291 }
292
293 #[test]
294 fn test_decimal_protobuf_conversion() {
295 let cardinality = 2048;
296 let mut builder = DecimalArrayBuilder::new(cardinality);
297 for i in 0..cardinality {
298 if i % 2 == 0 {
299 builder.append(Some(Decimal::from(i)));
300 } else {
301 builder.append(None);
302 }
303 }
304 let col: ArrayImpl = builder.finish().into();
305 let new_col = ArrayImpl::from_protobuf(&col.to_protobuf(), cardinality).unwrap();
306 assert_eq!(new_col.len(), cardinality);
307 let arr: &DecimalArray = new_col.as_decimal();
308 arr.iter().enumerate().for_each(|(i, x)| {
309 if i % 2 == 0 {
310 assert_eq!(Decimal::from(i), x.unwrap());
311 } else {
312 assert!(x.is_none());
313 }
314 });
315 }
316
317 #[test]
318 fn test_date_protobuf_conversion() {
319 let cardinality = 2048;
320 let mut builder = DateArrayBuilder::new(cardinality);
321 for i in 0..cardinality {
322 if i % 2 == 0 {
323 builder.append(Date::with_days_since_ce(i as i32).ok());
324 } else {
325 builder.append(None);
326 }
327 }
328 let col: ArrayImpl = builder.finish().into();
329 let new_col = ArrayImpl::from_protobuf(&col.to_protobuf(), cardinality).unwrap();
330 assert_eq!(new_col.len(), cardinality);
331 let arr: &DateArray = new_col.as_date();
332 arr.iter().enumerate().for_each(|(i, x)| {
333 if i % 2 == 0 {
334 assert_eq!(Date::with_days_since_ce(i as i32).ok().unwrap(), x.unwrap());
335 } else {
336 assert!(x.is_none());
337 }
338 });
339 }
340
341 #[test]
342 fn test_time_protobuf_conversion() {
343 let cardinality = 2048;
344 let mut builder = TimeArrayBuilder::new(cardinality);
345 for i in 0..cardinality {
346 if i % 2 == 0 {
347 builder.append(Time::with_secs_nano(i as u32, i as u32 * 1000).ok());
348 } else {
349 builder.append(None);
350 }
351 }
352 let col: ArrayImpl = builder.finish().into();
353 let new_col = ArrayImpl::from_protobuf(&col.to_protobuf(), cardinality).unwrap();
354 assert_eq!(new_col.len(), cardinality);
355 let arr: &TimeArray = new_col.as_time();
356 arr.iter().enumerate().for_each(|(i, x)| {
357 if i % 2 == 0 {
358 assert_eq!(
359 Time::with_secs_nano(i as u32, i as u32 * 1000)
360 .ok()
361 .unwrap(),
362 x.unwrap()
363 );
364 } else {
365 assert!(x.is_none());
366 }
367 });
368 }
369
370 #[test]
371 fn test_timestamp_protobuf_conversion() {
372 let cardinality = 2048;
373 let mut builder = TimestampArrayBuilder::new(cardinality);
374 for i in 0..cardinality {
375 if i % 2 == 0 {
376 builder.append(Timestamp::with_secs_nsecs(i as i64, i as u32 * 1000).ok());
377 } else {
378 builder.append(None);
379 }
380 }
381 let col: ArrayImpl = builder.finish().into();
382 let new_col = ArrayImpl::from_protobuf(&col.to_protobuf(), cardinality).unwrap();
383 assert_eq!(new_col.len(), cardinality);
384 let arr: &TimestampArray = new_col.as_timestamp();
385 arr.iter().enumerate().for_each(|(i, x)| {
386 if i % 2 == 0 {
387 assert_eq!(
388 Timestamp::with_secs_nsecs(i as i64, i as u32 * 1000)
389 .ok()
390 .unwrap(),
391 x.unwrap()
392 );
393 } else {
394 assert!(x.is_none());
395 }
396 });
397 }
398}