From 348fc26c9904d800cd471947ba98abb5e8431b60 Mon Sep 17 00:00:00 2001 From: Taesu <166604494+bytaesu@users.noreply.github.com> Date: Sun, 13 Sep 2026 07:17:08 +0000 Subject: [PATCH] fix(db): use reported MySQL index byte bounds (#11272) --- .changeset/mysql-index-byte-bounds.md | 5 ++ .../adapter.kysely.mysql.test.ts | 46 ++++++++++++++++++- packages/better-auth/src/db/get-migration.ts | 2 +- 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 .changeset/mysql-index-byte-bounds.md diff --git a/.changeset/mysql-index-byte-bounds.md b/.changeset/mysql-index-byte-bounds.md new file mode 100644 index 0000000000..e47965b932 --- /dev/null +++ b/.changeset/mysql-index-byte-bounds.md @@ -0,0 +1,5 @@ +--- +"better-auth": patch +--- + +Use MySQL's reported byte lengths when validating indexes on existing string columns. diff --git a/e2e/adapter/test/kysely-adapter/adapter.kysely.mysql.test.ts b/e2e/adapter/test/kysely-adapter/adapter.kysely.mysql.test.ts index 29fe7b1c33..bd996acbd3 100644 --- a/e2e/adapter/test/kysely-adapter/adapter.kysely.mysql.test.ts +++ b/e2e/adapter/test/kysely-adapter/adapter.kysely.mysql.test.ts @@ -25,10 +25,52 @@ const kyselyDB = new Kysely({ dialect: new MysqlDialect(mysqlDB), }); -const mysqlDisabledIndexTestSuite = createTestSuite( +const mysqlMigrationIndexTestSuite = createTestSuite( "mysql migration index introspection", {}, () => ({ + /** + * @see https://dev.mysql.com/doc/refman/8.4/en/information-schema-columns-table.html + */ + "uses the column byte length when validating an index": async () => { + const tableName = "mysql_index_byte_length_subject"; + const indexName = "mysql_byte_length_subject_idx"; + const options = { + database: mysqlDB, + plugins: [ + { + id: "mysql-index-byte-length", + schema: { + mysqlIndexByteLengthSubject: { + modelName: tableName, + fields: { + subject: { type: "string" }, + }, + indexes: [{ fields: ["subject"], name: indexName }], + }, + }, + } satisfies BetterAuthPlugin, + ], + } satisfies BetterAuthOptions; + + await mysqlDB.query(` + CREATE TABLE \`${tableName}\` ( + \`id\` varchar(191) NOT NULL, + \`subject\` varchar(1000) CHARACTER SET latin1 NOT NULL, + PRIMARY KEY (\`id\`) + ) ENGINE=InnoDB + `); + try { + const migrations = await getMigrations(options); + expect(await migrations.compileMigrations()).toContain( + `create index \`${indexName}\` on \`${tableName}\` (\`subject\`)`, + ); + await migrations.runMigrations(); + } finally { + await mysqlDB.query(`DROP TABLE \`${tableName}\``); + } + }, + /** * @see https://dev.mysql.com/doc/refman/8.4/en/alter-table.html */ @@ -103,7 +145,7 @@ const { execute } = await testAdapter({ numberIdTestSuite(), joinsTestSuite(), uuidTestSuite(), - mysqlDisabledIndexTestSuite(), + mysqlMigrationIndexTestSuite(), caseInsensitiveTestSuite({ disableTests: { "findOne - eq with mode sensitive (default) should not match different case": true, diff --git a/packages/better-auth/src/db/get-migration.ts b/packages/better-auth/src/db/get-migration.ts index 57313eb187..7e15290a0d 100644 --- a/packages/better-auth/src/db/get-migration.ts +++ b/packages/better-auth/src/db/get-migration.ts @@ -399,7 +399,7 @@ async function getDatabaseColumnBounds( SELECT table_name AS tableName, column_name AS columnName, - character_maximum_length * 4 AS maxIndexBytes + character_octet_length AS maxIndexBytes FROM information_schema.columns WHERE table_schema = DATABASE() `.execute(db)