risingwave_expr/expr/wrapper/
non_strict.rs1use std::sync::LazyLock;
16
17use auto_impl::auto_impl;
18use risingwave_common::array::{ArrayRef, DataChunk};
19use risingwave_common::log::LogSuppressor;
20use risingwave_common::row::OwnedRow;
21use risingwave_common::types::{DataType, Datum};
22use thiserror_ext::AsReport;
23
24use crate::ExprError;
25use crate::error::Result;
26use crate::expr::{AsyncExpression, ExpressionInfo, SyncExpression, ValueImpl};
27
28#[auto_impl(&, Arc)]
30pub trait EvalErrorReport: Clone + Send + Sync {
31 fn report(&self, error: ExprError);
36}
37
38impl EvalErrorReport for ! {
43 fn report(&self, _error: ExprError) {
44 unreachable!()
45 }
46}
47
48#[derive(Clone)]
50pub struct LogReport;
51
52impl EvalErrorReport for LogReport {
53 fn report(&self, error: ExprError) {
54 static LOG_SUPPRESSOR: LazyLock<LogSuppressor> = LazyLock::new(LogSuppressor::default);
55 if let Ok(suppressed_count) = LOG_SUPPRESSOR.check() {
56 tracing::error!(error=%error.as_report(), suppressed_count, "failed to evaluate expression");
57 }
58 }
59}
60
61pub(crate) struct NonStrict<E, R> {
65 inner: E,
66 report: R,
67}
68
69impl<E, R> std::fmt::Debug for NonStrict<E, R>
70where
71 E: std::fmt::Debug,
72{
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 f.debug_struct("NonStrict")
75 .field("inner", &self.inner)
76 .field("report", &std::any::type_name::<R>())
77 .finish()
78 }
79}
80
81impl<E, R> NonStrict<E, R>
82where
83 E: ExpressionInfo,
84 R: EvalErrorReport,
85{
86 pub fn new(inner: E, report: R) -> Self {
87 Self { inner, report }
88 }
89}
90
91impl<E, R> ExpressionInfo for NonStrict<E, R>
92where
93 E: ExpressionInfo,
94 R: EvalErrorReport,
95{
96 fn return_type(&self) -> DataType {
97 self.inner.return_type()
98 }
99
100 fn input_ref_index(&self) -> Option<usize> {
101 self.inner.input_ref_index()
102 }
103}
104
105macro_rules! non_strict_eval_array {
106 ($mode:ident, $this:expr, $input:expr) => {{
107 Ok(match forward!($mode, $this.inner, eval($input)) {
108 Ok(array) => array,
109 Err(ExprError::Multiple(array, errors)) => {
110 for error in errors {
111 $this.report.report(error);
112 }
113 array
114 }
115 Err(e) => {
116 $this.report.report(e);
117 let mut builder = $this.return_type().create_array_builder($input.capacity());
118 builder.append_n_null($input.capacity());
119 builder.finish().into()
120 }
121 })
122 }};
123}
124
125macro_rules! non_strict_eval_value {
126 ($mode:ident, $this:expr, $input:expr) => {{
127 Ok(match forward!($mode, $this.inner, eval_v2($input)) {
128 Ok(array) => array,
129 Err(ExprError::Multiple(array, errors)) => {
130 for error in errors {
131 $this.report.report(error);
132 }
133 array.into()
134 }
135 Err(e) => {
136 $this.report.report(e);
137 ValueImpl::Scalar {
138 value: None,
139 capacity: $input.capacity(),
140 }
141 }
142 })
143 }};
144}
145
146macro_rules! non_strict_eval_row {
147 ($mode:ident, $this:expr, $input:expr) => {{
148 Ok(match forward!($mode, $this.inner, eval_row($input)) {
149 Ok(datum) => datum,
150 Err(error) => {
151 $this.report.report(error);
152 None }
154 })
155 }};
156}
157
158impl<E, R> SyncExpression for NonStrict<E, R>
159where
160 E: SyncExpression,
161 R: EvalErrorReport,
162{
163 fn eval(&self, input: &DataChunk) -> Result<ArrayRef> {
164 non_strict_eval_array!(sync, self, input)
165 }
166
167 fn eval_v2(&self, input: &DataChunk) -> Result<ValueImpl> {
168 non_strict_eval_value!(sync, self, input)
169 }
170
171 fn eval_row(&self, input: &OwnedRow) -> Result<Datum> {
173 non_strict_eval_row!(sync, self, input)
174 }
175
176 fn eval_const(&self) -> Result<Datum> {
177 self.inner.eval_const() }
179}
180
181impl<E, R> AsyncExpression for NonStrict<E, R>
182where
183 E: AsyncExpression,
184 R: EvalErrorReport,
185{
186 async fn eval(&self, input: &DataChunk) -> Result<ArrayRef> {
187 non_strict_eval_array!(async, self, input)
188 }
189
190 async fn eval_v2(&self, input: &DataChunk) -> Result<ValueImpl> {
191 non_strict_eval_value!(async, self, input)
192 }
193
194 async fn eval_row(&self, input: &OwnedRow) -> Result<Datum> {
196 non_strict_eval_row!(async, self, input)
197 }
198}