NAME
DBIO::PostgreSQL::Test::Conformance - Answers the shared conformance case table for the PostgreSQL driver
VERSION
version 0.900004
SYNOPSIS
use DBIO::PostgreSQL::Test::Conformance;
DBIO::PostgreSQL::Test::Conformance->run('DDL');
done_testing;
DESCRIPTION
The driver's half of the shared case table of DBIO::Test::Conformance (core ADR 0060). Core owns the cases and the runner; this class says how to reach a PostgreSQL server, how to install a declaration into it through DBIO::PostgreSQL::Deploy, and how to read a fact back through DBIO::PostgreSQL::Introspect.
The server is the one DBIO_TEST_PG_DSN, DBIO_TEST_PG_USER and DBIO_TEST_PG_PASS name; without the DSN (or without DBD::Pg) only the declarations are checked. A run needs a role that may create schemas and databases in it: "diff" in DBIO::PostgreSQL::Deploy builds its target in a temporary database.
The namespace of a case is a schema of its own. Every case gets a schema dbio_cf_<pid>_<n> ("conformance_namespace"), and the connection of the case is bound to it three ways: pg_schemas restricts the deploy and the introspector to it, pg_search_path names it (the install script no longer writes that), and the DSN carries it as the connection's search_path (options=-csearch_path=...), which the temporary database of a diff inherits because its DSN is derived from the live one. So a table the case declares without a pg_schema is created in that schema both in the live database and in the target of the diff, and the diff compares nothing else. A schema is dropped with CASCADE in "conformance_cleanup" only when "conformance_namespace" of this run created it; one that was there before is never dropped.
The class names no storage class and never decides the driver, the DSN does (see "conformance_connect").
METHODS
conformance_live_available
True when DBIO_TEST_PG_DSN is set and DBD::Pg loads.
conformance_connect
Names the schema of the case, loads the PostgreSQL schema component into the case's schema class and the PostgreSQL::Result component into each of its result classes, with pg_fk_constraints_from_rels switched on (the default, set here so the case does not depend on it) -- the case declares a belongs_to and expects the server to hold the key -- binds the schema class to its namespace (see "DESCRIPTION") and connects. storage_type is not set by this class beyond what the component does: the DSN is PostgreSQL's.
conformance_namespace
Creates the case's schema and returns it, with the other schemas the case's sources are qualified with (they are created by the install, from pg_schemas), as the token for "conformance_cleanup". A qualifying schema that is in the database already ends the case: it is not this run's to drop. The case's schema is marked as the run's own only when it was not in the database before; the qualifying schemas are marked once the check above found them absent.
conformance_install
Installs the declaration with $schema->deploy, the public entry point, which hands over to "install" in DBIO::PostgreSQL::Deploy.
conformance_cleanup
Drops with CASCADE the schemas of the token that "conformance_namespace" of this run created, and disconnects. Nothing else is dropped: without a token ("conformance_namespace" threw) or for a schema that was not marked as created, no schema is touched. Where the case's own connection is no longer usable, the marked schemas are dropped through a connection of their own.
conformance_diff_is_empty
True when "diff" in DBIO::PostgreSQL::Deploy of the installed schema against the same declaration has no changes.
conformance_upgrade
Connects the class of the target declaration to the namespace of the case -- the schema the installed one works in -- and runs "upgrade" in DBIO::PostgreSQL::Deploy, the public entry point, through it. The namespace, the schemas the target qualifies with and the marks of what this run created pass from the class of the installed schema to the target's, so "conformance_cleanup" of the schema returned drops them; a schema the target qualifies with that is in the database already ends the case. The runner closes the installed schema itself. A refusal of the diff is thrown from here as it came.
conformance_deploy
The seam of the deploy cases of the Diff list (diff-deploy-inherited, diff-deploy-dry-run, diff-deploy-destructive-guard): connects the class of the target declaration as "conformance_upgrade" does and returns DBIO::PostgreSQL::Deploy->new(schema => $to) over it, without running anything. The runner calls apply and upgrade on it.
conformance_name_kinds
{ schema => 1, extension => 1 }: the connect key schema (a namespace) and the name of a database extension in pg_extensions. There is no library: the one place the driver writes a library, LOAD 'library' for the activation of an extension ("_apply_connection_schema" in DBIO::PostgreSQL::Storage), goes through quote_literal, but a library is a file the server has to find, there is no catalog that lists a loaded one, and a name the Names list hands over is never one that exists -- the only answer would be the server's own error, which the list holds a failure. The quoting is held by a test of its own (t/146-extension-activation-live.t).
conformance_apply_name
$class->conformance_apply_name(schema => 'a"b');
$class->conformance_apply_name(extension => 'a b');
The whole of one case of the Names list. schema: connects a fresh schema class with the connect key schema => $name, installs it (which creates the namespace), reads the namespace back from DBIO::PostgreSQL::Introspect, drops it again and disconnects. extension: declares $name with pg_extensions, connects and installs, reads the installed extensions back and drops the one it made. Returns the name as introspection shows it.
The answers: a name is set and read back as given (a"b, a b, a\b as a schema), or refused with a DBIO::Exception before a statement that could meet it -- ;, a line break and NUL by the check of core, an extension that this server does not have ("_check_extensions_available" in DBIO::PostgreSQL::Deploy, which reads pg_available_extensions with a bind and names the extension in the message with the identifier rule). An extension name the Names list hands over is never one the server can install, so each of these cases ends as a refusal. A namespace or an extension that is in the database already is not the case's to use or drop, and ends it with a plain error.
conformance_answered_through
The table versions the answers were written against, per area: { DDL => 2, Diff => 4, Bind => 1, Names => 1 }, every list as it stands (version 2 of the DDL list splits the type-size case into ddl-type-size-char and ddl-type-size-bit, version 2 of the Diff list splits U13 into diff-constraint-changed and diff-fk-action-changed, both answered right). Every case of all three is answered: correctly, or by a declared refusal or deviation of "conformance_refusals".
Version 3 of the Diff list replaces diff-column-dropped-with-index by diff-indexed-column-dropped; it runs.
Version 4 adds the three deploy cases diff-deploy-inherited, diff-deploy-dry-run and diff-deploy-destructive-guard, which run through "conformance_deploy": apply and upgrade are the base's, a drop is refused without allow_destructive, and dry_run executes nothing.
conformance_refusals
One deviation is declared, ddl-default-digit-string (maintainer decision 2026-10-12). The column is char(5) with the default '007', and PostgreSQL pads a char(n) value with blanks to its length, so the row reads back as '007 '. That is the type's definition: the driver does not trim, and the case does not either. The declared fact is the runner's own failure text of that read-back, so a different wrong value is not hidden behind the declaration.
diff-column-added-not-null-populated and diff-not-null-over-nulls: the server cannot give the rows a table holds a value for a new NOT NULL column without a default, nor accept a NOT NULL over a NULL. "_refuse_unfillable" in DBIO::PostgreSQL::Deploy refuses both before the first statement, naming table and column. The reasons are PostgreSQL's: ALTER TABLE ... ADD COLUMN ... NOT NULL without a default fails on a table with rows because the new column would be NULL there, and SET NOT NULL scans the table and fails on a NULL (https://www.postgresql.org/docs/current/sql-altertable.html, parameters ADD COLUMN and SET/DROP NOT NULL).
No other refusals are declared.
The driver answers the foreign key cases of the diff list of ADR 0060 (appendix B) -- U4 (a table with a foreign key added), U11 (a foreign key dropped) and U12 (a foreign key onto a unique key created in the same upgrade) -- in t/160-diff-foreign-key-live.t, claims 1, 4 and 5. Core's table has no diff cases in code yet, so a declaration by their names would be refused as an unknown case.
conformance_fact
Reads one fact through DBIO::PostgreSQL::Introspect, restricted to the case's schema (or, for table_in_namespace, to the namespace asked); the vocabulary is the one of "Facts" in DBIO::Test::Conformance.
SEE ALSO
DBIO::Test::Conformance - the runner and the contract of the seams
DBIO::Test::Conformance::Cases::DDL - the DDL case list
DBIO::PostgreSQL::Deploy - install and diff, as the cases reach them
DBIO::PostgreSQL::Introspect - what the facts are read through
AUTHOR
DBIO & DBIx::Class Authors
COPYRIGHT AND LICENSE
Copyright (C) 2026 DBIO Authors Portions Copyright (C) 2005-2025 DBIx::Class Authors Based on DBIx::Class, heavily modified.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.