• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gluesql / gluesql / 27895806754

21 Jun 2026 06:20AM UTC coverage: 98.637% (-0.07%) from 98.711%
27895806754

push

github

web-flow
Convert core and native storages to sync execution (#1928)

GlueSQL's async support has mostly been driven by browser-facing storage constraints such as IndexedDB, rather than by the core execution model itself.

That async boundary ended up spreading through the planner, executor, storage traits, CLI, examples, tests, and native storage implementations. For Rust users and native storages, this added futures/stream plumbing and async dependencies even when the underlying work was synchronous or backed by synchronous APIs.

With the JavaScript and Python packages being split out of this workspace, this PR makes the Rust core synchronous again and keeps browser/package-specific async concerns out of the core storage contract.

2100 of 2147 new or added lines in 141 files covered. (97.81%)

18 existing lines in 9 files now uncovered.

44000 of 44608 relevant lines covered (98.64%)

77908.96 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.15
/core/src/executor/evaluate.rs
1
mod error;
2
mod evaluated;
3
mod expr;
4
mod function;
5

6
use {
7
    self::function::BreakCase,
8
    super::{
9
        context::{AggregateValues, RowContext},
10
        select::select,
11
    },
12
    crate::{
13
        data::{CustomFunction, Interval, Row, Value},
14
        mock::MockStorage,
15
        plan::{ExprPlan, FunctionPlan, ProjectionPlan, SetExprPlan, plan_scalar_expr},
16
        result::{Error, Result},
17
        store::GStore,
18
    },
19
    chrono::prelude::Utc,
20
    std::{borrow::Cow, ops::ControlFlow, rc::Rc},
21
};
22

23
pub use {error::EvaluateError, evaluated::Evaluated};
24

25
pub fn evaluate<'a, 'b, T>(
121,380✔
26
    storage: &'a T,
121,380✔
27
    context: Option<&Rc<RowContext<'b>>>,
121,380✔
28
    aggregated: Option<&Rc<AggregateValues>>,
121,380✔
29
    expr: &'a ExprPlan,
121,380✔
30
) -> Result<Evaluated<'a>>
121,380✔
31
where
121,380✔
32
    'b: 'a,
121,380✔
33
    T: GStore,
121,380✔
34
{
35
    evaluate_inner(Some(storage), context, aggregated, expr)
121,380✔
36
}
121,380✔
37

38
pub fn evaluate_stateless<'a, 'b: 'a>(
3,044,615✔
39
    context: Option<RowContext<'b>>,
3,044,615✔
40
    expr: &'a ExprPlan,
3,044,615✔
41
) -> Result<Evaluated<'a>> {
3,044,615✔
42
    let context = context.map(Rc::new);
3,044,615✔
43
    let storage: Option<&MockStorage> = None;
3,044,615✔
44

45
    evaluate_inner(storage, context.as_ref(), None, expr)
3,044,615✔
46
}
3,044,615✔
47

48
fn evaluate_inner<'a, 'b, T>(
3,772,199✔
49
    storage: Option<&'a T>,
3,772,199✔
50
    context: Option<&Rc<RowContext<'b>>>,
3,772,199✔
51
    aggregated: Option<&Rc<AggregateValues>>,
3,772,199✔
52
    expr: &'a ExprPlan,
3,772,199✔
53
) -> Result<Evaluated<'a>>
3,772,199✔
54
where
3,772,199✔
55
    'b: 'a,
3,772,199✔
56
    T: GStore,
