Skip to content
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

fix: fix sync creating the reference multiple time if lower_case_table_names = 1 #17256

Closed
wants to merge 0 commits into from

Conversation

aamir-alii
Copy link

Pull Request Checklist

  • Have you added new tests to prevent regressions?
  • If a documentation update is necessary, have you opened a PR to the documentation repository?
  • Did you update the typescript typings accordingly (if applicable)?
  • Does the description below contain a link to an existing issue (Closes #[issue]) or a description of the issue you are solving?
  • Does the name of your PR follow our conventions?

Description of Changes

Link to issue this PR resolve
(#17255)

List of Breaking Changes

@aamir-alii aamir-alii requested a review from a team as a code owner April 6, 2024 12:25
@aamir-alii aamir-alii requested review from ephys and WikiRik April 6, 2024 12:25
@ephys
Copy link
Member

ephys commented Apr 6, 2024

Sorry this is not the right solution for the problem as it would introduce problems in systems that are case sensitive

In my opinion, the solution to this would be to implement #15312, and make sure all names are generated lowercase if that flag is on

@aamir-alii aamir-alii closed this Apr 6, 2024
@aamir-alii aamir-alii reopened this Apr 6, 2024
@aamir-alii
Copy link
Author

yes, you are right to implement naming conventions and making all names lowercase if that flag is set to true but what if some one first create tables with migrations and then after some time he turn that flag to true, then the same issue will be persist what I think if there is any way to know if server does not support particular case and we then handle that accordingly.

@aamir-alii
Copy link
Author

what if we check default COLLATE of SQL SERVER and modify condition accordingly as it occurs when COLLATE is case insensitive and these two collates are case insensitive Latin1_General_CI_AS, SQL_Latin1_General_CP1_CI_AS

@ephys
Copy link
Member

ephys commented Apr 6, 2024

According to mysql's documentation, lower_case_table_names cannot be changed after the server has been initialized for the first time

If we look at all possible options for lower_case_table_names,

  • 0 - stored as-is and case-sensitive comparison: everything works as expected, that's what Sequelize expects
  • 2 - stored as-is and case-insensitive comparison: also fine because the value we'll get back from the database will be with the expected casing, so we can do a case-sensitive comparison
  • 1 - stored as lower case, and case-insensitive comparison: this one is the one we're really incompatible with as we don't generate lowercase names. Ideally we should match what will be returned from the introspection query. This can be fully solved by Redesign naming Strategies #15312, as it doesn't matter if the comparison is case-insensitive if we always compare lowercase strings, which is good because converting to lowercase is not a simple task, it depends on the collation

@ephys ephys changed the title Fix: creating multiple references fix: fix sync creating the reference multiple time if lower_case_table_names = 1 Apr 7, 2024
@ephys ephys changed the title fix: fix sync creating the reference multiple time if lower_case_table_names = 1 fix: fix sync creating the reference multiple time if lower_case_table_names = 1 Apr 7, 2024
@aamir-alii
Copy link
Author

According to mysql's documentation, lower_case_table_names cannot be changed after the server has been initialized for the first time

If we look at all possible options for lower_case_table_names,

  • 0 - stored as-is and case-sensitive comparison: everything works as expected, that's what Sequelize expects
  • 2 - stored as-is and case-insensitive comparison: also fine because the value we'll get back from the database will be with the expected casing, so we can do a case-sensitive comparison
  • 1 - stored as lower case, and case-insensitive comparison: this one is the one we're really incompatible with as we don't generate lowercase names. Ideally we should match what will be returned from the introspection query. This can be fully solved by Redesign naming Strategies #15312, as it doesn't matter if the comparison is case-insensitive if we always compare lowercase strings, which is good because converting to lowercase is not a simple task, it depends on the collation

you are referring to something else when make query to database it does not create problem in the provided example in the issue section my query from database is executing right as it search case insensitive search but when we compare it here in sequelize it generate issue.

the following query give me reference table schema and referenced table name which is from database and if it is stored in lowercase and in code some one using camel case then it would not delete previous references.

SELECT 
   c.CONSTRAINT_SCHEMA AS constraintSchema,
   c.CONSTRAINT_NAME AS constraintName,
   c.CONSTRAINT_TYPE AS constraintType,
   c.TABLE_SCHEMA AS tableSchema,
   c.TABLE_NAME AS tableName,
   kcu.COLUMN_NAME AS columnNames,
   kcu.REFERENCED_TABLE_SCHEMA AS referencedTableSchema,
   kcu.REFERENCED_TABLE_NAME AS referencedTableName,
   kcu.REFERENCED_COLUMN_NAME AS referencedColumnNames,
   r.DELETE_RULE AS deleteAction,
   r.UPDATE_RULE AS updateAction,
   ch.CHECK_CLAUSE AS definition
FROM
   INFORMATION_SCHEMA.TABLE_CONSTRAINTS c
       LEFT JOIN
   INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS r ON c.CONSTRAINT_CATALOG = r.CONSTRAINT_CATALOG
       AND c.CONSTRAINT_SCHEMA = r.CONSTRAINT_SCHEMA
       AND c.CONSTRAINT_NAME = r.CONSTRAINT_NAME
       AND c.TABLE_NAME = r.TABLE_NAME
       LEFT JOIN
   INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu ON c.CONSTRAINT_CATALOG = kcu.CONSTRAINT_CATALOG
       AND c.CONSTRAINT_SCHEMA = kcu.CONSTRAINT_SCHEMA
       AND c.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME
       AND c.TABLE_NAME = kcu.TABLE_NAME
       LEFT JOIN
   INFORMATION_SCHEMA.CHECK_CONSTRAINTS ch ON c.CONSTRAINT_CATALOG = ch.CONSTRAINT_CATALOG
       AND c.CONSTRAINT_SCHEMA = ch.CONSTRAINT_SCHEMA
       AND c.CONSTRAINT_NAME = ch.CONSTRAINT_NAME
WHERE
   c.TABLE_NAME = 'Products'
       AND c.TABLE_SCHEMA = 'SEQ-DB-Dev'
       AND c.CONSTRAINT_TYPE = 'FOREIGN KEY'
ORDER BY c.CONSTRAINT_NAME , kcu.ORDINAL_POSITION;

we have problem in the following condition

 (constraintName &&
                  (foreignKeyReference.tableCatalog
                    ? foreignKeyReference.tableCatalog === database
                    : true) &&
                  (schema ? foreignKeyReference.tableSchema === schema : true) &&
                  foreignKeyReference.referencedTableName === foreignReferenceTableName &&
                  foreignKeyReference.referencedColumnNames.includes(references.key) &&
                  (foreignReferenceSchema
                    ? foreignKeyReference.referencedTableSchema === foreignReferenceSchema
                    : true) &&
                  !removedConstraints[constraintName]) ||
                this.sequelize.dialect.name === 'ibmi'
              ) 

I don't think so to allow some one to create same table or schema name with different cases and if consider it then case insensitive search here would not generate any issue. like user should not be allowed to create Users and users two different tables.

@ephys
Copy link
Member

ephys commented Apr 8, 2024

you are referring to something else when make query to database it does not create problem in the provided example in the issue section my query from database is executing right as it search case insensitive search but when we compare it here in sequelize it generate issue.

No, I am talking about the issue of comparing the value in JavaScript, and as stated, if we generate a value that MySQL considers lowercase when lower_case_table_names = 1, there will not be any comparison issues.

I don't think so to allow some one to create same table or schema name with different cases and if consider it then case insensitive search here would not generate any issue. like user should not be allowed to create Users and users two different tables.

I disagree, if the database is case-sensitive, then we need to compare the values in a case-sensitive way, the alternative would not be safe and would lead Sequelize to think two different identifiers are the same even though they are not. It's impossible for us to prevent users from creating two identifiers that are equal when case-sensitive, but not when insensitive. Degrading the support for case-sensitive databases is not a solution to support case-insensitive databases

Copy link
Member

@ephys ephys left a comment

Choose a reason for hiding this comment

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

In the current state, this is not something we can merge so I'm posting a change request

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.

None yet

2 participants