Skip to content

Commit 85901b5

Browse files
committed
Add support for Snowflake SHOW DATABASES/SCHEMAS/TABLES/VIEWS/COLUMNS statements
1 parent a5b0092 commit 85901b5

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
@@ -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

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,
@@ -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

Lines changed: 234 additions & 40 deletions
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

@@ -12289,6 +12352,137 @@ impl<'a> Parser<'a> {
1228912352
}
1229012353
false
1229112354
}
12355+
12356+
/// Look for an expected keyword, without consuming it
12357+
fn peek_keyword(&self, expected: Keyword) -> bool {
12358+
match self.peek_token().token {
12359+
Token::Word(w) => expected == w.keyword,
12360+
_ => false,
12361+
}
12362+
}
12363+
12364+
/// Look for one of expected keyword, without consuming it
12365+
fn peek_keywords(&self, expected: &[Keyword]) -> bool {
12366+
for kw in expected {
12367+
if self.peek_keyword(*kw) {
12368+
return true;
12369+
}
12370+
}
12371+
false
12372+
}
12373+
12374+
fn parse_show_opt_in(&mut self) -> Result<Option<ShowStatementIn>, ParserError> {
12375+
let clause = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
12376+
Some(Keyword::FROM) => ShowStatementInClause::FROM,
12377+
Some(Keyword::IN) => ShowStatementInClause::IN,
12378+
_ => return Ok(None),
12379+
};
12380+
12381+
if self.parse_keyword(Keyword::DATABASE) {
12382+
if self.peek_keywords(&[Keyword::STARTS, Keyword::WITH]) {
12383+
Ok(Some(ShowStatementIn {
12384+
clause,
12385+
parent_type: Some(ShowStatementInParentType::Database),
12386+
parent_name: None,
12387+
}))
12388+
} else {
12389+
let parent_name = match self.parse_object_name(false) {
12390+
Ok(n) => Some(n),
12391+
Err(_) => None,
12392+
};
12393+
Ok(Some(ShowStatementIn {
12394+
clause,
12395+
parent_type: Some(ShowStatementInParentType::Database),
12396+
parent_name,
12397+
}))
12398+
}
12399+
} else if self.parse_keyword(Keyword::SCHEMA) {
12400+
if self.peek_keywords(&[Keyword::STARTS, Keyword::WITH]) {
12401+
Ok(Some(ShowStatementIn {
12402+
clause,
12403+
parent_type: Some(ShowStatementInParentType::Schema),
12404+
parent_name: None,
12405+
}))
12406+
} else {
12407+
let parent_name = match self.parse_object_name(false) {
12408+
Ok(n) => Some(n),
12409+
Err(_) => None,
12410+
};
12411+
Ok(Some(ShowStatementIn {
12412+
clause,
12413+
parent_type: Some(ShowStatementInParentType::Schema),
12414+
parent_name,
12415+
}))
12416+
}
12417+
} else if self.parse_keyword(Keyword::ACCOUNT) {
12418+
let parent_name = match self.parse_object_name(false) {
12419+
Ok(n) => Some(n),
12420+
Err(_) => None,
12421+
};
12422+
Ok(Some(ShowStatementIn {
12423+
clause,
12424+
parent_type: Some(ShowStatementInParentType::Account),
12425+
parent_name,
12426+
}))
12427+
} else if self.parse_keyword(Keyword::TABLE) {
12428+
let parent_name = match self.parse_object_name(false) {
12429+
Ok(n) => Some(n),
12430+
Err(_) => None,
12431+
};
12432+
Ok(Some(ShowStatementIn {
12433+
clause,
12434+
parent_type: Some(ShowStatementInParentType::Table),
12435+
parent_name,
12436+
}))
12437+
} else if self.parse_keyword(Keyword::VIEW) {
12438+
let parent_name = match self.parse_object_name(false) {
12439+
Ok(n) => Some(n),
12440+
Err(_) => None,
12441+
};
12442+
Ok(Some(ShowStatementIn {
12443+
clause,
12444+
parent_type: Some(ShowStatementInParentType::View),
12445+
parent_name,
12446+
}))
12447+
} else {
12448+
// Parsing MySQL style FROM tbl_name FROM db_name
12449+
// which is equivalent to FROM tbl_name.db_name
12450+
let mut parent_name = self.parse_object_name(false)?;
12451+
if self
12452+
.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN])
12453+
.is_some()
12454+
{
12455+
parent_name.0.insert(0, self.parse_identifier(false)?);
12456+
}
12457+
12458+
Ok(Some(ShowStatementIn {
12459+
clause,
12460+
parent_type: None,
12461+
parent_name: Some(parent_name),
12462+
}))
12463+
}
12464+
}
12465+
12466+
fn parse_show_opt_starts_with(&mut self) -> Result<Option<Value>, ParserError> {
12467+
match self.parse_keywords(&[Keyword::STARTS, Keyword::WITH]) {
12468+
true => Ok(Some(self.parse_value()?)),
12469+
false => Ok(None),
12470+
}
12471+
}
12472+
12473+
fn parse_show_opt_limit(&mut self) -> Result<Option<Expr>, ParserError> {
12474+
match self.parse_keyword(Keyword::LIMIT) {
12475+
true => Ok(self.parse_limit()?),
12476+
false => Ok(None),
12477+
}
12478+
}
12479+
12480+
fn parse_show_opt_from(&mut self) -> Result<Option<Value>, ParserError> {
12481+
match self.parse_keyword(Keyword::FROM) {
12482+
true => Ok(Some(self.parse_value()?)),
12483+
false => Ok(None),
12484+
}
12485+
}
1229212486
}
1229312487

1229412488
impl Word {

0 commit comments

Comments
 (0)