Skip to content

Commit 6f3f8a8

Browse files
authored
Merge pull request MaterializeInc#11728 from aalexandrov/protobuf_eval_error
2 parents 353bbb9 + adc978f commit 6f3f8a8

File tree

8 files changed

+317
-9
lines changed

8 files changed

+317
-9
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ rustc-demangle = { opt-level = 3 }
8282
# production installations, but we still want useful crash reports.
8383
debug = 1
8484

85+
# Use this section only to change the source of dependencies that might
86+
# also appear as transitive dependencies of other external dependencies in
87+
# the dependency graph. For everything else (e.g. rust-postgres, rdkafka,
88+
# differential-dataflow, proptest, timely) set the `git` sourcce
89+
# direclty in each dependency entry.
8590
[patch.crates-io]
8691
# Until https://github.com/jorgecarleitao/parquet-format-rs/pull/2 is merged and released
8792
parquet-format-async-temp = { git = "https://github.com/MaterializeInc/parquet-format-rs", branch = "main" }

deny.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ allow-git = [
152152
"https://github.com/MaterializeInc/parquet-format-rs.git",
153153

154154
# Waiting on https://github.com/AltSysrq/proptest/pull/264.
155-
"https://github.com/materializeInc/proptest.git",
155+
"https://github.com/MaterializeInc/proptest.git",
156156

157157
# Dependencies that we control upstream whose official releases we don't
158158
# care about.

src/expr/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ sha-1 = "0.10.0"
4646
sha2 = "0.10.2"
4747
uncased = "0.9.6"
4848
uuid = "0.8.2"
49-
proptest = { git = "https://github.com/materializeInc/proptest.git", default-features = false, features = ["std"], optional = true }
50-
proptest-derive = { git = "https://github.com/materializeInc/proptest.git", optional = true }
49+
proptest = { git = "https://github.com/MaterializeInc/proptest.git", default-features = false, features = ["std"], optional = true }
50+
proptest-derive = { git = "https://github.com/MaterializeInc/proptest.git", optional = true }
5151

5252
[dev-dependencies]
5353
criterion = { git = "https://github.com/MaterializeInc/criterion.rs.git" }

src/expr/src/proto/scalar.proto

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
syntax = "proto3";
1313

1414
import "google/protobuf/empty.proto";
15+
import "adt/array.proto";
16+
import "strconv.proto";
1517

1618
package scalar;
1719

@@ -22,3 +24,97 @@ message ProtoDomainLimit {
2224
int64 exclusive = 3;
2325
}
2426
}
27+
28+
message ProtoEvalError {
29+
message ProtoUnsupported {
30+
string feature = 1;
31+
optional uint64 issue_no = 2;
32+
};
33+
message ProtoInvalidLayer {
34+
uint64 max_layer = 1;
35+
int64 val = 2;
36+
}
37+
message ProtoInvalidByteSequence {
38+
string byte_sequence = 1;
39+
string encoding_name = 2;
40+
}
41+
message ProtoInvalidJsonbCast {
42+
string from = 1;
43+
string to = 2;
44+
}
45+
message ProtoUnsupportedUnits {
46+
string units = 1;
47+
string typ = 2;
48+
}
49+
message ProtoOutOfDomain {
50+
ProtoDomainLimit lower = 1;
51+
ProtoDomainLimit upper = 2;
52+
string id = 3;
53+
}
54+
message ProtoStringValueTooLong {
55+
string target_type = 1;
56+
uint64 length = 2;
57+
}
58+
message ProtoIncompatibleArrayDimensions {
59+
message ProtoDims {
60+
uint64 f0 = 1;
61+
uint64 f1 = 2;
62+
}
63+
ProtoDims dims = 1;
64+
}
65+
oneof kind {
66+
int32 character_not_valid_for_encoding = 1;
67+
int32 character_too_large_for_encoding = 2;
68+
string date_bin_out_of_range = 3;
69+
google.protobuf.Empty division_by_zero = 4;
70+
ProtoUnsupported unsupported = 5;
71+
google.protobuf.Empty float_overflow = 6;
72+
google.protobuf.Empty float_underflow = 7;
73+
google.protobuf.Empty numeric_field_overflow = 8;
74+
google.protobuf.Empty float32_out_of_range = 9;
75+
google.protobuf.Empty float64_out_of_range = 10;
76+
google.protobuf.Empty int16_out_of_range = 11;
77+
google.protobuf.Empty int32_out_of_range = 12;
78+
google.protobuf.Empty int64_out_of_range = 13;
79+
google.protobuf.Empty oid_out_of_range = 14;
80+
google.protobuf.Empty interval_out_of_range = 15;
81+
google.protobuf.Empty timestamp_out_of_range = 16;
82+
google.protobuf.Empty char_out_of_range = 17;
83+
google.protobuf.Empty invalid_base64_equals = 18;
84+
uint32 invalid_base64_symbol = 19;
85+
google.protobuf.Empty invalid_base64_end_sequence = 20;
86+
string invalid_timezone = 21;
87+
google.protobuf.Empty invalid_timezone_interval = 22;
88+
google.protobuf.Empty invalid_timezone_conversion = 23;
89+
ProtoInvalidLayer invalid_layer = 24;
90+
adt.array.ProtoInvalidArrayError invalid_array = 25;
91+
string invalid_encoding_name = 26;
92+
string invalid_hash_algorithm = 27;
93+
ProtoInvalidByteSequence invalid_byte_sequence = 28;
94+
ProtoInvalidJsonbCast invalid_jsonb_cast = 29;
95+
string invalid_regex = 30;
96+
uint32 invalid_regex_flag = 31;
97+
string invalid_parameter_value = 32;
98+
google.protobuf.Empty neg_sqrt = 33;
99+
google.protobuf.Empty null_character_not_permitted = 34;
100+
string unknown_units = 35;
101+
ProtoUnsupportedUnits unsupported_units = 36;
102+
google.protobuf.Empty unterminated_like_escape_sequence = 37;
103+
strconv.ProtoParseError parse = 38;
104+
strconv.ProtoParseHexError parse_hex = 39;
105+
string internal = 40;
106+
string infinity_out_of_domain = 41;
107+
string negative_out_of_domain = 42;
108+
string zero_out_of_domain = 43;
109+
ProtoOutOfDomain out_of_domain = 44;
110+
string complex_out_of_range = 45;
111+
google.protobuf.Empty multiple_rows_from_subquery = 46;
112+
string undefined = 47;
113+
google.protobuf.Empty like_pattern_too_long = 48;
114+
google.protobuf.Empty like_escape_too_long = 49;
115+
ProtoStringValueTooLong string_value_too_long = 50;
116+
google.protobuf.Empty multidimensional_array_removal_not_supported = 51;
117+
ProtoIncompatibleArrayDimensions incompatible_array_dimensions = 52;
118+
string type_from_oid = 53;
119+
}
120+
}

