Skip to content

Fix create statement for mysql #602

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 11 commits into from
Closed

Fix create statement for mysql #602

wants to merge 11 commits into from

Conversation

RainJoe
Copy link

@RainJoe RainJoe commented Sep 5, 2022

  1. Add ON UPDATE CURRENT_TIMESTAMP support.
  2. Add KEY/INDEX support

src/ast/ddl.rs Outdated
@@ -256,11 +263,38 @@ impl fmt::Display for TableConstraint {
name,
columns,
is_primary,
is_mysql_unique_key,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bad design that can turn this code huge when considering other dialects.

If you really need the dialect info here, maybe you could have the Dialect itself, not that level of specificity here.

Since there are 3 possible options, couldn't we use an enum variant? Like:

pub enum UniqueType {
    PrimaryKey,
    Key,
    Simple
} 

(ignore the horrible naming, but you got the idea hehe)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use enum variant would not work, i think using specific dialect is a good solution, but when I add dialect trait in TableConstrait struct, the compiler says: the trait bound dyn dialect::Dialect: Clone is not satisfied。
There may not have explict constrait key word in mysql create statement, constraint keyword is optional, like:

CREATE TABLE table_name(
   column_name1 column_definition,
   column_name2 column_definition,
   ...,
   [CONSTRAINT constraint_name]
      UNIQUE(column_name1,column_name2)
);

so use the origin display_constraint_name method not work,This is why I use is_mysql_unique_key to distinguish mysql dialect specifically.

I haven't been able to find an elegant way to solve it yet, any good idea?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use enum variant would not work

Why would this not work?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I remove is_mysql_unique_key and use the original display method, then run the parse_table_colum_option_key test, it would panic, the painc message show the difference:

thread parse_table_colum_option_key panicked at assertion failed: (left == right)
left: "CREATE TABLE foo (modification_time DATETIME ON UPDATE, UNIQUE KEY u_m_t (modification_time))",
right: "CREATE TABLE foo (modification_time DATETIME ON UPDATE, CONSTRAINT u_m_t UNIQUE (modification_time))", src/test_utils.rs:95:13

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RainJoe but you can still use an enum or something like that. Using a single boolean makes the expansion difficult, and doesn't make that much sense as it is really specific information added to the general AST. Using an enum there allows the upper levels to match and handle as desired when, for example, they're using the PostgreSQL dialect.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AugustoFKL Thanks for your suggestion,I will make some modifications and create a now PR later.

Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution @RainJoe

I suggest following the idea of @AugustoFKL and using an enum variant to describe the different possible parsed versions of the CONSTRAINTs keyword.

I am not familiar with the differences in syntax -- perhaps if you could summarize the differences in the description of this PR we could offer some more helpful feedback

@@ -247,6 +249,11 @@ pub enum TableConstraint {
name: Option<Ident>,
expr: Box<Expr>,
},
Key {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add comments here about what this field means / how it maps back to SQL?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RainJoe please LMK if I'm wrong, but UNIQUE KEY isn't the same as a UNIQUE constraint, while only KEY refers to the same as CREATE INDEX?

Wouldn't be better to keep UNIQUE [KEY | INDEX] as a UNIQUE table constraint?

Copy link
Author

@RainJoe RainJoe Oct 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's not same. I have fixed it, PTAL @AugustoFKL

src/ast/ddl.rs Outdated
@@ -228,6 +229,7 @@ pub enum TableConstraint {
columns: Vec<Ident>,
/// Whether this is a `PRIMARY KEY` or just a `UNIQUE` constraint
is_primary: bool,
is_mysql_unique_key: bool,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add comments to this field explaining what it means (aka how is this different)

src/ast/ddl.rs Outdated
@@ -256,11 +263,38 @@ impl fmt::Display for TableConstraint {
name,
columns,
is_primary,
is_mysql_unique_key,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use enum variant would not work

Why would this not work?

@coveralls
Copy link

coveralls commented Sep 27, 2022

Pull Request Test Coverage Report for Build 3169255008

  • 156 of 167 (93.41%) changed or added relevant lines in 3 files are covered.
  • 845 unchanged lines in 12 files lost coverage.
  • Overall coverage increased (+0.1%) to 85.687%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/parser.rs 20 23 86.96%
src/ast/ddl.rs 20 28 71.43%
Files with Coverage Reduction New Missed Lines %
src/ast/ddl.rs 1 80.0%
src/dialect/hive.rs 1 94.12%
src/dialect/mod.rs 1 91.67%
src/test_utils.rs 1 83.58%
src/dialect/postgresql.rs 2 93.75%
tests/sqlparser_postgres.rs 5 97.72%
src/ast/data_type.rs 7 91.03%
src/ast/value.rs 8 88.24%
src/tokenizer.rs 46 89.42%
tests/sqlparser_common.rs 81 97.08%
Totals Coverage Status
Change from base Build 2957846519: 0.1%
Covered Lines: 10339
Relevant Lines: 12066

💛 - Coveralls

@RainJoe
Copy link
Author

RainJoe commented Oct 2, 2022

@AugustoFKL PTAL
I made some modifications at your suggestion.

@@ -247,6 +249,11 @@ pub enum TableConstraint {
name: Option<Ident>,
expr: Box<Expr>,
},
Key {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RainJoe please LMK if I'm wrong, but UNIQUE KEY isn't the same as a UNIQUE constraint, while only KEY refers to the same as CREATE INDEX?

Wouldn't be better to keep UNIQUE [KEY | INDEX] as a UNIQUE table constraint?

src/parser.rs Outdated
Token::Word(w) if w.keyword == Keyword::PRIMARY || w.keyword == Keyword::UNIQUE => {
let is_primary = w.keyword == Keyword::PRIMARY;
if is_primary {
self.expect_keyword(Keyword::KEY)?;
} else if dialect_of!(self is MySqlDialect) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add the GenericDialect here. The idea of that, as long as I understood by this comment, is to support everything possible.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard to cover all dialects now. so using the specific dialect to avoid affecting other dialects.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RainJoe THeGenericDialect is the one that contains literally EVERY single possible AST structure. Therefore, it should contemplate any possible query

dialect_of!(self is GenericDialect | MySqlDialect) should be enough

columns,
format: KeyFormat::Index,
})),
_ => unreachable!(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please replace this with an error. I left a possible approach for cases like that here

Copy link
Author

@RainJoe RainJoe Oct 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There would be only two cases, and both of them are covered, so it's actually unreachable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine, but can't you return an error here?

It's better to have an error (like the self.expected(...)) than having a unreachable

Ok(Some(ColumnOption::DialectSpecific(vec![
Token::make_keyword("ON UPDATE"),
])))
if self.parse_keyword(Keyword::CURRENT_TIMESTAMP) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did it change?

It's not related to your PR, so shouldn't have changed at all

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mentioned it in my first comment.

@@ -428,6 +474,19 @@ fn display_constraint_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
ConstraintName(name)
}

fn display_key_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too much complex, this isn't necessary at all...

Please can you try to make it simple? LMK if you need any help

Copy link
Author

@RainJoe RainJoe Oct 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's similar to display_constraint_name methed, the name dose not implement display method, so i think it's necessary to do this.

/// For mysql index, here may be there format for index, there patterns are similar。
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum KeyFormat {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I stated in another comment, UNIQUE is a constraint. Please don't change the current handle structure for it, as this doesn't make sense. You're changing the AST to match only one dialect.

Copy link
Author

@RainJoe RainJoe Oct 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you don't do this. this libarary would never support for mysql create statement. I think we should make it work first, and if someone have a better solution,we can apply it later.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RainJoe would you mind if I tried a different approach and you took a look in a day or two?

Sorry for asking that, I know that this has been your work, don't want to look like throwing that away

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course not. waitting for your approach.

Copy link
Contributor

@AugustoFKL AugustoFKL Oct 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RainJoe @alamb could you please leave your opinion? #665

Sorry the delay, busy week at work + college

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AugustoFKL Thanks for your work, but it didn't solve my problem, maybe I would just use my fork repository. It's seems hard to consider all possible scenarios.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RainJoe can you give examples of what you intend about this task?

The index usage itself is being parsed... What is the syntax you need?

@alamb alamb marked this pull request as draft October 19, 2022 21:22
@alamb
Copy link
Contributor

alamb commented Oct 19, 2022

Marking as draft as it seems to be waiting on feedback. Please mark as ready for review if/when it is

@alamb
Copy link
Contributor

alamb commented Dec 28, 2022

@RainJoe can you see if #685 works for you?

@alamb alamb closed this Dec 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants