Skip to content

Commit 9ce24ba

Browse files
committed
Add support for Snowflake SHOW DATABASES/SCHEMAS/TABLES/VIEWS/COLUMNS statements
1 parent 334a5bf commit 9ce24ba

File tree

8 files changed

+717
-130
lines changed

8 files changed

+717
-130
lines changed

src/ast/mod.rs

+276-56
Large diffs are not rendered by default.

src/dialect/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,12 @@ pub trait Dialect: Debug + Any {
606606
fn supports_top_before_distinct(&self) -> bool {
607607
false
608608
}
609+
610+
/// Returns true if this dialect support the `LIKE 'pattern'` option in
611+
/// a `SHOW` statement before the `IN` option
612+
fn supports_show_like_before_in(&self) -> bool {
613+
false
614+
}
609615
}
610616

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

src/dialect/snowflake.rs

+6
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

+3
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,
@@ -709,6 +710,7 @@ define_keywords!(
709710
STABLE,
710711
STAGE,
711712
START,
713+
STARTS,
712714
STATEMENT,
713715
STATIC,
714716
STATISTICS,
@@ -745,6 +747,7 @@ define_keywords!(
745747
TEMP,
746748
TEMPORARY,
747749
TERMINATED,
750+
TERSE,
748751
TEXT,
749752
TEXTFILE,
750753
THEN,

src/parser/mod.rs

+234-40
Original file line numberDiff line numberDiff line change
@@ -9591,21 +9591,23 @@ impl<'a> Parser<'a> {
95919591
}
95929592

95939593
pub fn parse_show(&mut self) -> Result<Statement, ParserError> {
9594+
let terse = self.parse_keyword(Keyword::TERSE);
95949595
let extended = self.parse_keyword(Keyword::EXTENDED);
95959596
let full = self.parse_keyword(Keyword::FULL);
95969597
let session = self.parse_keyword(Keyword::SESSION);
95979598
let global = self.parse_keyword(Keyword::GLOBAL);
9599+
let external = self.parse_keyword(Keyword::EXTERNAL);
95989600
if self
95999601
.parse_one_of_keywords(&[Keyword::COLUMNS, Keyword::FIELDS])
96009602
.is_some()
96019603
{
96029604
Ok(self.parse_show_columns(extended, full)?)
96039605
} else if self.parse_keyword(Keyword::TABLES) {
9604-
Ok(self.parse_show_tables(extended, full)?)
9606+
Ok(self.parse_show_tables(terse, extended, full, external)?)
96059607
} else if self.parse_keywords(&[Keyword::MATERIALIZED, Keyword::VIEWS]) {
9606-
Ok(self.parse_show_views(true)?)
9608+
Ok(self.parse_show_views(terse, true)?)
96079609
} else if self.parse_keyword(Keyword::VIEWS) {
9608-
Ok(self.parse_show_views(false)?)
9610+
Ok(self.parse_show_views(terse, false)?)
96099611
} else if self.parse_keyword(Keyword::FUNCTIONS) {
96109612
Ok(self.parse_show_functions()?)
96119613
} else if extended || full {
@@ -9633,25 +9635,49 @@ impl<'a> Parser<'a> {
96339635
global,
96349636
})
96359637
} else if self.parse_keyword(Keyword::DATABASES) {
9636-
self.parse_show_databases()
9638+
self.parse_show_databases(terse)
96379639
} else if self.parse_keyword(Keyword::SCHEMAS) {
9638-
self.parse_show_schemas()
9640+
self.parse_show_schemas(terse)
96399641
} else {
96409642
Ok(Statement::ShowVariable {
96419643
variable: self.parse_identifiers()?,
96429644
})
96439645
}
96449646
}
96459647

9646-
fn parse_show_databases(&mut self) -> Result<Statement, ParserError> {
9648+
fn parse_show_databases(&mut self, terse: bool) -> Result<Statement, ParserError> {
9649+
let history = self.parse_keyword(Keyword::HISTORY);
9650+
let filter = self.parse_show_statement_filter()?;
9651+
let show_in = self.parse_show_opt_in()?;
9652+
let starts_with = self.parse_show_opt_starts_with()?;
9653+
let limit = self.parse_show_opt_limit()?;
9654+
let from = self.parse_show_opt_from()?;
96479655
Ok(Statement::ShowDatabases {
9648-
filter: self.parse_show_statement_filter()?,
9656+
terse,
9657+
history,
9658+
filter,
9659+
show_in,
9660+
starts_with,
9661+
limit,
9662+
from,
96499663
})
96509664
}
96519665

9652-
fn parse_show_schemas(&mut self) -> Result<Statement, ParserError> {
9666+
fn parse_show_schemas(&mut self, terse: bool) -> Result<Statement, ParserError> {
9667+
let history = self.parse_keyword(Keyword::HISTORY);
9668+
let filter = self.parse_show_statement_filter()?;
9669+
let show_in = self.parse_show_opt_in()?;
9670+
let starts_with = self.parse_show_opt_starts_with()?;
9671+
let limit = self.parse_show_opt_limit()?;
9672+
let from = self.parse_show_opt_from()?;
96539673
Ok(Statement::ShowSchemas {
9654-
filter: self.parse_show_statement_filter()?,
9674+
terse,
9675+
history,
9676+
filter,
9677+
show_in,
9678+
starts_with,
9679+
limit,
9680+
from,
96559681
})
96569682
}
96579683

@@ -9685,58 +9711,95 @@ impl<'a> Parser<'a> {
96859711
extended: bool,
96869712
full: bool,
96879713
) -> Result<Statement, ParserError> {
9688-
self.expect_one_of_keywords(&[Keyword::FROM, Keyword::IN])?;
9689-
let object_name = self.parse_object_name(false)?;
9690-
let table_name = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
9691-
Some(_) => {
9692-
let db_name = vec![self.parse_identifier(false)?];
9693-
let ObjectName(table_name) = object_name;
9694-
let object_name = db_name.into_iter().chain(table_name).collect();
9695-
ObjectName(object_name)
9696-
}
9697-
None => object_name,
9698-
};
9699-
let filter = self.parse_show_statement_filter()?;
9714+
let filter;
9715+
let filter_position;
9716+
let show_in;
9717+
if self.dialect.supports_show_like_before_in() {
9718+
filter = self.parse_show_statement_filter()?;
9719+
filter_position = ShowStatementFilterPosition::InTheMiddle;
9720+
show_in = self.parse_show_opt_in()?;
9721+
} else {
9722+
show_in = self.parse_show_opt_in()?;
9723+
filter = self.parse_show_statement_filter()?;
9724+
filter_position = ShowStatementFilterPosition::AtTheEnd;
9725+
}
97009726
Ok(Statement::ShowColumns {
97019727
extended,
97029728
full,
9703-
table_name,
9729+
show_in,
97049730
filter,
9731+
filter_position,
97059732
})
97069733
}
97079734

9708-
pub fn parse_show_tables(
9735+
fn parse_show_tables(
97099736
&mut self,
9737+
terse: bool,
97109738
extended: bool,
97119739
full: bool,
9740+
external: bool,
97129741
) -> Result<Statement, ParserError> {
9713-
let (clause, db_name) = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
9714-
Some(Keyword::FROM) => (Some(ShowClause::FROM), Some(self.parse_identifier(false)?)),
9715-
Some(Keyword::IN) => (Some(ShowClause::IN), Some(self.parse_identifier(false)?)),
9716-
_ => (None, None),
9717-
};
9718-
let filter = self.parse_show_statement_filter()?;
9742+
let history = !external && self.parse_keyword(Keyword::HISTORY);
9743+
let filter;
9744+
let show_in;
9745+
let filter_position;
9746+
if self.dialect.supports_show_like_before_in() {
9747+
filter = self.parse_show_statement_filter()?;
9748+
//YOAV: here we have a problem, the hint is DB-dependent (table in a schemas or some other object)
9749+
show_in = self.parse_show_opt_in()?;
9750+
filter_position = ShowStatementFilterPosition::InTheMiddle;
9751+
} else {
9752+
show_in = self.parse_show_opt_in()?;
9753+
filter = self.parse_show_statement_filter()?;
9754+
filter_position = ShowStatementFilterPosition::AtTheEnd;
9755+
}
9756+
let starts_with = self.parse_show_opt_starts_with()?;
9757+
let limit = self.parse_show_opt_limit()?;
9758+
let from = self.parse_show_opt_from()?;
97199759
Ok(Statement::ShowTables {
9760+
terse,
9761+
history,
97209762
extended,
97219763
full,
9722-
clause,
9723-
db_name,
9764+
external,
97249765
filter,
9766+
show_in,
9767+
starts_with,
9768+
limit,
9769+
from,
9770+
filter_position,
97259771
})
97269772
}
97279773

9728-
fn parse_show_views(&mut self, materialized: bool) -> Result<Statement, ParserError> {
9729-
let (clause, db_name) = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
9730-
Some(Keyword::FROM) => (Some(ShowClause::FROM), Some(self.parse_identifier(false)?)),
9731-
Some(Keyword::IN) => (Some(ShowClause::IN), Some(self.parse_identifier(false)?)),
9732-
_ => (None, None),
9733-
};
9734-
let filter = self.parse_show_statement_filter()?;
9774+
fn parse_show_views(
9775+
&mut self,
9776+
terse: bool,
9777+
materialized: bool,
9778+
) -> Result<Statement, ParserError> {
9779+
let filter;
9780+
let show_in;
9781+
let filter_position;
9782+
if self.dialect.supports_show_like_before_in() {
9783+
filter = self.parse_show_statement_filter()?;
9784+
show_in = self.parse_show_opt_in()?;
9785+
filter_position = ShowStatementFilterPosition::InTheMiddle;
9786+
} else {
9787+
show_in = self.parse_show_opt_in()?;
9788+
filter = self.parse_show_statement_filter()?;
9789+
filter_position = ShowStatementFilterPosition::AtTheEnd;
9790+
}
9791+
let starts_with = self.parse_show_opt_starts_with()?;
9792+
let limit = self.parse_show_opt_limit()?;
9793+
let from = self.parse_show_opt_from()?;
97359794
Ok(Statement::ShowViews {
97369795
materialized,
9737-
clause,
9738-
db_name,
9796+
terse,
97399797
filter,
9798+
filter_position,
9799+
show_in,
9800+
starts_with,
9801+
limit,
9802+
from,
97409803
})
97419804
}
97429805

@@ -12315,6 +12378,137 @@ impl<'a> Parser<'a> {
1231512378
}
1231612379
false
1231712380
}
12381+
12382+
/// Look for an expected keyword, without consuming it
12383+
fn peek_keyword(&self, expected: Keyword) -> bool {
12384+
match self.peek_token().token {
12385+
Token::Word(w) => expected == w.keyword,
12386+
_ => false,
12387+
}
12388+
}
12389+
12390+
/// Look for one of expected keyword, without consuming it
12391+
fn peek_keywords(&self, expected: &[Keyword]) -> bool {
12392+
for kw in expected {
12393+
if self.peek_keyword(*kw) {
12394+
return true;
12395+
}
12396+
}
12397+
false
12398+
}
12399+
12400+
fn parse_show_opt_in(&mut self) -> Result<Option<ShowStatementIn>, ParserError> {
12401+
let clause = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
12402+
Some(Keyword::FROM) => ShowStatementInClause::FROM,
12403+
Some(Keyword::IN) => ShowStatementInClause::IN,
12404+
_ => return Ok(None),
12405+
};
12406+
12407+
if self.parse_keyword(Keyword::DATABASE) {
12408+
if self.peek_keywords(&[Keyword::STARTS, Keyword::WITH]) {
12409+
Ok(Some(ShowStatementIn {
12410+
clause,
12411+
parent_type: Some(ShowStatementInParentType::Database),
12412+
parent_name: None,
12413+
}))
12414+
} else {
12415+
let parent_name = match self.parse_object_name(false) {
12416+
Ok(n) => Some(n),
12417+
Err(_) => None,
12418+
};
12419+
Ok(Some(ShowStatementIn {
12420+
clause,
12421+
parent_type: Some(ShowStatementInParentType::Database),
12422+
parent_name,
12423+
}))
12424+
}
12425+
} else if self.parse_keyword(Keyword::SCHEMA) {
12426+
if self.peek_keywords(&[Keyword::STARTS, Keyword::WITH]) {
12427+
Ok(Some(ShowStatementIn {
12428+
clause,
12429+
parent_type: Some(ShowStatementInParentType::Schema),
12430+
parent_name: None,
12431+
}))
12432+
} else {
12433+
let parent_name = match self.parse_object_name(false) {
12434+
Ok(n) => Some(n),
12435+
Err(_) => None,
12436+
};
12437+
Ok(Some(ShowStatementIn {
12438+
clause,
12439+
parent_type: Some(ShowStatementInParentType::Schema),
12440+
parent_name,
12441+
}))
12442+
}
12443+
} else if self.parse_keyword(Keyword::ACCOUNT) {
12444+
let parent_name = match self.parse_object_name(false) {
12445+
Ok(n) => Some(n),
12446+
Err(_) => None,
12447+
};
12448+
Ok(Some(ShowStatementIn {
12449+
clause,
12450+
parent_type: Some(ShowStatementInParentType::Account),
12451+
parent_name,
12452+
}))
12453+
} else if self.parse_keyword(Keyword::TABLE) {
12454+
let parent_name = match self.parse_object_name(false) {
12455+
Ok(n) => Some(n),
12456+
Err(_) => None,
12457+
};
12458+
Ok(Some(ShowStatementIn {
12459+
clause,
12460+
parent_type: Some(ShowStatementInParentType::Table),
12461+
parent_name,
12462+
}))
12463+
} else if self.parse_keyword(Keyword::VIEW) {
12464+
let parent_name = match self.parse_object_name(false) {
12465+
Ok(n) => Some(n),
12466+
Err(_) => None,
12467+
};
12468+
Ok(Some(ShowStatementIn {
12469+
clause,
12470+
parent_type: Some(ShowStatementInParentType::View),
12471+
parent_name,
12472+
}))
12473+
} else {
12474+
// Parsing MySQL style FROM tbl_name FROM db_name
12475+
// which is equivalent to FROM tbl_name.db_name
12476+
let mut parent_name = self.parse_object_name(false)?;
12477+
if self
12478+
.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN])
12479+
.is_some()
12480+
{
12481+
parent_name.0.insert(0, self.parse_identifier(false)?);
12482+
}
12483+
12484+
Ok(Some(ShowStatementIn {
12485+
clause,
12486+
parent_type: None,
12487+
parent_name: Some(parent_name),
12488+
}))
12489+
}
12490+
}
12491+
12492+
fn parse_show_opt_starts_with(&mut self) -> Result<Option<Value>, ParserError> {
12493+
match self.parse_keywords(&[Keyword::STARTS, Keyword::WITH]) {
12494+
true => Ok(Some(self.parse_value()?)),
12495+
false => Ok(None),
12496+
}
12497+
}
12498+
12499+
fn parse_show_opt_limit(&mut self) -> Result<Option<Expr>, ParserError> {
12500+
match self.parse_keyword(Keyword::LIMIT) {
12501+
true => Ok(self.parse_limit()?),
12502+
false => Ok(None),
12503+
}
12504+
}
12505+
12506+
fn parse_show_opt_from(&mut self) -> Result<Option<Value>, ParserError> {
12507+
match self.parse_keyword(Keyword::FROM) {
12508+
true => Ok(Some(self.parse_value()?)),
12509+
false => Ok(None),
12510+
}
12511+
}
1231812512
}
1231912513

1232012514
impl Word {

0 commit comments

Comments
 (0)