Skip to content

Commit cf25749

Browse files
committed
Add support for Snowflake SHOW DATABASES/SCHEMAS/TABLES/VIEWS/COLUMNS statements
1 parent 3a8369a commit cf25749

File tree

8 files changed

+717
-130
lines changed

8 files changed

+717
-130
lines changed

src/ast/mod.rs

Lines changed: 276 additions & 56 deletions
Large diffs are not rendered by default.

src/dialect/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,12 @@ pub trait Dialect: Debug + Any {
622622
fn supports_boolean_literals(&self) -> bool {
623623
true
624624
}
625+
626+
/// Returns true if this dialect support the `LIKE 'pattern'` option in
627+
/// a `SHOW` statement before the `IN` option
628+
fn supports_show_like_before_in(&self) -> bool {
629+
false
630+
}
625631
}
626632

627633
/// This represents the operators for which precedence must be defined

src/dialect/snowflake.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,12 @@ impl Dialect for SnowflakeDialect {
203203
fn allow_extract_single_quotes(&self) -> bool {
204204
true
205205
}
206+
207+
/// Snowflake expects the `LIKE` option before the `IN` option,
208+
/// for example: https://docs.snowflake.com/en/sql-reference/sql/show-views#syntax
209+
fn supports_show_like_before_in(&self) -> bool {
210+
true
211+
}
206212
}
207213

208214
/// Parse snowflake create table statement.

