mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-08 01:15:00 +00:00
Add support for Snowflake SHOW DATABASES/SCHEMAS/TABLES/VIEWS/COLUMNS statements (#1501)
This commit is contained in:
parent
632ba4cf8e
commit
76322baf2f
8 changed files with 591 additions and 159 deletions
223
src/ast/mod.rs
223
src/ast/mod.rs
|
@ -2773,41 +2773,45 @@ pub enum Statement {
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// SHOW COLUMNS
|
/// SHOW COLUMNS
|
||||||
/// ```
|
/// ```
|
||||||
///
|
|
||||||
/// Note: this is a MySQL-specific statement.
|
|
||||||
ShowColumns {
|
ShowColumns {
|
||||||
extended: bool,
|
extended: bool,
|
||||||
full: bool,
|
full: bool,
|
||||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
show_options: ShowStatementOptions,
|
||||||
table_name: ObjectName,
|
|
||||||
filter: Option<ShowStatementFilter>,
|
|
||||||
},
|
},
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// SHOW DATABASES [LIKE 'pattern']
|
/// SHOW DATABASES
|
||||||
/// ```
|
/// ```
|
||||||
ShowDatabases { filter: Option<ShowStatementFilter> },
|
ShowDatabases {
|
||||||
|
terse: bool,
|
||||||
|
history: bool,
|
||||||
|
show_options: ShowStatementOptions,
|
||||||
|
},
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// SHOW SCHEMAS [LIKE 'pattern']
|
/// SHOW SCHEMAS
|
||||||
/// ```
|
/// ```
|
||||||
ShowSchemas { filter: Option<ShowStatementFilter> },
|
ShowSchemas {
|
||||||
|
terse: bool,
|
||||||
|
history: bool,
|
||||||
|
show_options: ShowStatementOptions,
|
||||||
|
},
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// SHOW TABLES
|
/// SHOW TABLES
|
||||||
/// ```
|
/// ```
|
||||||
ShowTables {
|
ShowTables {
|
||||||
|
terse: bool,
|
||||||
|
history: bool,
|
||||||
extended: bool,
|
extended: bool,
|
||||||
full: bool,
|
full: bool,
|
||||||
clause: Option<ShowClause>,
|
external: bool,
|
||||||
db_name: Option<Ident>,
|
show_options: ShowStatementOptions,
|
||||||
filter: Option<ShowStatementFilter>,
|
|
||||||
},
|
},
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// SHOW VIEWS
|
/// SHOW VIEWS
|
||||||
/// ```
|
/// ```
|
||||||
ShowViews {
|
ShowViews {
|
||||||
|
terse: bool,
|
||||||
materialized: bool,
|
materialized: bool,
|
||||||
clause: Option<ShowClause>,
|
show_options: ShowStatementOptions,
|
||||||
db_name: Option<Ident>,
|
|
||||||
filter: Option<ShowStatementFilter>,
|
|
||||||
},
|
},
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// SHOW COLLATION
|
/// SHOW COLLATION
|
||||||
|
@ -4387,79 +4391,72 @@ impl fmt::Display for Statement {
|
||||||
Statement::ShowColumns {
|
Statement::ShowColumns {
|
||||||
extended,
|
extended,
|
||||||
full,
|
full,
|
||||||
table_name,
|
show_options,
|
||||||
filter,
|
|
||||||
} => {
|
} => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"SHOW {extended}{full}COLUMNS FROM {table_name}",
|
"SHOW {extended}{full}COLUMNS{show_options}",
|
||||||
extended = if *extended { "EXTENDED " } else { "" },
|
extended = if *extended { "EXTENDED " } else { "" },
|
||||||
full = if *full { "FULL " } else { "" },
|
full = if *full { "FULL " } else { "" },
|
||||||
table_name = table_name,
|
|
||||||
)?;
|
)?;
|
||||||
if let Some(filter) = filter {
|
|
||||||
write!(f, " {filter}")?;
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Statement::ShowDatabases { filter } => {
|
Statement::ShowDatabases {
|
||||||
write!(f, "SHOW DATABASES")?;
|
terse,
|
||||||
if let Some(filter) = filter {
|
history,
|
||||||
write!(f, " {filter}")?;
|
show_options,
|
||||||
}
|
} => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"SHOW {terse}DATABASES{history}{show_options}",
|
||||||
|
terse = if *terse { "TERSE " } else { "" },
|
||||||
|
history = if *history { " HISTORY" } else { "" },
|
||||||
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Statement::ShowSchemas { filter } => {
|
Statement::ShowSchemas {
|
||||||
write!(f, "SHOW SCHEMAS")?;
|
terse,
|
||||||
if let Some(filter) = filter {
|
history,
|
||||||
write!(f, " {filter}")?;
|
show_options,
|
||||||
}
|
} => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"SHOW {terse}SCHEMAS{history}{show_options}",
|
||||||
|
terse = if *terse { "TERSE " } else { "" },
|
||||||
|
history = if *history { " HISTORY" } else { "" },
|
||||||
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Statement::ShowTables {
|
Statement::ShowTables {
|
||||||
|
terse,
|
||||||
|
history,
|
||||||
extended,
|
extended,
|
||||||
full,
|
full,
|
||||||
clause: show_clause,
|
external,
|
||||||
db_name,
|
show_options,
|
||||||
filter,
|
|
||||||
} => {
|
} => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"SHOW {extended}{full}TABLES",
|
"SHOW {terse}{extended}{full}{external}TABLES{history}{show_options}",
|
||||||
|
terse = if *terse { "TERSE " } else { "" },
|
||||||
extended = if *extended { "EXTENDED " } else { "" },
|
extended = if *extended { "EXTENDED " } else { "" },
|
||||||
full = if *full { "FULL " } else { "" },
|
full = if *full { "FULL " } else { "" },
|
||||||
|
external = if *external { "EXTERNAL " } else { "" },
|
||||||
|
history = if *history { " HISTORY" } else { "" },
|
||||||
)?;
|
)?;
|
||||||
if let Some(show_clause) = show_clause {
|
|
||||||
write!(f, " {show_clause}")?;
|
|
||||||
}
|
|
||||||
if let Some(db_name) = db_name {
|
|
||||||
write!(f, " {db_name}")?;
|
|
||||||
}
|
|
||||||
if let Some(filter) = filter {
|
|
||||||
write!(f, " {filter}")?;
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Statement::ShowViews {
|
Statement::ShowViews {
|
||||||
|
terse,
|
||||||
materialized,
|
materialized,
|
||||||
clause: show_clause,
|
show_options,
|
||||||
db_name,
|
|
||||||
filter,
|
|
||||||
} => {
|
} => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"SHOW {}VIEWS",
|
"SHOW {terse}{materialized}VIEWS{show_options}",
|
||||||
if *materialized { "MATERIALIZED " } else { "" }
|
terse = if *terse { "TERSE " } else { "" },
|
||||||
|
materialized = if *materialized { "MATERIALIZED " } else { "" }
|
||||||
)?;
|
)?;
|
||||||
if let Some(show_clause) = show_clause {
|
|
||||||
write!(f, " {show_clause}")?;
|
|
||||||
}
|
|
||||||
if let Some(db_name) = db_name {
|
|
||||||
write!(f, " {db_name}")?;
|
|
||||||
}
|
|
||||||
if let Some(filter) = filter {
|
|
||||||
write!(f, " {filter}")?;
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Statement::ShowFunctions { filter } => {
|
Statement::ShowFunctions { filter } => {
|
||||||
|
@ -6172,14 +6169,14 @@ impl fmt::Display for ShowStatementFilter {
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
pub enum ShowClause {
|
pub enum ShowStatementInClause {
|
||||||
IN,
|
IN,
|
||||||
FROM,
|
FROM,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ShowClause {
|
impl fmt::Display for ShowStatementInClause {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use ShowClause::*;
|
use ShowStatementInClause::*;
|
||||||
match self {
|
match self {
|
||||||
FROM => write!(f, "FROM"),
|
FROM => write!(f, "FROM"),
|
||||||
IN => write!(f, "IN"),
|
IN => write!(f, "IN"),
|
||||||
|
@ -7357,6 +7354,108 @@ impl Display for UtilityOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the different options available for `SHOW`
|
||||||
|
/// statements to filter the results. Example from Snowflake:
|
||||||
|
/// <https://docs.snowflake.com/en/sql-reference/sql/show-tables>
|
||||||
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
|
pub struct ShowStatementOptions {
|
||||||
|
pub show_in: Option<ShowStatementIn>,
|
||||||
|
pub starts_with: Option<Value>,
|
||||||
|
pub limit: Option<Expr>,
|
||||||
|
pub limit_from: Option<Value>,
|
||||||
|
pub filter_position: Option<ShowStatementFilterPosition>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ShowStatementOptions {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let (like_in_infix, like_in_suffix) = match &self.filter_position {
|
||||||
|
Some(ShowStatementFilterPosition::Infix(filter)) => {
|
||||||
|
(format!(" {filter}"), "".to_string())
|
||||||
|
}
|
||||||
|
Some(ShowStatementFilterPosition::Suffix(filter)) => {
|
||||||
|
("".to_string(), format!(" {filter}"))
|
||||||
|
}
|
||||||
|
None => ("".to_string(), "".to_string()),
|
||||||
|
};
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{like_in_infix}{show_in}{starts_with}{limit}{from}{like_in_suffix}",
|
||||||
|
show_in = match &self.show_in {
|
||||||
|
Some(i) => format!(" {i}"),
|
||||||
|
None => String::new(),
|
||||||
|
},
|
||||||
|
starts_with = match &self.starts_with {
|
||||||
|
Some(s) => format!(" STARTS WITH {s}"),
|
||||||
|
None => String::new(),
|
||||||
|
},
|
||||||
|
limit = match &self.limit {
|
||||||
|
Some(l) => format!(" LIMIT {l}"),
|
||||||
|
None => String::new(),
|
||||||
|
},
|
||||||
|
from = match &self.limit_from {
|
||||||
|
Some(f) => format!(" FROM {f}"),
|
||||||
|
None => String::new(),
|
||||||
|
}
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
|
pub enum ShowStatementFilterPosition {
|
||||||
|
Infix(ShowStatementFilter), // For example: SHOW COLUMNS LIKE '%name%' IN TABLE tbl
|
||||||
|
Suffix(ShowStatementFilter), // For example: SHOW COLUMNS IN tbl LIKE '%name%'
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
|
pub enum ShowStatementInParentType {
|
||||||
|
Account,
|
||||||
|
Database,
|
||||||
|
Schema,
|
||||||
|
Table,
|
||||||
|
View,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ShowStatementInParentType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
ShowStatementInParentType::Account => write!(f, "ACCOUNT"),
|
||||||
|
ShowStatementInParentType::Database => write!(f, "DATABASE"),
|
||||||
|
ShowStatementInParentType::Schema => write!(f, "SCHEMA"),
|
||||||
|
ShowStatementInParentType::Table => write!(f, "TABLE"),
|
||||||
|
ShowStatementInParentType::View => write!(f, "VIEW"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
|
pub struct ShowStatementIn {
|
||||||
|
pub clause: ShowStatementInClause,
|
||||||
|
pub parent_type: Option<ShowStatementInParentType>,
|
||||||
|
pub parent_name: Option<ObjectName>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ShowStatementIn {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.clause)?;
|
||||||
|
if let Some(parent_type) = &self.parent_type {
|
||||||
|
write!(f, " {}", parent_type)?;
|
||||||
|
}
|
||||||
|
if let Some(parent_name) = &self.parent_name {
|
||||||
|
write!(f, " {}", parent_name)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -622,6 +622,12 @@ pub trait Dialect: Debug + Any {
|
||||||
fn supports_boolean_literals(&self) -> bool {
|
fn supports_boolean_literals(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if this dialect supports the `LIKE 'pattern'` option in
|
||||||
|
/// a `SHOW` statement before the `IN` option
|
||||||
|
fn supports_show_like_before_in(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This represents the operators for which precedence must be defined
|
/// This represents the operators for which precedence must be defined
|
||||||
|
|
|
@ -203,6 +203,12 @@ impl Dialect for SnowflakeDialect {
|
||||||
fn allow_extract_single_quotes(&self) -> bool {
|
fn allow_extract_single_quotes(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Snowflake expects the `LIKE` option before the `IN` option,
|
||||||
|
/// for example: <https://docs.snowflake.com/en/sql-reference/sql/show-views#syntax>
|
||||||
|
fn supports_show_like_before_in(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse snowflake create table statement.
|
/// Parse snowflake create table statement.
|
||||||
|
|
|
@ -76,6 +76,7 @@ define_keywords!(
|
||||||
ABS,
|
ABS,
|
||||||
ABSOLUTE,
|
ABSOLUTE,
|
||||||
ACCESS,
|
ACCESS,
|
||||||
|
ACCOUNT,
|
||||||
ACTION,
|
ACTION,
|
||||||
ADD,
|
ADD,
|
||||||
ADMIN,
|
ADMIN,
|
||||||
|
@ -91,6 +92,7 @@ define_keywords!(
|
||||||
AND,
|
AND,
|
||||||
ANTI,
|
ANTI,
|
||||||
ANY,
|
ANY,
|
||||||
|
APPLICATION,
|
||||||
APPLY,
|
APPLY,
|
||||||
ARCHIVE,
|
ARCHIVE,
|
||||||
ARE,
|
ARE,
|
||||||
|
@ -710,6 +712,7 @@ define_keywords!(
|
||||||
STABLE,
|
STABLE,
|
||||||
STAGE,
|
STAGE,
|
||||||
START,
|
START,
|
||||||
|
STARTS,
|
||||||
STATEMENT,
|
STATEMENT,
|
||||||
STATIC,
|
STATIC,
|
||||||
STATISTICS,
|
STATISTICS,
|
||||||
|
@ -746,6 +749,7 @@ define_keywords!(
|
||||||
TEMP,
|
TEMP,
|
||||||
TEMPORARY,
|
TEMPORARY,
|
||||||
TERMINATED,
|
TERMINATED,
|
||||||
|
TERSE,
|
||||||
TEXT,
|
TEXT,
|
||||||
TEXTFILE,
|
TEXTFILE,
|
||||||
THEN,
|
THEN,
|
||||||
|
|
|
@ -3205,6 +3205,22 @@ impl<'a> Parser<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Look for all of the expected keywords in sequence, without consuming them
|
||||||
|
fn peek_keyword(&mut self, expected: Keyword) -> bool {
|
||||||
|
let index = self.index;
|
||||||
|
let matched = self.parse_keyword(expected);
|
||||||
|
self.index = index;
|
||||||
|
matched
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Look for all of the expected keywords in sequence, without consuming them
|
||||||
|
fn peek_keywords(&mut self, expected: &[Keyword]) -> bool {
|
||||||
|
let index = self.index;
|
||||||
|
let matched = self.parse_keywords(expected);
|
||||||
|
self.index = index;
|
||||||
|
matched
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the first non-whitespace token that has not yet been processed
|
/// Return the first non-whitespace token that has not yet been processed
|
||||||
/// (or None if reached end-of-file) and mark it as processed. OK to call
|
/// (or None if reached end-of-file) and mark it as processed. OK to call
|
||||||
/// repeatedly after reaching EOF.
|
/// repeatedly after reaching EOF.
|
||||||
|
@ -9611,21 +9627,23 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_show(&mut self) -> Result<Statement, ParserError> {
|
pub fn parse_show(&mut self) -> Result<Statement, ParserError> {
|
||||||
|
let terse = self.parse_keyword(Keyword::TERSE);
|
||||||
let extended = self.parse_keyword(Keyword::EXTENDED);
|
let extended = self.parse_keyword(Keyword::EXTENDED);
|
||||||
let full = self.parse_keyword(Keyword::FULL);
|
let full = self.parse_keyword(Keyword::FULL);
|
||||||
let session = self.parse_keyword(Keyword::SESSION);
|
let session = self.parse_keyword(Keyword::SESSION);
|
||||||
let global = self.parse_keyword(Keyword::GLOBAL);
|
let global = self.parse_keyword(Keyword::GLOBAL);
|
||||||
|
let external = self.parse_keyword(Keyword::EXTERNAL);
|
||||||
if self
|
if self
|
||||||
.parse_one_of_keywords(&[Keyword::COLUMNS, Keyword::FIELDS])
|
.parse_one_of_keywords(&[Keyword::COLUMNS, Keyword::FIELDS])
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
Ok(self.parse_show_columns(extended, full)?)
|
Ok(self.parse_show_columns(extended, full)?)
|
||||||
} else if self.parse_keyword(Keyword::TABLES) {
|
} else if self.parse_keyword(Keyword::TABLES) {
|
||||||
Ok(self.parse_show_tables(extended, full)?)
|
Ok(self.parse_show_tables(terse, extended, full, external)?)
|
||||||
} else if self.parse_keywords(&[Keyword::MATERIALIZED, Keyword::VIEWS]) {
|
} else if self.parse_keywords(&[Keyword::MATERIALIZED, Keyword::VIEWS]) {
|
||||||
Ok(self.parse_show_views(true)?)
|
Ok(self.parse_show_views(terse, true)?)
|
||||||
} else if self.parse_keyword(Keyword::VIEWS) {
|
} else if self.parse_keyword(Keyword::VIEWS) {
|
||||||
Ok(self.parse_show_views(false)?)
|
Ok(self.parse_show_views(terse, false)?)
|
||||||
} else if self.parse_keyword(Keyword::FUNCTIONS) {
|
} else if self.parse_keyword(Keyword::FUNCTIONS) {
|
||||||
Ok(self.parse_show_functions()?)
|
Ok(self.parse_show_functions()?)
|
||||||
} else if extended || full {
|
} else if extended || full {
|
||||||
|
@ -9653,9 +9671,9 @@ impl<'a> Parser<'a> {
|
||||||
global,
|
global,
|
||||||
})
|
})
|
||||||
} else if self.parse_keyword(Keyword::DATABASES) {
|
} else if self.parse_keyword(Keyword::DATABASES) {
|
||||||
self.parse_show_databases()
|
self.parse_show_databases(terse)
|
||||||
} else if self.parse_keyword(Keyword::SCHEMAS) {
|
} else if self.parse_keyword(Keyword::SCHEMAS) {
|
||||||
self.parse_show_schemas()
|
self.parse_show_schemas(terse)
|
||||||
} else {
|
} else {
|
||||||
Ok(Statement::ShowVariable {
|
Ok(Statement::ShowVariable {
|
||||||
variable: self.parse_identifiers()?,
|
variable: self.parse_identifiers()?,
|
||||||
|
@ -9663,15 +9681,23 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_show_databases(&mut self) -> Result<Statement, ParserError> {
|
fn parse_show_databases(&mut self, terse: bool) -> Result<Statement, ParserError> {
|
||||||
|
let history = self.parse_keyword(Keyword::HISTORY);
|
||||||
|
let show_options = self.parse_show_stmt_options()?;
|
||||||
Ok(Statement::ShowDatabases {
|
Ok(Statement::ShowDatabases {
|
||||||
filter: self.parse_show_statement_filter()?,
|
terse,
|
||||||
|
history,
|
||||||
|
show_options,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_show_schemas(&mut self) -> Result<Statement, ParserError> {
|
fn parse_show_schemas(&mut self, terse: bool) -> Result<Statement, ParserError> {
|
||||||
|
let history = self.parse_keyword(Keyword::HISTORY);
|
||||||
|
let show_options = self.parse_show_stmt_options()?;
|
||||||
Ok(Statement::ShowSchemas {
|
Ok(Statement::ShowSchemas {
|
||||||
filter: self.parse_show_statement_filter()?,
|
terse,
|
||||||
|
history,
|
||||||
|
show_options,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9705,58 +9731,43 @@ impl<'a> Parser<'a> {
|
||||||
extended: bool,
|
extended: bool,
|
||||||
full: bool,
|
full: bool,
|
||||||
) -> Result<Statement, ParserError> {
|
) -> Result<Statement, ParserError> {
|
||||||
self.expect_one_of_keywords(&[Keyword::FROM, Keyword::IN])?;
|
let show_options = self.parse_show_stmt_options()?;
|
||||||
let object_name = self.parse_object_name(false)?;
|
|
||||||
let table_name = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
|
|
||||||
Some(_) => {
|
|
||||||
let db_name = vec![self.parse_identifier(false)?];
|
|
||||||
let ObjectName(table_name) = object_name;
|
|
||||||
let object_name = db_name.into_iter().chain(table_name).collect();
|
|
||||||
ObjectName(object_name)
|
|
||||||
}
|
|
||||||
None => object_name,
|
|
||||||
};
|
|
||||||
let filter = self.parse_show_statement_filter()?;
|
|
||||||
Ok(Statement::ShowColumns {
|
Ok(Statement::ShowColumns {
|
||||||
extended,
|
extended,
|
||||||
full,
|
full,
|
||||||
table_name,
|
show_options,
|
||||||
filter,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_show_tables(
|
fn parse_show_tables(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
terse: bool,
|
||||||
extended: bool,
|
extended: bool,
|
||||||
full: bool,
|
full: bool,
|
||||||
|
external: bool,
|
||||||
) -> Result<Statement, ParserError> {
|
) -> Result<Statement, ParserError> {
|
||||||
let (clause, db_name) = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
|
let history = !external && self.parse_keyword(Keyword::HISTORY);
|
||||||
Some(Keyword::FROM) => (Some(ShowClause::FROM), Some(self.parse_identifier(false)?)),
|
let show_options = self.parse_show_stmt_options()?;
|
||||||
Some(Keyword::IN) => (Some(ShowClause::IN), Some(self.parse_identifier(false)?)),
|
|
||||||
_ => (None, None),
|
|
||||||
};
|
|
||||||
let filter = self.parse_show_statement_filter()?;
|
|
||||||
Ok(Statement::ShowTables {
|
Ok(Statement::ShowTables {
|
||||||
|
terse,
|
||||||
|
history,
|
||||||
extended,
|
extended,
|
||||||
full,
|
full,
|
||||||
clause,
|
external,
|
||||||
db_name,
|
show_options,
|
||||||
filter,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_show_views(&mut self, materialized: bool) -> Result<Statement, ParserError> {
|
fn parse_show_views(
|
||||||
let (clause, db_name) = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
|
&mut self,
|
||||||
Some(Keyword::FROM) => (Some(ShowClause::FROM), Some(self.parse_identifier(false)?)),
|
terse: bool,
|
||||||
Some(Keyword::IN) => (Some(ShowClause::IN), Some(self.parse_identifier(false)?)),
|
materialized: bool,
|
||||||
_ => (None, None),
|
) -> Result<Statement, ParserError> {
|
||||||
};
|
let show_options = self.parse_show_stmt_options()?;
|
||||||
let filter = self.parse_show_statement_filter()?;
|
|
||||||
Ok(Statement::ShowViews {
|
Ok(Statement::ShowViews {
|
||||||
materialized,
|
materialized,
|
||||||
clause,
|
terse,
|
||||||
db_name,
|
show_options,
|
||||||
filter,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12395,6 +12406,124 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_show_stmt_options(&mut self) -> Result<ShowStatementOptions, ParserError> {
|
||||||
|
let show_in;
|
||||||
|
let mut filter_position = None;
|
||||||
|
if self.dialect.supports_show_like_before_in() {
|
||||||
|
if let Some(filter) = self.parse_show_statement_filter()? {
|
||||||
|
filter_position = Some(ShowStatementFilterPosition::Infix(filter));
|
||||||
|
}
|
||||||
|
show_in = self.maybe_parse_show_stmt_in()?;
|
||||||
|
} else {
|
||||||
|
show_in = self.maybe_parse_show_stmt_in()?;
|
||||||
|
if let Some(filter) = self.parse_show_statement_filter()? {
|
||||||
|
filter_position = Some(ShowStatementFilterPosition::Suffix(filter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let starts_with = self.maybe_parse_show_stmt_starts_with()?;
|
||||||
|
let limit = self.maybe_parse_show_stmt_limit()?;
|
||||||
|
let from = self.maybe_parse_show_stmt_from()?;
|
||||||
|
Ok(ShowStatementOptions {
|
||||||
|
filter_position,
|
||||||
|
show_in,
|
||||||
|
starts_with,
|
||||||
|
limit,
|
||||||
|
limit_from: from,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maybe_parse_show_stmt_in(&mut self) -> Result<Option<ShowStatementIn>, ParserError> {
|
||||||
|
let clause = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) {
|
||||||
|
Some(Keyword::FROM) => ShowStatementInClause::FROM,
|
||||||
|
Some(Keyword::IN) => ShowStatementInClause::IN,
|
||||||
|
None => return Ok(None),
|
||||||
|
_ => return self.expected("FROM or IN", self.peek_token()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let (parent_type, parent_name) = match self.parse_one_of_keywords(&[
|
||||||
|
Keyword::ACCOUNT,
|
||||||
|
Keyword::DATABASE,
|
||||||
|
Keyword::SCHEMA,
|
||||||
|
Keyword::TABLE,
|
||||||
|
Keyword::VIEW,
|
||||||
|
]) {
|
||||||
|
// If we see these next keywords it means we don't have a parent name
|
||||||
|
Some(Keyword::DATABASE)
|
||||||
|
if self.peek_keywords(&[Keyword::STARTS, Keyword::WITH])
|
||||||
|
| self.peek_keyword(Keyword::LIMIT) =>
|
||||||
|
{
|
||||||
|
(Some(ShowStatementInParentType::Database), None)
|
||||||
|
}
|
||||||
|
Some(Keyword::SCHEMA)
|
||||||
|
if self.peek_keywords(&[Keyword::STARTS, Keyword::WITH])
|
||||||
|
| self.peek_keyword(Keyword::LIMIT) =>
|
||||||
|
{
|
||||||
|
(Some(ShowStatementInParentType::Schema), None)
|
||||||
|
}
|
||||||
|
Some(parent_kw) => {
|
||||||
|
// The parent name here is still optional, for example:
|
||||||
|
// SHOW TABLES IN ACCOUNT, so parsing the object name
|
||||||
|
// may fail because the statement ends.
|
||||||
|
let parent_name = self.maybe_parse(|p| p.parse_object_name(false))?;
|
||||||
|
match parent_kw {
|
||||||
|
Keyword::ACCOUNT => (Some(ShowStatementInParentType::Account), parent_name),
|
||||||
|
Keyword::DATABASE => (Some(ShowStatementInParentType::Database), parent_name),
|
||||||
|
Keyword::SCHEMA => (Some(ShowStatementInParentType::Schema), parent_name),
|
||||||
|
Keyword::TABLE => (Some(ShowStatementInParentType::Table), parent_name),
|
||||||
|
Keyword::VIEW => (Some(ShowStatementInParentType::View), parent_name),
|
||||||
|
_ => {
|
||||||
|
return self.expected(
|
||||||
|
"one of ACCOUNT, DATABASE, SCHEMA, TABLE or VIEW",
|
||||||
|
self.peek_token(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// Parsing MySQL style FROM tbl_name FROM db_name
|
||||||
|
// which is equivalent to FROM tbl_name.db_name
|
||||||
|
let mut parent_name = self.parse_object_name(false)?;
|
||||||
|
if self
|
||||||
|
.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN])
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
parent_name.0.insert(0, self.parse_identifier(false)?);
|
||||||
|
}
|
||||||
|
(None, Some(parent_name))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Some(ShowStatementIn {
|
||||||
|
clause,
|
||||||
|
parent_type,
|
||||||
|
parent_name,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maybe_parse_show_stmt_starts_with(&mut self) -> Result<Option<Value>, ParserError> {
|
||||||
|
if self.parse_keywords(&[Keyword::STARTS, Keyword::WITH]) {
|
||||||
|
Ok(Some(self.parse_value()?))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maybe_parse_show_stmt_limit(&mut self) -> Result<Option<Expr>, ParserError> {
|
||||||
|
if self.parse_keyword(Keyword::LIMIT) {
|
||||||
|
Ok(self.parse_limit()?)
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maybe_parse_show_stmt_from(&mut self) -> Result<Option<Value>, ParserError> {
|
||||||
|
if self.parse_keyword(Keyword::FROM) {
|
||||||
|
Ok(Some(self.parse_value()?))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Word {
|
impl Word {
|
||||||
|
|
|
@ -11395,23 +11395,43 @@ fn test_try_convert() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_show_dbs_schemas_tables_views() {
|
fn test_show_dbs_schemas_tables_views() {
|
||||||
verified_stmt("SHOW DATABASES");
|
// These statements are parsed the same by all dialects
|
||||||
verified_stmt("SHOW DATABASES LIKE '%abc'");
|
let stmts = vec![
|
||||||
verified_stmt("SHOW SCHEMAS");
|
"SHOW DATABASES",
|
||||||
verified_stmt("SHOW SCHEMAS LIKE '%abc'");
|
"SHOW SCHEMAS",
|
||||||
verified_stmt("SHOW TABLES");
|
"SHOW TABLES",
|
||||||
verified_stmt("SHOW TABLES IN db1");
|
"SHOW VIEWS",
|
||||||
verified_stmt("SHOW TABLES IN db1 'abc'");
|
"SHOW TABLES IN db1",
|
||||||
verified_stmt("SHOW VIEWS");
|
"SHOW VIEWS FROM db1",
|
||||||
verified_stmt("SHOW VIEWS IN db1");
|
"SHOW MATERIALIZED VIEWS",
|
||||||
verified_stmt("SHOW VIEWS IN db1 'abc'");
|
"SHOW MATERIALIZED VIEWS IN db1",
|
||||||
verified_stmt("SHOW VIEWS FROM db1");
|
"SHOW MATERIALIZED VIEWS FROM db1",
|
||||||
verified_stmt("SHOW VIEWS FROM db1 'abc'");
|
];
|
||||||
verified_stmt("SHOW MATERIALIZED VIEWS");
|
for stmt in stmts {
|
||||||
verified_stmt("SHOW MATERIALIZED VIEWS IN db1");
|
verified_stmt(stmt);
|
||||||
verified_stmt("SHOW MATERIALIZED VIEWS IN db1 'abc'");
|
}
|
||||||
verified_stmt("SHOW MATERIALIZED VIEWS FROM db1");
|
|
||||||
verified_stmt("SHOW MATERIALIZED VIEWS FROM db1 'abc'");
|
// These statements are parsed the same by all dialects
|
||||||
|
// except for how the parser interprets the location of
|
||||||
|
// LIKE option (infix/suffix)
|
||||||
|
let stmts = vec!["SHOW DATABASES LIKE '%abc'", "SHOW SCHEMAS LIKE '%abc'"];
|
||||||
|
for stmt in stmts {
|
||||||
|
all_dialects_where(|d| d.supports_show_like_before_in()).verified_stmt(stmt);
|
||||||
|
all_dialects_where(|d| !d.supports_show_like_before_in()).verified_stmt(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// These statements are only parsed by dialects that
|
||||||
|
// support the LIKE option in the suffix
|
||||||
|
let stmts = vec![
|
||||||
|
"SHOW TABLES IN db1 'abc'",
|
||||||
|
"SHOW VIEWS IN db1 'abc'",
|
||||||
|
"SHOW VIEWS FROM db1 'abc'",
|
||||||
|
"SHOW MATERIALIZED VIEWS IN db1 'abc'",
|
||||||
|
"SHOW MATERIALIZED VIEWS FROM db1 'abc'",
|
||||||
|
];
|
||||||
|
for stmt in stmts {
|
||||||
|
all_dialects_where(|d| !d.supports_show_like_before_in()).verified_stmt(stmt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -223,14 +223,22 @@ fn parse_flush() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_show_columns() {
|
fn parse_show_columns() {
|
||||||
let table_name = ObjectName(vec![Ident::new("mytable")]);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mysql_and_generic().verified_stmt("SHOW COLUMNS FROM mytable"),
|
mysql_and_generic().verified_stmt("SHOW COLUMNS FROM mytable"),
|
||||||
Statement::ShowColumns {
|
Statement::ShowColumns {
|
||||||
extended: false,
|
extended: false,
|
||||||
full: false,
|
full: false,
|
||||||
table_name: table_name.clone(),
|
show_options: ShowStatementOptions {
|
||||||
filter: None,
|
show_in: Some(ShowStatementIn {
|
||||||
|
clause: ShowStatementInClause::FROM,
|
||||||
|
parent_type: None,
|
||||||
|
parent_name: Some(ObjectName(vec![Ident::new("mytable")])),
|
||||||
|
}),
|
||||||
|
filter_position: None,
|
||||||
|
limit_from: None,
|
||||||
|
limit: None,
|
||||||
|
starts_with: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -238,8 +246,17 @@ fn parse_show_columns() {
|
||||||
Statement::ShowColumns {
|
Statement::ShowColumns {
|
||||||
extended: false,
|
extended: false,
|
||||||
full: false,
|
full: false,
|
||||||
table_name: ObjectName(vec![Ident::new("mydb"), Ident::new("mytable")]),
|
show_options: ShowStatementOptions {
|
||||||
filter: None,
|
show_in: Some(ShowStatementIn {
|
||||||
|
clause: ShowStatementInClause::FROM,
|
||||||
|
parent_type: None,
|
||||||
|
parent_name: Some(ObjectName(vec![Ident::new("mydb"), Ident::new("mytable")])),
|
||||||
|
}),
|
||||||
|
filter_position: None,
|
||||||
|
limit_from: None,
|
||||||
|
limit: None,
|
||||||
|
starts_with: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -247,8 +264,17 @@ fn parse_show_columns() {
|
||||||
Statement::ShowColumns {
|
Statement::ShowColumns {
|
||||||
extended: true,
|
extended: true,
|
||||||
full: false,
|
full: false,
|
||||||
table_name: table_name.clone(),
|
show_options: ShowStatementOptions {
|
||||||
filter: None,
|
show_in: Some(ShowStatementIn {
|
||||||
|
clause: ShowStatementInClause::FROM,
|
||||||
|
parent_type: None,
|
||||||
|
parent_name: Some(ObjectName(vec![Ident::new("mytable")])),
|
||||||
|
}),
|
||||||
|
filter_position: None,
|
||||||
|
limit_from: None,
|
||||||
|
limit: None,
|
||||||
|
starts_with: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -256,8 +282,17 @@ fn parse_show_columns() {
|
||||||
Statement::ShowColumns {
|
Statement::ShowColumns {
|
||||||
extended: false,
|
extended: false,
|
||||||
full: true,
|
full: true,
|
||||||
table_name: table_name.clone(),
|
show_options: ShowStatementOptions {
|
||||||
filter: None,
|
show_in: Some(ShowStatementIn {
|
||||||
|
clause: ShowStatementInClause::FROM,
|
||||||
|
parent_type: None,
|
||||||
|
parent_name: Some(ObjectName(vec![Ident::new("mytable")])),
|
||||||
|
}),
|
||||||
|
filter_position: None,
|
||||||
|
limit_from: None,
|
||||||
|
limit: None,
|
||||||
|
starts_with: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -265,8 +300,19 @@ fn parse_show_columns() {
|
||||||
Statement::ShowColumns {
|
Statement::ShowColumns {
|
||||||
extended: false,
|
extended: false,
|
||||||
full: false,
|
full: false,
|
||||||
table_name: table_name.clone(),
|
show_options: ShowStatementOptions {
|
||||||
filter: Some(ShowStatementFilter::Like("pattern".into())),
|
show_in: Some(ShowStatementIn {
|
||||||
|
clause: ShowStatementInClause::FROM,
|
||||||
|
parent_type: None,
|
||||||
|
parent_name: Some(ObjectName(vec![Ident::new("mytable")])),
|
||||||
|
}),
|
||||||
|
filter_position: Some(ShowStatementFilterPosition::Suffix(
|
||||||
|
ShowStatementFilter::Like("pattern".into())
|
||||||
|
)),
|
||||||
|
limit_from: None,
|
||||||
|
limit: None,
|
||||||
|
starts_with: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -274,18 +320,27 @@ fn parse_show_columns() {
|
||||||
Statement::ShowColumns {
|
Statement::ShowColumns {
|
||||||
extended: false,
|
extended: false,
|
||||||
full: false,
|
full: false,
|
||||||
table_name,
|
show_options: ShowStatementOptions {
|
||||||
filter: Some(ShowStatementFilter::Where(
|
show_in: Some(ShowStatementIn {
|
||||||
mysql_and_generic().verified_expr("1 = 2")
|
clause: ShowStatementInClause::FROM,
|
||||||
)),
|
parent_type: None,
|
||||||
|
parent_name: Some(ObjectName(vec![Ident::new("mytable")])),
|
||||||
|
}),
|
||||||
|
filter_position: Some(ShowStatementFilterPosition::Suffix(
|
||||||
|
ShowStatementFilter::Where(mysql_and_generic().verified_expr("1 = 2"))
|
||||||
|
)),
|
||||||
|
limit_from: None,
|
||||||
|
limit: None,
|
||||||
|
starts_with: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
mysql_and_generic()
|
mysql_and_generic()
|
||||||
.one_statement_parses_to("SHOW FIELDS FROM mytable", "SHOW COLUMNS FROM mytable");
|
.one_statement_parses_to("SHOW FIELDS FROM mytable", "SHOW COLUMNS FROM mytable");
|
||||||
mysql_and_generic()
|
mysql_and_generic()
|
||||||
.one_statement_parses_to("SHOW COLUMNS IN mytable", "SHOW COLUMNS FROM mytable");
|
.one_statement_parses_to("SHOW COLUMNS IN mytable", "SHOW COLUMNS IN mytable");
|
||||||
mysql_and_generic()
|
mysql_and_generic()
|
||||||
.one_statement_parses_to("SHOW FIELDS IN mytable", "SHOW COLUMNS FROM mytable");
|
.one_statement_parses_to("SHOW FIELDS IN mytable", "SHOW COLUMNS IN mytable");
|
||||||
mysql_and_generic().one_statement_parses_to(
|
mysql_and_generic().one_statement_parses_to(
|
||||||
"SHOW COLUMNS FROM mytable FROM mydb",
|
"SHOW COLUMNS FROM mytable FROM mydb",
|
||||||
"SHOW COLUMNS FROM mydb.mytable",
|
"SHOW COLUMNS FROM mydb.mytable",
|
||||||
|
@ -327,63 +382,111 @@ fn parse_show_tables() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mysql_and_generic().verified_stmt("SHOW TABLES"),
|
mysql_and_generic().verified_stmt("SHOW TABLES"),
|
||||||
Statement::ShowTables {
|
Statement::ShowTables {
|
||||||
|
terse: false,
|
||||||
|
history: false,
|
||||||
extended: false,
|
extended: false,
|
||||||
full: false,
|
full: false,
|
||||||
clause: None,
|
external: false,
|
||||||
db_name: None,
|
show_options: ShowStatementOptions {
|
||||||
filter: None,
|
starts_with: None,
|
||||||
|
limit: None,
|
||||||
|
limit_from: None,
|
||||||
|
show_in: None,
|
||||||
|
filter_position: None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mysql_and_generic().verified_stmt("SHOW TABLES FROM mydb"),
|
mysql_and_generic().verified_stmt("SHOW TABLES FROM mydb"),
|
||||||
Statement::ShowTables {
|
Statement::ShowTables {
|
||||||
|
terse: false,
|
||||||
|
history: false,
|
||||||
extended: false,
|
extended: false,
|
||||||
full: false,
|
full: false,
|
||||||
clause: Some(ShowClause::FROM),
|
external: false,
|
||||||
db_name: Some(Ident::new("mydb")),
|
show_options: ShowStatementOptions {
|
||||||
filter: None,
|
starts_with: None,
|
||||||
|
limit: None,
|
||||||
|
limit_from: None,
|
||||||
|
show_in: Some(ShowStatementIn {
|
||||||
|
clause: ShowStatementInClause::FROM,
|
||||||
|
parent_type: None,
|
||||||
|
parent_name: Some(ObjectName(vec![Ident::new("mydb")])),
|
||||||
|
}),
|
||||||
|
filter_position: None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mysql_and_generic().verified_stmt("SHOW EXTENDED TABLES"),
|
mysql_and_generic().verified_stmt("SHOW EXTENDED TABLES"),
|
||||||
Statement::ShowTables {
|
Statement::ShowTables {
|
||||||
|
terse: false,
|
||||||
|
history: false,
|
||||||
extended: true,
|
extended: true,
|
||||||
full: false,
|
full: false,
|
||||||
clause: None,
|
external: false,
|
||||||
db_name: None,
|
show_options: ShowStatementOptions {
|
||||||
filter: None,
|
starts_with: None,
|
||||||
|
limit: None,
|
||||||
|
limit_from: None,
|
||||||
|
show_in: None,
|
||||||
|
filter_position: None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mysql_and_generic().verified_stmt("SHOW FULL TABLES"),
|
mysql_and_generic().verified_stmt("SHOW FULL TABLES"),
|
||||||
Statement::ShowTables {
|
Statement::ShowTables {
|
||||||
|
terse: false,
|
||||||
|
history: false,
|
||||||
extended: false,
|
extended: false,
|
||||||
full: true,
|
full: true,
|
||||||
clause: None,
|
external: false,
|
||||||
db_name: None,
|
show_options: ShowStatementOptions {
|
||||||
filter: None,
|
starts_with: None,
|
||||||
|
limit: None,
|
||||||
|
limit_from: None,
|
||||||
|
show_in: None,
|
||||||
|
filter_position: None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mysql_and_generic().verified_stmt("SHOW TABLES LIKE 'pattern'"),
|
mysql_and_generic().verified_stmt("SHOW TABLES LIKE 'pattern'"),
|
||||||
Statement::ShowTables {
|
Statement::ShowTables {
|
||||||
|
terse: false,
|
||||||
|
history: false,
|
||||||
extended: false,
|
extended: false,
|
||||||
full: false,
|
full: false,
|
||||||
clause: None,
|
external: false,
|
||||||
db_name: None,
|
show_options: ShowStatementOptions {
|
||||||
filter: Some(ShowStatementFilter::Like("pattern".into())),
|
starts_with: None,
|
||||||
|
limit: None,
|
||||||
|
limit_from: None,
|
||||||
|
show_in: None,
|
||||||
|
filter_position: Some(ShowStatementFilterPosition::Suffix(
|
||||||
|
ShowStatementFilter::Like("pattern".into())
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mysql_and_generic().verified_stmt("SHOW TABLES WHERE 1 = 2"),
|
mysql_and_generic().verified_stmt("SHOW TABLES WHERE 1 = 2"),
|
||||||
Statement::ShowTables {
|
Statement::ShowTables {
|
||||||
|
terse: false,
|
||||||
|
history: false,
|
||||||
extended: false,
|
extended: false,
|
||||||
full: false,
|
full: false,
|
||||||
clause: None,
|
external: false,
|
||||||
db_name: None,
|
show_options: ShowStatementOptions {
|
||||||
filter: Some(ShowStatementFilter::Where(
|
starts_with: None,
|
||||||
mysql_and_generic().verified_expr("1 = 2")
|
limit: None,
|
||||||
)),
|
limit_from: None,
|
||||||
|
show_in: None,
|
||||||
|
filter_position: Some(ShowStatementFilterPosition::Suffix(
|
||||||
|
ShowStatementFilter::Where(mysql_and_generic().verified_expr("1 = 2"))
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
mysql_and_generic().verified_stmt("SHOW TABLES IN mydb");
|
mysql_and_generic().verified_stmt("SHOW TABLES IN mydb");
|
||||||
|
|
|
@ -2781,3 +2781,68 @@ fn test_parentheses_overflow() {
|
||||||
snowflake_with_recursion_limit(max_nesting_level).parse_sql_statements(sql.as_str());
|
snowflake_with_recursion_limit(max_nesting_level).parse_sql_statements(sql.as_str());
|
||||||
assert_eq!(parsed.err(), Some(ParserError::RecursionLimitExceeded));
|
assert_eq!(parsed.err(), Some(ParserError::RecursionLimitExceeded));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_show_databases() {
|
||||||
|
snowflake().verified_stmt("SHOW DATABASES");
|
||||||
|
snowflake().verified_stmt("SHOW DATABASES HISTORY");
|
||||||
|
snowflake().verified_stmt("SHOW DATABASES LIKE '%abc%'");
|
||||||
|
snowflake().verified_stmt("SHOW DATABASES STARTS WITH 'demo_db'");
|
||||||
|
snowflake().verified_stmt("SHOW DATABASES LIMIT 12");
|
||||||
|
snowflake()
|
||||||
|
.verified_stmt("SHOW DATABASES HISTORY LIKE '%aa' STARTS WITH 'demo' LIMIT 20 FROM 'abc'");
|
||||||
|
snowflake().verified_stmt("SHOW DATABASES IN ACCOUNT abc");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_show_schemas() {
|
||||||
|
snowflake().verified_stmt("SHOW SCHEMAS");
|
||||||
|
snowflake().verified_stmt("SHOW SCHEMAS IN ACCOUNT");
|
||||||
|
snowflake().verified_stmt("SHOW SCHEMAS IN ACCOUNT abc");
|
||||||
|
snowflake().verified_stmt("SHOW SCHEMAS IN DATABASE");
|
||||||
|
snowflake().verified_stmt("SHOW SCHEMAS IN DATABASE xyz");
|
||||||
|
snowflake().verified_stmt("SHOW SCHEMAS HISTORY LIKE '%xa%'");
|
||||||
|
snowflake().verified_stmt("SHOW SCHEMAS STARTS WITH 'abc' LIMIT 20");
|
||||||
|
snowflake().verified_stmt("SHOW SCHEMAS IN DATABASE STARTS WITH 'abc' LIMIT 20 FROM 'xyz'");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_show_tables() {
|
||||||
|
snowflake().verified_stmt("SHOW TABLES");
|
||||||
|
snowflake().verified_stmt("SHOW TABLES IN ACCOUNT");
|
||||||
|
snowflake().verified_stmt("SHOW TABLES IN DATABASE");
|
||||||
|
snowflake().verified_stmt("SHOW TABLES IN DATABASE xyz");
|
||||||
|
snowflake().verified_stmt("SHOW TABLES IN SCHEMA");
|
||||||
|
snowflake().verified_stmt("SHOW TABLES IN SCHEMA xyz");
|
||||||
|
snowflake().verified_stmt("SHOW TABLES HISTORY LIKE '%xa%'");
|
||||||
|
snowflake().verified_stmt("SHOW TABLES STARTS WITH 'abc' LIMIT 20");
|
||||||
|
snowflake().verified_stmt("SHOW TABLES IN SCHEMA STARTS WITH 'abc' LIMIT 20 FROM 'xyz'");
|
||||||
|
snowflake().verified_stmt("SHOW EXTERNAL TABLES");
|
||||||
|
snowflake().verified_stmt("SHOW EXTERNAL TABLES IN ACCOUNT");
|
||||||
|
snowflake().verified_stmt("SHOW EXTERNAL TABLES IN DATABASE");
|
||||||
|
snowflake().verified_stmt("SHOW EXTERNAL TABLES IN DATABASE xyz");
|
||||||
|
snowflake().verified_stmt("SHOW EXTERNAL TABLES IN SCHEMA");
|
||||||
|
snowflake().verified_stmt("SHOW EXTERNAL TABLES IN SCHEMA xyz");
|
||||||
|
snowflake().verified_stmt("SHOW EXTERNAL TABLES STARTS WITH 'abc' LIMIT 20");
|
||||||
|
snowflake()
|
||||||
|
.verified_stmt("SHOW EXTERNAL TABLES IN SCHEMA STARTS WITH 'abc' LIMIT 20 FROM 'xyz'");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_show_views() {
|
||||||
|
snowflake().verified_stmt("SHOW VIEWS");
|
||||||
|
snowflake().verified_stmt("SHOW VIEWS IN ACCOUNT");
|
||||||
|
snowflake().verified_stmt("SHOW VIEWS IN DATABASE");
|
||||||
|
snowflake().verified_stmt("SHOW VIEWS IN DATABASE xyz");
|
||||||
|
snowflake().verified_stmt("SHOW VIEWS IN SCHEMA");
|
||||||
|
snowflake().verified_stmt("SHOW VIEWS IN SCHEMA xyz");
|
||||||
|
snowflake().verified_stmt("SHOW VIEWS STARTS WITH 'abc' LIMIT 20");
|
||||||
|
snowflake().verified_stmt("SHOW VIEWS IN SCHEMA STARTS WITH 'abc' LIMIT 20 FROM 'xyz'");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_show_columns_sql() {
|
||||||
|
snowflake().verified_stmt("SHOW COLUMNS IN TABLE");
|
||||||
|
snowflake().verified_stmt("SHOW COLUMNS IN TABLE abc");
|
||||||
|
snowflake().verified_stmt("SHOW COLUMNS LIKE '%xyz%' IN TABLE abc");
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue