mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-31 19:27:21 +00:00

T-SQL (and Oracle) support non-standard syntax, which is similar in functionality to LATERAL joins in ANSI and PostgreSQL <https://blog.jooq.org/tag/lateral-derived-table/>: it allows to use the columns from the tables defined to the left of `APPLY` in the "derived tables" (subqueries) to the right of `APPLY`. Unlike ANSI LATERAL (but like Postgres' implementation), APPLY is also used with table-valued function calls. Despite them being similar, we represent "APPLY" joins with `JoinOperator`s of its own (`CrossApply` and `OuterApply`). Doing otherwise seemed like it would cause unnecessary confusion, as those interested in dialect-specific parsing would probably not expect APPLY being parsed as LATERAL, and those wanting to forbid non-standard SQL would not be helped by this either. This also renames existing JoinOperator::Cross -> CrossJoin to avoid confusion with CrossApply.
80 lines
2.6 KiB
Rust
80 lines
2.6 KiB
Rust
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#![warn(clippy::all)]
|
|
//! Test SQL syntax specific to Microsoft's T-SQL. The parser based on the
|
|
//! generic dialect is also tested (on the inputs it can handle).
|
|
|
|
use sqlparser::dialect::{GenericSqlDialect, MsSqlDialect};
|
|
use sqlparser::sqlast::*;
|
|
use sqlparser::test_utils::*;
|
|
|
|
#[test]
|
|
fn parse_mssql_identifiers() {
|
|
let sql = "SELECT @@version, _foo$123 FROM ##temp";
|
|
let select = ms_and_generic().verified_only_select(sql);
|
|
assert_eq!(
|
|
&ASTNode::SQLIdentifier("@@version".to_string()),
|
|
expr_from_projection(&select.projection[0]),
|
|
);
|
|
assert_eq!(
|
|
&ASTNode::SQLIdentifier("_foo$123".to_string()),
|
|
expr_from_projection(&select.projection[1]),
|
|
);
|
|
assert_eq!(2, select.projection.len());
|
|
match &only(&select.from).relation {
|
|
TableFactor::Table { name, .. } => {
|
|
assert_eq!("##temp".to_string(), name.to_string());
|
|
}
|
|
_ => unreachable!(),
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn parse_mssql_single_quoted_aliases() {
|
|
let _ = ms_and_generic().one_statement_parses_to("SELECT foo 'alias'", "SELECT foo AS 'alias'");
|
|
}
|
|
|
|
#[test]
|
|
fn parse_mssql_delimited_identifiers() {
|
|
let _ = ms().one_statement_parses_to(
|
|
"SELECT [a.b!] [FROM] FROM foo [WHERE]",
|
|
"SELECT [a.b!] AS [FROM] FROM foo AS [WHERE]",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn parse_mssql_apply_join() {
|
|
let _ = ms_and_generic().verified_only_select(
|
|
"SELECT * FROM sys.dm_exec_query_stats AS deqs \
|
|
CROSS APPLY sys.dm_exec_query_plan(deqs.plan_handle)",
|
|
);
|
|
let _ = ms_and_generic().verified_only_select(
|
|
"SELECT * FROM sys.dm_exec_query_stats AS deqs \
|
|
OUTER APPLY sys.dm_exec_query_plan(deqs.plan_handle)",
|
|
);
|
|
let _ = ms_and_generic().verified_only_select(
|
|
"SELECT * FROM foo \
|
|
OUTER APPLY (SELECT foo.x + 1) AS bar",
|
|
);
|
|
}
|
|
|
|
fn ms() -> TestedDialects {
|
|
TestedDialects {
|
|
dialects: vec![Box::new(MsSqlDialect {})],
|
|
}
|
|
}
|
|
fn ms_and_generic() -> TestedDialects {
|
|
TestedDialects {
|
|
dialects: vec![Box::new(MsSqlDialect {}), Box::new(GenericSqlDialect {})],
|
|
}
|
|
}
|