-
-
Notifications
You must be signed in to change notification settings - Fork 172
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
MySQL error trying to delete a constraint #722
Comments
It looks like on MySQL it's creating an index as well as the constraint which needs to be deleted in the revert as well. You'll probably need to drop down to raw SQL for this |
Thank you, @0xTim. I have done some more investigation. If I use MySQL client on the table created by the ALTER TABLE Unit DROP FOREIGN KEY Then it works and deletes the index as well. So, the raw query will have to delete the foreign key rather than the index, which suggests that there is a problem in the ALTER TABLE Unit DROP CONSTRAINT And this deletes the foreign key but leaves the index of the same name untouched. Postgres does let you delete a foreign key via the constraint syntax. I think there is a (second) issue that although I have attempted to name the constraint in the |
Same issue here |
After some research, I sloved this problem by writing raw sql import Foundation
import Fluent
import Vapor
import SQLKit
struct CreateArticleHeadCommit: AsyncMigration {
func prepare(on database: Database) async throws {
try await database.schema(ArticleEntry.schema)
.field("head_commit_id", .uuid)
.update()
let sqlDB = database as! SQLDatabase
let _ = try await sqlDB.raw(
"""
ALTER TABLE \(ArticleEntry.schema)
ADD CONSTRAINT FK_head_commit_id
FOREIGN KEY (head_commit_id)
REFERENCES \(ArticleCommitEntry.schema)(id);
"""
).all()
}
func revert(on database: Database) async throws {
let sqlDB = database as! SQLDatabase
let _ = try await sqlDB.raw(
"""
ALTER TABLE \(ArticleEntry.schema)
DROP CONSTRAINT FK_head_commit_id;
"""
).all()
try await database.schema(ArticleEntry.schema)
.deleteField("head_commit_id").update()
}
}
|
Here is my new approach @0xTim struct CreateArticleHeadCommit: AsyncMigration {
func prepare(on database: Database) async throws {
try await database.schema(ArticleEntry.schema)
.field("head_commit_id", .uuid)
.foreignKey("head_commit_id",
references: ArticleCommitEntry.schema,
"id",
onDelete: .setNull,
name: "created_head_commit_id")
.update()
}
func revert(on database: Database) async throws {
try await database.schema(ArticleEntry.schema)
.deleteConstraint(name: "created_head_commit_id")
.update()
try await database.schema(ArticleEntry.schema).deleteField("head_commit_id")
.update()
}
} This approach result in the same as this issue
to debug this problem, I traced the mysql log migration
revert
|
@0xTim just wrote a new unit test to debug final class DatabaseSQLTests: XCTestCase {
func testDatabaseSQLTests() throws {
let db = DummyDatabaseForTestSQLSerializer()
try db.schema(ArticleEntry.schema)
.deleteConstraint(name: "created_head_commit_id")
.update().wait()
print(db.sqlSerializers)
}
} the sql looks normal [SQLKit.SQLSerializer(sql: "ALTER TABLE \"article_entry\" DROP CONSTRAINT \"created_head_commit_id\"", binds: [], database: AppTests.DummyDatabaseForTestSQLSerializer)] so why mysql recieved these sql?
I'll keep digging |
According to MySQL's reference Conditions and Restrictions
So yes, adding foregin key reference will also produce an index. But when we want to delete Foregin Key Reference field, there is no need to delete index first Seems Fluent tries to delete the index first. |
I made a breakpoint in FluentMySQLDatabase#48 Looks like it convert deleteConstraint into
|
Okey, I find out whats the problem public func serialize(to serializer: inout SQLSerializer) {
if serializer.dialect.name == "mysql" {
serializer.write("KEY ")
} else {
serializer.write("CONSTRAINT ")
}
let normalizedName = serializer.dialect.normalizeSQLConstraint(identifier: name)
normalizedName.serialize(to: &serializer)
} Here we can find out that at runtime, SQLDropConstraint was converted to KEY instead of CONSTRAINT |
So here is the truth, when db is mysql, it produces So why we are using |
@gwynne any idea? |
I leave some new invesgation on PR vapor/fluent-kit#492 (comment) @gwynne I would like to know your oppion. |
This should have been fixed by vapor/fluent-kit#522 |
This should now be actually fixed, see the release notes for details on how to update your code. |
Hi
Sadly, I can’t reproduce the fix with my minimal example previous submitted. I’ve tried using:
.field("imagesUploadedByUserId", .uuid, .references("User", "id"))
.foreignKey("idkId", references: "User", "id", name: "waddyaKnow")
To create the foreign key fields. And:
.deleteForeignKey(name:"waddyaKnow”)
.deleteConstraint(name:”waddyaKnow”)
Attempting to delete the field.
In all cases, it reports that it is failing to delete the column/key using the normalised constraint/key name, such as:
0c2da0c13abec57e8c4ccd235ae7b4d070b2e686
I’ve also uncovered a similar issue with multiple-index ‘unique’ indices, which I have logged.
N
… On 30 Jul 2023, at 03:11, Gwynne Raskind ***@***.***> wrote:
Closed #722 <#722> as completed.
—
Reply to this email directly, view it on GitHub <#722 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/ABK5DRI5JAR3YND4EE5XBPDXSW7EHANCNFSM42TNSK4A>.
You are receiving this because you were mentioned.
|
I've got a
Migration
that adds a foreign key field to aModel
:The
prepare
works, butrevert
errors with:Thinking it might be that it can't be done in a single update to the schema, I tried:
However, this just gives a different error:
Reverting to the original, single update and reversing the order of deleting the field and constraint doesn't help either.
Looking through the fluent source code, it looks like it doesn't take account of the existence of the index that is created with the constraint so doesn't try to. delete it.
The text was updated successfully, but these errors were encountered: