mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-07 17:04:59 +00:00
Add support for MSSQL's OPENJSON WITH
clause (#1498)
This commit is contained in:
parent
e857787309
commit
90824486df
5 changed files with 476 additions and 6 deletions
|
@ -193,6 +193,341 @@ fn parse_mssql_apply_join() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_mssql_openjson() {
|
||||
let select = ms().verified_only_select(
|
||||
"SELECT B.kind, B.id_list \
|
||||
FROM t_test_table AS A \
|
||||
CROSS APPLY OPENJSON(A.param, '$.config') WITH (kind VARCHAR(20) '$.kind', [id_list] NVARCHAR(MAX) '$.id_list' AS JSON) AS B",
|
||||
);
|
||||
assert_eq!(
|
||||
vec![TableWithJoins {
|
||||
relation: TableFactor::Table {
|
||||
name: ObjectName(vec![Ident {
|
||||
value: "t_test_table".into(),
|
||||
quote_style: None,
|
||||
},]),
|
||||
alias: Some(TableAlias {
|
||||
name: Ident {
|
||||
value: "A".into(),
|
||||
quote_style: None
|
||||
},
|
||||
columns: vec![]
|
||||
}),
|
||||
args: None,
|
||||
with_hints: vec![],
|
||||
version: None,
|
||||
with_ordinality: false,
|
||||
partitions: vec![]
|
||||
},
|
||||
joins: vec![Join {
|
||||
relation: TableFactor::OpenJsonTable {
|
||||
json_expr: Expr::CompoundIdentifier(vec![
|
||||
Ident {
|
||||
value: "A".into(),
|
||||
quote_style: None,
|
||||
},
|
||||
Ident {
|
||||
value: "param".into(),
|
||||
quote_style: None,
|
||||
}
|
||||
]),
|
||||
json_path: Some(Value::SingleQuotedString("$.config".into())),
|
||||
columns: vec![
|
||||
OpenJsonTableColumn {
|
||||
name: Ident {
|
||||
value: "kind".into(),
|
||||
quote_style: None,
|
||||
},
|
||||
r#type: DataType::Varchar(Some(CharacterLength::IntegerLength {
|
||||
length: 20,
|
||||
unit: None
|
||||
})),
|
||||
path: Some("$.kind".into()),
|
||||
as_json: false
|
||||
},
|
||||
OpenJsonTableColumn {
|
||||
name: Ident {
|
||||
value: "id_list".into(),
|
||||
quote_style: Some('['),
|
||||
},
|
||||
r#type: DataType::Nvarchar(Some(CharacterLength::Max)),
|
||||
path: Some("$.id_list".into()),
|
||||
as_json: true
|
||||
}
|
||||
],
|
||||
alias: Some(TableAlias {
|
||||
name: Ident {
|
||||
value: "B".into(),
|
||||
quote_style: None
|
||||
},
|
||||
columns: vec![]
|
||||
})
|
||||
},
|
||||
global: false,
|
||||
join_operator: JoinOperator::CrossApply
|
||||
}]
|
||||
}],
|
||||
select.from
|
||||
);
|
||||
let select = ms().verified_only_select(
|
||||
"SELECT B.kind, B.id_list \
|
||||
FROM t_test_table AS A \
|
||||
CROSS APPLY OPENJSON(A.param) WITH (kind VARCHAR(20) '$.kind', [id_list] NVARCHAR(MAX) '$.id_list' AS JSON) AS B",
|
||||
);
|
||||
assert_eq!(
|
||||
vec![TableWithJoins {
|
||||
relation: TableFactor::Table {
|
||||
name: ObjectName(vec![Ident {
|
||||
value: "t_test_table".into(),
|
||||
quote_style: None,
|
||||
},]),
|
||||
alias: Some(TableAlias {
|
||||
name: Ident {
|
||||
value: "A".into(),
|
||||
quote_style: None
|
||||
},
|
||||
columns: vec![]
|
||||
}),
|
||||
args: None,
|
||||
with_hints: vec![],
|
||||
version: None,
|
||||
with_ordinality: false,
|
||||
partitions: vec![]
|
||||
},
|
||||
joins: vec![Join {
|
||||
relation: TableFactor::OpenJsonTable {
|
||||
json_expr: Expr::CompoundIdentifier(vec![
|
||||
Ident {
|
||||
value: "A".into(),
|
||||
quote_style: None,
|
||||
},
|
||||
Ident {
|
||||
value: "param".into(),
|
||||
quote_style: None,
|
||||
}
|
||||
]),
|
||||
json_path: None,
|
||||
columns: vec![
|
||||
OpenJsonTableColumn {
|
||||
name: Ident {
|
||||
value: "kind".into(),
|
||||
quote_style: None,
|
||||
},
|
||||
r#type: DataType::Varchar(Some(CharacterLength::IntegerLength {
|
||||
length: 20,
|
||||
unit: None
|
||||
})),
|
||||
path: Some("$.kind".into()),
|
||||
as_json: false
|
||||
},
|
||||
OpenJsonTableColumn {
|
||||
name: Ident {
|
||||
value: "id_list".into(),
|
||||
quote_style: Some('['),
|
||||
},
|
||||
r#type: DataType::Nvarchar(Some(CharacterLength::Max)),
|
||||
path: Some("$.id_list".into()),
|
||||
as_json: true
|
||||
}
|
||||
],
|
||||
alias: Some(TableAlias {
|
||||
name: Ident {
|
||||
value: "B".into(),
|
||||
quote_style: None
|
||||
},
|
||||
columns: vec![]
|
||||
})
|
||||
},
|
||||
global: false,
|
||||
join_operator: JoinOperator::CrossApply
|
||||
}]
|
||||
}],
|
||||
select.from
|
||||
);
|
||||
let select = ms().verified_only_select(
|
||||
"SELECT B.kind, B.id_list \
|
||||
FROM t_test_table AS A \
|
||||
CROSS APPLY OPENJSON(A.param) WITH (kind VARCHAR(20), [id_list] NVARCHAR(MAX)) AS B",
|
||||
);
|
||||
assert_eq!(
|
||||
vec![TableWithJoins {
|
||||
relation: TableFactor::Table {
|
||||
name: ObjectName(vec![Ident {
|
||||
value: "t_test_table".into(),
|
||||
quote_style: None,
|
||||
},]),
|
||||
alias: Some(TableAlias {
|
||||
name: Ident {
|
||||
value: "A".into(),
|
||||
quote_style: None
|
||||
},
|
||||
columns: vec![]
|
||||
}),
|
||||
args: None,
|
||||
with_hints: vec![],
|
||||
version: None,
|
||||
with_ordinality: false,
|
||||
partitions: vec![]
|
||||
},
|
||||
joins: vec![Join {
|
||||
relation: TableFactor::OpenJsonTable {
|
||||
json_expr: Expr::CompoundIdentifier(vec![
|
||||
Ident {
|
||||
value: "A".into(),
|
||||
quote_style: None,
|
||||
},
|
||||
Ident {
|
||||
value: "param".into(),
|
||||
quote_style: None,
|
||||
}
|
||||
]),
|
||||
json_path: None,
|
||||
columns: vec![
|
||||
OpenJsonTableColumn {
|
||||
name: Ident {
|
||||
value: "kind".into(),
|
||||
quote_style: None,
|
||||
},
|
||||
r#type: DataType::Varchar(Some(CharacterLength::IntegerLength {
|
||||
length: 20,
|
||||
unit: None
|
||||
})),
|
||||
path: None,
|
||||
as_json: false
|
||||
},
|
||||
OpenJsonTableColumn {
|
||||
name: Ident {
|
||||
value: "id_list".into(),
|
||||
quote_style: Some('['),
|
||||
},
|
||||
r#type: DataType::Nvarchar(Some(CharacterLength::Max)),
|
||||
path: None,
|
||||
as_json: false
|
||||
}
|
||||
],
|
||||
alias: Some(TableAlias {
|
||||
name: Ident {
|
||||
value: "B".into(),
|
||||
quote_style: None
|
||||
},
|
||||
columns: vec![]
|
||||
})
|
||||
},
|
||||
global: false,
|
||||
join_operator: JoinOperator::CrossApply
|
||||
}]
|
||||
}],
|
||||
select.from
|
||||
);
|
||||
let select = ms_and_generic().verified_only_select(
|
||||
"SELECT B.kind, B.id_list \
|
||||
FROM t_test_table AS A \
|
||||
CROSS APPLY OPENJSON(A.param, '$.config') AS B",
|
||||
);
|
||||
assert_eq!(
|
||||
vec![TableWithJoins {
|
||||
relation: TableFactor::Table {
|
||||
name: ObjectName(vec![Ident {
|
||||
value: "t_test_table".into(),
|
||||
quote_style: None,
|
||||
},]),
|
||||
alias: Some(TableAlias {
|
||||
name: Ident {
|
||||
value: "A".into(),
|
||||
quote_style: None
|
||||
},
|
||||
columns: vec![]
|
||||
}),
|
||||
args: None,
|
||||
with_hints: vec![],
|
||||
version: None,
|
||||
with_ordinality: false,
|
||||
partitions: vec![]
|
||||
},
|
||||
joins: vec![Join {
|
||||
relation: TableFactor::OpenJsonTable {
|
||||
json_expr: Expr::CompoundIdentifier(vec![
|
||||
Ident {
|
||||
value: "A".into(),
|
||||
quote_style: None,
|
||||
},
|
||||
Ident {
|
||||
value: "param".into(),
|
||||
quote_style: None,
|
||||
}
|
||||
]),
|
||||
json_path: Some(Value::SingleQuotedString("$.config".into())),
|
||||
columns: vec![],
|
||||
alias: Some(TableAlias {
|
||||
name: Ident {
|
||||
value: "B".into(),
|
||||
quote_style: None
|
||||
},
|
||||
columns: vec![]
|
||||
})
|
||||
},
|
||||
global: false,
|
||||
join_operator: JoinOperator::CrossApply
|
||||
}]
|
||||
}],
|
||||
select.from
|
||||
);
|
||||
let select = ms_and_generic().verified_only_select(
|
||||
"SELECT B.kind, B.id_list \
|
||||
FROM t_test_table AS A \
|
||||
CROSS APPLY OPENJSON(A.param) AS B",
|
||||
);
|
||||
assert_eq!(
|
||||
vec![TableWithJoins {
|
||||
relation: TableFactor::Table {
|
||||
name: ObjectName(vec![Ident {
|
||||
value: "t_test_table".into(),
|
||||
quote_style: None,
|
||||
},]),
|
||||
alias: Some(TableAlias {
|
||||
name: Ident {
|
||||
value: "A".into(),
|
||||
quote_style: None
|
||||
},
|
||||
columns: vec![]
|
||||
}),
|
||||
args: None,
|
||||
with_hints: vec![],
|
||||
version: None,
|
||||
with_ordinality: false,
|
||||
partitions: vec![]
|
||||
},
|
||||
joins: vec![Join {
|
||||
relation: TableFactor::OpenJsonTable {
|
||||
json_expr: Expr::CompoundIdentifier(vec![
|
||||
Ident {
|
||||
value: "A".into(),
|
||||
quote_style: None,
|
||||
},
|
||||
Ident {
|
||||
value: "param".into(),
|
||||
quote_style: None,
|
||||
}
|
||||
]),
|
||||
json_path: None,
|
||||
columns: vec![],
|
||||
alias: Some(TableAlias {
|
||||
name: Ident {
|
||||
value: "B".into(),
|
||||
quote_style: None
|
||||
},
|
||||
columns: vec![]
|
||||
})
|
||||
},
|
||||
global: false,
|
||||
join_operator: JoinOperator::CrossApply
|
||||
}]
|
||||
}],
|
||||
select.from
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_mssql_top_paren() {
|
||||
let sql = "SELECT TOP (5) * FROM foo";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue