apache / apache/datafusion-sqlparser-rs

Keywords are parsed as functions in select statements

未關閉
#1,909 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視
主要語言
Rust
星號
3.5k
分支
772
平均合併
4 天 9 小時
30 天內合併 PR
17

描述

# Abstract
Qualified names like of the form `.` are sometimes parsed as functions, like in:

```sql
SELECT t.user FROM t;
```

# Current Behavior
This is done with `cargo run --example cli -- test.sql --generic`:

```sql
select t.user from t;
```

results in:

```text
[
Query(
Query {
with: None,
body: Select(
Select {
select_token: TokenWithSpan {
token: Word(
Word {
value: "select",
quote_style: None,
keyword: SELECT,
},
),
span: Span(Location(1,1)..Location(1,7)),
},
distinct: None,
top: None,
top_before_distinct: false,
projection: [
UnnamedExpr(
Function(
Function {
name: ObjectName(
[
Identifier(
Ident {
value: "t",
quote_style: None,
span: Span(Location(1,8)..Location(1,9)),
},
),
Identifier(
Ident {
value: "user",
quote_style: None,
span: Span(Location(1,10)..Location(1,14)),
},
),
],
),
uses_odbc_syntax: false,
parameters: None,
args: None,
filter: None,
null_treatment: None,
over: None,
within_group: [],
},
),
),
],
into: None,
from: [
TableWithJoins {
relation: Table {
name: ObjectName(
[
Identifier(
Ident {
value: "t",
quote_style: None,
span: Span(Location(1,20)..Location(1,21)),
},
),
],
),
alias: None,
args: None,
with_hints: [],
version: None,
with_ordinality: false,
partitions: [],
json_path: None,
sample: None,
index_hints: [],
},
joins: [],
},
],
lateral_views: [],
prewhere: None,
selection: None,
group_by: Expressions(
[],
[],
),
cluster_by: [],
distribute_by: [],
sort_by: [],
having: None,
named_window: [],
qualify: None,
window_before_qualify: false,
value_table_mode: None,
connect_by: None,
flavor: Standard,
},
),
order_by: None,
limit_clause: None,
fetch: None,
locks: [],
for_clause: None,
settings: None,
format_clause: None,
pipe_operators: [],
},
),
]
```

and `cargo run --example cli -- test.sql --postgres` is the same:

```text
[
Query(
Query {
with: None,
body: Select(
Select {
select_token: TokenWithSpan {
token: Word(
Word {
value: "select",
quote_style: None,
keyword: SELECT,
},
),
span: Span(Location(1,1)..Location(1,7)),
},
distinct: None,
top: None,
top_before_distinct: false,
projection: [
UnnamedExpr(
Function(
Function {
name: ObjectName(
[
Identifier(
Ident {
value: "t",
quote_style: None,
span: Span(Location(1,8)..Location(1,9)),
},
),
Identifier(
Ident {
value: "user",
quote_style: None,
span: Span(Location(1,10)..Location(1,14)),
},
),
],
),
uses_odbc_syntax: false,
parameters: None,
args: None,
filter: None,
null_treatment: None,
over: None,
within_group: [],
},
),
),
],
into: None,
from: [
TableWithJoins {
relation: Table {
name: ObjectName(
[
Identifier(
Ident {
value: "t",
quote_style: None,
span: Span(Location(1,20)..Location(1,21)),
},
),
],
),
alias: None,
args: None,
with_hints: [],
version: None,
with_ordinality: false,
partitions: [],
json_path: None,
sample: None,
index_hints: [],
},
joins: [],
},
],
lateral_views: [],
prewhere: None,
selection: None,
group_by: Expressions(
[],
[],
),
cluster_by: [],
distribute_by: [],
sort_by: [],
having: None,
named_window: [],
qualify: None,
window_before_qualify: false,
value_table_mode: None,
connect_by: None,
flavor: Standard,
},
),
order_by: None,
limit_clause: None,
fetch: None,
locks: [],
for_clause: None,
settings: None,
format_clause: None,
pipe_operators: [],
},
),
]
```

# Expected Behavior
I think this should parse similar to

```sql
select t.foo from t;
```

with `cargo run --example cli -- test.sql --generic`:

```text
[
Query(
Query {
with: None,
body: Select(
Select {
select_token: TokenWithSpan {
token: Word(
Word {
value: "select",
quote_style: None,
keyword: SELECT,
},
),
span: Span(Location(1,1)..Location(1,7)),
},
distinct: None,
top: None,
top_before_distinct: false,
projection: [
UnnamedExpr(
CompoundIdentifier(
[
Ident {
value: "t",
quote_style: None,
span: Span(Location(1,8)..Location(1,9)),
},
Ident {
value: "foo",
quote_style: None,
span: Span(Location(1,10)..Location(1,13)),
},
],
),
),
],
into: None,
from: [
TableWithJoins {
relation: Table {
name: ObjectName(
[
Identifier(
Ident {
value: "t",
quote_style: None,
span: Span(Location(1,19)..Location(1,20)),
},
),
],
),
alias: None,
args: None,
with_hints: [],
version: None,
with_ordinality: false,
partitions: [],
json_path: None,
sample: None,
index_hints: [],
},
joins: [],
},
],
lateral_views: [],
prewhere: None,
selection: None,
group_by: Expressions(
[],
[],
),
cluster_by: [],
distribute_by: [],
sort_by: [],
having: None,
named_window: [],
qualify: None,
window_before_qualify: false,
value_table_mode: None,
connect_by: None,
flavor: Standard,
},
),
order_by: None,
limit_clause: None,
fetch: None,
locks: [],
for_clause: None,
settings: None,
format_clause: None,
pipe_operators: [],
},
),
]
```

# Others
Also see PostgreSQL:

```text
psql (17.5 (Debian 17.5-1.pgdg120+1))
Type "help" for help.

postgres=# create table t(a int, "user" text);
CREATE TABLE
postgres=# insert into t values (1, 'foo');
INSERT 0 1
postgres=# select t.user from t;
user
------
foo
(1 row)
```

Interestingly, even the plain `user` works:

```text
postgres=# select user from t;
user
----------
postgres
(1 row)
```

# References
- a potentially valid case of treating `user` as a function: #1658
- downstream: https://github.com/apache/datafusion/issues/14141

貢獻指南

這個儲存庫沒有索引到貢獻指南

研究方向

使用 test.sql 以及 --generic 和 --postgres,重現使用所提到的 cargo run --example cli 指令時出現的問題。追蹤 SQL 表達式解析過程,該過程將 t.user 分類為 Function,而不是 t.foo 所示的 CompoundIdentifier,然後為失敗的查詢新增覆蓋,並驗證兩種方言都會產生預期的解析形式。

由索引模型根據 Issue 內容生成。

評估

技術堆疊
rust, sql
領域
compilers
Issue 類型
缺陷
難度
3/5
預估耗時
1-2 天
活躍度
停滯
描述清晰度
基本清楚
新手友好度
45/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。