From 1df5061bcc20628d298f97ae5048692a94cadd0d Mon Sep 17 00:00:00 2001 From: Denys Tsomenko Date: Sun, 15 Nov 2026 13:03:32 +0200 Subject: [PATCH] fix: unify the native constraint-reliance parser pin --- Cargo.lock | 4 +-- Cargo.toml | 2 +- datafusion/sql/src/parser.rs | 70 ++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3942f2866e18e..c2c9c1707c3d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5877,7 +5877,7 @@ dependencies = [ [[package]] name = "sqlparser" version = "0.62.0" -source = "git+https://github.com/Embucket/datafusion-sqlparser-rs.git?rev=874cfbb81d2a34e6ee101d3a7ecd1ae6b60000c6#874cfbb81d2a34e6ee101d3a7ecd1ae6b60000c6" +source = "git+https://github.com/Embucket/datafusion-sqlparser-rs.git?rev=ee24d34fe4e49bc6d405a4da163a555bdabd9879#ee24d34fe4e49bc6d405a4da163a555bdabd9879" dependencies = [ "log", "recursive", @@ -5887,7 +5887,7 @@ dependencies = [ [[package]] name = "sqlparser_derive" version = "0.5.0" -source = "git+https://github.com/Embucket/datafusion-sqlparser-rs.git?rev=874cfbb81d2a34e6ee101d3a7ecd1ae6b60000c6#874cfbb81d2a34e6ee101d3a7ecd1ae6b60000c6" +source = "git+https://github.com/Embucket/datafusion-sqlparser-rs.git?rev=ee24d34fe4e49bc6d405a4da163a555bdabd9879#ee24d34fe4e49bc6d405a4da163a555bdabd9879" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index e5a8026a3c4da..83b3955de9560 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -196,7 +196,7 @@ regex = "1.12" rstest = "0.26.1" serde_json = "1" sha2 = "^0.11.0" -sqlparser = { git = "https://github.com/Embucket/datafusion-sqlparser-rs.git", rev = "874cfbb81d2a34e6ee101d3a7ecd1ae6b60000c6", default-features = false, features = [ +sqlparser = { git = "https://github.com/Embucket/datafusion-sqlparser-rs.git", rev = "ee24d34fe4e49bc6d405a4da163a555bdabd9879", default-features = false, features = [ "std", "visitor", ] } diff --git a/datafusion/sql/src/parser.rs b/datafusion/sql/src/parser.rs index efd78ffabe35a..3539c1525416b 100644 --- a/datafusion/sql/src/parser.rs +++ b/datafusion/sql/src/parser.rs @@ -2452,4 +2452,74 @@ mod tests { "error should describe unknown option: {msg}" ); } + + #[test] + fn constraint_reliance_control_without_rely() { + let sql = "CREATE TABLE NE (ID INT PRIMARY KEY NOT ENFORCED)"; + let statements = DFParser::parse_sql_with_dialect(sql, &SnowflakeDialect {}) + .expect("existing inline primary key syntax"); + assert_eq!(statements.len(), 1); + assert_eq!(statements[0].to_string(), sql); + } + + #[test] + fn constraint_reliance_preserves_native_snowflake_declaration() { + let sql = "CREATE TABLE NE (ID INT PRIMARY KEY NOT ENFORCED RELY)"; + let statements = DFParser::parse_sql_with_dialect(sql, &SnowflakeDialect {}) + .expect("native Snowflake constraint reliance syntax"); + assert_eq!(statements.len(), 1); + assert_eq!(statements[0].to_string(), sql); + } + + #[test] + fn constraint_reliance_exposes_original_typed_characteristics() { + use sqlparser::ast::{ColumnOption, ConstraintCharacteristics, Visit, Visitor}; + use std::ops::ControlFlow; + + struct CharacteristicsVisitor<'a> { + expected: &'a ConstraintCharacteristics, + visits: usize, + } + + impl Visitor for CharacteristicsVisitor<'_> { + type Break = (); + + fn pre_visit_constraint_characteristics( + &mut self, + characteristics: &ConstraintCharacteristics, + ) -> ControlFlow { + assert!(std::ptr::eq(characteristics, self.expected)); + self.visits += 1; + ControlFlow::Continue(()) + } + } + + // Syntax and borrowed AST identity only: this grants no optimizer trust. + for (keyword, expected_rely) in [("RELY", true), ("NORELY", false)] { + let sql = + format!("CREATE TABLE NE (ID INT PRIMARY KEY NOT ENFORCED {keyword})"); + let statements = DFParser::parse_sql_with_dialect(&sql, &SnowflakeDialect {}) + .expect("native constraint reliance syntax"); + let Statement::Statement(statement) = &statements[0] else { + panic!("expected native statement"); + }; + let SQLStatement::CreateTable(create) = statement.as_ref() else { + panic!("expected CREATE TABLE"); + }; + let ColumnOption::PrimaryKey(key) = &create.columns[0].options[0].option + else { + panic!("expected inline primary key"); + }; + let characteristics = key.characteristics.as_ref().expect("characteristics"); + assert_eq!(characteristics.enforced, Some(false)); + assert_eq!(characteristics.rely, Some(expected_rely)); + let mut visitor = CharacteristicsVisitor { + expected: characteristics, + visits: 0, + }; + assert_eq!(statement.visit(&mut visitor), ControlFlow::Continue(())); + assert_eq!(visitor.visits, 1); + assert_eq!(statements[0].to_string(), sql); + } + } }