Skip to content

Commit 0048c9f

Browse files
committed
Merge remote-tracking branch 'origin/main'
2 parents cb0664f + e81eb14 commit 0048c9f

22 files changed

Lines changed: 607 additions & 455 deletions

src/ast/dml.rs

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ use super::{
4343
pub struct Insert {
4444
/// Token for the `INSERT` keyword (or its substitutes)
4545
pub insert_token: AttachedToken,
46-
/// A query optimizer hint
46+
/// Query optimizer hints
4747
///
4848
/// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/optimizer-hints.html)
4949
/// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Comments.html#GUID-D316D545-89E2-4D54-977F-FC97815CD62E)
50-
pub optimizer_hint: Option<OptimizerHint>,
50+
pub optimizer_hints: Vec<OptimizerHint>,
5151
/// Only for Sqlite
5252
pub or: Option<SqliteOnConflict>,
5353
/// Only for mysql
@@ -133,7 +133,7 @@ impl Display for Insert {
133133

134134
if let Some(on_conflict) = self.or {
135135
f.write_str("INSERT")?;
136-
if let Some(hint) = self.optimizer_hint.as_ref() {
136+
for hint in &self.optimizer_hints {
137137
write!(f, " {hint}")?;
138138
}
139139
write!(f, " {on_conflict} INTO {table_name} ")?;
@@ -147,7 +147,7 @@ impl Display for Insert {
147147
"INSERT"
148148
}
149149
)?;
150-
if let Some(hint) = self.optimizer_hint.as_ref() {
150+
for hint in &self.optimizer_hints {
151151
write!(f, " {hint}")?;
152152
}
153153
if let Some(priority) = self.priority {
@@ -267,11 +267,11 @@ impl Display for Insert {
267267
pub struct Delete {
268268
/// Token for the `DELETE` keyword
269269
pub delete_token: AttachedToken,
270-
/// A query optimizer hint
270+
/// Query optimizer hints
271271
///
272272
/// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/optimizer-hints.html)
273273
/// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Comments.html#GUID-D316D545-89E2-4D54-977F-FC97815CD62E)
274-
pub optimizer_hint: Option<OptimizerHint>,
274+
pub optimizer_hints: Vec<OptimizerHint>,
275275
/// Multi tables delete are supported in mysql
276276
pub tables: Vec<ObjectName>,
277277
/// FROM
@@ -291,7 +291,7 @@ pub struct Delete {
291291
impl Display for Delete {
292292
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293293
f.write_str("DELETE")?;
294-
if let Some(hint) = self.optimizer_hint.as_ref() {
294+
for hint in &self.optimizer_hints {
295295
f.write_str(" ")?;
296296
hint.fmt(f)?;
297297
}
@@ -345,11 +345,11 @@ impl Display for Delete {
345345
pub struct Update {
346346
/// Token for the `UPDATE` keyword
347347
pub update_token: AttachedToken,
348-
/// A query optimizer hint
348+
/// Query optimizer hints
349349
///
350350
/// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/optimizer-hints.html)
351351
/// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Comments.html#GUID-D316D545-89E2-4D54-977F-FC97815CD62E)
352-
pub optimizer_hint: Option<OptimizerHint>,
352+
pub optimizer_hints: Vec<OptimizerHint>,
353353
/// TABLE
354354
pub table: TableWithJoins,
355355
/// Column assignments
@@ -368,11 +368,12 @@ pub struct Update {
368368

369369
impl Display for Update {
370370
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
371-
f.write_str("UPDATE ")?;
372-
if let Some(hint) = self.optimizer_hint.as_ref() {
373-
hint.fmt(f)?;
371+
f.write_str("UPDATE")?;
372+
for hint in &self.optimizer_hints {
374373
f.write_str(" ")?;
374+
hint.fmt(f)?;
375375
}
376+
f.write_str(" ")?;
376377
if let Some(or) = &self.or {
377378
or.fmt(f)?;
378379
f.write_str(" ")?;
@@ -419,10 +420,10 @@ impl Display for Update {
419420
pub struct Merge {
420421
/// The `MERGE` token that starts the statement.
421422
pub merge_token: AttachedToken,
422-
/// A query optimizer hint
423+
/// Query optimizer hints
423424
///
424425
/// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Comments.html#GUID-D316D545-89E2-4D54-977F-FC97815CD62E)
425-
pub optimizer_hint: Option<OptimizerHint>,
426+
pub optimizer_hints: Vec<OptimizerHint>,
426427
/// optional INTO keyword
427428
pub into: bool,
428429
/// Specifies the table to merge
@@ -440,7 +441,7 @@ pub struct Merge {
440441
impl Display for Merge {
441442
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
442443
f.write_str("MERGE")?;
443-
if let Some(hint) = self.optimizer_hint.as_ref() {
444+
for hint in &self.optimizer_hints {
444445
write!(f, " {hint}")?;
445446
}
446447
if self.into {

src/ast/mod.rs

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2439,30 +2439,54 @@ impl fmt::Display for ShowCreateObject {
24392439
pub enum CommentObject {
24402440
/// A table column.
24412441
Column,
2442-
/// A table.
2443-
Table,
2442+
/// A database.
2443+
Database,
2444+
/// A domain.
2445+
Domain,
24442446
/// An extension.
24452447
Extension,
2448+
/// A function.
2449+
Function,
2450+
/// An index.
2451+
Index,
2452+
/// A materialized view.
2453+
MaterializedView,
2454+
/// A procedure.
2455+
Procedure,
2456+
/// A role.
2457+
Role,
24462458
/// A schema.
24472459
Schema,
2448-
/// A database.
2449-
Database,
2460+
/// A sequence.
2461+
Sequence,
2462+
/// A table.
2463+
Table,
2464+
/// A type.
2465+
Type,
24502466
/// A user.
24512467
User,
2452-
/// A role.
2453-
Role,
2468+
/// A view.
2469+
View,
24542470
}
24552471

24562472
impl fmt::Display for CommentObject {
24572473
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24582474
match self {
24592475
CommentObject::Column => f.write_str("COLUMN"),
2460-
CommentObject::Table => f.write_str("TABLE"),
2476+
CommentObject::Database => f.write_str("DATABASE"),
2477+
CommentObject::Domain => f.write_str("DOMAIN"),
24612478
CommentObject::Extension => f.write_str("EXTENSION"),
2479+
CommentObject::Function => f.write_str("FUNCTION"),
2480+
CommentObject::Index => f.write_str("INDEX"),
2481+
CommentObject::MaterializedView => f.write_str("MATERIALIZED VIEW"),
2482+
CommentObject::Procedure => f.write_str("PROCEDURE"),
2483+
CommentObject::Role => f.write_str("ROLE"),
24622484
CommentObject::Schema => f.write_str("SCHEMA"),
2463-
CommentObject::Database => f.write_str("DATABASE"),
2485+
CommentObject::Sequence => f.write_str("SEQUENCE"),
2486+
CommentObject::Table => f.write_str("TABLE"),
2487+
CommentObject::Type => f.write_str("TYPE"),
24642488
CommentObject::User => f.write_str("USER"),
2465-
CommentObject::Role => f.write_str("ROLE"),
2489+
CommentObject::View => f.write_str("VIEW"),
24662490
}
24672491
}
24682492
}
@@ -11650,12 +11674,19 @@ pub struct ResetStatement {
1165011674
/// `SELECT`, `INSERT`, `UPDATE`, `REPLACE`, `MERGE`, and `DELETE` keywords in
1165111675
/// the corresponding statements.
1165211676
///
11653-
/// See [Select::optimizer_hint]
11677+
/// See [Select::optimizer_hints]
1165411678
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1165511679
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1165611680
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1165711681
pub struct OptimizerHint {
11658-
/// the raw test of the optimizer hint without its markers
11682+
/// An optional prefix between the comment marker and `+`.
11683+
///
11684+
/// Standard optimizer hints like `/*+ ... */` have an empty prefix,
11685+
/// while system-specific hints like `/*abc+ ... */` have `prefix = "abc"`.
11686+
/// The prefix is any sequence of ASCII alphanumeric characters
11687+
/// immediately before the `+` marker.
11688+
pub prefix: String,
11689+
/// the raw text of the optimizer hint without its markers
1165911690
pub text: String,
1166011691
/// the style of the comment which `text` was extracted from,
1166111692
/// e.g. `/*+...*/` or `--+...`
@@ -11685,11 +11716,14 @@ impl fmt::Display for OptimizerHint {
1168511716
match &self.style {
1168611717
OptimizerHintStyle::SingleLine { prefix } => {
1168711718
f.write_str(prefix)?;
11719+
f.write_str(&self.prefix)?;
1168811720
f.write_str("+")?;
1168911721
f.write_str(&self.text)
1169011722
}
1169111723
OptimizerHintStyle::MultiLine => {
11692-
f.write_str("/*+")?;
11724+
f.write_str("/*")?;
11725+
f.write_str(&self.prefix)?;
11726+
f.write_str("+")?;
1169311727
f.write_str(&self.text)?;
1169411728
f.write_str("*/")
1169511729
}

src/ast/query.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -445,11 +445,11 @@ impl SelectModifiers {
445445
pub struct Select {
446446
/// Token for the `SELECT` keyword
447447
pub select_token: AttachedToken,
448-
/// A query optimizer hint
448+
/// Query optimizer hints
449449
///
450450
/// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/optimizer-hints.html)
451451
/// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Comments.html#GUID-D316D545-89E2-4D54-977F-FC97815CD62E)
452-
pub optimizer_hint: Option<OptimizerHint>,
452+
pub optimizer_hints: Vec<OptimizerHint>,
453453
/// `SELECT [DISTINCT] ...`
454454
pub distinct: Option<Distinct>,
455455
/// MySQL-specific SELECT modifiers.
@@ -521,7 +521,7 @@ impl fmt::Display for Select {
521521
}
522522
}
523523

524-
if let Some(hint) = self.optimizer_hint.as_ref() {
524+
for hint in &self.optimizer_hints {
525525
f.write_str(" ")?;
526526
hint.fmt(f)?;
527527
}

src/ast/spans.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,7 @@ impl Spanned for Delete {
900900
fn span(&self) -> Span {
901901
let Delete {
902902
delete_token,
903-
optimizer_hint: _,
903+
optimizer_hints: _,
904904
tables,
905905
from,
906906
using,
@@ -934,7 +934,7 @@ impl Spanned for Update {
934934
fn span(&self) -> Span {
935935
let Update {
936936
update_token,
937-
optimizer_hint: _,
937+
optimizer_hints: _,
938938
table,
939939
assignments,
940940
from,
@@ -1298,7 +1298,7 @@ impl Spanned for Insert {
12981298
fn span(&self) -> Span {
12991299
let Insert {
13001300
insert_token,
1301-
optimizer_hint: _,
1301+
optimizer_hints: _,
13021302
or: _, // enum, sqlite specific
13031303
ignore: _, // bool
13041304
into: _, // bool
@@ -2246,7 +2246,7 @@ impl Spanned for Select {
22462246
fn span(&self) -> Span {
22472247
let Select {
22482248
select_token,
2249-
optimizer_hint: _,
2249+
optimizer_hints: _,
22502250
distinct: _, // todo
22512251
select_modifiers: _,
22522252
top: _, // todo, mysql specific
@@ -2840,7 +2840,7 @@ WHERE id = 1
28402840
// ~ individual tokens within the statement
28412841
let Statement::Merge(Merge {
28422842
merge_token,
2843-
optimizer_hint: _,
2843+
optimizer_hints: _,
28442844
into: _,
28452845
table: _,
28462846
source: _,

src/dialect/mod.rs

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -756,17 +756,17 @@ pub trait Dialect: Debug + Any {
756756
};
757757
}
758758

759-
let token = parser.peek_token();
759+
let token = parser.peek_token_ref();
760760
debug!("get_next_precedence_full() {token:?}");
761-
match token.token {
761+
match &token.token {
762762
Token::Word(w) if w.keyword == Keyword::OR => Ok(p!(Or)),
763763
Token::Word(w) if w.keyword == Keyword::AND => Ok(p!(And)),
764764
Token::Word(w) if w.keyword == Keyword::XOR => Ok(p!(Xor)),
765765

766766
Token::Word(w) if w.keyword == Keyword::AT => {
767767
match (
768-
parser.peek_nth_token(1).token,
769-
parser.peek_nth_token(2).token,
768+
&parser.peek_nth_token_ref(1).token,
769+
&parser.peek_nth_token_ref(2).token,
770770
) {
771771
(Token::Word(w), Token::Word(w2))
772772
if w.keyword == Keyword::TIME && w2.keyword == Keyword::ZONE =>
@@ -777,28 +777,30 @@ pub trait Dialect: Debug + Any {
777777
}
778778
}
779779

780-
Token::Word(w) if w.keyword == Keyword::NOT => match parser.peek_nth_token(1).token {
781-
// The precedence of NOT varies depending on keyword that
782-
// follows it. If it is followed by IN, BETWEEN, or LIKE,
783-
// it takes on the precedence of those tokens. Otherwise, it
784-
// is not an infix operator, and therefore has zero
785-
// precedence.
786-
Token::Word(w) if w.keyword == Keyword::IN => Ok(p!(Between)),
787-
Token::Word(w) if w.keyword == Keyword::BETWEEN => Ok(p!(Between)),
788-
Token::Word(w) if w.keyword == Keyword::LIKE => Ok(p!(Like)),
789-
Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(p!(Like)),
790-
Token::Word(w) if w.keyword == Keyword::RLIKE => Ok(p!(Like)),
791-
Token::Word(w) if w.keyword == Keyword::REGEXP => Ok(p!(Like)),
792-
Token::Word(w) if w.keyword == Keyword::MATCH => Ok(p!(Like)),
793-
Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(p!(Like)),
794-
Token::Word(w) if w.keyword == Keyword::MEMBER => Ok(p!(Like)),
795-
Token::Word(w)
796-
if w.keyword == Keyword::NULL && !parser.in_column_definition_state() =>
797-
{
798-
Ok(p!(Is))
780+
Token::Word(w) if w.keyword == Keyword::NOT => {
781+
match &parser.peek_nth_token_ref(1).token {
782+
// The precedence of NOT varies depending on keyword that
783+
// follows it. If it is followed by IN, BETWEEN, or LIKE,
784+
// it takes on the precedence of those tokens. Otherwise, it
785+
// is not an infix operator, and therefore has zero
786+
// precedence.
787+
Token::Word(w) if w.keyword == Keyword::IN => Ok(p!(Between)),
788+
Token::Word(w) if w.keyword == Keyword::BETWEEN => Ok(p!(Between)),
789+
Token::Word(w) if w.keyword == Keyword::LIKE => Ok(p!(Like)),
790+
Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(p!(Like)),
791+
Token::Word(w) if w.keyword == Keyword::RLIKE => Ok(p!(Like)),
792+
Token::Word(w) if w.keyword == Keyword::REGEXP => Ok(p!(Like)),
793+
Token::Word(w) if w.keyword == Keyword::MATCH => Ok(p!(Like)),
794+
Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(p!(Like)),
795+
Token::Word(w) if w.keyword == Keyword::MEMBER => Ok(p!(Like)),
796+
Token::Word(w)
797+
if w.keyword == Keyword::NULL && !parser.in_column_definition_state() =>
798+
{
799+
Ok(p!(Is))
800+
}
801+
_ => Ok(self.prec_unknown()),
799802
}
800-
_ => Ok(self.prec_unknown()),
801-
},
803+
}
802804
Token::Word(w) if w.keyword == Keyword::NOTNULL && self.supports_notnull_operator() => {
803805
Ok(p!(Is))
804806
}
@@ -861,7 +863,7 @@ pub trait Dialect: Debug + Any {
861863
Token::DoubleColon | Token::ExclamationMark | Token::LBracket | Token::CaretAt => {
862864
Ok(p!(DoubleColon))
863865
}
864-
Token::Colon => match parser.peek_nth_token(1).token {
866+
Token::Colon => match &parser.peek_nth_token_ref(1).token {
865867
// When colon is followed by a string or a number, it's usually in MAP syntax.
866868
Token::SingleQuotedString(_) | Token::Number(_, _) => Ok(self.prec_unknown()),
867869
// In other cases, it's used in semi-structured data traversal like in variant or JSON

src/dialect/mssql.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ impl Dialect for MsSqlDialect {
159159
.is_some()
160160
|| matches!(p.peek_token_ref().token, Token::SemiColon | Token::EOF)
161161
{
162-
p.expected("statement", p.peek_token())
162+
p.expected_ref("statement", p.peek_token_ref())
163163
} else {
164164
Ok(())
165165
}
@@ -189,8 +189,8 @@ impl Dialect for MsSqlDialect {
189189
}
190190

191191
fn get_next_precedence(&self, parser: &Parser) -> Option<Result<u8, ParserError>> {
192-
let token = parser.peek_token();
193-
match token.token {
192+
let token = parser.peek_token_ref();
193+
match &token.token {
194194
// lowest prec to prevent it from turning into a binary op
195195
Token::Colon => Some(Ok(self.prec_unknown())),
196196
_ => None,

src/dialect/mysql.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ fn parse_lock_tables_type(parser: &mut Parser) -> Result<LockTableType, ParserEr
244244
} else if parser.parse_keywords(&[Keyword::LOW_PRIORITY, Keyword::WRITE]) {
245245
Ok(LockTableType::Write { low_priority: true })
246246
} else {
247-
parser.expected("an lock type in LOCK TABLES", parser.peek_token())
247+
parser.expected_ref("an lock type in LOCK TABLES", parser.peek_token_ref())
248248
}
249249
}
250250

0 commit comments

Comments
 (0)