vapor / mysql-nio

🐬 Non-blocking, event-driven Swift client for MySQL.
MIT License
87 stars 28 forks source link

MySQL cannot save long strings (over 252 chars long) #23

Closed TomShen1234 closed 4 years ago

TomShen1234 commented 4 years ago

Found another bug related to MySQL

Posting this directly here because it's related to MySQL (where my previous unrelated issue has been migrated to).

MySQL supports the TEXT data type for storing extra long strings. I can access it in Fluent by using .custom("text") during migration. Fluent is able to read from and write to it fine, with a caveat: the content cannot be over 252 characters long.

This does not happen with FluentSQLiteDriver, it can save string of any length to the column with text datatype. (I did not test with Postgre because I don't have it installed on my system)

Steps to reproduce

Create a new project from template (vapor new --branch=4), then add a new content field, when migrating, let it have the text data type:

struct CreateTodo: Migration {
    func prepare(on database: Database) -> EventLoopFuture<Void> {
        return database.schema("todos")
            .id()
            .field("title", .string, .required)
            .field("content", .custom("text"), .required)
            .create()
    }

    func revert(on database: Database) -> EventLoopFuture<Void> {
        return database.schema("todos").delete()
    }
}
final class Todo: Model, Content {
    static let schema = "todos"

    @ID(key: .id)
    var id: UUID?

    @Field(key: "title")
    var title: String

    @Field(key: "content")
    var content: String

    init() { }

    init(id: UUID? = nil, title: String) {
        self.id = id
        self.title = title
    }
}

Expected behavior

The server should be able to read and write strings of any length.

Actual behavior

If the string is over 252 characters long, FluentMySQLDriver will output an error:

[ ERROR ] MySQL error: Server error: Malformed communication packet.

If the string is over 255 characters long, the server will just crash with the following error:

Fatal error: Not enough bits to represent the passed value: file /AppleInternal/BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1103.8.25.8/swift/stdlib/public/core/Integers.swift, line 3447

Environment

tanner0101 commented 4 years ago

My guess is this is related to TEXT, I'd recommend trying VARCHAR as a workaround. I'll make sure this gets fixed before final release, thanks.

TomShen1234 commented 4 years ago

@tanner0101 Thanks for the response, the same error happens to VARCHAR type as well. Which makes me think that this is an error in creating the SQL command rather than a database issue?

tanner0101 commented 4 years ago

@TomShen1234 looks like this was an issue with length encoding not being implemented yet. I've put up a fix here: https://github.com/vapor/mysql-nio/pull/24