Skip to content

Commit

Permalink
cr
Browse files Browse the repository at this point in the history
  • Loading branch information
AvivDavid-Satori committed Jan 28, 2025
1 parent 3825c01 commit 3256813
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 47 deletions.
4 changes: 4 additions & 0 deletions src/dialect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,10 @@ pub trait Dialect: Debug + Any {
fn supports_string_escape_constant(&self) -> bool {
false
}
/// Returns true if the dialect supports the table hints in the `FROM` clause.
fn supports_table_hints(&self) -> bool {
false
}
}

/// This represents the operators for which precedence must be defined
Expand Down
4 changes: 4 additions & 0 deletions src/dialect/mysql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ impl Dialect for MySqlDialect {
|| (!keywords::RESERVED_FOR_TABLE_ALIAS.contains(kw)
&& !RESERVED_FOR_TABLE_ALIAS_MYSQL.contains(kw))
}

fn supports_table_hints(&self) -> bool {
true
}
}

/// `LOCK TABLES`
Expand Down
11 changes: 7 additions & 4 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11315,10 +11315,13 @@ impl<'a> Parser<'a> {

let alias = self.maybe_parse_table_alias()?;

// maybe parse so we will still support queries like 'SELECT * FROM T USE LIMIT 1' in BigQuery, for example
let index_hints = self
.maybe_parse(|p| p.parse_table_index_hints())?
.unwrap_or(vec![]);
// MYSQL-specific table hints:
let index_hints = if self.dialect.supports_table_hints() {
self.maybe_parse(|p| p.parse_table_index_hints())?
.unwrap_or(vec![])
} else {
vec![]
};

// MSSQL-specific table hints:
let mut with_hints = vec![];
Expand Down
28 changes: 0 additions & 28 deletions tests/sqlparser_bigquery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1605,34 +1605,6 @@ fn parse_join_constraint_unnest_alias() {
);
}

#[test]
fn parse_select_with_use() {
let sql = "SELECT * FROM T USE LIMIT 1";
let select =
bigquery().verified_only_select_with_canonical(sql, "SELECT * FROM T AS USE LIMIT 1");
assert_eq!(
select.from,
vec![TableWithJoins {
relation: TableFactor::Table {
name: ObjectName(vec![Ident::new("T")]),
alias: Some(TableAlias {
name: Ident::new("USE"),
columns: vec![],
}),
args: None,
with_hints: vec![],
version: None,
partitions: vec![],
with_ordinality: false,
json_path: None,
sample: None,
index_hints: vec![],
},
joins: vec![],
}]
);
}

#[test]
fn parse_merge() {
let sql = concat!(
Expand Down
65 changes: 65 additions & 0 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10030,6 +10030,71 @@ fn parse_unpivot_table() {
);
}

#[test]
fn parse_select_table_with_index_hints() {
let supported_dialects = all_dialects_where(|d| d.supports_table_hints());
let s = supported_dialects.verified_only_select(
"SELECT * FROM t1 USE INDEX (i1) IGNORE INDEX FOR ORDER BY (i2) ORDER BY a",
);
if let TableFactor::Table { index_hints, .. } = &s.from[0].relation {
assert_eq!(
vec![
TableIndexHints {
hint_type: TableIndexHintType::Use,
index_names: vec!["i1".into()],
index_type: TableIndexType::Index,
for_clause: None,
},
TableIndexHints {
hint_type: TableIndexHintType::Ignore,
index_names: vec!["i2".into()],
index_type: TableIndexType::Index,
for_clause: Some(TableIndexHintForClause::OrderBy),
},
],
*index_hints
);
} else {
panic!("Expected TableFactor::Table");
}
supported_dialects.verified_stmt("SELECT * FROM t1 USE INDEX (i1) USE INDEX (i1, i1)");
supported_dialects.verified_stmt(
"SELECT * FROM t1 USE INDEX () IGNORE INDEX (i2) USE INDEX (i1) USE INDEX (i2)",
);
supported_dialects.verified_stmt("SELECT * FROM t1 FORCE INDEX FOR JOIN (i2)");
supported_dialects.verified_stmt("SELECT * FROM t1 IGNORE INDEX FOR JOIN (i2)");
supported_dialects.verified_stmt(
"SELECT * FROM t USE INDEX (index1) IGNORE INDEX FOR ORDER BY (index1) IGNORE INDEX FOR GROUP BY (index1) WHERE A = B",
);

// Test that dialects that don't support table hints will keep parsing the USE as table alias
let sql = "SELECT * FROM T USE LIMIT 1";
let unsupported_dialects = all_dialects_where(|d| !d.supports_table_hints());
let select = unsupported_dialects
.verified_only_select_with_canonical(sql, "SELECT * FROM T AS USE LIMIT 1");
assert_eq!(
select.from,
vec![TableWithJoins {
relation: TableFactor::Table {
name: ObjectName(vec![Ident::new("T")]),
alias: Some(TableAlias {
name: Ident::new("USE"),
columns: vec![],
}),
args: None,
with_hints: vec![],
version: None,
partitions: vec![],
with_ordinality: false,
json_path: None,
sample: None,
index_hints: vec![],
},
joins: vec![],
}]
);
}

#[test]
fn parse_pivot_unpivot_table() {
let sql = concat!(
Expand Down
15 changes: 0 additions & 15 deletions tests/sqlparser_mysql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2905,21 +2905,6 @@ fn parse_lock_tables() {
mysql().verified_stmt("UNLOCK TABLES");
}

#[test]
fn parse_select_table_with_index_hints() {
mysql()
.verified_stmt("SELECT * FROM t1 USE INDEX (i1) IGNORE INDEX FOR ORDER BY (i2) ORDER BY a");
mysql().verified_stmt("SELECT * FROM t1 USE INDEX (i1) USE INDEX (i1, i1)");
mysql().verified_stmt(
"SELECT * FROM t1 USE INDEX () IGNORE INDEX (i2) USE INDEX (i1) USE INDEX (i2)",
);
mysql().verified_stmt("SELECT * FROM t1 FORCE INDEX FOR JOIN (i2)");
mysql().verified_stmt("SELECT * FROM t1 IGNORE INDEX FOR JOIN (i2)");
mysql().verified_stmt(
"SELECT * FROM t USE INDEX (index1) IGNORE INDEX FOR ORDER BY (index1) IGNORE INDEX FOR GROUP BY (index1) WHERE A = B",
);
}

#[test]
fn parse_json_table() {
mysql().verified_only_select("SELECT * FROM JSON_TABLE('[[1, 2], [3, 4]]', '$[*]' COLUMNS(a INT PATH '$[0]', b INT PATH '$[1]')) AS t");
Expand Down

0 comments on commit 3256813

Please sign in to comment.