3,772,199✔
57
{
58
    let eval = |expr| evaluate_inner(storage, context, aggregated, expr);
3,772,199✔
59

60
    match expr {
3,772,199✔
61
        ExprPlan::Literal(literal) => Ok(expr::literal(literal)),
2,957,671✔
62
        ExprPlan::Value(value) => Ok(Evaluated::Value(Cow::Borrowed(value))),
205,869✔
63
        ExprPlan::TypedString { data_type, value } => expr::typed_string(data_type, value),
20,305✔
64
        ExprPlan::Identifier(ident) => {
101,518✔
65
            let context = context
101,518✔
66
                .ok_or_else(|| EvaluateError::IdentifierRequiresRowContext(ident.to_owned()))?;
101,518✔
67

68
            match context.get_value(ident) {
100,244✔
69
                Some(value) => Ok(Evaluated::Value(Cow::Owned(value.clone()))),
100,202✔
70
                None => Err(EvaluateError::IdentifierNotFound(ident.to_owned()).into()),
42✔
71
            }
72
        }
73
        ExprPlan::Nested(expr) => eval(expr),
8,030✔
74
        ExprPlan::CompoundIdentifier { alias, ident } => {
66,682✔
75
            let context =
65,408✔
76
                context.ok_or_else(|| EvaluateError::CompoundIdentifierRequiresRowContext {
66,682✔
77
                    alias: alias.to_owned(),
1,274✔
78
                    ident: ident.to_owned(),
1,274✔
79
                })?;
1,274✔
80

81
            match context.get_alias_value(alias, ident) {
65,408✔
82
                Some(value) => Ok(Evaluated::Value(Cow::Owned(value.clone()))),
65,394✔
83
                None => Err(EvaluateError::CompoundIdentifierNotFound {
14✔
84
                    table_alias: alias.to_owned(),
14✔
85
                    column_name: ident.to_owned(),
14✔
86
                }
14✔
87
                .into()),
14✔
88
            }
89
        }
90
        ExprPlan::Subquery(query) => {
2,945✔
91
            let storage = storage.ok_or(EvaluateError::SubqueryNotAllowedInStatelessExpr)?;
2,945✔
92
            if let SetExprPlan::Select(select) = &query.body
1,671✔
93
                && matches!(select.projection, ProjectionPlan::SchemalessMap)
1,671✔
94
            {
95
                return Err(EvaluateError::SchemalessProjectionForSubQuery.into());
28✔
96
            }
1,643✔
97

98
            let evaluations = select(storage, query, context.cloned())?
1,643✔
99
                .map(|row| {
1,643✔
100
                    let values = row?.into_values();
1,573✔
101
                    if values.len() > 1 {
1,573✔
102
                        return Err(EvaluateError::MoreThanOneColumnReturned.into());
14✔
103
                    }
1,559✔
104
                    let value = values.into_iter().next();
1,559✔
105

106
                    Ok::<_, Error>(value)
1,559✔
107
                })
1,573✔
108
                .take(2)
1,643✔
109
                .collect::<Result<Vec<_>>>()?;
1,643✔
110

111
            if evaluations.len() > 1 {
1,629✔
112
                return Err(EvaluateError::MoreThanOneRowReturned.into());
14✔
113
            }
1,615✔
114

115
            let value = evaluations
1,615✔
116
                .into_iter()
1,615✔
117
                .next()
1,615✔
118
                .flatten()
1,615✔
119
                .unwrap_or(Value::Null);
1,615✔
120

121
            Ok(Evaluated::Value(Cow::Owned(value)))
1,615✔
122
        }
123
        ExprPlan::BinaryOp { op, left, right } => {
73,239✔
124
            let left = eval(left)?;
73,239✔
125
            let right = eval(right)?;
73,085✔
126

127
            expr::binary_op(op, left, right)
72,903✔
128
        }
129
        ExprPlan::UnaryOp { op, expr } => {
78,586✔
130
            let v = eval(expr)?;
78,586✔
131

132
            expr::unary_op(op, v)
78,586✔
133
        }
134
        ExprPlan::Aggregate(aggr) => match aggregated
1,982✔
135
            .as_ref()
1,982✔
136
            .and_then(|aggregated| aggr.slot.and_then(|slot| aggregated.get(slot)))
1,982✔
137
        {
138
            Some(value) => Ok(Evaluated::Value(Cow::Owned(value.clone()))),
1,980✔
139
            None if aggr.slot.is_none() => {
2✔
140
                Err(EvaluateError::UnplannedAggregate(aggr.clone()).into())
1✔
141
            }
142
            None => Err(EvaluateError::AggregateSlotValueMissing(aggr.clone()).into()),
1✔
143
        },
144
        ExprPlan::Function(func) => evaluate_function(storage, context, aggregated, func),
196,175✔
145
        ExprPlan::InList {
146
            expr,
8,218✔
147
            list,
8,218✔
148
            negated,
8,218✔
149
        } => {
150
            let negated = *negated;
8,218✔
151
            let target = eval(expr)?;
8,218✔
152

153
            if target.is_null() {
8,218✔
154
                return Ok(target);
28✔
155
            }
8,190✔
156

157
            let matched = list
8,190✔
158
                .iter()
8,190✔
159
                .map(eval)
8,190✔
160
                .collect::<Result<Vec<_>>>()?
8,190✔
161
                .into_iter()
8,190✔
162
                .any(|v| v.evaluate_eq(&target).is_true());
14,532✔
163

164
            Ok(Evaluated::Value(Cow::Owned(Value::Bool(matched ^ negated))))
8,190✔
165
        }
166
        ExprPlan::InSubquery {
167
            expr: target_expr,
2,441✔
168
            subquery,
2,441✔
169
            negated,
2,441✔
170
        } => {
171
            let storage = storage.ok_or(EvaluateError::InSubqueryNotAllowedInStatelessExpr)?;
2,441✔
172
            if let SetExprPlan::Select(select) = &subquery.body
1,167✔
173
                && matches!(select.projection, ProjectionPlan::SchemalessMap)
1,167✔
174
            {
175
                return Err(EvaluateError::SchemalessProjectionForInSubQuery.into());
28✔
176
            }
1,139✔
177
            let target = eval(target_expr)?;
1,139✔
178

179
            let mut matched = false;
1,139✔
180
            for row in select(storage, subquery, context.cloned())? {
1,825✔
181
                let value = row?.into_values().into_iter().next().unwrap_or(Value::Null);
1,825✔
182
                let evaluated = Evaluated::Value(Cow::Owned(value));
1,825✔
183

184
                if evaluated.evaluate_eq(&target).is_true() {
1,825✔
185
                    matched = true;
547✔
186
                    break;
547✔
187
                }
1,278✔
188
            }
189

190
            Ok(Evaluated::Value(Cow::Owned(Value::Bool(matched ^ negated))))
1,139✔
191
        }
192
        ExprPlan::Between {
193
            expr,
3,164✔
194
            negated,
3,164✔
195
            low,
3,164✔
196
            high,
3,164✔
197
        } => {
198
            let target = eval(expr)?;
3,164✔
199
            let low = eval(low)?;
3,164✔
200
            let high = eval(high)?;
3,164✔
201

202
            Ok(expr::between(&target, *negated, &low, &high))
3,164✔
203
        }
204
        ExprPlan::Like {
205
            expr,
4,914✔
206
            negated,
4,914✔
207
            pattern,
4,914✔
208
        } => {
209
            let target = eval(expr)?;
4,914✔
210
            let pattern = eval(pattern)?;
4,914✔
211
            let evaluated = target.like(pattern, true)?;
4,914✔
212

213
            Ok(match negated {
4,886✔
214
                true => {
215
                    let t =
1,456✔
216
                        evaluated.evaluate_eq(&Evaluated::Value(Cow::Owned(Value::Bool(false))));
1,456✔
217
                    Evaluated::Value(Cow::Owned(Value::from(t)))
1,456✔
218
                }
219
                false => evaluated,
3,430✔
220
            })
221
        }
222
        ExprPlan::ILike {
223
            expr,
3,220✔
224
            negated,
3,220✔
225
            pattern,
3,220✔
226
        } => {
227
            let target = eval(expr)?;
3,220✔
228
            let pattern = eval(pattern)?;
3,220✔
229
            let evaluated = target.like(pattern, false)?;
3,220✔
230

231
            Ok(match negated {
3,192✔
232
                true => {
233
                    let t =
1,456✔
234
                        evaluated.evaluate_eq(&Evaluated::Value(Cow::Owned(Value::Bool(false))));
1,456✔
235
                    Evaluated::Value(Cow::Owned(Value::from(t)))
1,456✔
236
                }
237
                false => evaluated,
1,736✔
238
            })
239
        }
240
        ExprPlan::Exists { subquery, negated } => {
1,328✔
241
            let storage = storage.ok_or(EvaluateError::ExistsSubqueryNotAllowedInStatelessExpr)?;
1,328✔
242

243
            let exists = select(storage, subquery, context.cloned())?
145✔
244
                .next()
145✔
245
                .transpose()?
145✔
246
                .is_some();
145✔
247

248
            Ok(Evaluated::Value(Cow::Owned(Value::Bool(exists ^ negated))))
145✔
249
        }
250
        ExprPlan::IsNull(expr) => {
3,534✔
251
            let v = eval(expr)?.is_null();
3,534✔
252

253
            Ok(Evaluated::Value(Cow::Owned(Value::Bool(v))))
3,534✔
254
        }
255
        ExprPlan::IsNotNull(expr) => {
3,011✔
256
            let v = eval(expr)?.is_null();
3,011✔
257

258
            Ok(Evaluated::Value(Cow::Owned(Value::Bool(!v))))
3,011✔
259
        }
260
        ExprPlan::Case {
261
            operand,
383✔
262
            when_then,
383✔
263
            else_result,
383✔
264
        } => {
265
            let operand = match operand {
383✔
266
                Some(op) => eval(op)?,
103✔
267
                None => Evaluated::Value(Cow::Owned(Value::Bool(true))),
280✔
268
            };
269

270
            for (when, then) in when_then {
565✔
271
                let when = eval(when)?;
565✔
272

273
                if when.evaluate_eq(&operand).is_true() {
565✔
274
                    return eval(then);
254✔
275
                }
311✔
276
            }
277

278
            match else_result {
129✔
279
                Some(er) => eval(er),
73✔
280
                None => Ok(Evaluated::Value(Cow::Owned(Value::Null))),
56✔
281
            }
282
        }
283
        ExprPlan::ArrayIndex { obj, indexes } => {
1,386✔
284
            let obj = eval(obj)?;
1,386✔
285
            let indexes = indexes.iter().map(eval).collect::<Result<Vec<_>>>()?;
1,386✔
286
            expr::array_index(obj, indexes)
1,386✔
287
        }
288
        ExprPlan::Array { elem } => elem
7,672✔
289
            .iter()
7,672✔
290
            .map(eval)
7,672✔
291
            .collect::<Result<Vec<_>>>()?
7,672✔
292
            .into_iter()
7,672✔
293
            .map(Value::try_from)
7,672✔
294
            .collect::<Result<Vec<_>>>()
7,672✔
295
            .map(Value::List)
7,672✔
296
            .map(|v| Evaluated::Value(Cow::Owned(v))),
7,672✔
297
        ExprPlan::Interval {
298
            expr,
19,926✔
299
            leading_field,
19,926✔
300
            last_field,
19,926✔
301
        } => {
302
            let value = eval(expr).and_then(Value::try_from).map(String::from)?;
19,926✔
303

304
            Interval::try_from_str(&value, *leading_field, *last_field)
19,926✔
305
                .map(Value::Interval)
19,926✔
306
                .map(|v| Evaluated::Value(Cow::Owned(v)))
19,926✔
307
        }
308
    }
309
}
3,772,199✔
310

