Skip to content

Commit 991298d

Browse files
committed
Add support for Snowflake SHOW DATABASES/SCHEMAS/TABLES/VIEWS/COLUMNS statements
1 parent 05821cc commit 991298d

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
@@ -600,6 +600,12 @@ pub trait Dialect: Debug + Any {
600600
fn supports_notify(&self) -> bool {
601601
false
602602
}
603+
604+
/// Returns true if this dialect support the `LIKE 'pattern'` option in
605+
/// a `SHOW` statement before the `IN` option
606+
fn supports_show_like_before_in(&self) -> bool {
607+
false
608+
}
603609
}
604610

605611
/// 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
@@ -9587,21 +9587,23 @@ impl<'a> Parser<'a> {
95879587
}
95889588

95899589
pub fn parse_show(&mut self) -> Result<Statement, ParserError> {
9590+
let terse = self.parse_keyword(Keyword::TERSE);
95909591
let extended = self.parse_keyword(Keyword::EXTENDED);
95919592
let full = self.parse_keyword(Keyword::FULL);
95929593
let session = self.parse_keyword(Keyword::SESSION);
95939594
let global = self.parse_keyword(Keyword::GLOBAL);
9595+
let external = self.parse_keyword(Keyword::EXTERNAL);
95949596
if self
95959597
.parse_one_of_keywords(&[Keyword::COLUMNS, Keyword::FIELDS])
95969598
.is_some()
95979599
{
95989600
Ok(self.parse_show_columns(extended, full)?)
95999601
} else if self.parse_keyword(Keyword::TABLES) {
9600-
Ok(self.parse_show_tables(extended, full)?)
9602+
Ok(self.parse_show_tables(terse, extended, full, external)?)
96019603
} else if self.parse_keywords(&[Keyword::MATERIALIZED, Keyword::VIEWS]) {
9602-
Ok(self.parse_show_views(true)?)
9604+
Ok(self.parse_show_views(terse, true)?)
96039605
} else if self.parse_keyword(Keyword::VIEWS) {
9604-
Ok(self.parse_show_views(false)?)
9606+
Ok(self.parse_show_views(terse, false)?)
96059607
} else if self.parse_keyword(Keyword::FUNCTIONS) {
96069608
Ok(self.parse_show_functions()?)
96079609
} else if extended || full {
@@ -9629,25 +9631,49 @@ impl<'a> Parser<'a> {
96299631
global,
96309632
})
96319633
} else if self.parse_keyword(Keyword::DATABASES) {
9632-
self.parse_show_databases()
9634+
self.parse_show_databases(terse)
96339635
} else if self.parse_keyword(Keyword::SCHEMAS) {
9634-
self.parse_show_schemas()
9636+
self.parse_show_schemas(terse)
96359637
} else {
96369638
Ok(Statement::ShowVariable {
96379639
variable: self.parse_identifiers()?,
96389640
})
96399641
}
96409642
}
96419643

