Enable new features unconditionally

This commit is contained in:
Petr Novotnik 2025-11-25 19:40:24 +01:00 committed by xitep
parent 24185d15b7
commit 9e098c333a
6 changed files with 8 additions and 211 deletions

View file

@ -545,8 +545,6 @@ pub struct MergeInsertExpr {
/// The insert type used by the statement.
pub kind: MergeInsertKind,
/// An optional condition to restrict the insertion (Oracle specific)
///
/// Enabled via [`Dialect::supports_merge_insert_predicate`](crate::dialect::Dialect::supports_merge_insert_predicate).
pub insert_predicate: Option<Expr>,
}
@ -582,12 +580,8 @@ pub struct MergeUpdateExpr {
/// The update assiment expressions
pub assignments: Vec<Assignment>,
/// `where_clause` for the update (Oralce specific)
///
/// Enabled via [`Dialect::supports_merge_update_predicate`](crate::dialect::Dialect::supports_merge_update_predicate).
pub update_predicate: Option<Expr>,
/// `delete_clause` for the update "delete where" (Oracle specific)
///
/// Enabled via [`Dialect::supports_merge_update_delete_predicate`](crate::dialect::Dialect::supports_merge_update_delete_predicate).
pub delete_predicate: Option<Expr>,
}

View file

@ -610,119 +610,6 @@ pub trait Dialect: Debug + Any {
false
}
/// Returns `true` if the dialect supports qualified column names
/// as part of a MERGE's INSERT's column list. Example:
///
/// ```sql
/// MERGE INTO FOO
/// USING FOO_IMP
/// ON (FOO.ID = FOO_IMP.ID)
/// WHEN NOT MATCHED THEN
/// -- no qualifier
/// INSERT (ID, NAME)
/// VALUES (FOO_IMP.ID, UPPER(FOO_IMP.NAME))
/// ```
/// vs.
/// ```sql
/// MERGE INTO FOO
/// USING FOO_IMP
/// ON (FOO.ID = FOO_IMP.ID)
/// WHEN NOT MATCHED THEN
/// -- here: qualified
/// INSERT (FOO.ID, FOO.NAME)
/// VALUES (FOO_IMP.ID, UPPER(FOO_IMP.NAME))
/// ```
/// or
/// ```sql
/// MERGE INTO FOO
/// USING FOO_IMP
/// ON (FOO.ID = FOO_IMP.ID)
/// WHEN NOT MATCHED THEN
/// -- here: qualified with array subscripts
/// INSERT (FOO.ID[1], FOO.NAME[1:12])
/// VALUES (FOO_IMP.ID, UPPER(FOO_IMP.NAME))
/// ```
/// or
/// ```sql
/// MERGE INTO FOO X
/// USING FOO_IMP
/// ON (X.ID = FOO_IMP.ID)
/// WHEN NOT MATCHED THEN
/// -- here: qualified using the alias
/// INSERT (X.ID, X.NAME)
/// VALUES (FOO_IMP.ID, UPPER(FOO_IMP.NAME))
/// ```
///
/// By default, qualifiers are allowed.
fn supports_merge_insert_qualified_columns(&self) -> bool {
true
}
/// Returns `true` if the dialect supports specify an INSERT predicate in
/// MERGE statements. Example:
///
/// ```sql
/// MERGE INTO FOO
/// USING FOO_IMP
/// ON (FOO.ID = FOO_IMP.ID)
/// WHEN NOT MATCHED THEN
/// INSERT (ID, NAME)
/// VALUES (FOO_IMP.ID, UPPER(FOO_IMP.NAME))
/// -- insert predicate
/// WHERE NOT FOO_IMP.NAME like '%.IGNORE'
/// ```
///
/// By default, the additional predicate support is enabled.
///
/// See also [Dialect::supports_merge_update_predicate] and
/// [Dialect::supports_merge_update_delete_predicate].
fn supports_merge_insert_predicate(&self) -> bool {
true
}
/// Indicates the supports of UPDATE predicates in MERGE
/// statements. Example:
///
/// ```sql
/// MERGE INTO FOO
/// USING FOO_IMPORT
/// ON (FOO.ID = FOO_IMPORT.ID)
/// WHEN MATCHED THEN
/// UPDATE SET FOO.NAME = FOO_IMPORT.NAME
/// -- update predicate
/// WHERE FOO.NAME <> 'pete'
/// ```
///
/// By default, the additional predicate is enabled.
///
/// See also [Dialect::supports_merge_insert_predicate] and
/// [Dialect::supports_merge_update_delete_predicate].
fn supports_merge_update_predicate(&self) -> bool {
true
}
/// Indicates the supports of UPDATE ... DELETEs and associated predicates
/// in MERGE statements. Example:
///
/// ```sql
/// MERGE INTO FOO
/// USING FOO_IMPORT
/// ON (FOO.ID = FOO_IMPORT.ID)
/// WHEN MATCHED THEN
/// UPDATE SET FOO.NAME = FOO_IMPORT.NAME
/// -- update delete with predicate
/// DELETE WHERE UPPER(FOO.NAME) == FOO.NAME
/// ```
///
/// By default, the support for the `UPDATE ... DELETE` and its associated
/// predicate is enabled.
///
/// See also [Dialect::supports_merge_insert_predicate] and
/// [Dialect::supports_merge_update_predicate].
fn supports_merge_update_delete_predicate(&self) -> bool {
true
}
/// Dialect-specific infix parser override
///
/// This method is called to parse the next infix expression.

