-
Notifications
You must be signed in to change notification settings - Fork 333
Description
Environment
- Elixir version: v1.11.2
- Database and version: MariaDB 10.1.48
- Ecto version: v3.6.1
- Database adapter and version: myxql, v0.5.1
- Operating system: macOS
Current behavior
Adding a :bigserial column to a table that already has a primary_key/autogenerated column throws an error.
# migration
create table(:some_audit_table, primary_key: false) do
add(:audit_id, :bigserial, primary_key: true, null: false)
add(:id, :bigserial, null: false) # id of some audited table, reference() wouldn't make sense here
...
end$> mix ecto.migrate --log-sql
[debug] QUERY ERROR db=1.7ms queue=2.1ms idle=49.2ms CREATE TABLE `some_audit_table` (`audit_id` bigint unsigned not null auto_increment NOT NULL, `id` bigint unsigned not null auto_increment NOT NULL ..., PRIMARY KEY (`audit_id`)) ENGINE = INNODB
** (MyXQL.Error) (1075) Incorrect table definition; there can be only one auto column and it must be defined as a keyExpected behavior
For the migration to not quietly make a second autoincrement column when it's a regular :bigserial (i.e. not a reference())
I'll note though that is this is tricky, because I understand that SERIAL is an alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE in MySQL/MariaDB, and this setting makes it easier to catch early, before you've accidentally added a primary key to a table you had intended to have some other kind of primary key.
After looking at the Ecto.Adapters.MyXQL.Connection and Ecto.Adapters.Postgres.Connection adapters I noticed that both adapters mention in an error for ecto_to_db/2 that the type can be an atom, string, or tuple, but when I set the type to be a string, e.g. add(:id, "bigint unsigned", null: false), I get the following error:
** (FunctionClauseError) no function clause matching in Ecto.Migration.validate_type!/1
The following arguments were given to Ecto.Migration.validate_type!/1:
# 1
"bigint unsigned"
Attempted function clauses (showing 5 out of 5):
defp validate_type!(:datetime)
defp validate_type!(type) when is_atom(type)
defp validate_type!({type, subtype}) when is_atom(type) and is_atom(subtype)
defp validate_type!({type, subtype}) when is_atom(type) and is_tuple(subtype)
defp validate_type!(%Ecto.Migration.Reference{} = reference)If I switch the type to a "stringy" atom, (:"bigint unsigned") the migration works as expected, but that seems like a bad idea in the long-run since it relies on the implementation of a private function.
With the error text from the adapters, I'd assume that being able to set the type using a string would be something that should've been supported but I wasn't sure.
If this would be better as a proposal discussion on the Google Forum I can post this there.
I'm also happy to make a PR or discuss whether this even is a bug. I'm not fluent in much of the data mapping logic, but I think I understand the migration/runner/connection logic a bit more now.
Thank you for your time 😃