Skip to content

Commit 57113a9

Browse files
authored
Support DECLARE syntax for snowflake and bigquery (#1122)
1 parent f75bb4b commit 57113a9

File tree

5 files changed

+741
-68
lines changed

5 files changed

+741
-68
lines changed

src/ast/mod.rs

Lines changed: 209 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,6 +1422,211 @@ pub enum Password {
14221422
NullPassword,
14231423
}
14241424

1425+
/// Represents an expression assignment within a variable `DECLARE` statement.
1426+
///
1427+
/// Examples:
1428+
/// ```sql
1429+
/// DECLARE variable_name := 42
1430+
/// DECLARE variable_name DEFAULT 42
1431+
/// ```
1432+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1433+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1434+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1435+
pub enum DeclareAssignment {
1436+
/// Plain expression specified.
1437+
Expr(Box<Expr>),
1438+
1439+
/// Expression assigned via the `DEFAULT` keyword
1440+
Default(Box<Expr>),
1441+
1442+
/// Expression assigned via the `:=` syntax
1443+
///
1444+
/// Example:
1445+
/// ```sql
1446+
/// DECLARE variable_name := 42;
1447+
/// ```
1448+
DuckAssignment(Box<Expr>),
1449+
1450+
/// Expression via the `FOR` keyword
1451+
///
1452+
/// Example:
1453+
/// ```sql
1454+
/// DECLARE c1 CURSOR FOR res
1455+
/// ```
1456+
For(Box<Expr>),
1457+
}
1458+
1459+
impl fmt::Display for DeclareAssignment {
1460+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1461+
match self {
1462+
DeclareAssignment::Expr(expr) => {
1463+
write!(f, "{expr}")
1464+
}
1465+
DeclareAssignment::Default(expr) => {
1466+
write!(f, "DEFAULT {expr}")
1467+
}
1468+
DeclareAssignment::DuckAssignment(expr) => {
1469+
write!(f, ":= {expr}")
1470+
}
1471+
DeclareAssignment::For(expr) => {
1472+
write!(f, "FOR {expr}")
1473+
}
1474+
}
1475+
}
1476+
}
1477+
1478+
/// Represents the type of a `DECLARE` statement.
1479+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1480+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1481+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1482+
pub enum DeclareType {
1483+
/// Cursor variable type. e.g. [Snowflake] [Postgres]
1484+
///
1485+
/// [Snowflake]: https://docs.snowflake.com/en/developer-guide/snowflake-scripting/cursors#declaring-a-cursor
1486+
/// [Postgres]: https://www.postgresql.org/docs/current/plpgsql-cursors.html
1487+
Cursor,
1488+
1489+
/// Result set variable type. [Snowflake]
1490+
///
1491+
/// Syntax:
1492+
/// ```text
1493+
/// <resultset_name> RESULTSET [ { DEFAULT | := } ( <query> ) ] ;
1494+
/// ```
1495+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/snowflake-scripting/declare#resultset-declaration-syntax
1496+
ResultSet,
1497+
1498+
/// Exception declaration syntax. [Snowflake]
1499+
///
1500+
/// Syntax:
1501+
/// ```text
1502+
/// <exception_name> EXCEPTION [ ( <exception_number> , '<exception_message>' ) ] ;
1503+
/// ```
1504+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/snowflake-scripting/declare#exception-declaration-syntax
1505+
Exception,
1506+
}
1507+
1508+
impl fmt::Display for DeclareType {
1509+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1510+
match self {
1511+
DeclareType::Cursor => {
1512+
write!(f, "CURSOR")
1513+
}
1514+
DeclareType::ResultSet => {
1515+
write!(f, "RESULTSET")
1516+
}
1517+
DeclareType::Exception => {
1518+
write!(f, "EXCEPTION")
1519+
}
1520+
}
1521+
}
1522+
}
1523+
1524+
/// A `DECLARE` statement.
1525+
/// [Postgres] [Snowflake] [BigQuery]
1526+
///
1527+
/// Examples:
1528+
/// ```sql
1529+
/// DECLARE variable_name := 42
1530+
/// DECLARE liahona CURSOR FOR SELECT * FROM films;
1531+
/// ```
1532+
///
1533+
/// [Postgres]: https://www.postgresql.org/docs/current/sql-declare.html
1534+
/// [Snowflake]: https://docs.snowflake.com/en/sql-reference/snowflake-scripting/declare
1535+
/// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#declare
1536+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1537+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1538+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1539+
pub struct Declare {
1540+
/// The name(s) being declared.
1541+
/// Example: `DECLARE a, b, c DEFAULT 42;
1542+
pub names: Vec<Ident>,
1543+
/// Data-type assigned to the declared variable.
1544+
/// Example: `DECLARE x INT64 DEFAULT 42;
1545+
pub data_type: Option<DataType>,
1546+
/// Expression being assigned to the declared variable.
1547+
pub assignment: Option<DeclareAssignment>,
1548+
/// Represents the type of the declared variable.
1549+
pub declare_type: Option<DeclareType>,
1550+
/// Causes the cursor to return data in binary rather than in text format.
1551+
pub binary: Option<bool>,
1552+
/// None = Not specified
1553+
/// Some(true) = INSENSITIVE
1554+
/// Some(false) = ASENSITIVE
1555+
pub sensitive: Option<bool>,
1556+
/// None = Not specified
1557+
/// Some(true) = SCROLL
1558+
/// Some(false) = NO SCROLL
1559+
pub scroll: Option<bool>,
1560+
/// None = Not specified
1561+
/// Some(true) = WITH HOLD, specifies that the cursor can continue to be used after the transaction that created it successfully commits
1562+
/// Some(false) = WITHOUT HOLD, specifies that the cursor cannot be used outside of the transaction that created it
1563+
pub hold: Option<bool>,
1564+
/// `FOR <query>` clause in a CURSOR declaration.
1565+
pub for_query: Option<Box<Query>>,
1566+
}
1567+
1568+
impl fmt::Display for Declare {
1569+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1570+
let Declare {
1571+
names,
1572+
data_type,
1573+
assignment,
1574+
declare_type,
1575+
binary,
1576+
sensitive,
1577+
scroll,
1578+
hold,
1579+
for_query,
1580+
} = self;
1581+
write!(f, "{}", display_comma_separated(names))?;
1582+
1583+
if let Some(true) = binary {
1584+
write!(f, " BINARY")?;
1585+
}
1586+
1587+
if let Some(sensitive) = sensitive {
1588+
if *sensitive {
1589+
write!(f, " INSENSITIVE")?;
1590+
} else {
1591+
write!(f, " ASENSITIVE")?;
1592+
}
1593+
}
1594+
1595+
if let Some(scroll) = scroll {
1596+
if *scroll {
1597+
write!(f, " SCROLL")?;
1598+
} else {
1599+
write!(f, " NO SCROLL")?;
1600+
}
1601+
}
1602+
1603+
if let Some(declare_type) = declare_type {
1604+
write!(f, " {declare_type}")?;
1605+
}
1606+
1607+
if let Some(hold) = hold {
1608+
if *hold {
1609+
write!(f, " WITH HOLD")?;
1610+
} else {
1611+
write!(f, " WITHOUT HOLD")?;
1612+
}
1613+
}
1614+
1615+
if let Some(query) = for_query {
1616+
write!(f, " FOR {query}")?;
1617+
}
1618+
1619+
if let Some(data_type) = data_type {
1620+
write!(f, " {data_type}")?;
1621+
}
1622+
1623+
if let Some(expr) = assignment {
1624+
write!(f, " {expr}")?;
1625+
}
1626+
Ok(())
1627+
}
1628+
}
1629+
14251630
/// Sql options of a `CREATE TABLE` statement.
14261631
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
14271632
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -1873,25 +2078,7 @@ pub enum Statement {
18732078
///
18742079
/// Note: this is a PostgreSQL-specific statement,
18752080
/// but may also compatible with other SQL.
1876-
Declare {
1877-
/// Cursor name
1878-
name: Ident,
1879-
/// Causes the cursor to return data in binary rather than in text format.
1880-
binary: bool,
1881-
/// None = Not specified
1882-
/// Some(true) = INSENSITIVE
1883-
/// Some(false) = ASENSITIVE
1884-
sensitive: Option<bool>,
1885-
/// None = Not specified
1886-
/// Some(true) = SCROLL
1887-
/// Some(false) = NO SCROLL
1888-
scroll: Option<bool>,
1889-
/// None = Not specified
1890-
/// Some(true) = WITH HOLD, specifies that the cursor can continue to be used after the transaction that created it successfully commits
1891-
/// Some(false) = WITHOUT HOLD, specifies that the cursor cannot be used outside of the transaction that created it
1892-
hold: Option<bool>,
1893-
query: Box<Query>,
1894-
},
2081+
Declare { stmts: Vec<Declare> },
18952082
/// ```sql
18962083
/// CREATE EXTENSION [ IF NOT EXISTS ] extension_name
18972084
/// [ WITH ] [ SCHEMA schema_name ]
@@ -2447,47 +2634,9 @@ impl fmt::Display for Statement {
24472634
write!(f, "{statement}")
24482635
}
24492636
Statement::Query(s) => write!(f, "{s}"),
2450-
Statement::Declare {
2451-
name,
2452-
binary,
2453-
sensitive,
2454-
scroll,
2455-
hold,
2456-
query,
2457-
} => {
2458-
write!(f, "DECLARE {name} ")?;
2459-
2460-
if *binary {
2461-
write!(f, "BINARY ")?;
2462-
}
2463-
2464-
if let Some(sensitive) = sensitive {
2465-
if *sensitive {
2466-
write!(f, "INSENSITIVE ")?;
2467-
} else {
2468-
write!(f, "ASENSITIVE ")?;
2469-
}
2470-
}
2471-
2472-
if let Some(scroll) = scroll {
2473-
if *scroll {
2474-
write!(f, "SCROLL ")?;
2475-
} else {
2476-
write!(f, "NO SCROLL ")?;
2477-
}
2478-
}
2479-
2480-
write!(f, "CURSOR ")?;
2481-
2482-
if let Some(hold) = hold {
2483-
if *hold {
2484-
write!(f, "WITH HOLD ")?;
2485-
} else {
2486-
write!(f, "WITHOUT HOLD ")?;
2487-
}
2488-
}
2489-
2490-
write!(f, "FOR {query}")
2637+
Statement::Declare { stmts } => {
2638+
write!(f, "DECLARE ")?;
2639+
write!(f, "{}", display_separated(stmts, "; "))
24912640
}
24922641
Statement::Fetch {
24932642
name,

src/keywords.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ define_keywords!(
261261
EVENT,
262262
EVERY,
263263
EXCEPT,
264+
EXCEPTION,
264265
EXCLUDE,
265266
EXCLUSIVE,
266267
EXEC,
@@ -562,6 +563,7 @@ define_keywords!(
562563
RESTART,
563564
RESTRICT,
564565
RESULT,
566+
RESULTSET,
565567
RETAIN,
566568
RETURN,
567569
RETURNING,

0 commit comments

Comments
 (0)