View file

@ -123,26 +123,6 @@ impl Dialect for MsSqlDialect {
true
}
/// Set <https://learn.microsoft.com/en-us/sql/t-sql/statements/merge-transact-sql>
fn supports_merge_insert_predicate(&self) -> bool {
false
}
/// Set <https://learn.microsoft.com/en-us/sql/t-sql/statements/merge-transact-sql>
fn supports_merge_insert_qualified_columns(&self) -> bool {
false
}
/// Set <https://learn.microsoft.com/en-us/sql/t-sql/statements/merge-transact-sql>
fn supports_merge_update_delete_predicate(&self) -> bool {
false
}
/// Set <https://learn.microsoft.com/en-us/sql/t-sql/statements/merge-transact-sql>
fn supports_merge_update_predicate(&self) -> bool {
false
}
/// See <https://learn.microsoft.com/en-us/sql/relational-databases/security/authentication-access/server-level-roles>
fn get_reserved_grantees_types(&self) -> &[GranteesType] {
&[GranteesType::Public]

View file

@ -280,19 +280,4 @@ impl Dialect for PostgreSqlDialect {
fn supports_interval_options(&self) -> bool {
true
}
/// See <https://www.postgresql.org/docs/current/sql-merge.html>
fn supports_merge_insert_predicate(&self) -> bool {
false
}
/// See <https://www.postgresql.org/docs/current/sql-merge.html>
fn supports_merge_update_delete_predicate(&self) -> bool {
false
}
/// See <https://www.postgresql.org/docs/current/sql-merge.html>
fn supports_merge_update_predicate(&self) -> bool {
false
}
}

View file

@ -18,7 +18,7 @@ use alloc::{boxed::Box, format, string::ToString, vec, vec::Vec};
use crate::{
ast::{
Merge, MergeAction, MergeClause, MergeClauseKind, MergeInsertExpr, MergeInsertKind,
MergeUpdateExpr, ObjectName, ObjectNamePart, OutputClause, SetExpr, Statement,
MergeUpdateExpr, ObjectName, OutputClause, SetExpr, Statement,
},
dialect::{BigQueryDialect, GenericDialect, MySqlDialect},
keywords::Keyword,
@ -116,16 +116,12 @@ impl Parser<'_> {
let update_token = self.get_current_token().clone();
self.expect_keyword_is(Keyword::SET)?;
let assignments = self.parse_comma_separated(Parser::parse_assignment)?;
let update_predicate = if self.dialect.supports_merge_update_predicate()
&& self.parse_keyword(Keyword::WHERE)
{
let update_predicate = if self.parse_keyword(Keyword::WHERE) {
Some(self.parse_expr()?)
} else {
None
};
let delete_predicate = if self.dialect.supports_merge_update_delete_predicate()
&& self.parse_keyword(Keyword::DELETE)
{
let delete_predicate = if self.parse_keyword(Keyword::DELETE) {
let _ = self.expect_keyword(Keyword::WHERE)?;
Some(self.parse_expr()?)
} else {
@ -179,9 +175,7 @@ impl Parser<'_> {
let values = self.parse_values(is_mysql, false)?;
(MergeInsertKind::Values(values), values_token)
};
let insert_predicate = if self.dialect.supports_merge_insert_predicate()
&& self.parse_keyword(Keyword::WHERE)
{
let insert_predicate = if self.parse_keyword(Keyword::WHERE) {
Some(self.parse_expr()?)
} else {
None
@ -216,25 +210,7 @@ impl Parser<'_> {
&mut self,
allow_empty: bool,
) -> Result<Vec<ObjectName>, ParserError> {
if self.dialect.supports_merge_insert_qualified_columns() {
self.parse_parenthesized_qualified_column_list(IsOptional::Optional, allow_empty)
} else {
self.parse_parenthesized_column_list_as_object_names(IsOptional::Optional, allow_empty)
}
}
/// Just like [Parser::parse_parenthesized_column_list] parses a
/// parenthesized list of (simple) column names but returns them as object
/// names.
fn parse_parenthesized_column_list_as_object_names(
&mut self,
optional: IsOptional,
allow_empty: bool,
) -> Result<Vec<ObjectName>, ParserError> {
self.parse_parenthesized_column_list_inner(optional, allow_empty, |p| {
p.parse_identifier()
.map(|ident| ObjectName(vec![ObjectNamePart::Identifier(ident)]))
})
self.parse_parenthesized_qualified_column_list(IsOptional::Optional, allow_empty)
}
fn parse_output(

View file

@ -1641,14 +1641,6 @@ fn ms_and_generic() -> TestedDialects {
TestedDialects::new(vec![Box::new(MsSqlDialect {}), Box::new(GenericDialect {})])
}
fn only_ms() -> TestedDialects {
TestedDialects::new(vec![Box::new(MsSqlDialect {})])
}
fn only_generic() -> TestedDialects {
TestedDialects::new(vec![Box::new(GenericDialect {})])
}
#[test]
fn parse_json_ops_without_colon() {
use self::BinaryOperator::*;
@ -10101,7 +10093,7 @@ WHEN NOT MATCHED THEN \
INSERT (ID, NAME) \
VALUES (FOO_IMPORT.ID, UPPER(FOO_IMPORT.NAME)) \
WHERE NOT FOO_IMPORT.NAME LIKE '%.DO_NOT_INSERT'";
only_generic().verified_stmt(sql);
all_dialects().verified_stmt(sql);
}
#[test]
@ -10121,7 +10113,7 @@ MERGE INTO FOO USING FOO_IMPORT ON (FOO.ID = FOO_IMPORT.ID) \
WHEN NOT MATCHED THEN \
INSERT (FOO.ID, FOO.NAME) \
VALUES (1, 'abc')";
pg_and_generic().verified_stmt(sql);
all_dialects().verified_stmt(sql);
}
#[test]
@ -10131,24 +10123,7 @@ MERGE INTO PLAYGROUND.FOO USING FOO_IMPORT ON (PLAYGROUND.FOO.ID = FOO_IMPORT.ID
WHEN NOT MATCHED THEN \
INSERT (PLAYGROUND.FOO.ID, PLAYGROUND.FOO.NAME) \
VALUES (1, 'abc')";
pg_and_generic().verified_stmt(sql);
}
#[test]
fn test_merge_insert_with_qualified_columns_not_supported() {
let sql = "\
MERGE INTO FOO USING FOO_IMPORT ON (FOO.ID = FOO_IMPORT.ID) \
WHEN NOT MATCHED THEN \
INSERT (FOO.ID, FOO.NAME) \
VALUES (1, 'abc')";
assert!(only_ms().parse_sql_statements(sql).is_err());
let sql = "\
MERGE INTO PLAYGROUND.FOO USING FOO_IMPORT ON (PLAYGROUND.FOO.ID = FOO_IMPORT.ID) \
WHEN NOT MATCHED THEN \
INSERT (PLAYGROUND.FOO.ID, PLAYGROUND.FOO.NAME) \
VALUES (1, 'abc')";
assert!(only_ms().parse_sql_statements(sql).is_err());
all_dialects().verified_stmt(sql);
}
#[test]