9642-
fn parse_show_databases(&mut self) -> Result<Statement, ParserError> {
9644+
fn parse_show_databases(&mut self, terse: bool) -> Result<Statement, ParserError> {
9645+
let history = self.parse_keyword(Keyword::HISTORY);
9646+
let filter = self.parse_show_statement_filter()?;
9647+
let show_in = self.parse_show_opt_in()?;
9648+
let starts_with = self.parse_show_opt_starts_with()?;
9649+
let limit = self.parse_show_opt_limit()?;
9650+
let from = self.parse_show_opt_from()?;
96439651
Ok(Statement::ShowDatabases {
9644-
filter: self.parse_show_statement_filter()?,
9652+
terse,
9653+
history,
9654+
filter,
9655+
show_in,
9656+
starts_with,
9657+
limit,
9658+
from,
96459659
})
96469660
}
96479661

9648-
fn parse_show_schemas(&mut self) -> Result<Statement, ParserError> {
9662+
fn parse_show_schemas(&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()?;
96499669
Ok(Statement::ShowSchemas {
9650-
filter: self.parse_show_statement_filter()?,
9670+
terse,
9671+
history,
9672+
filter,
9673+
show_in,
9674+
starts_with,
9675+
limit,
9676+
from,
96519677
})
96529678
}
96539679

@@ -9681,58 +9707,95 @@ impl<'a> Parser<'a> {
96819707
extended: bool,
96829708
full: bool,
96839709
) -> Result<Statement, ParserError> {
9684-
self.expect_one_of_keywords(&[Keyword::FROM, Keyword::IN])?;
9685-
let object_name = self.parse_object_name(false)?;
9686-
let table_name = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
9687-
Some(_) => {
9688-
let db_name = vec![self.parse_identifier(false)?];
9689-
let ObjectName(table_name) = object_name;
9690-
let object_name = db_name.into_iter().chain(table_name).collect();
9691-
ObjectName(object_name)
9692-
}
9693-
None => object_name,
9694-
};
9695-
let filter = self.parse_show_statement_filter()?;
9710+
let filter;
9711+
let filter_position;
9712+
let show_in;
9713+
if self.dialect.supports_show_like_before_in() {
9714+
filter = self.parse_show_statement_filter()?;
9715+
filter_position = ShowStatementFilterPosition::InTheMiddle;
9716+
show_in = self.parse_show_opt_in()?;
9717+
} else {
9718+
show_in = self.parse_show_opt_in()?;
9719+
filter = self.parse_show_statement_filter()?;
9720+
filter_position = ShowStatementFilterPosition::AtTheEnd;
9721+
}
96969722
Ok(Statement::ShowColumns {
96979723
extended,
96989724
full,
9699-
table_name,
9725+
show_in,
97009726
filter,
9727+
filter_position,
97019728
})
97029729
}
97039730

9704-
pub fn parse_show_tables(
9731+
fn parse_show_tables(
97059732
&mut self,
9733+
terse: bool,
97069734
extended: bool,
97079735
full: bool,
9736+
external: bool,
97089737
) -> Result<Statement, ParserError> {
9709-
let (clause, db_name) = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
9710-
Some(Keyword::FROM) => (Some(ShowClause::FROM), Some(self.parse_identifier(false)?)),
9711-
Some(Keyword::IN) => (Some(ShowClause::IN), Some(self.parse_identifier(false)?)),
9712-
_ => (None, None),
9713-
};
9714-
let filter = self.parse_show_statement_filter()?;
9738+
let history = !external && self.parse_keyword(Keyword::HISTORY);
9739+
let filter;
9740+
let show_in;
9741+
let filter_position;
9742+
if self.dialect.supports_show_like_before_in() {
9743+
filter = self.parse_show_statement_filter()?;
9744+
//YOAV: here we have a problem, the hint is DB-dependent (table in a schemas or some other object)
9745+
show_in = self.parse_show_opt_in()?;
9746+
filter_position = ShowStatementFilterPosition::InTheMiddle;
9747+
} else {
9748+
show_in = self.parse_show_opt_in()?;
9749+
filter = self.parse_show_statement_filter()?;
9750+
filter_position = ShowStatementFilterPosition::AtTheEnd;
9751+
}
9752+
let starts_with = self.parse_show_opt_starts_with()?;
9753+
let limit = self.parse_show_opt_limit()?;
9754+
let from = self.parse_show_opt_from()?;
97159755
Ok(Statement::ShowTables {
9756+
terse,
9757+
history,
97169758
extended,
97179759
full,
9718-
clause,
9719-
db_name,
9760+
external,
97209761
filter,
9762+
show_in,
9763+
starts_with,
9764+
limit,
9765+
from,
9766+
filter_position,
97219767
})
97229768
}
97239769

9724-
fn parse_show_views(&mut self, materialized: bool) -> Result<Statement, ParserError> {
9725-
let (clause, db_name) = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
9726-
Some(Keyword::FROM) => (Some(ShowClause::FROM), Some(self.parse_identifier(false)?)),
9727-
Some(Keyword::IN) => (Some(ShowClause::IN), Some(self.parse_identifier(false)?)),
9728-
_ => (None, None),
9729-
};
9730-
let filter = self.parse_show_statement_filter()?;
9770+
fn parse_show_views(
9771+
&mut self,
9772+
terse: bool,
9773+
materialized: bool,
9774+
) -> Result<Statement, ParserError> {
9775+
let filter;
9776+
let show_in;
9777+
let filter_position;
9778+
if self.dialect.supports_show_like_before_in() {
9779+
filter = self.parse_show_statement_filter()?;
9780+
show_in = self.parse_show_opt_in()?;
9781+
filter_position = ShowStatementFilterPosition::InTheMiddle;
9782+
} else {
9783+
show_in = self.parse_show_opt_in()?;
9784+
filter = self.parse_show_statement_filter()?;
9785+
filter_position = ShowStatementFilterPosition::AtTheEnd;
9786+
}
9787+
let starts_with = self.parse_show_opt_starts_with()?;
9788+
let limit = self.parse_show_opt_limit()?;
9789+
let from = self.parse_show_opt_from()?;
97319790
Ok(Statement::ShowViews {
97329791
materialized,
9733-
clause,
9734-
db_name,
9792+
terse,
97359793
filter,
9794+
filter_position,
9795+
show_in,
9796+
starts_with,
9797+
limit,
9798+
from,
97369799
})
97379800
}
97389801

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

1229012484
impl Word {

0 commit comments

Comments
 (0)