///|
/// How the interpreter handles runtime type failures. Permissive mode yields
/// MISSING; strict mode raises `TypeError`. Data and unsupported-form failures
/// raise in either mode.
pub(all) enum Mode {
Permissive
Strict
} derive(Debug, Eq)
///|
/// An evaluation failure with a source location, or the original parse error.
/// `TypeError` is a strict-mode operand failure; `DataError` is invalid data or
/// a static error in either mode; `Unsupported` is an unimplemented form.
pub(all) suberror EvalError {
TypeError(message~ : String, span~ : @ast.Span)
DataError(message~ : String, span~ : @ast.Span)
Unsupported(message~ : String, span~ : @ast.Span)
Syntax(@ast.ParseError)
} derive(Debug, Eq)
///|
/// One step of a path.
pub(all) enum Step {
Field(String, delimited~ : Bool)
Index(Expr)
AllElements
AllFields
} derive(Debug)
///|
/// The local fallback of a FROM source after global lookup has failed.
pub(all) enum LocalLookup {
Bound(String)
Ambiguous(Array[String])
} derive(Debug)
///|
/// A lowered scalar expression (spec M4a §3). Names are resolved, literals
/// are values.
pub(all) enum Expr {
Const(@value.Value, @ast.Span)
Global(String, delimited~ : Bool, @ast.Span)
ListOf(Array[Expr], @ast.Span)
BagOf(Array[Expr], @ast.Span)
TupleOf(Array[(Expr, Expr)], @ast.Span)
/// `MAP { k: v, ... }`. A key or value type that every entry declares by
/// CAST is known at lowering (spec M4d2 §3.3); otherwise it is inferred.
MapOf(
Array[(Expr, Expr)],
key_type~ : @value.MapType?,
value_type~ : @value.MapType?,
@ast.Span
)
Path(Expr, Array[Step], @ast.Span)
IsNull(Expr, negated~ : Bool, @ast.Span)
IsMissing(Expr, negated~ : Bool, @ast.Span)
Unary(@ast.UnaryOp, Expr, @ast.Span)
Binary(@ast.BinaryOp, Expr, Expr, @ast.Span)
And(Expr, Expr, @ast.Span)
Or(Expr, Expr, @ast.Span)
Not(Expr, @ast.Span)
/// `IS [NOT] TRUE | FALSE | UNKNOWN`; `None` is UNKNOWN.
BoolTest(Expr, Bool?, negated~ : Bool, @ast.Span)
Like(Expr, pattern~ : Expr, escape~ : Expr?, negated~ : Bool, @ast.Span)
Between(Expr, low~ : Expr, high~ : Expr, negated~ : Bool, @ast.Span)
In(Expr, Expr, negated~ : Bool, @ast.Span)
IsType(Expr, @ast.DataType, negated~ : Bool, @ast.Span)
Case(
operand~ : Expr?,
branches~ : Array[(Expr, Expr)],
default~ : Expr?,
@ast.Span
)
Coalesce(Array[Expr], @ast.Span)
NullIf(Expr, Expr, @ast.Span)
/// A built-in scalar function (spec M4d1 §2), with its arguments in the
/// positions `Function` documents.
Call(Function, Array[Expr], @ast.Span)
/// `CAST(e AS T)` with its resolved target (spec M4d2 §3).
Cast(Expr, @ops.CastTarget, @ast.Span)
/// A FROM variable, by the name it was declared with.
Local(String, @ast.Span)
/// A name in a FROM source: the global of that name if there is one, else
/// the local lookup `variable`, which may be ambiguous (partiql-tests select.ion,
/// `joinWithShadowedGlobal`; `@name` selects the variable only).
GlobalOrLocal(String, variable~ : LocalLookup, delimited~ : Bool, @ast.Span)
/// A name that no variable declares, inside a query: the attribute of that
/// name of the first tuple among the query variables `locals` (FROM AS and
/// AT, and LET; innermost query first, each in declared order), else the
/// global of that name, else MISSING (permissive) or a `TypeError`
/// (strict).
Implicit(String, delimited~ : Bool, locals~ : Array[String], @ast.Span)
/// A query block: the projection of each binding tuple of `rel`, as a bag.
Select(Rel, Projection, distinct~ : Bool, @ast.Span)
/// A single-column `SELECT` (the first operand, a `Select`) used where a
/// value is needed: see `SubqueryUse`.
Subquery(Expr, SubqueryUse, @ast.Span)
/// A query with ORDER BY, LIMIT or OFFSET over `body`: the elements of the
/// body sorted by `order`: a list with ORDER BY, else a bag (a tuple for a
/// PIVOT body). `aliases` are the output names that sort keys may use (a
/// SELECT list's names, in order).
Query(
Expr,
order~ : Array[SortKey],
limit~ : Expr?,
offset~ : Expr?,
aliases~ : Array[String],
@ast.Span
)
/// `left op right`, as a bag. `outer` is the PartiQL bag operator (OUTER);
/// otherwise SQL rules apply: both operands are relations, matched by
/// position or by `corresponding` (plan rulings 4-7). `all` keeps
/// duplicates.
SetOp(
@ast.SetOpKind,
all~ : Bool,
outer~ : Bool,
corresponding~ : @ast.Corresponding?,
Expr,
Expr,
@ast.Span
)
/// `WITH name AS (query), ... body`: each binding is evaluated once, in
/// order; later bindings and the body see the earlier ones as variables.
With(Array[(String, Expr)], Expr, @ast.Span)
/// `COLL_f(e)`: the aggregate of the elements of the collection `e`; NULL
/// for NULL, MISSING for MISSING, a type failure for any other value.
CollAggregate(AggregateKind, distinct~ : Bool, Expr, @ast.Span)
/// A SQL aggregate `f(e)` (spec section 11.2.2): `e` evaluated for each
/// member tuple of the group variable `group`, with each variable of
/// `members` (the non-key FROM and LET variables) bound to the member's
/// attribute of that name, then folded.
Aggregate(
AggregateKind,
distinct~ : Bool,
Expr,
members~ : Array[String],
group~ : String,
@ast.Span
)
/// A key expression in a FROM source: a name there finds a global before
/// a variable, so `otherwise` (the expression without key variables) when
/// one of the names `globals` (name, delimited, span) is a global, else `key`.
GlobalsFirst(
Array[(String, Bool, @ast.Span)],
key~ : Expr,
otherwise~ : Expr,
@ast.Span
)
} derive(Debug)
///|
/// A key of ORDER BY. `nulls_first` is resolved: the explicit `NULLS FIRST`
/// or `NULLS LAST`, else NULL and MISSING come last for ASC and first for
/// DESC.
pub(all) struct SortKey {
expr : Expr
desc : Bool
nulls_first : Bool
} derive(Debug)
///|
/// The variable that holds an output element for the sort keys of a query
/// whose body is not a SELECT. No identifier can name it.
pub let row_variable : String = "\u{0}row"
///|
/// The name of the frame that holds the output name `name` of a SELECT list
/// while ORDER BY runs: apart from every variable name.
pub fn output_variable(name : String) -> String {
"\u{0}out:" + name
}
///|
/// How a single-column subquery is coerced at its use site.
/// Each variant defines its empty-input and cardinality behavior.
pub(all) enum SubqueryUse {
/// One value: NULL for no row, the value of the column for one row, and
/// for more rows MISSING (permissive) or a `TypeError` (strict).
Scalar
/// The bag of the value of the column of each row (`x IN (SELECT a ...)`).
Column
/// The attribute values of the only row, as a list (array coercion): NULL
/// for no row; more rows as for `Scalar`.
Row
} derive(Debug)
///|
/// A relational plan node (spec M4b1 §3): it produces binding tuples.
pub(all) enum Rel {
/// One binding of `as_` per element of a collection; `at` binds the
/// element's position.
Scan(Expr, as_~ : String, at~ : String?, @ast.Span)
/// One binding of `as_` per attribute value of a tuple; `at` binds the
/// attribute name.
Unpivot(Expr, as_~ : String, at~ : String?, @ast.Span)
/// The binding tuples for which the predicate is TRUE.
Filter(Rel, Expr, @ast.Span)
/// The pairs of a left and a right binding tuple. The right side sees the
/// variables of the left (lateral), except for `Right`. `on` is `None` when
/// every pair matches. `Left` and `Right` pad the side that finds no match
/// with NULL.
Join(JoinKind, Rel, Rel, on~ : Expr?, @ast.Span)
/// Each binding tuple with one more variable per `(name, expr)`, bound in
/// order: an expression sees the variables before it (LET).
Let(Rel, Array[(String, Expr)], @ast.Span)
/// One binding tuple per group of the binding tuples of the input (spec
/// section 11.1): the key variables and `group_as`, the bag of the member
/// tuples of the group. A member tuple has one attribute per variable of
/// `members` (FROM AS and AT, and LET, in order); a MISSING one is left
/// out. Keys compare with `eqg` after MISSING becomes NULL.
Group(Rel, Grouping, group_as~ : String, members~ : Array[String], @ast.Span)
} derive(Debug)
///|
/// A lowered join strategy. Left and right outer joins pad unmatched
/// bindings with NULL; cross and inner joins produce only matching pairs.
pub(all) enum JoinKind {
Cross
Inner
Left
Right
} derive(Debug, Eq)
///|
/// What a query block makes of each binding tuple.
pub(all) enum Projection {
/// `SELECT VALUE e`
Value(Expr)
/// `SELECT item, ...`: the attributes of one tuple.
Items(Array[Item])
/// `SELECT *`: the attributes of the tuple of each FROM variable `names`,
/// in order.
Star(Array[String])
/// `PIVOT value AT key`: per row a one-attribute tuple (the empty tuple
/// for a row without an attribute); the query joins them into one tuple.
Pivot(value~ : Expr, key~ : Expr)
} derive(Debug)
///|
/// An item of a SELECT list.
pub(all) enum Item {
/// `expr AS name`, the name given or implied.
Named(String, Expr)
/// `expr.*`
AllFields(Expr)
} derive(Debug)
///|
/// Where an expression is in the source.
pub fn Expr::span(self : Expr) -> @ast.Span {
match self {
Const(_, span)
| Global(_, delimited=_, span)
| ListOf(_, span)
| BagOf(_, span)
| TupleOf(_, span)
| MapOf(_, key_type=_, value_type=_, span)
| Path(_, _, span)
| IsNull(_, negated=_, span)
| IsMissing(_, negated=_, span)
| Unary(_, _, span)
| Binary(_, _, _, span)
| And(_, _, span)
| Or(_, _, span)
| Not(_, span)
| BoolTest(_, _, negated=_, span)
| Like(_, pattern=_, escape=_, negated=_, span)
| Between(_, low=_, high=_, negated=_, span)
| In(_, _, negated=_, span)
| IsType(_, _, negated=_, span)
| Case(operand=_, branches=_, default=_, span)
| Coalesce(_, span)
| NullIf(_, _, span)
| Call(_, _, span)
| Cast(_, _, span)
| Local(_, span)
| GlobalOrLocal(_, variable=_, delimited=_, span)
| Implicit(_, delimited=_, locals=_, span)
| Select(_, _, distinct=_, span)
| Subquery(_, _, span)
| Query(_, order=_, limit=_, offset=_, aliases=_, span)
| SetOp(_, all=_, outer=_, corresponding=_, _, _, span)
| With(_, _, span)
| CollAggregate(_, distinct=_, _, span)
| Aggregate(_, distinct=_, _, members=_, group=_, span)
| GlobalsFirst(_, key=_, otherwise=_, span) => span
}
}
///|
/// Where a relation is in the source.
pub fn Rel::span(self : Rel) -> @ast.Span {
match self {
Scan(_, as_=_, at=_, span)
| Unpivot(_, as_=_, at=_, span)
| Filter(_, _, span)
| Join(_, _, _, on=_, span)
| Let(_, _, span)
| Group(_, _, group_as=_, members=_, span) => span
}
}
///|
/// An aggregate function (spec M4c §3.3). SOME is `Any`.
pub(all) enum AggregateKind {
Count
Sum
Avg
Min
Max
Any
Every
} derive(Debug, Eq)
///|
/// The keys of a GROUP BY (spec M4c §4).
pub(all) enum Grouping {
/// One group of every binding tuple, also when there are none: GROUP ALL,
/// or a query with an aggregate or HAVING and no GROUP BY.
All
/// The key variables and their expressions.
By(Array[(String, Expr)])
} derive(Debug)
///|
/// The group variable of a grouped query without GROUP AS. No identifier
/// can name it.
pub let group_variable : String = "\u{0}group"
///|
/// A built-in scalar function (spec M4d1). One argument unless a variant
/// says otherwise.
pub(all) enum Function {
CharLength
OctetLength
BitLength
Size
Cardinality
Exists
/// Zero or more tuples.
TupleUnion
/// [map, key]
MapGet
/// [map, key]
MapContainsKey
MapKeys
MapValues
MapEntries
Abs
/// [dividend, divisor]
Mod
/// [target] or [characters, target] (source order)
Trim(@ast.TrimSpec)
/// [value, start] or [value, start, length]
Substring
/// [needle, haystack]
Position
/// [value, placing, from] or [value, placing, from, for]
Overlay
/// [value, pattern, replacement]
TextReplace
Upper
Lower
/// The datetime functions (spec M4d3). The field is part of the call.
Extract(@ast.DatetimeField)
DateAdd(@ast.DatetimeField)
DateDiff(@ast.DatetimeField)
Overlaps
ToString
ToTimestamp
/// The clock functions (spec session-clock §4); the precision is resolved.
CurrentDate
CurrentTime(Int32)
CurrentTimestamp(Int32)
UtcNow
} derive(Debug, Eq)
///|
/// The SQL name, for messages.
pub fn Function::name(self : Function) -> String {
match self {
CharLength => "CHAR_LENGTH"
OctetLength => "OCTET_LENGTH"
BitLength => "BIT_LENGTH"
Size => "SIZE"
Cardinality => "CARDINALITY"
Exists => "EXISTS"
TupleUnion => "TUPLEUNION"
MapGet => "MAP_GET"
MapContainsKey => "MAP_CONTAINS_KEY"
MapKeys => "MAP_KEYS"
MapValues => "MAP_VALUES"
MapEntries => "MAP_ENTRIES"
Abs => "ABS"
Mod => "MOD"
Trim(_) => "TRIM"
Substring => "SUBSTRING"
Position => "POSITION"
Overlay => "OVERLAY"
TextReplace => "TEXT_REPLACE"
Upper => "UPPER"
Lower => "LOWER"
Extract(_) => "EXTRACT"
DateAdd(_) => "DATE_ADD"
DateDiff(_) => "DATE_DIFF"
Overlaps => "OVERLAPS"
ToString => "TO_STRING"
ToTimestamp => "TO_TIMESTAMP"
CurrentDate => "CURRENT_DATE"
CurrentTime(_) => "CURRENT_TIME"
CurrentTimestamp(_) => "CURRENT_TIMESTAMP"
UtcNow => "UTCNOW"
}
}