activerecord-cockroachdb-adapter icon indicating copy to clipboard operation
activerecord-cockroachdb-adapter copied to clipboard

Hash indexes are not supported

Open mmalek-sa opened this issue 3 months ago • 1 comments

I can't create a hash index using:

add_index(
  :users,
  :username,
  using:         "hash",
  algorithm:     :concurrently,
  if_not_exists: true
)

Which prints this error:

ActiveRecord::StatementInvalid: PG::FeatureNotSupported: ERROR:  at or near "hash": syntax error: unimplemented: this syntax
DETAIL:  source SQL:
CREATE INDEX CONCURRENTLY IF NOT EXISTS "index_users_on_username" ON "users" USING hash ("username")
                                                                                        ^
HINT:  You have attempted to use a feature that is not yet implemented.

As a workaround, we are using:

execute <<-SQL.squish
  CREATE INDEX CONCURRENTLY index_users_on_username ON users(username) USING HASH;
SQL

Steps to reproduce

# frozen_string_literal: true

require 'bundler/inline'

gemfile(true) do
  source 'https://rubygems.org'

  gem 'activerecord'

  gem 'activerecord-cockroachdb-adapter'
end

require 'active_record'
require 'activerecord-cockroachdb-adapter'
require 'minitest/autorun'
require 'logger'

# You might want to change the database name for another one.
ActiveRecord::Base.establish_connection('cockroachdb://root@localhost:26255/defaultdb')
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table :users, force: true do |t|
    t.string 'username'
  end
end

class User < ActiveRecord::Base
end

class BugTest < ActiveSupport::TestCase

  def dump_schema
    stream = StringIO.new
    ActiveRecord::SchemaDumper.dump(
      ActiveRecord::Base.connection,
      stream
    )
    stream.string
  end

  def test_schema_migration_with_hash_index
    hash_index_migration = Class.new(ActiveRecord::Migration::Current) do
      def up
        add_index(
          :users,
          :username,
          name:          "index_users_on_username",
          using:         "hash",
          algorithm:     :concurrently,
          if_not_exists: true
        )
      end

      def down
        remove_index :users, name: "index_users_on_username", algorithm: :concurrently, if_exists: true
      end
    end

    hash_index_migration.migrate(:up)

    schema = dump_schema
    assert schema.include?('t.index ["crdb_internal_username_shard_16", "username"], name: "index_users_on_username"'), schema
    assert schema.include?('t.virtual "crdb_internal_username_shard_16"'), schema
    assert schema.include?('t.check_constraint "(crdb_internal_username_shard_16'), schema

    hash_index_migration.migrate(:down)
    schema = dump_schema
    assert_not schema.include?('t.index ["crdb_internal_username_shard_16", "username"], name: "index_users_on_username"'), schema
    assert_not schema.include?('t.virtual "crdb_internal_username_shard_16"'), schema
    assert_not schema.include?('t.check_constraint "(crdb_internal_username_shard_16'), schema

    hash_index_migration.migrate(:up)
  end
end

mmalek-sa avatar Oct 29 '24 00:10 mmalek-sa