parquet 0.5.12 → 0.6.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.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +295 -98
  3. data/Cargo.toml +1 -1
  4. data/Gemfile +1 -0
  5. data/README.md +94 -3
  6. data/ext/parquet/Cargo.toml +8 -5
  7. data/ext/parquet/src/adapter_ffi.rs +156 -0
  8. data/ext/parquet/src/lib.rs +13 -21
  9. data/ext/parquet-core/Cargo.toml +23 -0
  10. data/ext/parquet-core/src/arrow_conversion.rs +1133 -0
  11. data/ext/parquet-core/src/error.rs +163 -0
  12. data/ext/parquet-core/src/lib.rs +60 -0
  13. data/ext/parquet-core/src/reader.rs +263 -0
  14. data/ext/parquet-core/src/schema.rs +283 -0
  15. data/ext/parquet-core/src/test_utils.rs +308 -0
  16. data/ext/parquet-core/src/traits/mod.rs +5 -0
  17. data/ext/parquet-core/src/traits/schema.rs +151 -0
  18. data/ext/parquet-core/src/value.rs +209 -0
  19. data/ext/parquet-core/src/writer.rs +839 -0
  20. data/ext/parquet-core/tests/arrow_conversion_tests.rs +423 -0
  21. data/ext/parquet-core/tests/binary_data.rs +437 -0
  22. data/ext/parquet-core/tests/column_projection.rs +557 -0
  23. data/ext/parquet-core/tests/complex_types.rs +821 -0
  24. data/ext/parquet-core/tests/compression_tests.rs +434 -0
  25. data/ext/parquet-core/tests/concurrent_access.rs +430 -0
  26. data/ext/parquet-core/tests/decimal_tests.rs +488 -0
  27. data/ext/parquet-core/tests/edge_cases_corner_cases.rs +322 -0
  28. data/ext/parquet-core/tests/error_handling_comprehensive_tests.rs +547 -0
  29. data/ext/parquet-core/tests/null_handling_tests.rs +430 -0
  30. data/ext/parquet-core/tests/performance_memory.rs +181 -0
  31. data/ext/parquet-core/tests/primitive_types.rs +547 -0
  32. data/ext/parquet-core/tests/real_world_patterns.rs +777 -0
  33. data/ext/parquet-core/tests/roundtrip_correctness.rs +279 -0
  34. data/ext/parquet-core/tests/schema_comprehensive_tests.rs +534 -0
  35. data/ext/parquet-core/tests/temporal_tests.rs +518 -0
  36. data/ext/parquet-core/tests/test_helpers.rs +132 -0
  37. data/ext/parquet-core/tests/writer_tests.rs +545 -0
  38. data/ext/parquet-ruby-adapter/Cargo.toml +22 -0
  39. data/ext/parquet-ruby-adapter/build.rs +5 -0
  40. data/ext/parquet-ruby-adapter/examples/try_into_value_demo.rs +98 -0
  41. data/ext/parquet-ruby-adapter/src/batch_manager.rs +116 -0
  42. data/ext/parquet-ruby-adapter/src/chunk_reader.rs +237 -0
  43. data/ext/parquet-ruby-adapter/src/converter.rs +1685 -0
  44. data/ext/parquet-ruby-adapter/src/error.rs +148 -0
  45. data/ext/{parquet/src/ruby_reader.rs → parquet-ruby-adapter/src/io.rs} +190 -56
  46. data/ext/parquet-ruby-adapter/src/lib.rs +90 -0
  47. data/ext/parquet-ruby-adapter/src/logger.rs +64 -0
  48. data/ext/parquet-ruby-adapter/src/metadata.rs +427 -0
  49. data/ext/parquet-ruby-adapter/src/reader.rs +317 -0
  50. data/ext/parquet-ruby-adapter/src/schema.rs +810 -0
  51. data/ext/parquet-ruby-adapter/src/string_cache.rs +106 -0
  52. data/ext/parquet-ruby-adapter/src/try_into_value.rs +91 -0
  53. data/ext/parquet-ruby-adapter/src/types.rs +94 -0
  54. data/ext/parquet-ruby-adapter/src/utils.rs +186 -0
  55. data/ext/parquet-ruby-adapter/src/writer.rs +435 -0
  56. data/lib/parquet/schema.rb +19 -0
  57. data/lib/parquet/version.rb +1 -1
  58. metadata +50 -24
  59. data/ext/parquet/src/enumerator.rs +0 -68
  60. data/ext/parquet/src/header_cache.rs +0 -99
  61. data/ext/parquet/src/logger.rs +0 -171
  62. data/ext/parquet/src/reader/common.rs +0 -111
  63. data/ext/parquet/src/reader/mod.rs +0 -211
  64. data/ext/parquet/src/reader/parquet_column_reader.rs +0 -44
  65. data/ext/parquet/src/reader/parquet_row_reader.rs +0 -43
  66. data/ext/parquet/src/reader/unified/mod.rs +0 -363
  67. data/ext/parquet/src/types/core_types.rs +0 -120
  68. data/ext/parquet/src/types/mod.rs +0 -100
  69. data/ext/parquet/src/types/parquet_value.rs +0 -1275
  70. data/ext/parquet/src/types/record_types.rs +0 -603
  71. data/ext/parquet/src/types/schema_converter.rs +0 -290
  72. data/ext/parquet/src/types/schema_node.rs +0 -424
  73. data/ext/parquet/src/types/timestamp.rs +0 -285
  74. data/ext/parquet/src/types/type_conversion.rs +0 -1949
  75. data/ext/parquet/src/types/writer_types.rs +0 -329
  76. data/ext/parquet/src/utils.rs +0 -184
  77. data/ext/parquet/src/writer/mod.rs +0 -505
  78. data/ext/parquet/src/writer/write_columns.rs +0 -238
  79. data/ext/parquet/src/writer/write_rows.rs +0 -488
