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

Bug: CreateTableQuery fails to set VARCHAR length (MSSQL and MySQL) #736

Closed
bevzzz opened this issue Dec 28, 2022 · 1 comment
Closed

Bug: CreateTableQuery fails to set VARCHAR length (MSSQL and MySQL) #736

bevzzz opened this issue Dec 28, 2022 · 1 comment

Comments

@bevzzz
Copy link
Contributor

bevzzz commented Dec 28, 2022

I've encountered this odd behavior with CreateTableQuery.Varchar(n):

// Regular query
db.NewCreateTable().Model(new(Model))
// Output:
// pg:			CREATE TABLE "models" ("id" VARCHAR)
// pgx:			CREATE TABLE "models" ("id" VARCHAR)
// sqlite:		CREATE TABLE "models" ("id" VARCHAR)
// mysql5:		CREATE TABLE `models` (`id` VARCHAR(255))
// mysql8:		CREATE TABLE `models` (`id` VARCHAR(255))
// mariadb:		CREATE TABLE `models` (`id` VARCHAR(255))
// mssql2019: 	        CREATE TABLE "models" ("id" VARCHAR(255))

// Specify VARCHAR length
db.NewCreateTable().Model(new(Model)).Varchar(10)
// Output:
// pg:        CREATE TABLE "models" ("id" varchar(10))
// pgx:       CREATE TABLE "models" ("id" varchar(10))
// sqlite:    CREATE TABLE "models" ("id" varchar(10))
// mysql5:    CREATE TABLE `models` (`id` VARCHAR(255))
// mysql8:    CREATE TABLE `models` (`id` VARCHAR(255))
// mariadb:   CREATE TABLE `models` (`id` VARCHAR(255))
// mssql2019: CREATE TABLE "models" ("id" VARCHAR(255))

I've also noticed there is no unit tests that check .Varchar() method, so I guess it could be a bug.

Problem
Specifying VARCHAR length is mandatory in MySQL and MSSQL, so the default 255 is hardcoded in their DiscoveredSQLType:

return field.DiscoveredSQLType + "(255)"

return field.DiscoveredSQLType + "(255)"

As a result, this function in query_table_create.go fails to recognize VARCHAR column in those dialects :

Click for a commented version
func (q *CreateTableQuery) appendSQLType(b []byte, field *schema.Field) []byte {
        // Most of the time these two will be identical, but for the cases where DiscoveredSQLType is dialect-specific,
        // e.g. pgdialect would change sqltype.SmallInt to pgTypeSmallSerial for columns that have `bun:",autoincrement"`
	if field.CreateTableSQLType != field.DiscoveredSQLType {
		return append(b, field.CreateTableSQLType...)
	}

        // For all common SQL types except VARCHAR, both UserDefinedSQLType and DiscoveredSQLType specify the correct type,
       // and we needn't modify it. For VARCHAR columns, we will stop to check if a valid length has been set in .Varchar(int).
	if q.varchar > 0 &&
		field.CreateTableSQLType == sqltype.VarChar {
		b = append(b, "varchar("...)
		b = strconv.AppendInt(b, int64(q.varchar), 10)
		b = append(b, ")"...)
		return b
	}

	return append(b, field.CreateTableSQLType...)
}

Solution
We could have each dialect provide a method like d.DefaultVarcharLen() and then use that value if no other valid length is specified.
Dialects for which specifying the length is not mandatory (PG, SQLite) could simply return a 0, which would be ignored.

I can do a PR with a fix, if that's indeed a bug and the solution is OK.

@vmihailenco
Copy link
Member

I guess this is fixed by #738

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

No branches or pull requests

2 participants