Skip to content

Commit b88bca6

Browse files
authored
parser: syntax-error for try_cast (#593)
1 parent 79188ce commit b88bca6

File tree

5 files changed

+64
-7
lines changed

5 files changed

+64
-7
lines changed

PLAN.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -704,8 +704,6 @@ name: nullable varchar(255)
704704
The name of the user in the system.
705705
```
706706

707-
- https://r.ena.to/blog/optimizing-postgres-table-layout-for-maximum-efficiency/
708-
709707
rust analyzer gives:
710708

711709
```
@@ -714,13 +712,21 @@ Error { pub(crate) msg: String, }
714712
size = 24 (0x18), align = 0x8, needs Drop
715713
```
716714

717-
does alignment make sense to have with postgres?
715+
other fields?
716+
717+
- alignment
718+
719+
- https://r.ena.to/blog/optimizing-postgres-table-layout-for-maximum-efficiency/
720+
721+
- common values and distribution
722+
723+
- https://observablehq.com/documentation/cells/data-table#data-table-cell
718724

719-
maybe have common values and distribution somehow?
725+
- index size on hover
720726

721-
show index size on hover too?
727+
- https://www.peterbe.com/plog/index-size-postgresql
722728

723-
- https://www.peterbe.com/plog/index-size-postgresql
729+
- data staleness -- if you have a daily batch job to calculate data, we could expose the staleness date
724730

725731
#### Table
726732

crates/squawk_parser/src/grammar.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1814,6 +1814,7 @@ fn arg_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
18141814
p.eat(VARIADIC_KW);
18151815
let r = Restrictions {
18161816
order_by_allowed: true,
1817+
as_allowed: true,
18171818
..Restrictions::default()
18181819
};
18191820
expr_bp(p, 1, &r)
@@ -2300,6 +2301,7 @@ fn current_op(p: &Parser<'_>, r: &Restrictions) -> (u8, SyntaxKind, Associativit
23002301
PERCENT if p.next_not_joined_op(0) => (9, PERCENT, Left), // symbol
23012302
// and
23022303
AND_KW if !r.and_disabled => (2, AND_KW, Left),
2304+
AS_KW if r.as_allowed => (7, AS_KW, Left),
23032305
// /
23042306
SLASH if p.next_not_joined_op(0) => (9, SLASH, Left), // symbol
23052307
// *
@@ -2326,6 +2328,7 @@ const OVERLAPPING_TOKENS: TokenSet = TokenSet::new(&[OR_KW, AND_KW, IS_KW, COLLA
23262328
#[derive(Default)]
23272329
struct Restrictions {
23282330
order_by_allowed: bool,
2331+
as_allowed: bool,
23292332
in_disabled: bool,
23302333
is_disabled: bool,
23312334
not_disabled: bool,
@@ -2383,7 +2386,7 @@ fn expr_bp(p: &mut Parser<'_>, bp: u8, r: &Restrictions) -> Option<CompletedMark
23832386
let _ = expr_bp(p, op_bp, r);
23842387
lhs = m.complete(
23852388
p,
2386-
if op == SyntaxKind::COLON_COLON {
2389+
if matches!(op, COLON_COLON | AS_KW) {
23872390
CAST_EXPR
23882391
} else if matches!(op, FAT_ARROW | COLON_EQ) {
23892392
NAMED_ARG
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
source: crates/squawk_syntax/src/test.rs
3+
input_file: crates/squawk_syntax/test_data/validation/call_expr.sql
4+
---
5+
SOURCE_FILE@0..97
6+
COMMENT@0..69 "-- Trino/Snowflake/Da ..."
7+
WHITESPACE@69..70 "\n"
8+
SELECT@70..95
9+
SELECT_CLAUSE@70..95
10+
SELECT_KW@70..76 "select"
11+
WHITESPACE@76..77 " "
12+
TARGET_LIST@77..95
13+
TARGET@77..95
14+
CALL_EXPR@77..95
15+
NAME_REF@77..85
16+
IDENT@77..85 "try_cast"
17+
ARG_LIST@85..95
18+
L_PAREN@85..86 "("
19+
CAST_EXPR@86..94
20+
NAME_REF@86..87
21+
IDENT@86..87 "x"
22+
WHITESPACE@87..88 " "
23+
AS_KW@88..90 "as"
24+
WHITESPACE@90..91 " "
25+
NAME_REF@91..94
26+
INT_KW@91..94 "int"
27+
R_PAREN@94..95 ")"
28+
SEMICOLON@95..96 ";"
29+
WHITESPACE@96..97 "\n"
30+
31+
ERROR@86:94 "Invalid cast. Use `cast`, `treat`, or `::` instead."

crates/squawk_syntax/src/validation.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub(crate) fn validate(root: &SyntaxNode, errors: &mut Vec<SyntaxError>) {
1818
ast::PrefixExpr(it) => validate_prefix_expr(it, errors),
1919
ast::ArrayExpr(it) => validate_array_expr(it, errors),
2020
ast::DropAggregate(it) => validate_drop_aggregate(it, errors),
21+
ast::CallExpr(it) => validate_call_expr(it, errors),
2122
ast::JoinExpr(it) => validate_join_expr(it, errors),
2223
ast::Literal(it) => validate_literal(it, errors),
2324
ast::NonStandardParam(it) => validate_non_standard_param(it, errors),
@@ -27,6 +28,20 @@ pub(crate) fn validate(root: &SyntaxNode, errors: &mut Vec<SyntaxError>) {
2728
}
2829
}
2930

31+
fn validate_call_expr(it: ast::CallExpr, acc: &mut Vec<SyntaxError>) {
32+
let Some(arg_list) = it.arg_list() else {
33+
return;
34+
};
35+
for arg in arg_list.args() {
36+
if let ast::Expr::CastExpr(cast_expr) = &arg {
37+
acc.push(SyntaxError::new(
38+
"Invalid cast. Use `cast`, `treat`, or `::` instead.",
39+
cast_expr.syntax().text_range(),
40+
));
41+
}
42+
}
43+
}
44+
3045
fn validate_create_table(it: ast::CreateTable, acc: &mut Vec<SyntaxError>) {
3146
let Some(arg_list) = it.table_arg_list() else {
3247
return;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- Trino/Snowflake/Databricks extension that Postgres doesn't support
2+
select try_cast(x as int);

0 commit comments

Comments
 (0)