Skip to content

Commit 8afe0fe

Browse files
gatesnlwwmanning
andauthored
Remove var expression (#3829)
Fixes #3671 * Removes the Var expression, leaving instead a `root()` expression for resolving the scope root. * The expression scope can hold context variables, useful for passing in auth tokens for example, but not variables that would impact the return_dtype of the expression. * ScopeDType has therefore been removed, because the dtype of the scope _is_ just the dtype of the root array. * Simplifies some transformation / partitioning logic where vars no longer need to be considered. Signed-off-by: Nicholas Gates <[email protected]> Co-authored-by: Will Manning <[email protected]>
1 parent 42fc2d6 commit 8afe0fe

File tree

61 files changed

+375
-1172
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+375
-1172
lines changed

java/vortex-jni/src/main/java/dev/vortex/api/Expression.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ default <T> T accept(Visitor<T> visitor) {
3434
interface Visitor<T> {
3535
T visitLiteral(Literal<?> literal);
3636

37-
T visitIdentity(Identity identity);
37+
T visitRoot(Root root);
3838

3939
T visitBinary(Binary binary);
4040

java/vortex-jni/src/main/java/dev/vortex/api/expressions/Identity.java

Lines changed: 0 additions & 65 deletions
This file was deleted.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
package dev.vortex.api.expressions;
5+
6+
import dev.vortex.api.Expression;
7+
8+
import java.util.List;
9+
import java.util.Optional;
10+
11+
public final class Root implements Expression {
12+
public static final Root INSTANCE = new Root();
13+
14+
private Root() {}
15+
16+
public static Root parse(byte[] _metadata, List<Expression> children) {
17+
if (!children.isEmpty()) {
18+
throw new IllegalArgumentException("Root expression must have no children, found: " + children.size());
19+
}
20+
return INSTANCE;
21+
}
22+
23+
@Override
24+
public String id() {
25+
return "root";
26+
}
27+
28+
@Override
29+
public List<Expression> children() {
30+
return List.of();
31+
}
32+
33+
@Override
34+
public Optional<byte[]> metadata() {
35+
return Optional.of(new byte[] {});
36+
}
37+
38+
@Override
39+
public String toString() {
40+
return "$";
41+
}
42+
43+
// equals and hashCode depend on address equality to INSTANCE.
44+
45+
@Override
46+
public <T> T accept(Visitor<T> visitor) {
47+
return visitor.visitRoot(this);
48+
}
49+
}

java/vortex-jni/src/main/java/dev/vortex/api/proto/Expressions.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ public static Expression deserialize(ExprProtos.Expr expr) {
4242
return Binary.parse(metadata, children);
4343
case "get_item":
4444
return GetItem.parse(metadata, children);
45-
case "var":
46-
return Identity.parse(metadata, children);
45+
case "root":
46+
return Root.parse(metadata, children);
4747
case "literal":
4848
return Literal.parse(metadata, children);
4949
case "not":

java/vortex-jni/src/test/java/dev/vortex/api/TestMinimal.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77

88
import dev.vortex.api.expressions.Binary;
99
import dev.vortex.api.expressions.GetItem;
10-
import dev.vortex.api.expressions.Identity;
10+
import dev.vortex.api.expressions.Root;
1111
import dev.vortex.api.expressions.Literal;
1212
import java.math.BigDecimal;
1313
import java.util.ArrayList;
1414
import java.util.List;
1515
import java.util.Map;
1616
import java.util.Objects;
17+
1718
import org.junit.jupiter.api.Test;
1819

1920
public final class TestMinimal {
@@ -159,7 +160,7 @@ public Person readRow(Array[] fields, int idx) {
159160
public void testProjectedScanWithFilter() {
160161
var filterOptions = ScanOptions.builder()
161162
.addColumns("State", "Salary", "Name")
162-
.predicate(Binary.eq(GetItem.of(Identity.INSTANCE, "State"), Literal.string("VA")))
163+
.predicate(Binary.eq(GetItem.of(Root.INSTANCE, "State"), Literal.string("VA")))
163164
.build();
164165

165166
try (var file = Files.open(MINIMAL_PATH);

java/vortex-jni/src/test/java/dev/vortex/api/expressions/proto/TestExpressionProtos.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ public final class TestExpressionProtos {
1515
@Test
1616
public void testRoundTrip() {
1717
Expression expression = Binary.and(
18-
GetItem.of(Identity.INSTANCE, "a.b.c"),
19-
Binary.or(Identity.INSTANCE, Not.of(Literal.bool(null)), Literal.bool(false)),
18+
GetItem.of(Root.INSTANCE, "a.b.c"),
19+
Binary.or(Root.INSTANCE, Not.of(Literal.bool(null)), Literal.bool(false)),
2020
Binary.eq(Literal.bool(true), Not.of(Literal.bool(false))));
2121
ExprProtos.Expr proto = Expressions.serialize(expression);
2222
Expression deserialized = Expressions.deserialize(proto);

vortex-array/src/arrays/struct_/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,17 @@ impl StructArray {
9191
struct_dtype
9292
}
9393

94+
/// Create a new `StructArray` with the given length, but without any fields.
95+
pub fn new_with_len(len: usize) -> Self {
96+
Self::try_new(
97+
FieldNames::default(),
98+
Vec::new(),
99+
len,
100+
Validity::NonNullable,
101+
)
102+
.vortex_expect("StructArray::new_with_len should not fail")
103+
}
104+
94105
pub fn try_new(
95106
names: FieldNames,
96107
fields: Vec<ArrayRef>,

vortex-expr/src/analysis.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

44
use vortex_array::stats::Stat;
5+
use vortex_dtype::FieldPath;
56

6-
use crate::{AccessPath, ExprRef};
7+
use crate::ExprRef;
78

89
pub trait StatsCatalog {
9-
/// Given an id, field and stat return an expression that when evaluated will return that stat
10-
/// this would be a column reference or a literal value, if the value is known at planning time.
11-
fn stats_ref(&mut self, _access_path: &AccessPath, _stat: Stat) -> Option<ExprRef> {
10+
/// Given a field path and statist, return an expression that when evaluated over the catalog
11+
/// will return that stat for the referenced field.
12+
///
13+
/// This is likely to be a column expression, or a literal.
14+
///
15+
/// Returns `None` if the stat is not available for the field path.
16+
fn stats_ref(&mut self, _field_path: &FieldPath, _stat: Stat) -> Option<ExprRef> {
1217
None
1318
}
1419
}
@@ -56,7 +61,7 @@ pub trait AnalysisExpr {
5661
None
5762
}
5863

59-
fn field_path(&self) -> Option<AccessPath> {
64+
fn field_path(&self) -> Option<FieldPath> {
6065
None
6166
}
6267

vortex-expr/src/exprs/between.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ use vortex_error::{VortexResult, vortex_bail};
1111
use vortex_proto::expr as pb;
1212

1313
use crate::{
14-
AnalysisExpr, BinaryExpr, ExprEncodingRef, ExprId, ExprRef, IntoExpr, Scope, ScopeDType,
15-
VTable, vtable,
14+
AnalysisExpr, BinaryExpr, ExprEncodingRef, ExprId, ExprRef, IntoExpr, Scope, VTable, vtable,
1615
};
1716

1817
vtable!(Between);
@@ -102,7 +101,7 @@ impl VTable for BetweenVTable {
102101
between_compute(&arr_val, &lower_arr_val, &upper_arr_val, &expr.options)
103102
}
104103

105-
fn return_dtype(expr: &Self::Expr, scope: &ScopeDType) -> VortexResult<DType> {
104+
fn return_dtype(expr: &Self::Expr, scope: &DType) -> VortexResult<DType> {
106105
let arr_dt = expr.arr.return_dtype(scope)?;
107106
let lower_dt = expr.lower.return_dtype(scope)?;
108107
let upper_dt = expr.upper.return_dtype(scope)?;

vortex-expr/src/exprs/binary.rs

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use vortex_error::{VortexResult, vortex_bail};
1111
use vortex_proto::expr as pb;
1212

1313
use crate::{
14-
AnalysisExpr, ExprEncodingRef, ExprId, ExprRef, IntoExpr, Operator, Scope, ScopeDType,
15-
StatsCatalog, VTable, vtable,
14+
AnalysisExpr, ExprEncodingRef, ExprId, ExprRef, IntoExpr, Operator, Scope, StatsCatalog,
15+
VTable, vtable,
1616
};
1717

1818
vtable!(Binary);
@@ -93,7 +93,7 @@ impl VTable for BinaryVTable {
9393
}
9494
}
9595

96-
fn return_dtype(expr: &Self::Expr, scope: &ScopeDType) -> VortexResult<DType> {
96+
fn return_dtype(expr: &Self::Expr, scope: &DType) -> VortexResult<DType> {
9797
let lhs = expr.lhs.return_dtype(scope)?;
9898
let rhs = expr.rhs.return_dtype(scope)?;
9999

@@ -426,8 +426,8 @@ mod tests {
426426
use vortex_dtype::{DType, Nullability};
427427

428428
use crate::{
429-
ScopeDType, VortexExpr, and, and_collect, and_collect_right, col, eq, gt, gt_eq, lit, lt,
430-
lt_eq, not_eq, or, test_harness,
429+
VortexExpr, and, and_collect, and_collect_right, col, eq, gt, gt_eq, lit, lt, lt_eq,
430+
not_eq, or, test_harness,
431431
};
432432

433433
#[test]
@@ -455,13 +455,13 @@ mod tests {
455455
let bool2: Arc<dyn VortexExpr> = col("bool2");
456456
assert_eq!(
457457
and(bool1.clone(), bool2.clone())
458-
.return_dtype(&ScopeDType::new(dtype.clone()))
458+
.return_dtype(&dtype)
459459
.unwrap(),
460460
DType::Bool(Nullability::NonNullable)
461461
);
462462
assert_eq!(
463463
or(bool1.clone(), bool2.clone())
464-
.return_dtype(&ScopeDType::new(dtype.clone()))
464+
.return_dtype(&dtype)
465465
.unwrap(),
466466
DType::Bool(Nullability::NonNullable)
467467
);
@@ -470,38 +470,32 @@ mod tests {
470470
let col2: Arc<dyn VortexExpr> = col("col2");
471471

472472
assert_eq!(
473-
eq(col1.clone(), col2.clone())
474-
.return_dtype(&ScopeDType::new(dtype.clone()))
475-
.unwrap(),
473+
eq(col1.clone(), col2.clone()).return_dtype(&dtype).unwrap(),
476474
DType::Bool(Nullability::Nullable)
477475
);
478476
assert_eq!(
479477
not_eq(col1.clone(), col2.clone())
480-
.return_dtype(&ScopeDType::new(dtype.clone()))
478+
.return_dtype(&dtype)
481479
.unwrap(),
482480
DType::Bool(Nullability::Nullable)
483481
);
484482
assert_eq!(
485-
gt(col1.clone(), col2.clone())
486-
.return_dtype(&ScopeDType::new(dtype.clone()))
487-
.unwrap(),
483+
gt(col1.clone(), col2.clone()).return_dtype(&dtype).unwrap(),
488484
DType::Bool(Nullability::Nullable)
489485
);
490486
assert_eq!(
491487
gt_eq(col1.clone(), col2.clone())
492-
.return_dtype(&ScopeDType::new(dtype.clone()))
488+
.return_dtype(&dtype)
493489
.unwrap(),
494490
DType::Bool(Nullability::Nullable)
495491
);
496492
assert_eq!(
497-
lt(col1.clone(), col2.clone())
498-
.return_dtype(&ScopeDType::new(dtype.clone()))
499-
.unwrap(),
493+
lt(col1.clone(), col2.clone()).return_dtype(&dtype).unwrap(),
500494
DType::Bool(Nullability::Nullable)
501495
);
502496
assert_eq!(
503497
lt_eq(col1.clone(), col2.clone())
504-
.return_dtype(&ScopeDType::new(dtype.clone()))
498+
.return_dtype(&dtype)
505499
.unwrap(),
506500
DType::Bool(Nullability::Nullable)
507501
);
@@ -511,7 +505,7 @@ mod tests {
511505
lt(col1.clone(), col2.clone()),
512506
not_eq(col1.clone(), col2.clone())
513507
)
514-
.return_dtype(&ScopeDType::new(dtype))
508+
.return_dtype(&dtype)
515509
.unwrap(),
516510
DType::Bool(Nullability::Nullable)
517511
);

0 commit comments

Comments
 (0)