src/keywords.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ define_keywords!(
7676
ABS,
7777
ABSOLUTE,
7878
ACCESS,
79+
ACCOUNT,
7980
ACTION,
8081
ADD,
8182
ADMIN,
@@ -710,6 +711,7 @@ define_keywords!(
710711
STABLE,
711712
STAGE,
712713
START,
714+
STARTS,
713715
STATEMENT,
714716
STATIC,
715717
STATISTICS,
@@ -746,6 +748,7 @@ define_keywords!(
746748
TEMP,
747749
TEMPORARY,
748750
TERMINATED,
751+
TERSE,
749752
TEXT,
750753
TEXTFILE,
751754
THEN,

src/parser/mod.rs

Lines changed: 234 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9605,21 +9605,23 @@ impl<'a> Parser<'a> {
96059605
}
96069606

96079607
pub fn parse_show(&mut self) -> Result<Statement, ParserError> {
9608+
let terse = self.parse_keyword(Keyword::TERSE);
96089609
let extended = self.parse_keyword(Keyword::EXTENDED);
96099610
let full = self.parse_keyword(Keyword::FULL);
96109611
let session = self.parse_keyword(Keyword::SESSION);
96119612
let global = self.parse_keyword(Keyword::GLOBAL);
9613+
let external = self.parse_keyword(Keyword::EXTERNAL);
96129614
if self
96139615
.parse_one_of_keywords(&[Keyword::COLUMNS, Keyword::FIELDS])
96149616
.is_some()
96159617
{
96169618
Ok(self.parse_show_columns(extended, full)?)
96179619
} else if self.parse_keyword(Keyword::TABLES) {
9618-
Ok(self.parse_show_tables(extended, full)?)
9620+
Ok(self.parse_show_tables(terse, extended, full, external)?)
96199621
} else if self.parse_keywords(&[Keyword::MATERIALIZED, Keyword::VIEWS]) {
9620-
Ok(self.parse_show_views(true)?)
9622+
Ok(self.parse_show_views(terse, true)?)
96219623
} else if self.parse_keyword(Keyword::VIEWS) {
9622-
Ok(self.parse_show_views(false)?)
9624+
Ok(self.parse_show_views(terse, false)?)
96239625
} else if self.parse_keyword(Keyword::FUNCTIONS) {
96249626
Ok(self.parse_show_functions()?)
96259627
} else if extended || full {
@@ -9647,25 +9649,49 @@ impl<'a> Parser<'a> {
96479649
global,
96489650
})
96499651
} else if self.parse_keyword(Keyword::DATABASES) {
9650-
self.parse_show_databases()
9652+
self.parse_show_databases(terse)
96519653
} else if self.parse_keyword(Keyword::SCHEMAS) {
9652-
self.parse_show_schemas()
9654+
self.parse_show_schemas(terse)
96539655
} else {
96549656
Ok(Statement::ShowVariable {
96559657
variable: self.parse_identifiers()?,
96569658
})
96579659
}
96589660
}
96599661

9660-
fn parse_show_databases(&mut self) -> Result<Statement, ParserError> {
9662+
fn parse_show_databases(&mut self, terse: bool) -> Result<Statement, ParserError> {
9663+
let history = self.parse_keyword(Keyword::HISTORY);
9664+
let filter = self.parse_show_statement_filter()?;
9665+
let show_in = self.parse_show_opt_in()?;
9666+
let starts_with = self.parse_show_opt_starts_with()?;
9667+
let limit = self.parse_show_opt_limit()?;
9668+
let from = self.parse_show_opt_from()?;
96619669
Ok(Statement::ShowDatabases {
9662-
filter: self.parse_show_statement_filter()?,
9670+
terse,
9671+
history,
9672+
filter,
9673+
show_in,
9674+
starts_with,
9675+
limit,
9676+
from,
96639677
})
96649678
}
96659679

9666-
fn parse_show_schemas(&mut self) -> Result<Statement, ParserError> {
9680+
fn parse_show_schemas(&mut self, terse: bool) -> Result<Statement, ParserError> {
9681+
let history = self.parse_keyword(Keyword::HISTORY);
9682+
let filter = self.parse_show_statement_filter()?;
9683+
let show_in = self.parse_show_opt_in()?;
9684+
let starts_with = self.parse_show_opt_starts_with()?;
9685+
let limit = self.parse_show_opt_limit()?;
9686+
let from = self.parse_show_opt_from()?;
96679687
Ok(Statement::ShowSchemas {
9668-
filter: self.parse_show_statement_filter()?,
9688+
terse,
9689+
history,
9690+
filter,
9691+
show_in,
9692+
starts_with,
9693+
limit,
9694+
from,
96699695
})
96709696
}
96719697

@@ -9699,58 +9725,95 @@ impl<'a> Parser<'a> {
96999725
extended: bool,
97009726
full: bool,
97019727
) -> Result<Statement, ParserError> {
9702-
self.expect_one_of_keywords(&[Keyword::FROM, Keyword::IN])?;
9703-
let object_name = self.parse_object_name(false)?;
9704-
let table_name = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
9705-
Some(_) => {
9706-
let db_name = vec![self.parse_identifier(false)?];
9707-
let ObjectName(table_name) = object_name;
9708-
let object_name = db_name.into_iter().chain(table_name).collect();
9709-
ObjectName(object_name)
9710-
}
9711-
None => object_name,
9712-
};
9713-
let filter = self.parse_show_statement_filter()?;
9728+
let filter;
9729+
let filter_position;
9730+
let show_in;
9731+
if self.dialect.supports_show_like_before_in() {
9732+
filter = self.parse_show_statement_filter()?;
9733+
filter_position = ShowStatementFilterPosition::InTheMiddle;
9734+
show_in = self.parse_show_opt_in()?;
9735+
} else {
9736+
show_in = self.parse_show_opt_in()?;
9737+
filter = self.parse_show_statement_filter()?;
9738+
filter_position = ShowStatementFilterPosition::AtTheEnd;
9739+
}
97149740
Ok(Statement::ShowColumns {
97159741
extended,
97169742
full,
9717-
table_name,
9743+
show_in,
97189744
filter,
9745+
filter_position,
97199746
})
97209747
}
97219748

9722-
pub fn parse_show_tables(
9749+
fn parse_show_tables(
97239750
&mut self,
9751+
terse: bool,
97249752
extended: bool,
97259753
full: bool,
9754+
external: bool,
97269755
) -> Result<Statement, ParserError> {
9727-
let (clause, db_name) = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
9728-
Some(Keyword::FROM) => (Some(ShowClause::FROM), Some(self.parse_identifier(false)?)),
9729-
Some(Keyword::IN) => (Some(ShowClause::IN), Some(self.parse_identifier(false)?)),
9730-
_ => (None, None),
9731-
};
9732-
let filter = self.parse_show_statement_filter()?;
9756+
let history = !external && self.parse_keyword(Keyword::HISTORY);
9757+
let filter;
9758+
let show_in;
9759+
let filter_position;
9760+
if self.dialect.supports_show_like_before_in() {
9761+
filter = self.parse_show_statement_filter()?;
9762+
//YOAV: here we have a problem, the hint is DB-dependent (table in a schemas or some other object)
9763+
show_in = self.parse_show_opt_in()?;
9764+
filter_position = ShowStatementFilterPosition::InTheMiddle;
9765+
} else {
9766+
show_in = self.parse_show_opt_in()?;
9767+
filter = self.parse_show_statement_filter()?;
9768+
filter_position = ShowStatementFilterPosition::AtTheEnd;
9769+
}
9770+
let starts_with = self.parse_show_opt_starts_with()?;
9771+
let limit = self.parse_show_opt_limit()?;
9772+
let from = self.parse_show_opt_from()?;
97339773
Ok(Statement::ShowTables {
9774+
terse,
9775+
history,
97349776
extended,
97359777
full,
9736-
clause,
9737-
db_name,
9778+
external,
97389779
filter,
9780+
show_in,
9781+
starts_with,
9782+
limit,
9783+
from,
9784+
filter_position,
97399785
})
97409786
}
97419787

9742-
fn parse_show_views(&mut self, materialized: bool) -> Result<Statement, ParserError> {
9743-
let (clause, db_name) = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
9744-
Some(Keyword::FROM) => (Some(ShowClause::FROM), Some(self.parse_identifier(false)?)),
9745-
Some(Keyword::IN) => (Some(ShowClause::IN), Some(self.parse_identifier(false)?)),
9746-
_ => (None, None),
9747-
};
9748-
let filter = self.parse_show_statement_filter()?;
9788+
fn parse_show_views(
9789+
&mut self,
9790+
terse: bool,
9791+
materialized: bool,
9792+
) -> Result<Statement, ParserError> {
9793+
let filter;
9794+
let show_in;
9795+
let filter_position;
9796+
if self.dialect.supports_show_like_before_in() {
9797+
filter = self.parse_show_statement_filter()?;
9798+
show_in = self.parse_show_opt_in()?;
9799+
filter_position = ShowStatementFilterPosition::InTheMiddle;
9800+
} else {
9801+
show_in = self.parse_show_opt_in()?;
9802+
filter = self.parse_show_statement_filter()?;
9803+
filter_position = ShowStatementFilterPosition::AtTheEnd;
9804+
}
9805+
let starts_with = self.parse_show_opt_starts_with()?;
9806+
let limit = self.parse_show_opt_limit()?;
9807+
let from = self.parse_show_opt_from()?;
97499808
Ok(Statement::ShowViews {
97509809
materialized,
9751-
clause,
9752-
db_name,
9810+
terse,
97539811
filter,
9812+
filter_position,
9813+
show_in,
9814+
starts_with,
9815+
limit,
9816+
from,
97549817
})
97559818
}
97569819

@@ -12389,6 +12452,137 @@ impl<'a> Parser<'a> {
1238912452
}
1239012453
false
1239112454
}
12455+
12456+
/// Look for an expected keyword, without consuming it
12457+
fn peek_keyword(&self, expected: Keyword) -> bool {
12458+
match self.peek_token().token {
12459+
Token::Word(w) => expected == w.keyword,
12460+
_ => false,
12461+
}
12462+
}
12463+
12464+
/// Look for one of expected keyword, without consuming it
12465+
fn peek_keywords(&self, expected: &[Keyword]) -> bool {
12466+
for kw in expected {
12467+
if self.peek_keyword(*kw) {
12468+
return true;
12469+
}
12470+
}
12471+
false
12472+
}
12473+
12474+
fn parse_show_opt_in(&mut self) -> Result<Option<ShowStatementIn>, ParserError> {
12475+
let clause = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
12476+
Some(Keyword::FROM) => ShowStatementInClause::FROM,
12477+
Some(Keyword::IN) => ShowStatementInClause::IN,
12478+
_ => return Ok(None),
12479+
};
12480+
12481+
if self.parse_keyword(Keyword::DATABASE) {
12482+
if self.peek_keywords(&[Keyword::STARTS, Keyword::WITH]) {
12483+
Ok(Some(ShowStatementIn {
12484+
clause,
12485+
parent_type: Some(ShowStatementInParentType::Database),
12486+
parent_name: None,
12487+
}))
12488+
} else {
12489+
let parent_name = match self.parse_object_name(false) {
12490+
Ok(n) => Some(n),
12491+
Err(_) => None,
12492+
};
12493+
Ok(Some(ShowStatementIn {
12494+
clause,
12495+
parent_type: Some(ShowStatementInParentType::Database),
12496+
parent_name,
12497+
}))
12498+
}
12499+
} else if self.parse_keyword(Keyword::SCHEMA) {
12500+
if self.peek_keywords(&[Keyword::STARTS, Keyword::WITH]) {
12501+
Ok(Some(ShowStatementIn {
12502+
clause,
12503+
parent_type: Some(ShowStatementInParentType::Schema),
12504+
parent_name: None,
12505+
}))
12506+
} else {
12507+
let parent_name = match self.parse_object_name(false) {
12508+
Ok(n) => Some(n),
12509+
Err(_) => None,
12510+
};
12511+
Ok(Some(ShowStatementIn {
12512+
clause,
12513+
parent_type: Some(ShowStatementInParentType::Schema),
12514+
parent_name,
12515+
}))
12516+
}
12517+
} else if self.parse_keyword(Keyword::ACCOUNT) {
12518+
let parent_name = match self.parse_object_name(false) {
12519+
Ok(n) => Some(n),
12520+
Err(_) => None,
12521+
};
12522+
Ok(Some(ShowStatementIn {
12523+
clause,
12524+
parent_type: Some(ShowStatementInParentType::Account),
12525+
parent_name,
12526+
}))
12527+
} else if self.parse_keyword(Keyword::TABLE) {
12528+
let parent_name = match self.parse_object_name(false) {
12529+
Ok(n) => Some(n),
12530+
Err(_) => None,
12531+
};
12532+
Ok(Some(ShowStatementIn {
12533+
clause,
12534+
parent_type: Some(ShowStatementInParentType::Table),
12535+
parent_name,
12536+
}))
12537+
} else if self.parse_keyword(Keyword::VIEW) {
12538+
let parent_name = match self.parse_object_name(false) {
12539+
Ok(n) => Some(n),
12540+
Err(_) => None,
12541+
};
12542+
Ok(Some(ShowStatementIn {
12543+
clause,
12544+
parent_type: Some(ShowStatementInParentType::View),
12545+
parent_name,
12546+
}))
12547+
} else {
12548+
// Parsing MySQL style FROM tbl_name FROM db_name
12549+
// which is equivalent to FROM tbl_name.db_name
12550+
let mut parent_name = self.parse_object_name(false)?;
12551+
if self
12552+
.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN])
12553+
.is_some()
12554+
{
12555+
parent_name.0.insert(0, self.parse_identifier(false)?);
12556+
}
12557+
12558+
Ok(Some(ShowStatementIn {
12559+
clause,
12560+
parent_type: None,
12561+
parent_name: Some(parent_name),
12562+
}))
12563+
}
12564+
}
12565+
12566+
fn parse_show_opt_starts_with(&mut self) -> Result<Option<Value>, ParserError> {
12567+
match self.parse_keywords(&[Keyword::STARTS, Keyword::WITH]) {
12568+
true => Ok(Some(self.parse_value()?)),
12569+
false => Ok(None),
12570+
}
12571+
}
12572+
12573+
fn parse_show_opt_limit(&mut self) -> Result<Option<Expr>, ParserError> {
12574+
match self.parse_keyword(Keyword::LIMIT) {
12575+
true => Ok(self.parse_limit()?),
12576+
false => Ok(None),
12577+
}
12578+
}
12579+
12580+
fn parse_show_opt_from(&mut self) -> Result<Option<Value>, ParserError> {
12581+
match self.parse_keyword(Keyword::FROM) {
12582+
true => Ok(Some(self.parse_value()?)),
12583+
false => Ok(None),
12584+
}
12585+
}
1239212586
}
1239312587

1239412588
impl Word {

0 commit comments

Comments
 (0)