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

Problem with migration CreateActiveHashcashStamps and MySQL #9

Open
vakuum opened this issue Sep 5, 2024 · 1 comment
Open

Problem with migration CreateActiveHashcashStamps and MySQL #9

vakuum opened this issue Sep 5, 2024 · 1 comment

Comments

@vakuum
Copy link

vakuum commented Sep 5, 2024

When I run the migration 20240215143453_create_active_hashcash_stamps.rb with MySQL 8.0, the following error occurs:

Specified key was too long; max key length is 3072 bytes

Reproducing the error:

$ bundle exec rails c
Loading staging environment (Rails 6.1.7.8)

> class CreateActiveHashcashStamps < ActiveRecord::Migration[5.2]
  def change
    create_table :active_hashcash_stamps do |t|
      t.string :version, null: false
      t.integer :bits, null: false
      t.date :date, null: false
      t.string :resource, null: false
      t.string :ext, null: false
      t.string :rand, null: false
      t.string :counter, null: false
      t.string :request_path
      t.string :ip_address

      if t.respond_to?(:jsonb)
        t.jsonb :context # SQLite JSONB support from version 3.45 (2024-01-15)
      elsif t.respond_to?(:json)
        t.json :context
      end

      t.timestamps
    end
    add_index :active_hashcash_stamps, [:ip_address, :created_at], where: "ip_address IS NOT NULL"
    add_index :active_hashcash_stamps, [:counter, :rand, :date, :resource, :bits, :version, :ext], name: "index_active_hashcash_stamps_unique", unique: true
  end
end

> CreateActiveHashcashStamps.new.change
-- create_table(:active_hashcash_stamps)
   (164.1ms)  CREATE TABLE `active_hashcash_stamps` (`id` bigint NOT NULL AUTO_INCREMENT PRIMARY KEY, `version` varchar(255) NOT NULL, `bits` int NOT NULL, `date` date NOT NULL, `resource` varchar(255) NOT NULL, `ext` varchar(255) NOT NULL, `rand` varchar(255) NOT NULL, `counter` varchar(255) NOT NULL, `request_path` varchar(255), `ip_address` varchar(255), `context` json, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL)
   -> 0.1654s
-- add_index(:active_hashcash_stamps, [:ip_address, :created_at], {:where=>"ip_address IS NOT NULL"})
   (65.8ms)  CREATE INDEX `index_active_hashcash_stamps_on_ip_address_and_created_at` ON `active_hashcash_stamps` (`ip_address`, `created_at`)
   -> 0.0663s
-- add_index(:active_hashcash_stamps, [:counter, :rand, :date, :resource, :bits, :version, :ext], {:name=>"index_active_hashcash_stamps_unique", :unique=>true})
   (1.5ms)  CREATE UNIQUE INDEX `index_active_hashcash_stamps_unique` ON `active_hashcash_stamps` (`counter`, `rand`, `date`, `resource`, `bits`, `version`, `ext`)
/.../bundle/ruby/3.2.0/gems/mysql2-0.5.6/lib/mysql2/client.rb:151:in `_query': Mysql2::Error: Specified key was too long; max key length is 3072 bytes (ActiveRecord::StatementInvalid)
/.../bundle/ruby/3.2.0/gems/mysql2-0.5.6/lib/mysql2/client.rb:151:in `_query': Specified key was too long; max key length is 3072 bytes (Mysql2::Error)

Used MySQL version:

$ mysql
...
Server version: 8.0.39-0ubuntu0.24.04.2 (Ubuntu)
...

Workaround

If I reduce the size of the string columns that are part of the index index_active_hashcash_stamps_unique with limit: 100, the error no longer occurs:

$ bundle exec rails c
Loading staging environment (Rails 6.1.7.8)

> class CreateActiveHashcashStamps < ActiveRecord::Migration[5.2]
  def change
    create_table :active_hashcash_stamps do |t|
      t.string :version, null: false, limit: 100
      t.integer :bits, null: false
      t.date :date, null: false
      t.string :resource, null: false, limit: 100
      t.string :ext, null: false, limit: 100
      t.string :rand, null: false, limit: 100
      t.string :counter, null: false, limit: 100
      t.string :request_path
      t.string :ip_address

      if t.respond_to?(:jsonb)
        t.jsonb :context # SQLite JSONB support from version 3.45 (2024-01-15)
      elsif t.respond_to?(:json)
        t.json :context
      end

      t.timestamps
    end
    add_index :active_hashcash_stamps, [:ip_address, :created_at], where: "ip_address IS NOT NULL"
    add_index :active_hashcash_stamps, [:counter, :rand, :date, :resource, :bits, :version, :ext], name: "index_active_hashcash_stamps_unique", unique: true
  end
end

> CreateActiveHashcashStamps.new.change
-- create_table(:active_hashcash_stamps)
   (77.0ms)  CREATE TABLE `active_hashcash_stamps` (`id` bigint NOT NULL AUTO_INCREMENT PRIMARY KEY, `version` varchar(100) NOT NULL, `bits` int NOT NULL, `date` date NOT NULL, `resource` varchar(100) NOT NULL, `ext` varchar(100) NOT NULL, `rand` varchar(100) NOT NULL, `counter` varchar(100) NOT NULL, `request_path` varchar(255), `ip_address` varchar(255), `context` json, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL)
   -> 0.0785s
-- add_index(:active_hashcash_stamps, [:ip_address, :created_at], {:where=>"ip_address IS NOT NULL"})
   (50.1ms)  CREATE INDEX `index_active_hashcash_stamps_on_ip_address_and_created_at` ON `active_hashcash_stamps` (`ip_address`, `created_at`)
   -> 0.0509s
-- add_index(:active_hashcash_stamps, [:counter, :rand, :date, :resource, :bits, :version, :ext], {:name=>"index_active_hashcash_stamps_unique", :unique=>true})
   (43.1ms)  CREATE UNIQUE INDEX `index_active_hashcash_stamps_unique` ON `active_hashcash_stamps` (`counter`, `rand`, `date`, `resource`, `bits`, `version`, `ext`)
   -> 0.0436s
=> nil
@alexisbernard
Copy link
Member

Thanks for reporting the issue.

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