@@ -0,0 +1,488 @@
1
+ use bytes::Bytes;
2
+ use num::BigInt;
3
+ use parquet_core::*;
4
+ use std::sync::Arc;
5
+
6
+ #[test]
7
+ fn test_decimal128_precision_scale_combinations() {
8
+ // Test various precision and scale combinations for Decimal128
9
+ let schema = SchemaBuilder::new()
10
+ .with_root(SchemaNode::Struct {
11
+ name: "root".to_string(),
12
+ nullable: false,
13
+ fields: vec![
14
+ SchemaNode::Primitive {
15
+ name: "dec_5_2".to_string(),
16
+ primitive_type: PrimitiveType::Decimal128(5, 2),
17
+ nullable: false,
18
+ format: None,
19
+ },
20
+ SchemaNode::Primitive {
21
+ name: "dec_9_2".to_string(),
22
+ primitive_type: PrimitiveType::Decimal128(9, 2),
23
+ nullable: false,
24
+ format: None,
25
+ },
26
+ SchemaNode::Primitive {
27
+ name: "dec_18_0".to_string(),
28
+ primitive_type: PrimitiveType::Decimal128(18, 0),
29
+ nullable: false,
30
+ format: None,
31
+ },
32
+ SchemaNode::Primitive {
33
+ name: "dec_38_0".to_string(),
34
+ primitive_type: PrimitiveType::Decimal128(38, 0),
35
+ nullable: false,
36
+ format: None,
37
+ },
38
+ SchemaNode::Primitive {
39
+ name: "dec_38_10".to_string(),
40
+ primitive_type: PrimitiveType::Decimal128(38, 10),
41
+ nullable: false,
42
+ format: None,
43
+ },
44
+ SchemaNode::Primitive {
45
+ name: "dec_38_38".to_string(),
46
+ primitive_type: PrimitiveType::Decimal128(38, 38),
47
+ nullable: false,
48
+ format: None,
49
+ },
50
+ ],
51
+ })
52
+ .build()
53
+ .unwrap();
54
+
55
+ let test_cases = vec![
56
+ // Maximum positive values for each precision
57
+ vec![
58
+ ParquetValue::Decimal128(99999, 2), // 999.99 (max for 5,2)
59
+ ParquetValue::Decimal128(999_999_999, 2), // 9999999.99
60
+ ParquetValue::Decimal128(999999999999999999, 0), // 18 digits
61
+ ParquetValue::Decimal128(99999999999999999999999999999999999999_i128, 0), // Max 38 digits
62
+ ParquetValue::Decimal128(99_999_999_999_999_999_999_999_999_999_999_999_999i128, 10), // 38 digits, 10 scale
63
+ ParquetValue::Decimal128(99999999999999999999999999999999999999_i128, 38), // 0.99999... (38 9s after decimal)
64
+ ],
65
+ // Maximum negative values
66
+ vec![
67
+ ParquetValue::Decimal128(-99999, 2), // -999.99 (min for 5,2)
68
+ ParquetValue::Decimal128(-999_999_999, 2), // -9999999.99
69
+ ParquetValue::Decimal128(-999999999999999999, 0), // -18 digits
70
+ ParquetValue::Decimal128(-99999999999999999999999999999999999999_i128, 0), // Min 38 digits
71
+ ParquetValue::Decimal128(-99_999_999_999_999_999_999_999_999_999_999_999_999i128, 10), // -38 digits, 10 scale
72
+ ParquetValue::Decimal128(-99999999999999999999999999999999999999_i128, 38), // -0.99999...
73
+ ],
74
+ // Zero values
75
+ vec![
76
+ ParquetValue::Decimal128(0, 2), // 0.00
77
+ ParquetValue::Decimal128(0, 2),
78
+ ParquetValue::Decimal128(0, 0),
79
+ ParquetValue::Decimal128(0, 0), // 0
80
+ ParquetValue::Decimal128(0, 10),
81
+ ParquetValue::Decimal128(0, 38), // 0.00000... (38 zeros)
82
+ ],
83
+ // Small positive values
84
+ vec![
85
+ ParquetValue::Decimal128(1, 2), // 0.01 (smallest positive for 5,2)
86
+ ParquetValue::Decimal128(1, 2), // 0.01
87
+ ParquetValue::Decimal128(1, 0), // 1
88
+ ParquetValue::Decimal128(1, 0), // 1
89
+ ParquetValue::Decimal128(1, 10), // 0.0000000001
90
+ ParquetValue::Decimal128(1, 38), // 0.00000...01 (37 zeros then 1)
91
+ ],
92
+ // Maximum value for i128
93
+ vec![
94
+ ParquetValue::Decimal128(99999, 2),
95
+ ParquetValue::Decimal128(999_999_999, 2),
96
+ ParquetValue::Decimal128(i64::MAX as i128, 0),
97
+ ParquetValue::Decimal128(i128::MAX, 0),
98
+ ParquetValue::Decimal128(12345678901234567890123456789_i128, 10),
99
+ ParquetValue::Decimal128(1, 38),
100
+ ],
101
+ // Minimum value for i128
102
+ vec![
103
+ ParquetValue::Decimal128(-99999, 2),
104
+ ParquetValue::Decimal128(-999_999_999, 2),
105
+ ParquetValue::Decimal128(i64::MIN as i128, 0),
106
+ ParquetValue::Decimal128(i128::MIN, 0),
107
+ ParquetValue::Decimal128(-12345678901234567890123456789_i128, 10),
108
+ ParquetValue::Decimal128(-1, 38),
109
+ ],
110
+ ];
111
+
112
+ let mut buffer = Vec::new();
113
+ {
114
+ let mut writer = Writer::new(&mut buffer, schema).unwrap();
115
+ writer.write_rows(test_cases.clone()).unwrap();
116
+ writer.close().unwrap();
117
+ }
118
+
119
+ // Read back and verify
120
+ let bytes = Bytes::from(buffer);
121
+ let reader = Reader::new(bytes);
122
+
123
+ let read_rows: Vec<_> = reader
124
+ .read_rows()
125
+ .unwrap()
126
+ .collect::<Result<Vec<_>>>()
127
+ .unwrap();
128
+
129
+ assert_eq!(read_rows.len(), test_cases.len());
130
+ for (expected, actual) in test_cases.iter().zip(read_rows.iter()) {
131
+ assert_eq!(expected, actual);
132
+ }
133
+ }
134
+
135
+ #[test]
136
+ fn test_decimal256_large_values() {
137
+ // Test very large Decimal256 values
138
+ let schema = SchemaBuilder::new()
139
+ .with_root(SchemaNode::Struct {
140
+ name: "root".to_string(),
141
+ nullable: false,
142
+ fields: vec![
143
+ SchemaNode::Primitive {
144
+ name: "dec256_76_0".to_string(),
145
+ primitive_type: PrimitiveType::Decimal256(76, 0),
146
+ nullable: false,
147
+ format: None,
148
+ },
149
+ SchemaNode::Primitive {
150
+ name: "dec256_76_38".to_string(),
151
+ primitive_type: PrimitiveType::Decimal256(76, 38),
152
+ nullable: false,
153
+ format: None,
154
+ },
155
+ ],
156
+ })
157
+ .build()
158
+ .unwrap();
159
+
160
+ // Test values that require Decimal256
161
+ let large_positive = BigInt::parse_bytes(
162
+ b"9999999999999999999999999999999999999999999999999999999999999999999999999",
163
+ 10,
164
+ )
165
+ .unwrap();
166
+ let large_negative = -large_positive.clone();
167
+ let medium_value = BigInt::parse_bytes(
168
+ b"123456789012345678901234567890123456789012345678901234567890",
169
+ 10,
170
+ )
171
+ .unwrap();
172
+
173
+ let test_cases = vec![
174
+ vec![
175
+ ParquetValue::Decimal256(large_positive.clone(), 0),
176
+ ParquetValue::Decimal256(medium_value.clone(), 38),
177
+ ],
178
+ vec![
179
+ ParquetValue::Decimal256(large_negative.clone(), 0),
180
+ ParquetValue::Decimal256(-medium_value.clone(), 38),
181
+ ],
182
+ vec![
183
+ ParquetValue::Decimal256(BigInt::from(0), 0),
184
+ ParquetValue::Decimal256(BigInt::from(1), 38),
185
+ ],
186
+ ];
187
+
188
+ let mut buffer = Vec::new();
189
+ {
190
+ let mut writer = Writer::new(&mut buffer, schema).unwrap();
191
+ writer.write_rows(test_cases.clone()).unwrap();
192
+ writer.close().unwrap();
193
+ }
194
+
195
+ // Read back and verify
196
+ let bytes = Bytes::from(buffer);
197
+ let reader = Reader::new(bytes);
198
+
199
+ let read_rows: Vec<_> = reader
200
+ .read_rows()
201
+ .unwrap()
202
+ .collect::<Result<Vec<_>>>()
203
+ .unwrap();
204
+
205
+ assert_eq!(read_rows.len(), test_cases.len());
206
+ for (expected, actual) in test_cases.iter().zip(read_rows.iter()) {
207
+ assert_eq!(expected, actual);
208
+ }
209
+ }
210
+
211
+ #[test]
212
+ fn test_decimal_null_handling() {
213
+ // Test nullable decimal fields
214
+ let schema = SchemaBuilder::new()
215
+ .with_root(SchemaNode::Struct {
216
+ name: "root".to_string(),
217
+ nullable: false,
218
+ fields: vec![
219
+ SchemaNode::Primitive {
220
+ name: "nullable_dec128".to_string(),
221
+ primitive_type: PrimitiveType::Decimal128(18, 4),
222
+ nullable: true,
223
+ format: None,
224
+ },
225
+ SchemaNode::Primitive {
226
+ name: "nullable_dec256".to_string(),
227
+ primitive_type: PrimitiveType::Decimal256(50, 10),
228
+ nullable: true,
229
+ format: None,
230
+ },
231
+ ],
232
+ })
233
+ .build()
234
+ .unwrap();
235
+
236
+ let rows = vec![
237
+ vec![
238
+ ParquetValue::Decimal128(123456789012345678, 4),
239
+ ParquetValue::Decimal256(BigInt::from(987654321), 10),
240
+ ],
241
+ vec![
242
+ ParquetValue::Null,
243
+ ParquetValue::Decimal256(BigInt::from(0), 10),
244
+ ],
245
+ vec![
246
+ ParquetValue::Decimal128(-999999999999999999, 4),
247
+ ParquetValue::Null,
248
+ ],
249
+ vec![ParquetValue::Null, ParquetValue::Null],
250
+ ];
251
+
252
+ let mut buffer = Vec::new();
253
+ {
254
+ let mut writer = Writer::new(&mut buffer, schema).unwrap();
255
+ writer.write_rows(rows.clone()).unwrap();
256
+ writer.close().unwrap();
257
+ }
258
+
259
+ // Read back and verify
260
+ let bytes = Bytes::from(buffer);
261
+ let reader = Reader::new(bytes);
262
+
263
+ let read_rows: Vec<_> = reader
264
+ .read_rows()
265
+ .unwrap()
266
+ .collect::<Result<Vec<_>>>()
267
+ .unwrap();
268
+
269
+ assert_eq!(read_rows.len(), rows.len());
270
+ for (expected, actual) in rows.iter().zip(read_rows.iter()) {
271
+ assert_eq!(expected, actual);
272
+ }
273
+ }
274
+
275
+ #[test]
276
+ fn test_decimal_in_complex_types() {
277
+ use indexmap::IndexMap;
278
+
279
+ // Test decimals within lists, maps, and structs
280
+ let schema = SchemaBuilder::new()
281
+ .with_root(SchemaNode::Struct {
282
+ name: "root".to_string(),
283
+ nullable: false,
284
+ fields: vec![
285
+ SchemaNode::List {
286
+ name: "decimal_list".to_string(),
287
+ nullable: false,
288
+ item: Box::new(SchemaNode::Primitive {
289
+ name: "item".to_string(),
290
+ primitive_type: PrimitiveType::Decimal128(10, 2),
291
+ nullable: false,
292
+ format: None,
293
+ }),
294
+ },
295
+ SchemaNode::Map {
296
+ name: "decimal_map".to_string(),
297
+ nullable: false,
298
+ key: Box::new(SchemaNode::Primitive {
299
+ name: "key".to_string(),
300
+ primitive_type: PrimitiveType::String,
301
+ nullable: false,
302
+ format: None,
303
+ }),
304
+ value: Box::new(SchemaNode::Primitive {
305
+ name: "value".to_string(),
306
+ primitive_type: PrimitiveType::Decimal256(40, 10),
307
+ nullable: true,
308
+ format: None,
309
+ }),
310
+ },
311
+ SchemaNode::Struct {
312
+ name: "decimal_struct".to_string(),
313
+ nullable: true,
314
+ fields: vec![
315
+ SchemaNode::Primitive {
316
+ name: "amount".to_string(),
317
+ primitive_type: PrimitiveType::Decimal128(18, 2),
318
+ nullable: false,
319
+ format: None,
320
+ },
321
+ SchemaNode::Primitive {
322
+ name: "large_amount".to_string(),
323
+ primitive_type: PrimitiveType::Decimal256(50, 6),
324
+ nullable: true,
325
+ format: None,
326
+ },
327
+ ],
328
+ },
329
+ ],
330
+ })
331
+ .build()
332
+ .unwrap();
333
+
334
+ let rows = vec![
335
+ vec![
336
+ // List of decimals
337
+ ParquetValue::List(vec![
338
+ ParquetValue::Decimal128(100, 2), // 1.00
339
+ ParquetValue::Decimal128(250, 2), // 2.50
340
+ ParquetValue::Decimal128(-375, 2), // -3.75
341
+ ]),
342
+ // Map with decimal values
343
+ ParquetValue::Map(vec![
344
+ (
345
+ ParquetValue::String(Arc::from("total")),
346
+ ParquetValue::Decimal256(BigInt::from(1234567890123456789_i64), 10),
347
+ ),
348
+ (
349
+ ParquetValue::String(Arc::from("discount")),
350
+ ParquetValue::Null,
351
+ ),
352
+ (
353
+ ParquetValue::String(Arc::from("tax")),
354
+ ParquetValue::Decimal256(BigInt::from(98765432109876543_i64), 10),
355
+ ),
356
+ ]),
357
+ // Struct with decimals
358
+ ParquetValue::Record({
359
+ let mut map = IndexMap::new();
360
+ map.insert(
361
+ Arc::from("amount"),
362
+ ParquetValue::Decimal128(999999999999999999, 2),
363
+ );
364
+ map.insert(
365
+ Arc::from("large_amount"),
366
+ ParquetValue::Decimal256(
367
+ BigInt::parse_bytes(b"12345678901234567890123456789012345678901234", 10)
368
+ .unwrap(),
369
+ 6,
370
+ ),
371
+ );
372
+ map
373
+ }),
374
+ ],
375
+ vec![
376
+ // Empty list
377
+ ParquetValue::List(vec![]),
378
+ // Empty map
379
+ ParquetValue::Map(vec![]),
380
+ // Null struct
381
+ ParquetValue::Null,
382
+ ],
383
+ ];
384
+
385
+ let mut buffer = Vec::new();
386
+ {
387
+ let mut writer = Writer::new(&mut buffer, schema).unwrap();
388
+ writer.write_rows(rows.clone()).unwrap();
389
+ writer.close().unwrap();
390
+ }
391
+
392
+ // Read back and verify
393
+ let bytes = Bytes::from(buffer);
394
+ let reader = Reader::new(bytes);
395
+
396
+ let read_rows: Vec<_> = reader
397
+ .read_rows()
398
+ .unwrap()
399
+ .collect::<Result<Vec<_>>>()
400
+ .unwrap();
401
+
402
+ assert_eq!(read_rows.len(), rows.len());
403
+ for (expected, actual) in rows.iter().zip(read_rows.iter()) {
404
+ assert_eq!(expected, actual);
405
+ }
406
+ }
407
+
408
+ #[test]
409
+ fn test_decimal_precision_edge_cases() {
410
+ // Test decimal values at the edge of precision limits
411
+ let schema = SchemaBuilder::new()
412
+ .with_root(SchemaNode::Struct {
413
+ name: "root".to_string(),
414
+ nullable: false,
415
+ fields: vec![
416
+ SchemaNode::Primitive {
417
+ name: "dec_9_2".to_string(),
418
+ primitive_type: PrimitiveType::Decimal128(9, 2),
419
+ nullable: false,
420
+ format: None,
421
+ },
422
+ SchemaNode::Primitive {
423
+ name: "dec_18_0".to_string(),
424
+ primitive_type: PrimitiveType::Decimal128(18, 0),
425
+ nullable: false,
426
+ format: None,
427
+ },
428
+ SchemaNode::Primitive {
429
+ name: "dec_38_10".to_string(),
430
+ primitive_type: PrimitiveType::Decimal128(38, 10),
431
+ nullable: false,
432
+ format: None,
433
+ },
434
+ ],
435
+ })
436
+ .build()
437
+ .unwrap();
438
+
439
+ let decimal_values = vec![
440
+ // Maximum positive values for each precision
441
+ vec![
442
+ ParquetValue::Decimal128(999_999_999, 2), // 9999999.99
443
+ ParquetValue::Decimal128(999999999999999999, 0), // 18 digits
444
+ ParquetValue::Decimal128(99_999_999_999_999_999_999_999_999_999_999_999_999i128, 10), // 38 digits, 10 scale
445
+ ],
446
+ // Maximum negative values
447
+ vec![
448
+ ParquetValue::Decimal128(-999_999_999, 2), // -9999999.99
449
+ ParquetValue::Decimal128(-999999999999999999, 0), // -18 digits
450
+ ParquetValue::Decimal128(-99_999_999_999_999_999_999_999_999_999_999_999_999i128, 10), // -38 digits, 10 scale
451
+ ],
452
+ // Zero values
453
+ vec![
454
+ ParquetValue::Decimal128(0, 2),
455
+ ParquetValue::Decimal128(0, 0),
456
+ ParquetValue::Decimal128(0, 10),
457
+ ],
458
+ // Small values
459
+ vec![
460
+ ParquetValue::Decimal128(1, 2), // 0.01
461
+ ParquetValue::Decimal128(1, 0), // 1
462
+ ParquetValue::Decimal128(1, 10), // 0.0000000001
463
+ ],
464
+ ];
465
+
466
+ let mut buffer = Vec::new();
467
+ {
468
+ let mut writer = Writer::new(&mut buffer, schema).unwrap();
469
+ writer.write_rows(decimal_values.clone()).unwrap();
470
+ writer.close().unwrap();
471
+ }
472
+
473
+ // Read back and verify
474
+ let bytes = Bytes::from(buffer);
475
+ let reader = Reader::new(bytes);
476
+
477
+ let read_rows: Vec<_> = reader
478
+ .read_rows()
479
+ .unwrap()
480
+ .collect::<Result<Vec<_>>>()
481
+ .unwrap();
482
+
483
+ assert_eq!(read_rows.len(), decimal_values.len());
484
+
485
+ for (expected, actual) in decimal_values.iter().zip(read_rows.iter()) {
486
+ assert_eq!(expected, actual);
487
+ }
488
+ }