-
Couldn't load subscription status.
- Fork 2
Description
Codd seems to have issues with schema specifications in SQL depending on the search path. For example, consider the following:
ALTER TABLE ONLY public.email
ADD CONSTRAINT email_employee__id_fkey
FOREIGN KEY (employee__id)
REFERENCES public.employee(id);This code specifies the public schema, but doing so is not required when that schema is at the front of the search path. Indeed, the default search path is "$user", public and specifying public is not required (when a schema named after the current user does not exist). Note that some people customize the search path to include their schema, so this is not just an issue with public.
PostgreSQL dump files created with pg_dump set the search path to the empty string in order to avoid potential issues with an unknown (customized) search path, and they consistently specify the schema. Codd can add a dump file without issue, but verification then results in discrepancies due to inconsistent schema specifications when a schema that is in the search path is used.
As an example, please see my debugging log below.
(1) Create the test schema
Run a test database:
$ docker run \
--detach \
--name "pg_codd" \
--publish "127.0.0.1:5432:5432" \
--env POSTGRES_DB="postgres" \
--env POSTGRES_USER="postgres" \
--env POSTGRES_PASSWORD="password" \
"postgres:11-alpine"
Create a test project:
$ mkdir /tmp/codd-public
$ cd /tmp/codd-public
$ mkdir bin config sql-migrations expected-schema
$ wget -O bin/codd \
https://github.com/mzabani/codd/releases/download/v0.1.1/codd
$ chmod 0755 bin/codd
Configure settings in config/codd-dev.sh:
export CODD_CONNECTION=postgres://postgres:[email protected]/postgres
export CODD_EXPECTED_SCHEMA_DIR=expected-schema
export CODD_MIGRATION_DIRS=sql-migrationsLoad settings in the current shell:
$ source config/codd-dev.sh
Create a migration in 0001-init-codd.sql that allows Codd to initialize a database without having to create it (reference):
-- codd: no-txn
SELECT 1;Add the migration, initializing the database:
$ ./bin/codd add 0001-init-codd.sql
Create a migration in 0002-init-schema.sql that initializes the schema:
CREATE TABLE public.employee (
id SERIAL NOT NULL,
name TEXT NOT NULL,
CONSTRAINT employee_pkey PRIMARY KEY (id)
);
CREATE TABLE public.email (
employee__id INTEGER NOT NULL,
address TEXT NOT NULL,
CONSTRAINT email_pkey PRIMARY KEY (employee__id, address),
CONSTRAINT email_employee__id_fkey
FOREIGN KEY (employee__id)
REFERENCES public.employee(id)
);
CREATE UNIQUE INDEX email_lower_address_unique
ON public.email(lower(address));Note that specifying public here does not cause any problems.
Add the migration:
$ ./bin/codd add 0002-init-schema.sql
Verify the schema:
$ ./bin/codd verify-schema
[Info] Database and expected schemas match.
Dump the schema to dump.sql:
$ docker exec pg_codd \
pg_dump \
--host 127.0.0.1 \
--port 5432 \
--username postgres \
--no-password \
--schema-only \
--exclude-schema=codd_schema \
--quote-all-identifiers \
postgres \
> dump.sql
(2) Start over using the dumped schema
Stop the database and reset the project schema/migrations:
$ docker stop pg_codd
$ docker rm pg_codd
$ rm -rf expected-schema/*
$ mv sql-migrations/*-0001-init-codd.sql 0001-init-codd.sql
$ mv sql-migrations/*-0002-init-schema.sql 0002-init-schema.sql
Start a new (empty) database:
$ docker run \
--detach \
--name "pg_codd" \
--publish "127.0.0.1:5432:5432" \
--env POSTGRES_DB="postgres" \
--env POSTGRES_USER="postgres" \
--env POSTGRES_PASSWORD="password" \
"postgres:11-alpine"
Add the first migration, initializing the database:
$ ./bin/codd add 0001-init-codd.sql
Add the dumped schema:
$ ./bin/codd add dump.sql
Verifying the schema now results in an error:
$ ./bin/codd verify-schema
[Error] DB and expected schemas do not match. Differing objects and their current DB schemas are:
{
"schemas/public/tables/email/constraints/email_employee__id_fkey": [
"different-schemas",
{
"deferrable": false,
"deferred": false,
"definition": "FOREIGN KEY (employee__id) REFERENCES employee(id)",
"fk_deltype": "a",
"fk_matchtype": "s",
"fk_ref_table": "employee",
"fk_updtype": "a",
"inhcount": 0,
"local": true,
"noinherit": true,
"parent_constraint": null,
"supporting_index": "employee_pkey",
"type": "f",
"validated": true
}
],
"schemas/public/tables/employee/cols/id": [
"different-schemas",
{
"collation": null,
"collation_nsp": null,
"default": "nextval('employee_id_seq'::regclass)",
"hasdefault": true,
"identity": "",
"inhcount": 0,
"local": true,
"notnull": true,
"order": 1,
"privileges": null,
"type": "int4"
}
]
}Query the expected email_employee__id_fkey state:
$ cat expected-schema/schemas/public/tables/email/constraints/email_employee__id_fkey \
| python -m json.tool
{
"deferrable": false,
"deferred": false,
"definition": "FOREIGN KEY (employee__id) REFERENCES public.employee(id)",
"fk_deltype": "a",
"fk_matchtype": "s",
"fk_ref_table": "employee",
"fk_updtype": "a",
"inhcount": 0,
"local": true,
"noinherit": true,
"parent_constraint": null,
"supporting_index": "employee_pkey",
"type": "f",
"validated": true
}The difference is the schema specification:
- "definition": "FOREIGN KEY (employee__id) REFERENCES public.employee(id)",
+ "definition": "FOREIGN KEY (employee__id) REFERENCES employee(id)",Query the expected employee.id state:
$ cat expected-schema/schemas/public/tables/employee/cols/id \
| python -m json.tool
{
"collation": null,
"collation_nsp": null,
"default": "nextval('public.employee_id_seq'::regclass)",
"hasdefault": true,
"identity": "",
"inhcount": 0,
"local": true,
"notnull": true,
"order": 1,
"privileges": null,
"type": "int4"
}The difference is the schema specification:
- "default": "nextval('employee_id_seq'::regclass)",
+ "default": "nextval('public.employee_id_seq'::regclass)",(3) Start over using a dumped schema that is patched
Stop the database and reset the project schema/migrations:
$ docker stop pg_codd
$ docker rm pg_codd
$ rm -rf expected-schema/*
$ mv sql-migrations/*-0001-init-codd.sql 0001-init-codd.sql
$ mv sql-migrations/*-dump.sql dump.sql
The dump file includes the following settings:
$ sed -n '8,21p;22q' dump.sql
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
SET default_tablespace = '';
SET default_with_oids = false;This is the setting that clears the search path (on line 13):
SELECT pg_catalog.set_config('search_path', '', false);Create a patched dump with this setting commented out:
$ sed '13s/^/-- /' dump.sql > dump-patched.sql
Start a new (empty) database:
$ docker run \
--detach \
--name "pg_codd" \
--publish "127.0.0.1:5432:5432" \
--env POSTGRES_DB="postgres" \
--env POSTGRES_USER="postgres" \
--env POSTGRES_PASSWORD="password" \
"postgres:11-alpine"
Add the first migration, initializing the database:
$ ./bin/codd add 0001-init-codd.sql
Add the patched dump:
$ ./bin/codd add dump-patched.sql
Verify the schema:
$ ./bin/codd verify-schema
[Info] Database and expected schemas match.