311
fn evaluate_function<'a, 'b: 'a, T: GStore>(
196,175✔
312
    storage: Option<&'a T>,
196,175✔
313
    context: Option<&Rc<RowContext<'b>>>,
196,175✔
314
    aggregated: Option<&Rc<AggregateValues>>,
196,175✔
315
    func: &'a FunctionPlan,
196,175✔
316
) -> Result<Evaluated<'a>> {
196,175✔
317
    use function as f;
318

319
    let eval = |expr| evaluate_inner(storage, context, aggregated, expr);
274,791✔
320

321
    let name = func.to_string();
196,175✔
322

323
    let result = match func {
196,175✔
324
        // --- text ---
325
        FunctionPlan::Concat(exprs) => {
98✔
326
            let exprs = exprs.iter().map(eval).collect::<Result<Vec<_>>>()?;
98✔
327
            f::concat(exprs)
84✔
328
        }
329
        FunctionPlan::Custom { name, exprs } => {
100✔
330
            let CustomFunction {
331
                func_name,
7✔
332
                args,
7✔
333
                body,
7✔
334
            } = storage
100✔
335
                .ok_or(EvaluateError::UnsupportedCustomFunction)?
100✔
336
                .fetch_function(name)?
9✔
337
                .ok_or_else(|| EvaluateError::UnsupportedFunction(name.clone()))?;
7✔
338

339
            let min = args.iter().filter(|arg| arg.default.is_none()).count();
14✔
340
            let max = args.len();
7✔
341

342
            if !(min..=max).contains(&exprs.len()) {
7✔
343
                return Err((EvaluateError::FunctionArgsLengthNotWithinRange {
2✔
344
                    name: func_name.to_owned(),
2✔
345
                    expected_minimum: min,
2✔
346
                    expected_maximum: max,
2✔
347
                    found: exprs.len(),
2✔
348
                })
2✔
349
                .into());
2✔
350
            }
5✔
351

352
            let mut pairs = Vec::with_capacity(args.len());
5✔
353
            for (index, arg) in args.iter().enumerate() {
10✔
354
                let value = if let Some(expr) = exprs.get(index) {
10✔
355
                    eval(expr)?.try_into_value(&arg.data_type, true)
7✔
356
                } else {
357
                    let default = arg.default.as_ref().ok_or_else(|| {
3✔
358
                        EvaluateError::FunctionArgsLengthNotWithinRange {
×
359
                            name: func_name.to_owned(),
×
360
                            expected_minimum: min,
×
361
                            expected_maximum: max,
×
362
                            found: exprs.len(),
×
363
                        }
×
364
                    })?;
×
365
                    let default = plan_scalar_expr(default.clone());
3✔
366

367
                    evaluate_inner(storage, context, aggregated, &default)?
3✔
368
                        .try_into_value(&arg.data_type, true)
3✔
UNCOV
369
                }?;
×
370

371
                pairs.push((arg.name.clone(), value));
10✔
372
            }
373

374
            let (columns, values): (Vec<_>, Vec<_>) = pairs.into_iter().unzip();
5✔
375
            let row = Cow::Owned(Row {
5✔
376
                columns: columns.into(),
5✔
377
                values,
5✔
378
            });
5✔
379
            let context = RowContext::new(name, row, None);
5✔
380
            let context = Some(Rc::new(context));
5✔
381

382
            let body = plan_scalar_expr(body.clone());
5✔
383
            let evaluated = evaluate_inner(storage, context.as_ref(), None, &body)?;
5✔
384
            let value = evaluated.try_into()?;
5✔
385

386
            return Ok(Evaluated::Value(Cow::Owned(value)));
5✔
387
        }
388
        FunctionPlan::ConcatWs { separator, exprs } => {
1,372✔
389
            let separator = eval(separator)?;
1,372✔
390
            let exprs = exprs.iter().map(eval).collect::<Result<Vec<_>>>()?;
1,372✔
391
            f::concat_ws(&name, separator, exprs)
1,372✔
392
        }
393
        FunctionPlan::IfNull { expr, then } => f::ifnull(eval(expr)?, eval(then)?),
2,926✔
394
        FunctionPlan::NullIf { expr1, expr2 } => f::nullif(eval(expr1)?, &eval(expr2)?),
84✔
395
        FunctionPlan::Lower(expr) => f::lower(&name, eval(expr)?),
3,052✔
396
        FunctionPlan::Initcap(expr) => f::initcap(&name, eval(expr)?),
140✔
397
        FunctionPlan::Upper(expr) => f::upper(&name, eval(expr)?),
2,856✔
398
        FunctionPlan::Left { expr, size } | FunctionPlan::Right { expr, size } => {
2,716✔
399
            let expr = eval(expr)?;
4,074✔
400
            let size = eval(size)?;
4,074✔
401

402
            f::left_or_right(&name, expr, size)
4,074✔
403
        }
404
        FunctionPlan::Replace { expr, old, new } => {
1,330✔
405
            let expr = eval(expr)?;
1,330✔
406
            let old = eval(old)?;
1,330✔
407
            let new = eval(new)?;
1,330✔
408

409
            f::replace(&name, expr, old, new)
1,330✔
410
        }
411
        FunctionPlan::Lpad { expr, size, fill } | FunctionPlan::Rpad { expr, size, fill } => {
9,058✔
412
            let expr = eval(expr)?;
15,568✔
413
            let size = eval(size)?;
15,568✔
414
            let fill = match fill {
15,568✔
415
                Some(v) => Some(eval(v)?),
5,320✔
416
                None => None,
10,248✔
417
            };
418

419
            f::lpad_or_rpad(&name, expr, size, fill)
15,568✔
420
        }
421
        FunctionPlan::LastDay(expr) => {
3,850✔
422
            let expr = eval(expr)?;
3,850✔
423
            f::last_day(&name, expr)
3,850✔
424
        }
425
        FunctionPlan::Trim {
426
            expr,
3,080✔
427
            filter_chars,
3,080✔
428
            trim_where_field,
3,080✔
429
        } => {
430
            let expr = eval(expr)?;
3,080✔
431
            let filter_chars = match filter_chars {
3,080✔
432
                Some(v) => Some(eval(v)?),
1,652✔
433
                None => None,
1,428✔
434
            };
435

436
            return expr.trim(name, filter_chars, trim_where_field.as_ref());
3,080✔
437
        }
438
        FunctionPlan::Ltrim { expr, chars } => {
5,320✔
439
            let expr = eval(expr)?;
5,320✔
440
            let chars = match chars {
5,320✔
441
                Some(v) => Some(eval(v)?),
2,688✔
442
                None => None,
2,632✔
443
            };
444

445
            return expr.ltrim(name, chars);
5,320✔
446
        }
447
        FunctionPlan::Rtrim { expr, chars } => {
5,376✔
448
            let expr = eval(expr)?;
5,376✔
449
            let chars = match chars {
5,376✔
450
                Some(v) => Some(eval(v)?),
2,772✔
451
                None => None,
2,604✔
452
            };
453

454
            return expr.rtrim(name, chars);
5,376✔
455
        }
456
        FunctionPlan::Reverse(expr) => {
1,316✔
457
            let expr = eval(expr)?;
1,316✔
458

459
            f::reverse(&name, expr)
1,316✔
460
        }
461
        FunctionPlan::Repeat { expr, num } => {
1,330✔
462
            let expr = eval(expr)?;
1,330✔
463
            let num = eval(num)?;
1,330✔
464

465
            f::repeat(&name, expr, num)
1,330✔
466
        }
467
        FunctionPlan::Substr { expr, start, count } => {
9,297✔
468
            let expr = eval(expr)?;
9,297✔
469
            let start = eval(start)?;
9,297✔
470
            let count = match count {
9,297✔
471
                Some(v) => Some(eval(v)?),
1,947✔
472
                None => None,
7,350✔
473
            };
474

475
            return expr.substr(name, start, count);
9,297✔
476
        }
477
        FunctionPlan::Ascii(expr) => f::ascii(&name, eval(expr)?),
17,990✔
478
        FunctionPlan::Chr(expr) => f::chr(&name, eval(expr)?),
17,920✔
479
        FunctionPlan::Md5(expr) => f::md5(&name, eval(expr)?),
3,822✔
480
        FunctionPlan::Hex(expr) => f::hex(&name, eval(expr)?),
11,466✔
481

482
        // --- float ---
483
        FunctionPlan::Abs(expr) => f::abs(&name, eval(expr)?),
336✔
484
        FunctionPlan::Sign(expr) => f::sign(&name, eval(expr)?),
224✔
485
        FunctionPlan::Sqrt(expr) => f::sqrt(eval(expr)?),
84✔
486
        FunctionPlan::Power { expr, power } => {
154✔
487
            let expr = eval(expr)?;
154✔
488
            let power = eval(power)?;
154✔
489

490
            f::power(&name, expr, power)
154✔
491
        }
492
        FunctionPlan::Ceil(expr) => f::ceil(&name, eval(expr)?),
224✔
493
        FunctionPlan::Rand(expr) => {
2,632✔
494
            let expr = match expr {
2,632✔
495
                Some(v) => Some(eval(v)?),
1,358✔
496
                None => None,
1,274✔
497
            };
498

499
            f::rand(&name, expr)
2,632✔
500
        }
501
        FunctionPlan::Round(expr) => f::round(&name, eval(expr)?),
2,772✔
502
        FunctionPlan::Trunc(expr) => f::trunc(&name, eval(expr)?),
224✔
503
        FunctionPlan::Floor(expr) => f::floor(&name, eval(expr)?),
224✔
504
        FunctionPlan::Radians(expr) => f::radians(&name, eval(expr)?),
252✔
505
        FunctionPlan::Degrees(expr) => f::degrees(&name, eval(expr)?),
224✔
506
        FunctionPlan::Pi() => {
507
            return Ok(Evaluated::Value(Cow::Owned(Value::F64(
56✔
508
                std::f64::consts::PI,
56✔
509
            ))));
56✔
510
        }
511
        FunctionPlan::Exp(expr) => f::exp(&name, eval(expr)?),
70✔
512
        FunctionPlan::Log { antilog, base } => {
98✔
513
            let antilog = eval(antilog)?;
98✔
514
            let base = eval(base)?;
98✔
515

516
            f::log(&name, antilog, base)
98✔
517
        }
518
        FunctionPlan::Ln(expr) => f::ln(&name, eval(expr)?),
70✔
519
        FunctionPlan::Log2(expr) => f::log2(&name, eval(expr)?),
70✔
520
        FunctionPlan::Log10(expr) => f::log10(&name, eval(expr)?),
70✔
521
        FunctionPlan::Sin(expr) => f::sin(&name, eval(expr)?),
84✔
522
        FunctionPlan::Cos(expr) => f::cos(&name, eval(expr)?),
84✔
523
        FunctionPlan::Tan(expr) => f::tan(&name, eval(expr)?),
84✔
524
        FunctionPlan::Asin(expr) => f::asin(&name, eval(expr)?),
56✔
525
        FunctionPlan::Acos(expr) => f::acos(&name, eval(expr)?),
70✔
526
        FunctionPlan::Atan(expr) => f::atan(&name, eval(expr)?),
1,344✔
527

528
        // --- integer ---
529
        FunctionPlan::Div { dividend, divisor } => {
1,610✔
530
            let dividend = eval(dividend)?;
1,610✔
531
            let divisor = eval(divisor)?;
1,610✔
532

533
            f::div(&name, dividend, divisor)
1,610✔
534
        }
535
        FunctionPlan::Mod { dividend, divisor } => {
1,568✔
536
            let dividend = eval(dividend)?;
1,568✔
537
            let divisor = eval(divisor)?;
1,568✔
538

539
            return dividend.modulo(&divisor);
1,568✔
540
        }
541
        FunctionPlan::Gcd { left, right } => {
5,362✔
542
            let left = eval(left)?;
5,362✔
543
            let right = eval(right)?;
5,362✔
544

545
            f::gcd(&name, left, right)
5,362✔
546
        }
547
        FunctionPlan::Lcm { left, right } => {
5,362✔
548
            let left = eval(left)?;
5,362✔
549
            let right = eval(right)?;
5,362✔
550

551
            f::lcm(&name, left, right)
5,362✔
552
        }
553

554
        // --- spatial ---
555
        FunctionPlan::Point { x, y } => {
6,440✔
556
            let x = eval(x)?;
6,440✔
557
            let y = eval(y)?;
6,440✔
558

559
            f::point(&name, x, y)
6,440✔
560
        }
561
        FunctionPlan::GetX(expr) => f::get_x(&name, eval(expr)?),
56✔
562
        FunctionPlan::GetY(expr) => f::get_y(&name, eval(expr)?),
56✔
563
        FunctionPlan::CalcDistance {
564
            geometry1,
42✔
565
            geometry2,
42✔
566
        } => {
567
            let geometry1 = eval(geometry1)?;
42✔
568
            let geometry2 = eval(geometry2)?;
42✔
569

570
            f::calc_distance(&name, geometry1, geometry2)
42✔
571
        }
572

573
        // --- etc ---
574
        FunctionPlan::Unwrap { expr, selector } => {
1,750✔
575
            let expr = eval(expr)?;
1,750✔
576
            let selector = eval(selector)?;
1,750✔
577

578
            f::unwrap(&name, expr, selector)
1,750✔
579
        }
580
        FunctionPlan::GenerateUuid() => return Ok(f::generate_uuid()),
8,947✔
581
        FunctionPlan::Greatest(exprs) => {
112✔
582
            let exprs = exprs.iter().map(eval).collect::<Result<Vec<_>>>()?;
112✔
583
            return f::greatest(&name, exprs);
112✔
584
        }
585
        FunctionPlan::Now() | FunctionPlan::CurrentTimestamp() => {
586
            return Ok(Evaluated::Value(Cow::Owned(Value::Timestamp(
5,238✔
587
                Utc::now().naive_utc(),
5,238✔
588
            ))));
5,238✔
589
        }
590
        FunctionPlan::CurrentDate() => {
591
            return Ok(Evaluated::Value(Cow::Owned(Value::Date(
2,618✔
592
                Utc::now().date_naive(),
2,618✔
593
            ))));
2,618✔
594
        }
595
        FunctionPlan::CurrentTime() => {
596
            return Ok(Evaluated::Value(Cow::Owned(Value::Time(Utc::now().time()))));
3,864✔
597
        }
598
        FunctionPlan::Format { expr, format } => {
1,540✔
599
            let expr = eval(expr)?;
1,540✔
600
            let format = eval(format)?;
1,540✔
601

602
            f::format(&name, expr, format)
1,540✔
603
        }
604
        FunctionPlan::ToDate { expr, format } => {
1,442✔
605
            let expr = eval(expr)?;
1,442✔
606
            let format = eval(format)?;
1,442✔
607
            f::to_date(&name, expr, format)
1,442✔
608
        }
609
        FunctionPlan::ToTimestamp { expr, format } => {
1,442✔
610
            let expr = eval(expr)?;
1,442✔
611
            let format = eval(format)?;
1,442✔
612
            f::to_timestamp(&name, expr, format)
1,442✔
613
        }
614
        FunctionPlan::ToTime { expr, format } => {
1,372✔
615
            let expr = eval(expr)?;
1,372✔
616
            let format = eval(format)?;
1,372✔
617
            f::to_time(&name, expr, format)
1,372✔
618
        }
619
        FunctionPlan::Position {
620
            from_expr,
1,345✔
621
            sub_expr,
1,345✔
622
        } => {
623
            let from_expr = eval(from_expr)?;
1,345✔
624
            let sub_expr = eval(sub_expr)?;
1,345✔
625
            f::position(from_expr, sub_expr)
1,345✔
626
        }
627
        FunctionPlan::FindIdx {
628
            from_expr,
3,977✔
629
            sub_expr,
3,977✔
630
            start,
3,977✔
631
        } => {
632
            let from_expr = eval(from_expr)?;
3,977✔
633
            let sub_expr = eval(sub_expr)?;
3,977✔
634
            let start = match start {
3,977✔
635
                Some(idx) => Some(eval(idx)?),
2,618✔
636
                None => None,
1,359✔
637
            };
638
            f::find_idx(&name, from_expr, sub_expr, start)
3,977✔
639
        }
640
        FunctionPlan::Cast { expr, data_type } => return eval(expr)?.cast(data_type),
10,255✔
641
        FunctionPlan::Extract { field, expr } => {
239✔
642
            let expr = eval(expr)?;
239✔
643
            f::extract(*field, expr)
239✔
644
        }
645
        FunctionPlan::Coalesce(exprs) => {
4,508✔
646
            let exprs = exprs.iter().map(eval).collect::<Result<Vec<_>>>()?;
4,508✔
647
            return f::coalesce(exprs);
4,494✔
648
        }
649

650
        // --- list ---
651
        FunctionPlan::Append { expr, value } => {
1,316✔
652
            let expr = eval(expr)?;
1,316✔
653
            let value = eval(value)?;
1,316✔
654
            f::append(expr, value)
1,316✔
655
        }
656
        FunctionPlan::Prepend { expr, value } => {
1,316✔
657
            let expr = eval(expr)?;
1,316✔
658
            let value = eval(value)?;
1,316✔
659
            f::prepend(expr, value)
1,316✔
660
        }
661
        FunctionPlan::Skip { expr, size } => {
98✔
662
            let expr = eval(expr)?;
98✔
663
            let size = eval(size)?;
98✔
664
            f::skip(&name, expr, size)
98✔
665
        }
666
        FunctionPlan::Sort { expr, order } => {
140✔
667
            let expr = eval(expr)?;
140✔
668
            let order = match order {
140✔
669
                Some(o) => eval(o)?,
98✔
670
                None => Evaluated::Value(Cow::Owned(Value::Str("ASC".to_owned()))),
42✔
671
            };
672
            f::sort(expr, order)
140✔
673
        }
674
        FunctionPlan::Take { expr, size } => {
1,400✔
675
            let expr = eval(expr)?;
1,400✔
676
            let size = eval(size)?;
1,400✔
677
            f::take(&name, expr, size)
1,400✔
678
        }
679
        FunctionPlan::Slice {
680
            expr,
168✔
681
            start,
168✔
682
            length,
168✔
683
        } => {
684
            let expr = eval(expr)?;
168✔
685
            let start = eval(start)?;
168✔
686
            let length = eval(length)?;
168✔
687
            f::slice(&name, expr, start, length)
168✔
688
        }
689
        FunctionPlan::IsEmpty(expr) => {
154✔
690
            let expr = eval(expr)?;
154✔
691
            f::is_empty(expr)
154✔
692
        }
693
        FunctionPlan::AddMonth { expr, size } => {
154✔
694
            let expr = eval(expr)?;
154✔
695
            let size = eval(size)?;
154✔
696
            f::add_month(&name, expr, size)
154✔
697
        }
698
        FunctionPlan::Length(expr) => f::length(&name, eval(expr)?),
131✔
699
        FunctionPlan::Entries(expr) => f::entries(&name, eval(expr)?),
28✔
700
        FunctionPlan::Keys(expr) => f::keys(eval(expr)?),
56✔
701
        FunctionPlan::Values(expr) => {
70✔
702
            let expr = eval(expr)?;
70✔
703
            f::values(expr)
70✔
704
        }
705
        FunctionPlan::Splice {
706
            list_data,
84✔
707
            begin_index,
84✔
708
            end_index,
84✔
709
            values,
84✔
710
        } => {
711
            let list_data = eval(list_data)?;
84✔
712
            let begin_index = eval(begin_index)?;
84✔
713
            let end_index = eval(end_index)?;
84✔
714
            let values = match values {
84✔
715
                Some(v) => Some(eval(v)?),
56✔
716
                None => None,
28✔
717
            };
718
            f::splice(&name, list_data, begin_index, end_index, values)
84✔
719
        }
720
        FunctionPlan::Dedup(list) => f::dedup(eval(list)?),
42✔
721
    };
