1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//! Shared low-level helpers for the CQL → Arrow converter (feature = "arrow").
//!
//! Split out of `arrow_convert` (epic #1116 file-size split, issue #3096 Phase 0a)
//! with no behaviour change. Everything here is used by more than one of the
//! converter's modules:
//!
//! * the fail-closed `i32` offset/byte guards ([`checked_offset`],
//! [`checked_value_bytes`], [`checked_string_offsets`], [`checked_binary_offsets`])
//! — issues #1486 / #2235;
//! * the `Frozen` unwrapping helpers ([`unwrap_frozen_type`], [`unwrap_frozen_value`]);
//! * [`bigint_to_i128`], shared with the sibling `arrow_decimal` rescaler;
//! * the [`Cells`] alias naming a column's pre-resolved, row-aligned cell slice.
use ArrowConvertError;
use crateCqlType;
use crateValue;
/// A column's pre-resolved, row-aligned cell slice (issue #1495): element `i` is
/// row `i`'s value for the column, or `None` when absent. Produced once by
/// [`transpose_columns`](super::arrow_columnar::transpose_columns).
pub type Cells<'a> = &'a ;
// ============================================================================
// Fail-closed i32 offset / byte-length guards
// ============================================================================
/// Convert an accumulated collection-element count to an Arrow 32-bit offset,
/// failing closed instead of silently wrapping.
///
/// Arrow `List`/`Map` offset buffers are `i32`-backed. A plain `usize as i32`
/// cast wraps to a **negative** value once the flattened element count of a
/// row group crosses `i32::MAX` (2,147,483,647) — exactly the wide-partition
/// case — producing non-monotonic offsets that either panic
/// `OffsetBuffer::new` (monotonicity assert, on a library data path) or yield
/// a structurally corrupt array. This returns
/// [`ArrowConvertError::InvalidValue`] at that boundary instead. See issue
/// #1486. Normal-size collections take the identical fast path.
pub
/// Fail closed when the **cumulative byte length** of a `Utf8`/`Binary` column
/// would overflow the `i32`-backed value-offset buffer.
///
/// `StringArray`/`BinaryArray` (unlike their `Large*` siblings) store value
/// end-offsets as `i32`. The offset of the last value equals the total byte
/// length of the column; once that total crosses `i32::MAX` (2 GiB) the arrow
/// builder either panics on the offset conversion or silently produces a
/// non-monotonic/corrupt buffer. Flight/export batches are bounded by **row
/// count** (default 8192), not bytes, so a batch of moderately wide text/blob
/// values (e.g. ≥256 KiB each — all well within Cassandra's per-value limits)
/// can cross this ceiling on a library data path. This returns
/// [`ArrowConvertError::InvalidValue`] at that boundary instead. This is the
/// scalar analogue of [`checked_offset`]'s List/Map element-count guard (issue
/// #1486); see issue #2235. Normal-size columns take the identical fast path.
pub
/// Guard the cumulative byte length of a nullable `Utf8` column before handing
/// it to `StringArray::from`. Saturating summation cannot itself overflow.
///
/// Generic over `AsRef<str>` so the wide-text scalar/element paths can guard on
/// **borrowed** `&str`/`Cow<str>` slices of the already-materialized row values
/// — the check runs before any owned copy is made, so the fail-closed path
/// never clones ~2 GiB just to reject it (issue #2235).
pub
/// Guard the cumulative byte length of a nullable `Binary` column before
/// handing it to `BinaryArray::from`. Saturating summation cannot overflow.
///
/// Generic over `AsRef<[u8]>` so callers can guard on **borrowed** `&[u8]`
/// slices of the row values before any owned copy — see
/// [`checked_string_offsets`] (issue #2235).
pub
// ============================================================================
// BigInt → i128 helper
// ============================================================================
/// Convert a `num_bigint::BigInt` to `i128`, sign-extending if necessary.
///
/// Uses the two's-complement big-endian representation via
/// `to_signed_bytes_be()` and sign-extends to 16 bytes before reinterpreting
/// as `i128`. Returns an error if the value requires more than 16 bytes
/// (i.e. exceeds the i128 range).
pub
// ============================================================================
// Frozen unwrapping
// ============================================================================
/// Unwrap nested `CqlType::Frozen` wrappers to reach the effective type.
///
/// `Frozen(Frozen(T))` → `T`. This handles the rare but valid case of
/// double-frozen types in schema definitions.
pub
/// Unwrap a `Value::Frozen(inner)` reference to its inner value.
///
/// Returns the inner value reference if `v` is `Frozen`, or the original
/// reference otherwise. `None` (absent column value) is passed through.
pub