src/expr/src/proto/scalar/mod.rs

Lines changed: 208 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99

1010
include!(concat!(env!("OUT_DIR"), "/scalar.rs"));
1111

12-
use crate::scalar::DomainLimit;
13-
use mz_repr::proto::TryFromProtoError;
12+
use crate::scalar::{DomainLimit, EvalError};
13+
use mz_repr::proto::{ProtoRepr, TryFromProtoError, TryIntoIfSome};
1414

1515
impl From<&DomainLimit> for ProtoDomainLimit {
1616
fn from(limit: &DomainLimit) -> Self {
@@ -41,6 +41,203 @@ impl TryFrom<ProtoDomainLimit> for DomainLimit {
4141
}
4242
}
4343

44+
impl From<&EvalError> for ProtoEvalError {
45+
fn from(error: &EvalError) -> Self {
46+
use proto_eval_error::*;
47+
use proto_incompatible_array_dimensions::*;
48+
use Kind::*;
49+
let kind = match error {
50+
EvalError::CharacterNotValidForEncoding(v) => CharacterNotValidForEncoding(*v),
51+
EvalError::CharacterTooLargeForEncoding(v) => CharacterTooLargeForEncoding(*v),
52+
EvalError::DateBinOutOfRange(v) => DateBinOutOfRange(v.clone()),
53+
EvalError::DivisionByZero => DivisionByZero(()),
54+
EvalError::Unsupported { feature, issue_no } => Unsupported(ProtoUnsupported {
55+
feature: feature.clone(),
56+
issue_no: issue_no.into_proto(),
57+
}),
58+
EvalError::FloatOverflow => FloatOverflow(()),
59+
EvalError::FloatUnderflow => FloatUnderflow(()),
60+
EvalError::NumericFieldOverflow => NumericFieldOverflow(()),
61+
EvalError::Float32OutOfRange => Float32OutOfRange(()),
62+
EvalError::Float64OutOfRange => Float64OutOfRange(()),
63+
EvalError::Int16OutOfRange => Int16OutOfRange(()),
64+
EvalError::Int32OutOfRange => Int32OutOfRange(()),
65+
EvalError::Int64OutOfRange => Int64OutOfRange(()),
66+
EvalError::OidOutOfRange => OidOutOfRange(()),
67+
EvalError::IntervalOutOfRange => IntervalOutOfRange(()),
68+
EvalError::TimestampOutOfRange => TimestampOutOfRange(()),
69+
EvalError::CharOutOfRange => CharOutOfRange(()),
70+
EvalError::InvalidBase64Equals => InvalidBase64Equals(()),
71+
EvalError::InvalidBase64Symbol(sym) => InvalidBase64Symbol(sym.into_proto()),
72+
EvalError::InvalidBase64EndSequence => InvalidBase64EndSequence(()),
73+
EvalError::InvalidTimezone(tz) => InvalidTimezone(tz.clone()),
74+
EvalError::InvalidTimezoneInterval => InvalidTimezoneInterval(()),
75+
EvalError::InvalidTimezoneConversion => InvalidTimezoneConversion(()),
76+
EvalError::InvalidLayer { max_layer, val } => InvalidLayer(ProtoInvalidLayer {
77+
max_layer: max_layer.into_proto(),
78+
val: *val,
79+
}),
80+
EvalError::InvalidArray(error) => InvalidArray(error.into()),
81+
EvalError::InvalidEncodingName(v) => InvalidEncodingName(v.clone()),
82+
EvalError::InvalidHashAlgorithm(v) => InvalidHashAlgorithm(v.clone()),
83+
EvalError::InvalidByteSequence {
84+
byte_sequence,
85+
encoding_name,
86+
} => InvalidByteSequence(ProtoInvalidByteSequence {
87+
byte_sequence: byte_sequence.clone(),
88+
encoding_name: encoding_name.clone(),
89+
}),
90+
EvalError::InvalidJsonbCast { from, to } => InvalidJsonbCast(ProtoInvalidJsonbCast {
91+
from: from.clone(),
92+
to: to.clone(),
93+
}),
94+
EvalError::InvalidRegex(v) => InvalidRegex(v.clone()),
95+
EvalError::InvalidRegexFlag(v) => InvalidRegexFlag(v.into_proto()),
96+
EvalError::InvalidParameterValue(v) => InvalidParameterValue(v.clone()),
97+
EvalError::NegSqrt => NegSqrt(()),
98+
EvalError::NullCharacterNotPermitted => NullCharacterNotPermitted(()),
99+
EvalError::UnknownUnits(v) => UnknownUnits(v.clone()),
100+
EvalError::UnsupportedUnits(units, typ) => UnsupportedUnits(ProtoUnsupportedUnits {
101+
units: units.clone(),
102+
typ: typ.clone(),
103+
}),
104+
EvalError::UnterminatedLikeEscapeSequence => UnterminatedLikeEscapeSequence(()),
105+
EvalError::Parse(error) => Parse(error.into()),
106+
EvalError::ParseHex(error) => ParseHex(error.into()),
107+
EvalError::Internal(v) => Internal(v.clone()),
108+
EvalError::InfinityOutOfDomain(v) => InfinityOutOfDomain(v.clone()),
109+
EvalError::NegativeOutOfDomain(v) => NegativeOutOfDomain(v.clone()),
110+
EvalError::ZeroOutOfDomain(v) => ZeroOutOfDomain(v.clone()),
111+
EvalError::OutOfDomain(lower, upper, id) => OutOfDomain(ProtoOutOfDomain {
112+
lower: Some(lower.into()),
113+
upper: Some(upper.into()),
114+
id: id.clone(),
115+
}),
116+
EvalError::ComplexOutOfRange(v) => ComplexOutOfRange(v.clone()),
117+
EvalError::MultipleRowsFromSubquery => MultipleRowsFromSubquery(()),
118+
EvalError::Undefined(v) => Undefined(v.clone()),
119+
EvalError::LikePatternTooLong => LikePatternTooLong(()),
120+
EvalError::LikeEscapeTooLong => LikeEscapeTooLong(()),
121+
EvalError::StringValueTooLong {
122+
target_type,
123+
length,
124+
} => StringValueTooLong(ProtoStringValueTooLong {
125+
target_type: target_type.clone(),
126+
length: length.into_proto(),
127+
}),
128+
EvalError::MultidimensionalArrayRemovalNotSupported => {
129+
MultidimensionalArrayRemovalNotSupported(())
130+
}
131+
EvalError::IncompatibleArrayDimensions { dims } => {
132+
IncompatibleArrayDimensions(ProtoIncompatibleArrayDimensions {
133+
dims: dims.map(|dims| ProtoDims {
134+
f0: dims.0.into_proto(),
135+
f1: dims.1.into_proto(),
136+
}),
137+
})
138+
}
139+
EvalError::TypeFromOid(v) => TypeFromOid(v.clone()),
140+
};
141+
ProtoEvalError { kind: Some(kind) }
142+
}
143+
}
144+
145+
impl TryFrom<ProtoEvalError> for EvalError {
146+
type Error = TryFromProtoError;
147+
148+
fn try_from(error: ProtoEvalError) -> Result<Self, Self::Error> {
149+
use proto_eval_error::Kind::*;
150+
match error.kind {
151+
Some(kind) => match kind {
152+
CharacterNotValidForEncoding(v) => Ok(EvalError::CharacterNotValidForEncoding(v)),
153+
CharacterTooLargeForEncoding(v) => Ok(EvalError::CharacterTooLargeForEncoding(v)),
154+
DateBinOutOfRange(v) => Ok(EvalError::DateBinOutOfRange(v)),
155+
DivisionByZero(()) => Ok(EvalError::DivisionByZero),
156+
Unsupported(v) => Ok(EvalError::Unsupported {
157+
feature: v.feature,
158+
issue_no: Option::<usize>::from_proto(v.issue_no)?,
159+
}),
160+
FloatOverflow(()) => Ok(EvalError::FloatOverflow),
161+
FloatUnderflow(()) => Ok(EvalError::FloatUnderflow),
162+
NumericFieldOverflow(()) => Ok(EvalError::NumericFieldOverflow),
163+
Float32OutOfRange(()) => Ok(EvalError::Float32OutOfRange),
164+
Float64OutOfRange(()) => Ok(EvalError::Float64OutOfRange),
165+
Int16OutOfRange(()) => Ok(EvalError::Int16OutOfRange),
166+
Int32OutOfRange(()) => Ok(EvalError::Int32OutOfRange),
167+
Int64OutOfRange(()) => Ok(EvalError::Int64OutOfRange),
168+
OidOutOfRange(()) => Ok(EvalError::OidOutOfRange),
169+
IntervalOutOfRange(()) => Ok(EvalError::IntervalOutOfRange),
170+
TimestampOutOfRange(()) => Ok(EvalError::TimestampOutOfRange),
171+
CharOutOfRange(()) => Ok(EvalError::CharOutOfRange),
172+
InvalidBase64Equals(()) => Ok(EvalError::InvalidBase64Equals),
173+
InvalidBase64Symbol(v) => char::from_proto(v).map(EvalError::InvalidBase64Symbol),
174+
InvalidBase64EndSequence(()) => Ok(EvalError::InvalidBase64EndSequence),
175+
InvalidTimezone(v) => Ok(EvalError::InvalidTimezone(v)),
176+
InvalidTimezoneInterval(()) => Ok(EvalError::InvalidTimezoneInterval),
177+
InvalidTimezoneConversion(()) => Ok(EvalError::InvalidTimezoneConversion),
178+
InvalidLayer(v) => Ok(EvalError::InvalidLayer {
179+
max_layer: usize::from_proto(v.max_layer)?,
180+
val: v.val,
181+
}),
182+
InvalidArray(error) => Ok(EvalError::InvalidArray(error.try_into()?)),
183+
InvalidEncodingName(v) => Ok(EvalError::InvalidEncodingName(v)),
184+
InvalidHashAlgorithm(v) => Ok(EvalError::InvalidHashAlgorithm(v)),
185+
InvalidByteSequence(v) => Ok(EvalError::InvalidByteSequence {
186+
byte_sequence: v.byte_sequence,
187+
encoding_name: v.encoding_name,
188+
}),
189+
InvalidJsonbCast(v) => Ok(EvalError::InvalidJsonbCast {
190+
from: v.from,
191+
to: v.to,
192+
}),
193+
InvalidRegex(v) => Ok(EvalError::InvalidRegex(v)),
194+
InvalidRegexFlag(v) => Ok(EvalError::InvalidRegexFlag(char::from_proto(v)?)),
195+
InvalidParameterValue(v) => Ok(EvalError::InvalidParameterValue(v)),
196+
NegSqrt(()) => Ok(EvalError::NegSqrt),
197+
NullCharacterNotPermitted(()) => Ok(EvalError::NullCharacterNotPermitted),
198+
UnknownUnits(v) => Ok(EvalError::UnknownUnits(v)),
199+
UnsupportedUnits(v) => Ok(EvalError::UnsupportedUnits(v.units, v.typ)),
200+
UnterminatedLikeEscapeSequence(()) => Ok(EvalError::UnterminatedLikeEscapeSequence),
201+
Parse(error) => Ok(EvalError::Parse(error.try_into()?)),
202+
ParseHex(error) => Ok(EvalError::ParseHex(error.try_into()?)),
203+
Internal(v) => Ok(EvalError::Internal(v)),
204+
InfinityOutOfDomain(v) => Ok(EvalError::InfinityOutOfDomain(v)),
205+
NegativeOutOfDomain(v) => Ok(EvalError::NegativeOutOfDomain(v)),
206+
ZeroOutOfDomain(v) => Ok(EvalError::ZeroOutOfDomain(v)),
207+
OutOfDomain(v) => Ok(EvalError::OutOfDomain(
208+
v.lower.try_into_if_some("`ProtoDomainLimit::lower`")?,
209+
v.upper.try_into_if_some("`ProtoDomainLimit::upper`")?,
210+
v.id,
211+
)),
212+
ComplexOutOfRange(v) => Ok(EvalError::ComplexOutOfRange(v)),
213+
MultipleRowsFromSubquery(()) => Ok(EvalError::MultipleRowsFromSubquery),
214+
Undefined(v) => Ok(EvalError::Undefined(v)),
215+
LikePatternTooLong(()) => Ok(EvalError::LikePatternTooLong),
216+
LikeEscapeTooLong(()) => Ok(EvalError::LikeEscapeTooLong),
217+
StringValueTooLong(v) => Ok(EvalError::StringValueTooLong {
218+
target_type: v.target_type,
219+
length: usize::from_proto(v.length)?,
220+
}),
221+
MultidimensionalArrayRemovalNotSupported(()) => {
222+
Ok(EvalError::MultidimensionalArrayRemovalNotSupported)
223+
}
224+
IncompatibleArrayDimensions(v) => Ok(EvalError::IncompatibleArrayDimensions {
225+
dims: v
226+
.dims
227+
.map::<Result<_, TryFromProtoError>, _>(|dims| {
228+
let f0 = usize::from_proto(dims.f0)?;
229+
let f1 = usize::from_proto(dims.f1)?;
230+
Ok((f0, f1))
231+
})
232+
.transpose()?,
233+
}),
234+
TypeFromOid(v) => Ok(EvalError::TypeFromOid(v)),
235+
},
236+
None => Err(TryFromProtoError::missing_field("`ProtoEvalError::kind`")),
237+
}
238+
}
239+
}
240+
44241
#[cfg(test)]
45242
mod tests {
46243
use super::*;
@@ -55,4 +252,13 @@ mod tests {
55252
assert_eq!(actual.unwrap(), expect);
56253
}
57254
}
255+
256+
proptest! {
257+
#[test]
258+
fn eval_error_protobuf_roundtrip(expect in any::<EvalError>()) {
259+
let actual = protobuf_roundtrip::<_, ProtoEvalError>(&expect);
260+
assert!(actual.is_ok());
261+
assert_eq!(actual.unwrap(), expect);
262+
}
263+
}
58264
}

src/expr/src/scalar/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,6 +1229,7 @@ pub enum DomainLimit {
12291229
}
12301230

12311231
#[derive(Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect)]
1232+
#[cfg_attr(feature = "test-utils", derive(Arbitrary))]
12321233
pub enum EvalError {
12331234
CharacterNotValidForEncoding(i32),
12341235
CharacterTooLargeForEncoding(i32),

0 commit comments

Comments
 (0)