722

723
    match result {
12,922✔
724
        ControlFlow::Continue(v) => Ok(v),
122,900✔
725
        ControlFlow::Break(BreakCase::Null) => Ok(Evaluated::Value(Cow::Owned(Value::Null))),
5,964✔
726
        ControlFlow::Break(BreakCase::Err(err)) => Err(err),
6,958✔
727
    }
728
}
196,175✔
729

730
#[cfg(test)]
731
mod tests {
732
    use {
733
        super::{EvaluateError, evaluate, evaluate_stateless},
734
        crate::{
735
            ast::{Expr, Projection, SelectItem, SetExpr, Statement},
736
            executor::context::AggregateValues,
737
            mock::MockStorage,
738
            parse_sql::parse,
739
            plan::{AggregateFunctionPlan, AggregatePlan, CountArgExprPlan, ExprPlan},
740
            result::Error,
741
            translate::translate,
742
        },
743
        std::rc::Rc,
744
    };
745

746
    #[test]
747
    fn aggregate_requires_planner_binding() {
1✔
748
        let sql = "SELECT COUNT(*) FROM Item";
1✔
749
        let parsed = parse(sql)
1✔
750
            .expect(sql)
1✔
751
            .into_iter()
1✔
752
            .next()
1✔
753
            .expect("query statement");
1✔
754
        let translated = translate(&parsed).expect("translated statement");
1✔
755

756
        let expr = if let Statement::Query(query) = translated
1✔
757
            && let SetExpr::Select(select) = query.body
1✔
758
            && let Projection::SelectItems(items) = select.projection
1✔
759
            && let Some(SelectItem::Expr { expr, .. }) = items.into_iter().next()
1✔
760
        {
761
            expr
1✔
762
        } else {
763
            panic!("expected SELECT projection expression: {sql}");
×
764
        };
765

766
        let Expr::Aggregate(aggregate) = expr else {
1✔
767
            panic!("expected aggregate expression");
×
768
        };
769

770
        let expr = ExprPlan::Aggregate(Box::new(AggregatePlan::from((*aggregate).clone())));
1✔
771
        let result = evaluate_stateless(None, &expr);
1✔
772

773
        assert_eq!(
1✔
774
            result,
775
            Err(Error::from(EvaluateError::UnplannedAggregate(Box::new(
1✔
776
                AggregatePlan::from(*aggregate)
1✔
777
            ))))
1✔
778
        );
779
    }
1✔
780

781
    #[test]
782
    fn aggregate_slot_value_must_exist() {
1✔
783
        let aggregate = AggregatePlan {
1✔
784
            func: AggregateFunctionPlan::Count(CountArgExprPlan::Wildcard),
1✔
785
            distinct: false,
1✔
786
            slot: Some(0),
1✔
787
        };
1✔
788

789
        let expr = ExprPlan::Aggregate(Box::new(aggregate.clone()));
1✔
790
        let storage = MockStorage::default();
1✔
791
        let aggregated = Rc::new(AggregateValues::new(Vec::new()));
1✔
792

793
        let result = evaluate(&storage, None, Some(&aggregated), &expr);
1✔
794

795
        assert_eq!(
1✔
796
            result,
797
            Err(Error::from(EvaluateError::AggregateSlotValueMissing(
1✔
798
                Box::new(aggregate)
1✔
799
            )))
1✔
800
        );
801
    }
1✔
802
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc