Skip to main content

risingwave_sqlsmith/
validation.rs

1// Copyright 2022 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Provides validation logic for expected errors.
16use risingwave_expr::ExprError;
17use risingwave_frontend::optimizer::variant_key::VARIANT_KEY_HINT;
18
19/// Ignore errors related to `0`.
20fn is_zero_err(db_error: &str) -> bool {
21    db_error.contains(&ExprError::DivisionByZero.to_string()) || db_error.contains("can't be zero")
22}
23
24/// `Casting to u32 out of range` occurs when we have functions
25/// which expect non-negative arguments,
26/// e.g. `select 222 << -1`
27// NOTE: If this error occurs too often, perhaps it is better to
28// wrap call sites with `abs(rhs)`, e.g. 222 << abs(-1);
29fn is_numeric_out_of_range_err(db_error: &str) -> bool {
30    db_error.contains(&ExprError::NumericOutOfRange.to_string())
31        || db_error.contains("Casting to u32 out of range")
32}
33
34fn is_parse_err(db_error: &str) -> bool {
35    db_error.contains("Parse error")
36}
37
38/// Skip queries with unimplemented features
39fn is_unimplemented_error(db_error: &str) -> bool {
40    db_error.contains("not yet implemented")
41}
42
43/// This error occurs because we test `implicit` casts as well,
44/// generated expressions may be ambiguous as a result,
45/// if there are multiple candidates signatures.
46/// Additionally.
47fn not_unique_error(db_error: &str) -> bool {
48    db_error.contains("Bind error") && db_error.contains("is not unique")
49}
50
51fn is_window_error(db_error: &str) -> bool {
52    db_error.contains("Bind error: The size arg of window table function should be an interval literal")
53        || db_error.contains("Bind error: The 2nd arg of window table function should be a column name but not complex expression. Consider using an intermediate CTE or view as workaround")
54}
55
56// Streaming nested-loop join is not supported, as it is expensive.
57fn is_nested_loop_join_error(db_error: &str) -> bool {
58    db_error.contains("Not supported: streaming nested-loop join")
59}
60
61fn is_variant_key_error(db_error: &str) -> bool {
62    db_error.contains(VARIANT_KEY_HINT)
63}
64
65fn is_subquery_unnesting_error(db_error: &str) -> bool {
66    db_error.contains("Subquery cannot be unnested")
67        || db_error.contains("Scalar subquery might produce more than one row")
68}
69
70/// Can't avoid numeric overflows, we do not eval const expr
71fn is_numeric_overflow_error(db_error: &str) -> bool {
72    db_error.contains("Number") && db_error.contains("overflows")
73}
74
75/// Negative substr error
76fn is_neg_substr_error(db_error: &str) -> bool {
77    db_error.contains("negative substring length not allowed")
78}
79
80/// Zero or negative overlay start error
81fn is_overlay_start_error(db_error: &str) -> bool {
82    db_error.contains("Invalid parameter start") && db_error.contains("is not positive")
83}
84
85/// Broken channel error
86fn is_broken_channel_error(db_error: &str) -> bool {
87    db_error.contains("failed to finish command: channel closed")
88}
89
90/// Permit recovery error
91/// Suppose Out Of Range Error happens in the following query:
92/// ```sql
93/// SELECT sum0(v1) FROM t;
94/// ```
95/// It would be a valid scenario from Sqlsmith.
96/// In that case we would trigger recovery for the materialized view.
97/// We could encounter this error on subsequent queries:
98/// ```text
99/// Barrier read is unavailable for now. Likely the cluster is recovering
100/// ```
101/// Recovery should be successful after a while.
102/// Hence we should retry for some bound.
103pub fn is_recovery_in_progress_error(db_error: &str) -> bool {
104    db_error.contains("Barrier read is unavailable for now. Likely the cluster is recovering")
105        || db_error.contains("Service unavailable: The cluster is starting or recovering")
106}
107
108pub fn is_neg_exp_error(db_error: &str) -> bool {
109    db_error.contains("zero raised to a negative power is undefined")
110}
111
112pub fn is_neg_input_error(db_error: &str) -> bool {
113    db_error.contains("input cannot be negative value")
114}
115
116/// Certain errors are permitted to occur. This is because:
117/// 1. It is more complex to generate queries without these errors.
118/// 2. These errors seldom occur, skipping them won't affect overall effectiveness of sqlsmith.
119pub fn is_permissible_error(db_error: &str) -> bool {
120    is_numeric_out_of_range_err(db_error)
121        || is_zero_err(db_error)
122        || is_parse_err(db_error)
123        || is_unimplemented_error(db_error)
124        || not_unique_error(db_error)
125        || is_window_error(db_error)
126        || is_nested_loop_join_error(db_error)
127        || is_variant_key_error(db_error)
128        || is_subquery_unnesting_error(db_error)
129        || is_numeric_overflow_error(db_error)
130        || is_neg_substr_error(db_error)
131        || is_overlay_start_error(db_error)
132        || is_broken_channel_error(db_error)
133        || is_neg_exp_error(db_error)
134        || is_neg_input_error(db_error)
135}