Skip to content

Conversation

@oxzi
Copy link
Member

@oxzi oxzi commented Oct 14, 2025

The incident_contact table misses a primary key. While technically not relevant, certain Galera setups seems to be configured with "innodb_force_primary_key = 'ON'", rejecting tables without a primary key constraint.

This change adds a primary key to the table.

> $ docker run --name mariadb -e MARIADB_ROOT_PASSWORD=supersicher -d mariadb:latest
>
> $ docker exec mariadb mariadb --password=supersicher -e "set @@GLOBAL.innodb_force_primary_key = 'ON';"
> $ docker exec mariadb mariadb --password=supersicher -e "show variables like 'innodb_force_primary_key'\G"
> *************************** 1. row ***************************
> Variable_name: innodb_force_primary_key
>         Value: ON
>
> $ docker exec mariadb mariadb --password=supersicher -e "create database notifications;"
>
> $ docker exec -i mariadb mariadb --password=supersicher notifications < schema/mysql/schema.sql
> --------------
> CREATE TABLE incident_contact (
>     incident_id bigint NOT NULL,
>     contact_id bigint,
>     contactgroup_id bigint,
>     schedule_id bigint,
>     role enum('recipient', 'subscriber', 'manager'),
>
>     CONSTRAINT uk_incident_contact_incident_id_contact_id UNIQUE (incident_id, contact_id),
>     CONSTRAINT uk_incident_contact_incident_id_contactgroup_id UNIQUE (incident_id, contactgroup_id),
>     CONSTRAINT uk_incident_contact_incident_id_schedule_id UNIQUE (incident_id, schedule_id),
>
>     CONSTRAINT ck_incident_contact_has_exactly_one_recipient CHECK (if(contact_id IS NULL, 0, 1) + if(contactgroup_id IS NULL, 0, 1) + if(schedule_id IS NULL, 0, 1) = 1),
>     CONSTRAINT ck_incident_contact_role_notnull CHECK (role IS NOT NULL),
>     CONSTRAINT fk_incident_contact_incident FOREIGN KEY (incident_id) REFERENCES incident(id),
>     CONSTRAINT fk_incident_contact_contact FOREIGN KEY (contact_id) REFERENCES contact(id),
>     CONSTRAINT fk_incident_contact_contactgroup FOREIGN KEY (contactgroup_id) REFERENCES contactgroup(id),
>     CONSTRAINT fk_incident_contact_schedule FOREIGN KEY (schedule_id) REFERENCES schedule(id)
> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
> --------------
>
> ERROR 1173 (42000) at line 352: This table type requires a primary key
>
> $ git diff schema/mysql/schema.sql
> diff --git a/schema/mysql/schema.sql b/schema/mysql/schema.sql
> index 8688db8..f7734e1 100644
> --- a/schema/mysql/schema.sql
> +++ b/schema/mysql/schema.sql
> @@ -356,6 +356,8 @@ CREATE TABLE incident_contact (
>      schedule_id bigint,
>      role enum('recipient', 'subscriber', 'manager'), -- NOT NULL is enforced via CHECK not to default to 'recipient'
>
> +    CONSTRAINT pk_incident_contact PRIMARY KEY (incident_id, contact_id, contactgroup_id, schedule_id),
> +
>      CONSTRAINT uk_incident_contact_incident_id_contact_id UNIQUE (incident_id, contact_id),
>      CONSTRAINT uk_incident_contact_incident_id_contactgroup_id UNIQUE (incident_id, contactgroup_id),
>      CONSTRAINT uk_incident_contact_incident_id_schedule_id UNIQUE (incident_id, schedule_id),
>
> $ docker exec mariadb mariadb --password=supersicher -e "drop database notifications; create database notifications;"
>
> $ docker exec -i mariadb mariadb --password=supersicher notifications < schema/mysql/schema.sql

Fixes #340.


Based on top of #324, which already starts with a schema upgrade file. Draft until #324 got merged.

The incident_contact table misses a primary key. While technically not
relevant, certain Galera setups seems to be configured with
"innodb_force_primary_key = 'ON'", rejecting tables without a primary
key constraint.

This change adds a primary key to the table.

> $ docker run --name mariadb -e MARIADB_ROOT_PASSWORD=supersicher -d mariadb:latest
>
> $ docker exec mariadb mariadb --password=supersicher -e "set @@GLOBAL.innodb_force_primary_key = 'ON';"
> $ docker exec mariadb mariadb --password=supersicher -e "show variables like 'innodb_force_primary_key'\G"
> *************************** 1. row ***************************
> Variable_name: innodb_force_primary_key
>         Value: ON
>
> $ docker exec mariadb mariadb --password=supersicher -e "create database notifications;"
>
> $ docker exec -i mariadb mariadb --password=supersicher notifications < schema/mysql/schema.sql
> --------------
> CREATE TABLE incident_contact (
>     incident_id bigint NOT NULL,
>     contact_id bigint,
>     contactgroup_id bigint,
>     schedule_id bigint,
>     role enum('recipient', 'subscriber', 'manager'),
>
>     CONSTRAINT uk_incident_contact_incident_id_contact_id UNIQUE (incident_id, contact_id),
>     CONSTRAINT uk_incident_contact_incident_id_contactgroup_id UNIQUE (incident_id, contactgroup_id),
>     CONSTRAINT uk_incident_contact_incident_id_schedule_id UNIQUE (incident_id, schedule_id),
>
>     CONSTRAINT ck_incident_contact_has_exactly_one_recipient CHECK (if(contact_id IS NULL, 0, 1) + if(contactgroup_id IS NULL, 0, 1) + if(schedule_id IS NULL, 0, 1) = 1),
>     CONSTRAINT ck_incident_contact_role_notnull CHECK (role IS NOT NULL),
>     CONSTRAINT fk_incident_contact_incident FOREIGN KEY (incident_id) REFERENCES incident(id),
>     CONSTRAINT fk_incident_contact_contact FOREIGN KEY (contact_id) REFERENCES contact(id),
>     CONSTRAINT fk_incident_contact_contactgroup FOREIGN KEY (contactgroup_id) REFERENCES contactgroup(id),
>     CONSTRAINT fk_incident_contact_schedule FOREIGN KEY (schedule_id) REFERENCES schedule(id)
> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
> --------------
>
> ERROR 1173 (42000) at line 352: This table type requires a primary key
>
> $ git diff schema/mysql/schema.sql
> diff --git a/schema/mysql/schema.sql b/schema/mysql/schema.sql
> index 8688db8..f7734e1 100644
> --- a/schema/mysql/schema.sql
> +++ b/schema/mysql/schema.sql
> @@ -356,6 +356,8 @@ CREATE TABLE incident_contact (
>      schedule_id bigint,
>      role enum('recipient', 'subscriber', 'manager'), -- NOT NULL is enforced via CHECK not to default to 'recipient'
>
> +    CONSTRAINT pk_incident_contact PRIMARY KEY (incident_id, contact_id, contactgroup_id, schedule_id),
> +
>      CONSTRAINT uk_incident_contact_incident_id_contact_id UNIQUE (incident_id, contact_id),
>      CONSTRAINT uk_incident_contact_incident_id_contactgroup_id UNIQUE (incident_id, contactgroup_id),
>      CONSTRAINT uk_incident_contact_incident_id_schedule_id UNIQUE (incident_id, schedule_id),
>
> $ docker exec mariadb mariadb --password=supersicher -e "drop database notifications; create database notifications;"
>
> $ docker exec -i mariadb mariadb --password=supersicher notifications < schema/mysql/schema.sql

Fixes #340.
@oxzi oxzi added this to the 0.2.0 milestone Oct 14, 2025
@cla-bot cla-bot bot added the cla/signed CLA is signed by all contributors of a PR label Oct 14, 2025
schedule_id bigint,
role enum('recipient', 'subscriber', 'manager'), -- NOT NULL is enforced via CHECK not to default to 'recipient'

CONSTRAINT pk_incident_contact PRIMARY KEY (incident_id, contact_id, contactgroup_id, schedule_id),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MySQL documentation states for primary keys:

A unique index where all key columns must be defined as NOT NULL. If they are not explicitly declared as NOT NULL, MySQL declares them so implicitly (and silently).

Thus, this change would (silently) change these fields to NOT NULL, effectively violating ck_incident_contact_has_exactly_one_recipient for every insert. Sigh.

I will take another look at this at another time.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FTR, same applies to PostgreSQL:

Adding a primary key will automatically create a unique B-tree index on the column or group of columns listed in the primary key, and will force the column(s) to be marked NOT NULL.

@oxzi oxzi removed this from the 0.2.0 milestone Oct 21, 2025
@oxzi oxzi closed this Oct 21, 2025
@oxzi oxzi deleted the schema-pk-incident_contact branch October 21, 2025 08:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla/signed CLA is signed by all contributors of a PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants